| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #ifndef CHROME_BROWSER_MEMORY_TAB_MANAGER_DELEGATE_CHROMEOS_H_ | |
| 6 #define CHROME_BROWSER_MEMORY_TAB_MANAGER_DELEGATE_CHROMEOS_H_ | |
| 7 | |
| 8 #include <memory> | |
| 9 #include <string> | |
| 10 #include <utility> | |
| 11 #include <vector> | |
| 12 | |
| 13 #include "base/containers/hash_tables.h" | |
| 14 #include "base/gtest_prod_util.h" | |
| 15 #include "base/logging.h" | |
| 16 #include "base/macros.h" | |
| 17 #include "base/memory/weak_ptr.h" | |
| 18 #include "base/process/process.h" | |
| 19 #include "base/timer/timer.h" | |
| 20 #include "chrome/browser/chromeos/arc/process/arc_process.h" | |
| 21 #include "chrome/browser/memory/tab_manager.h" | |
| 22 #include "chrome/browser/memory/tab_stats.h" | |
| 23 #include "chrome/browser/ui/browser_list_observer.h" | |
| 24 #include "chromeos/dbus/debug_daemon_client.h" | |
| 25 #include "components/arc/common/process.mojom.h" | |
| 26 #include "components/arc/instance_holder.h" | |
| 27 #include "content/public/browser/notification_observer.h" | |
| 28 #include "content/public/browser/notification_registrar.h" | |
| 29 #include "ui/wm/public/activation_change_observer.h" | |
| 30 | |
| 31 namespace memory { | |
| 32 | |
| 33 // Possible types of Apps/Tabs processes. From most important to least | |
| 34 // important. | |
| 35 enum class ProcessType { | |
| 36 // Conceptually, the system cannot have both FOCUSED_TAB and FOCUSED_APP at | |
| 37 // the same time, but because Chrome cannot retrieve FOCUSED_APP status | |
| 38 // synchronously, Chrome may still see both at the same time. When that | |
| 39 // happens, treat FOCUSED_TAB as the most important since the (synchronously | |
| 40 // retrieved) tab information is more reliable and up-to-date. | |
| 41 FOCUSED_TAB = 1, | |
| 42 FOCUSED_APP = 2, | |
| 43 | |
| 44 // Important apps are protected in two ways: 1) Chrome never kills them, and | |
| 45 // 2) the kernel is still allowed to kill them, but their OOM adjustment | |
| 46 // scores are better than BACKGROUND_TABs and BACKGROUND_APPs. | |
| 47 IMPORTANT_APP = 3, | |
| 48 | |
| 49 BACKGROUND_TAB = 4, | |
| 50 BACKGROUND_APP = 5, | |
| 51 UNKNOWN_TYPE = 6, | |
| 52 }; | |
| 53 | |
| 54 // The Chrome OS TabManagerDelegate is responsible for keeping the | |
| 55 // renderers' scores up to date in /proc/<pid>/oom_score_adj. | |
| 56 class TabManagerDelegate : public wm::ActivationChangeObserver, | |
| 57 public content::NotificationObserver, | |
| 58 public chrome::BrowserListObserver { | |
| 59 public: | |
| 60 class MemoryStat; | |
| 61 | |
| 62 explicit TabManagerDelegate(const base::WeakPtr<TabManager>& tab_manager); | |
| 63 | |
| 64 TabManagerDelegate(const base::WeakPtr<TabManager>& tab_manager, | |
| 65 TabManagerDelegate::MemoryStat* mem_stat); | |
| 66 | |
| 67 ~TabManagerDelegate() override; | |
| 68 | |
| 69 void OnBrowserSetLastActive(Browser* browser) override; | |
| 70 | |
| 71 // aura::ActivationChangeObserver overrides. | |
| 72 void OnWindowActivated(wm::ActivationChangeObserver::ActivationReason reason, | |
| 73 aura::Window* gained_active, | |
| 74 aura::Window* lost_active) override; | |
| 75 | |
| 76 // Kills a process on memory pressure. | |
| 77 void LowMemoryKill(const TabStatsList& tab_stats); | |
| 78 | |
| 79 // Returns oom_score_adj of a process if the score is cached by |this|. | |
| 80 // If couldn't find the score in the cache, returns -1001 since the valid | |
| 81 // range of oom_score_adj is [-1000, 1000]. | |
| 82 int GetCachedOomScore(base::ProcessHandle process_handle); | |
| 83 | |
| 84 // Called when the timer fires, sets oom_adjust_score for all renderers. | |
| 85 void AdjustOomPriorities(const TabStatsList& tab_list); | |
| 86 | |
| 87 // Returns true if the process has recently been killed. | |
| 88 // Virtual for unit testing. | |
| 89 virtual bool IsRecentlyKilledArcProcess(const std::string& process_name, | |
| 90 const base::TimeTicks& now); | |
| 91 | |
| 92 protected: | |
| 93 // Kills an ARC process. Returns true if the kill request is successfully sent | |
| 94 // to Android. Virtual for unit testing. | |
| 95 virtual bool KillArcProcess(const int nspid); | |
| 96 | |
| 97 // Kills a tab. Returns true if the tab is killed successfully. | |
| 98 // Virtual for unit testing. | |
| 99 virtual bool KillTab(int64_t tab_id); | |
| 100 | |
| 101 // Get debugd client instance. Virtual for unit testing. | |
| 102 virtual chromeos::DebugDaemonClient* GetDebugDaemonClient(); | |
| 103 | |
| 104 private: | |
| 105 FRIEND_TEST_ALL_PREFIXES(TabManagerDelegateTest, CandidatesSorted); | |
| 106 FRIEND_TEST_ALL_PREFIXES(TabManagerDelegateTest, | |
| 107 CandidatesSortedWithFocusedAppAndTab); | |
| 108 FRIEND_TEST_ALL_PREFIXES(TabManagerDelegateTest, | |
| 109 DoNotKillRecentlyKilledArcProcesses); | |
| 110 FRIEND_TEST_ALL_PREFIXES(TabManagerDelegateTest, IsRecentlyKilledArcProcess); | |
| 111 FRIEND_TEST_ALL_PREFIXES(TabManagerDelegateTest, KillMultipleProcesses); | |
| 112 FRIEND_TEST_ALL_PREFIXES(TabManagerDelegateTest, SetOomScoreAdj); | |
| 113 | |
| 114 class Candidate; | |
| 115 class FocusedProcess; | |
| 116 | |
| 117 friend std::ostream& operator<<(std::ostream& out, | |
| 118 const Candidate& candidate); | |
| 119 | |
| 120 // content::NotificationObserver: | |
| 121 void Observe(int type, | |
| 122 const content::NotificationSource& source, | |
| 123 const content::NotificationDetails& details) override; | |
| 124 | |
| 125 // Pair to hold child process host id and ProcessHandle. | |
| 126 typedef std::pair<int, base::ProcessHandle> ProcessInfo; | |
| 127 | |
| 128 // Cache OOM scores in memory. | |
| 129 typedef base::hash_map<base::ProcessHandle, int> ProcessScoreMap; | |
| 130 | |
| 131 // A map from an ARC process name to a monotonic timestamp when it's killed. | |
| 132 typedef base::hash_map<std::string, base::TimeTicks> KilledArcProcessesMap; | |
| 133 | |
| 134 // Get the list of candidates to kill, sorted by descending importance. | |
| 135 static std::vector<Candidate> GetSortedCandidates( | |
| 136 const TabStatsList& tab_list, | |
| 137 const std::vector<arc::ArcProcess>& arc_processes); | |
| 138 | |
| 139 // Sets OOM score for the focused tab. | |
| 140 void OnFocusTabScoreAdjustmentTimeout(); | |
| 141 | |
| 142 // Kills a process after getting all info of tabs and apps. | |
| 143 void LowMemoryKillImpl(const TabStatsList& tab_list, | |
| 144 const std::vector<arc::ArcProcess>& arc_processes); | |
| 145 | |
| 146 // Public interface to adjust OOM scores. | |
| 147 void AdjustOomPriorities(const TabStatsList& tab_list, | |
| 148 const std::vector<arc::ArcProcess>& arc_processes); | |
| 149 | |
| 150 // Sets a newly focused tab the highest priority process if it wasn't. | |
| 151 void AdjustFocusedTabScore(base::ProcessHandle pid); | |
| 152 | |
| 153 // Called by AdjustOomPriorities. Runs on the main thread. | |
| 154 void AdjustOomPrioritiesImpl( | |
| 155 const TabStatsList& tab_list, | |
| 156 const std::vector<arc::ArcProcess>& arc_processes); | |
| 157 | |
| 158 // Sets OOM score for processes in the range [|rbegin|, |rend|) to integers | |
| 159 // distributed evenly in [|range_begin|, |range_end|). | |
| 160 // The new score is set in |new_map|. | |
| 161 void DistributeOomScoreInRange( | |
| 162 std::vector<TabManagerDelegate::Candidate>::const_iterator begin, | |
| 163 std::vector<TabManagerDelegate::Candidate>::const_iterator end, | |
| 164 int range_begin, | |
| 165 int range_end, | |
| 166 ProcessScoreMap* new_map); | |
| 167 | |
| 168 // Changes |candidates|' OOM scores to |score|. The new scores are set in | |
| 169 // |new_map|. | |
| 170 void SetOomScore(const std::vector<TabManagerDelegate::Candidate>& candidates, | |
| 171 int score, | |
| 172 ProcessScoreMap* new_map); | |
| 173 | |
| 174 // Initiates an oom priority adjustment. | |
| 175 void ScheduleEarlyOomPrioritiesAdjustment(); | |
| 176 | |
| 177 // Returns a TimeDelta object that represents a minimum delay for killing | |
| 178 // the same ARC process again. ARC processes sometimes respawn right after | |
| 179 // being killed. In that case, killing them every time is just a waste of | |
| 180 // resources. | |
| 181 static constexpr base::TimeDelta GetArcRespawnKillDelay() { | |
| 182 return base::TimeDelta::FromSeconds(60); | |
| 183 } | |
| 184 | |
| 185 // The lowest OOM adjustment score that will make the process non-killable. | |
| 186 static const int kLowestOomScore; | |
| 187 | |
| 188 // Holds a reference to the owning TabManager. | |
| 189 const base::WeakPtr<TabManager> tab_manager_; | |
| 190 | |
| 191 // Registrar to receive renderer notifications. | |
| 192 content::NotificationRegistrar registrar_; | |
| 193 | |
| 194 // Timer to guarantee that the tab or app is focused for a certain amount of | |
| 195 // time. | |
| 196 base::OneShotTimer focus_process_score_adjust_timer_; | |
| 197 // Holds the info of the newly focused tab or app. Its OOM score would be | |
| 198 // adjusted when |focus_process_score_adjust_timer_| is expired. | |
| 199 std::unique_ptr<FocusedProcess> focused_process_; | |
| 200 | |
| 201 // Map maintaining the process handle - oom_score mapping. | |
| 202 ProcessScoreMap oom_score_map_; | |
| 203 | |
| 204 // Map maintaing ARC process names and their last killed time. | |
| 205 KilledArcProcessesMap recently_killed_arc_processes_; | |
| 206 | |
| 207 // Util for getting system memory status. | |
| 208 std::unique_ptr<TabManagerDelegate::MemoryStat> mem_stat_; | |
| 209 | |
| 210 // Weak pointer factory used for posting tasks to other threads. | |
| 211 base::WeakPtrFactory<TabManagerDelegate> weak_ptr_factory_; | |
| 212 | |
| 213 DISALLOW_COPY_AND_ASSIGN(TabManagerDelegate); | |
| 214 }; | |
| 215 | |
| 216 // On ARC enabled machines, either a tab or an app could be a possible | |
| 217 // victim of low memory kill process. This is a helper class which holds a | |
| 218 // pointer to an app or a tab (but not both) to facilitate prioritizing the | |
| 219 // victims. | |
| 220 class TabManagerDelegate::Candidate { | |
| 221 public: | |
| 222 explicit Candidate(const TabStats* tab) | |
| 223 : tab_(tab), app_(nullptr), process_type_(GetProcessTypeInternal()) { | |
| 224 DCHECK(tab_); | |
| 225 } | |
| 226 explicit Candidate(const arc::ArcProcess* app) | |
| 227 : tab_(nullptr), app_(app), process_type_(GetProcessTypeInternal()) { | |
| 228 DCHECK(app_); | |
| 229 } | |
| 230 | |
| 231 // Move-only class. | |
| 232 Candidate(Candidate&&) = default; | |
| 233 Candidate& operator=(Candidate&& other); | |
| 234 | |
| 235 // Higher priority first. | |
| 236 bool operator<(const Candidate& rhs) const; | |
| 237 | |
| 238 const TabStats* tab() const { return tab_; } | |
| 239 const arc::ArcProcess* app() const { return app_; } | |
| 240 ProcessType process_type() const { return process_type_; } | |
| 241 | |
| 242 private: | |
| 243 // Derive process type for this candidate. Used to initialize |process_type_|. | |
| 244 ProcessType GetProcessTypeInternal() const; | |
| 245 | |
| 246 const TabStats* tab_; | |
| 247 const arc::ArcProcess* app_; | |
| 248 ProcessType process_type_; | |
| 249 DISALLOW_COPY_AND_ASSIGN(Candidate); | |
| 250 }; | |
| 251 | |
| 252 // A thin wrapper over library process_metric.h to get memory status so unit | |
| 253 // test get a chance to mock out. | |
| 254 class TabManagerDelegate::MemoryStat { | |
| 255 public: | |
| 256 MemoryStat() {} | |
| 257 virtual ~MemoryStat() {} | |
| 258 | |
| 259 // Returns target size of memory to free given current memory pressure and | |
| 260 // pre-configured low memory margin. | |
| 261 virtual int TargetMemoryToFreeKB(); | |
| 262 | |
| 263 // Returns estimated memory to be freed if the process |pid| is killed. | |
| 264 virtual int EstimatedMemoryFreedKB(base::ProcessHandle pid); | |
| 265 | |
| 266 private: | |
| 267 // Returns the low memory margin system config. Low memory condition is | |
| 268 // reported if available memory is under the number. | |
| 269 static int LowMemoryMarginKB(); | |
| 270 | |
| 271 // Reads in an integer. | |
| 272 static int ReadIntFromFile(const char* file_name, int default_val); | |
| 273 }; | |
| 274 | |
| 275 } // namespace memory | |
| 276 | |
| 277 #endif // CHROME_BROWSER_MEMORY_TAB_MANAGER_DELEGATE_CHROMEOS_H_ | |
| OLD | NEW |