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 |