Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(45)

Side by Side Diff: chrome/browser/memory/tab_manager_delegate_chromeos_unittest.cc

Issue 2898033002: [TabManager] Move TabManager into chrome/browser/resource_coordinator. (Closed)
Patch Set: rebase Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 #include "chrome/browser/memory/tab_manager_delegate_chromeos.h"
6
7 #include <map>
8 #include <string>
9 #include <vector>
10
11 #include "base/process/process_handle.h"
12 #include "chromeos/dbus/fake_debug_daemon_client.h"
13 #include "content/public/test/test_browser_thread_bundle.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace memory {
17
18 class TabManagerDelegateTest : public testing::Test {
19 public:
20 TabManagerDelegateTest() {}
21 ~TabManagerDelegateTest() override {}
22
23 private:
24 content::TestBrowserThreadBundle thread_bundle_;
25 };
26
27 namespace {
28 constexpr bool kIsFocused = true;
29 constexpr bool kNotFocused = false;
30 } // namespace
31
32 TEST_F(TabManagerDelegateTest, CandidatesSorted) {
33 std::vector<arc::ArcProcess> arc_processes;
34 arc_processes.emplace_back(1, 10, "focused", arc::mojom::ProcessState::TOP,
35 kIsFocused, 100);
36 arc_processes.emplace_back(2, 20, "visible1", arc::mojom::ProcessState::TOP,
37 kNotFocused, 200);
38 arc_processes.emplace_back(
39 3, 30, "service", arc::mojom::ProcessState::SERVICE, kNotFocused, 500);
40 arc_processes.emplace_back(4, 40, "visible2", arc::mojom::ProcessState::TOP,
41 kNotFocused, 150);
42
43 TabStats tab1, tab2, tab3, tab4, tab5;
44 tab1.tab_contents_id = 100;
45 tab1.is_pinned = true;
46
47 tab2.tab_contents_id = 200;
48 tab2.is_internal_page = true;
49
50 tab3.tab_contents_id = 300;
51 tab3.is_pinned = true;
52 tab3.is_media = true;
53
54 tab4.tab_contents_id = 400;
55 tab4.is_media = true;
56
57 tab5.tab_contents_id = 500;
58 tab5.is_app = true;
59 TabStatsList tab_list = {
60 tab1, tab2, tab3, tab4, tab5
61 };
62
63 std::vector<TabManagerDelegate::Candidate> candidates;
64
65 candidates = TabManagerDelegate::GetSortedCandidates(
66 tab_list, arc_processes);
67 ASSERT_EQ(9U, candidates.size());
68
69 // focused app.
70 ASSERT_TRUE(candidates[0].app());
71 EXPECT_EQ("focused", candidates[0].app()->process_name());
72 // visible app 1, last_activity_time larger than visible app 2.
73 ASSERT_TRUE(candidates[1].app());
74 EXPECT_EQ("visible1", candidates[1].app()->process_name());
75 // visible app 2, last_activity_time less than visible app 1.
76 ASSERT_TRUE(candidates[2].app());
77 EXPECT_EQ("visible2", candidates[2].app()->process_name());
78 // pinned and media.
79 ASSERT_TRUE(candidates[3].tab());
80 EXPECT_EQ(300, candidates[3].tab()->tab_contents_id);
81 // media.
82 ASSERT_TRUE(candidates[4].tab());
83 EXPECT_EQ(400, candidates[4].tab()->tab_contents_id);
84 // pinned.
85 ASSERT_TRUE(candidates[5].tab());
86 EXPECT_EQ(100, candidates[5].tab()->tab_contents_id);
87 // chrome app.
88 ASSERT_TRUE(candidates[6].tab());
89 EXPECT_EQ(500, candidates[6].tab()->tab_contents_id);
90 // internal page.
91 ASSERT_TRUE(candidates[7].tab());
92 EXPECT_EQ(200, candidates[7].tab()->tab_contents_id);
93 // background service.
94 ASSERT_TRUE(candidates[8].app());
95 EXPECT_EQ("service", candidates[8].app()->process_name());
96 }
97
98 // Occasionally, Chrome sees both FOCUSED_TAB and FOCUSED_APP at the same time.
99 // Test that Chrome treats the former as a more important process.
100 TEST_F(TabManagerDelegateTest, CandidatesSortedWithFocusedAppAndTab) {
101 std::vector<arc::ArcProcess> arc_processes;
102 arc_processes.emplace_back(1, 10, "focused", arc::mojom::ProcessState::TOP,
103 kIsFocused, 100);
104 TabStats tab1;
105 tab1.tab_contents_id = 100;
106 tab1.is_pinned = true;
107 tab1.is_selected = true;
108 const TabStatsList tab_list = {tab1};
109
110 const std::vector<TabManagerDelegate::Candidate> candidates =
111 TabManagerDelegate::GetSortedCandidates(tab_list, arc_processes);
112 ASSERT_EQ(2U, candidates.size());
113 // FOCUSED_TAB should be the first one.
114 ASSERT_TRUE(candidates[0].tab());
115 EXPECT_EQ(100, candidates[0].tab()->tab_contents_id);
116 ASSERT_TRUE(candidates[1].app());
117 EXPECT_EQ("focused", candidates[1].app()->process_name());
118 }
119
120 class MockTabManagerDelegate : public TabManagerDelegate {
121 public:
122 MockTabManagerDelegate()
123 : TabManagerDelegate(nullptr),
124 always_return_true_from_is_recently_killed_(false) {}
125
126 explicit MockTabManagerDelegate(TabManagerDelegate::MemoryStat* mem_stat)
127 : TabManagerDelegate(nullptr, mem_stat),
128 always_return_true_from_is_recently_killed_(false) {}
129
130 // unit test.
131 std::vector<int> GetKilledArcProcesses() {
132 return killed_arc_processes_;
133 }
134
135 // unit test.
136 std::vector<int64_t> GetKilledTabs() {
137 return killed_tabs_;
138 }
139
140 // unit test.
141 void Clear() {
142 killed_arc_processes_.clear();
143 killed_tabs_.clear();
144 }
145
146 // unit test.
147 void set_always_return_true_from_is_recently_killed(
148 bool always_return_true_from_is_recently_killed) {
149 always_return_true_from_is_recently_killed_ =
150 always_return_true_from_is_recently_killed;
151 }
152
153 bool IsRecentlyKilledArcProcess(const std::string& process_name,
154 const base::TimeTicks& now) override {
155 if (always_return_true_from_is_recently_killed_)
156 return true;
157 return TabManagerDelegate::IsRecentlyKilledArcProcess(process_name, now);
158 }
159
160 protected:
161 bool KillArcProcess(const int nspid) override {
162 killed_arc_processes_.push_back(nspid);
163 return true;
164 }
165
166 bool KillTab(int64_t tab_id) override {
167 killed_tabs_.push_back(tab_id);
168 return true;
169 }
170
171 chromeos::DebugDaemonClient* GetDebugDaemonClient() override {
172 return &debugd_client_;
173 }
174
175 private:
176 chromeos::FakeDebugDaemonClient debugd_client_;
177 std::vector<int> killed_arc_processes_;
178 std::vector<int64_t> killed_tabs_;
179 bool always_return_true_from_is_recently_killed_;
180 };
181
182 class MockMemoryStat : public TabManagerDelegate::MemoryStat {
183 public:
184 MockMemoryStat() {}
185 ~MockMemoryStat() override {}
186
187 int TargetMemoryToFreeKB() override {
188 return target_memory_to_free_kb_;
189 }
190
191 int EstimatedMemoryFreedKB(base::ProcessHandle pid) override {
192 return process_pss_[pid];
193 }
194
195 // unittest.
196 void SetTargetMemoryToFreeKB(const int target) {
197 target_memory_to_free_kb_ = target;
198 }
199
200 // unittest.
201 void SetProcessPss(base::ProcessHandle pid, int pss) {
202 process_pss_[pid] = pss;
203 }
204
205 private:
206 int target_memory_to_free_kb_;
207 std::map<base::ProcessHandle, int> process_pss_;
208 };
209
210 TEST_F(TabManagerDelegateTest, SetOomScoreAdj) {
211 MockTabManagerDelegate tab_manager_delegate;
212
213 std::vector<arc::ArcProcess> arc_processes;
214 arc_processes.emplace_back(1, 10, "focused", arc::mojom::ProcessState::TOP,
215 kIsFocused, 100);
216 arc_processes.emplace_back(2, 20, "visible1", arc::mojom::ProcessState::TOP,
217 kNotFocused, 200);
218 arc_processes.emplace_back(
219 3, 30, "service", arc::mojom::ProcessState::SERVICE, kNotFocused, 500);
220 arc_processes.emplace_back(4, 40, "visible2", arc::mojom::ProcessState::TOP,
221 kNotFocused, 150);
222 arc_processes.emplace_back(5, 50, "persistent",
223 arc::mojom::ProcessState::PERSISTENT, kNotFocused,
224 600);
225 arc_processes.emplace_back(6, 60, "persistent_ui",
226 arc::mojom::ProcessState::PERSISTENT_UI,
227 kNotFocused, 700);
228
229 TabStats tab1, tab2, tab3, tab4, tab5;
230 tab1.is_pinned = true;
231 tab1.renderer_handle = 11;
232
233 tab2.is_internal_page = true;
234 tab2.renderer_handle = 11;
235
236 tab3.is_pinned = true;
237 tab3.is_media = true;
238 tab3.renderer_handle = 12;
239
240 tab4.is_media = true;
241 tab4.renderer_handle = 12;
242
243 tab5.is_app = true;
244 tab5.renderer_handle = 12;
245 TabStatsList tab_list = {tab1, tab2, tab3, tab4, tab5};
246
247 // Sorted order (by GetSortedCandidates):
248 // app "focused" pid: 10
249 // app "persistent" pid: 50
250 // app "persistent_ui" pid: 60
251 // app "visible1" pid: 20
252 // app "visible2" pid: 40
253 // tab3 pid: 12
254 // tab4 pid: 12
255 // tab1 pid: 11
256 // tab5 pid: 12
257 // tab2 pid: 11
258 // app "service" pid: 30
259 tab_manager_delegate.AdjustOomPrioritiesImpl(tab_list, arc_processes);
260 auto& oom_score_map = tab_manager_delegate.oom_score_map_;
261
262 // 6 PIDs for apps + 2 PIDs for tabs.
263 EXPECT_EQ(6U + 2U, oom_score_map.size());
264
265 // Non-killable part. AdjustOomPrioritiesImpl() does make a focused app/tab
266 // kernel-killable, but does not do that for PERSISTENT and PERSISTENT_UI
267 // apps.
268 EXPECT_EQ(TabManagerDelegate::kLowestOomScore, oom_score_map[50]);
269 EXPECT_EQ(TabManagerDelegate::kLowestOomScore, oom_score_map[60]);
270
271 // Higher priority part.
272 EXPECT_EQ(300, oom_score_map[10]);
273 EXPECT_EQ(344, oom_score_map[20]);
274 EXPECT_EQ(388, oom_score_map[40]);
275 EXPECT_EQ(431, oom_score_map[12]);
276 EXPECT_EQ(475, oom_score_map[11]);
277
278 // Lower priority part.
279 EXPECT_EQ(650, oom_score_map[30]);
280 }
281
282 TEST_F(TabManagerDelegateTest, IsRecentlyKilledArcProcess) {
283 constexpr char kProcessName1[] = "org.chromium.arc.test1";
284 constexpr char kProcessName2[] = "org.chromium.arc.test2";
285
286 // Not owned.
287 MockMemoryStat* memory_stat = new MockMemoryStat();
288 // Instantiate the mock instance.
289 MockTabManagerDelegate tab_manager_delegate(memory_stat);
290
291 // When the process name is not in the map, IsRecentlyKilledArcProcess should
292 // return false.
293 const base::TimeTicks now = base::TimeTicks::Now();
294 EXPECT_FALSE(
295 tab_manager_delegate.IsRecentlyKilledArcProcess(kProcessName1, now));
296 EXPECT_FALSE(
297 tab_manager_delegate.IsRecentlyKilledArcProcess(kProcessName2, now));
298
299 // Update the map to tell the manager that the process was killed very
300 // recently.
301 tab_manager_delegate.recently_killed_arc_processes_[kProcessName1] = now;
302 EXPECT_TRUE(
303 tab_manager_delegate.IsRecentlyKilledArcProcess(kProcessName1, now));
304 EXPECT_FALSE(
305 tab_manager_delegate.IsRecentlyKilledArcProcess(kProcessName2, now));
306 tab_manager_delegate.recently_killed_arc_processes_[kProcessName1] =
307 now - base::TimeDelta::FromMicroseconds(1);
308 EXPECT_TRUE(
309 tab_manager_delegate.IsRecentlyKilledArcProcess(kProcessName1, now));
310 EXPECT_FALSE(
311 tab_manager_delegate.IsRecentlyKilledArcProcess(kProcessName2, now));
312 tab_manager_delegate.recently_killed_arc_processes_[kProcessName1] =
313 now - TabManagerDelegate::GetArcRespawnKillDelay();
314 EXPECT_TRUE(
315 tab_manager_delegate.IsRecentlyKilledArcProcess(kProcessName1, now));
316 EXPECT_FALSE(
317 tab_manager_delegate.IsRecentlyKilledArcProcess(kProcessName2, now));
318
319 // Update the map to tell the manager that the process was killed
320 // (GetArcRespawnKillDelay() + 1) seconds ago. In this case,
321 // IsRecentlyKilledArcProcess(kProcessName1) should return false.
322 tab_manager_delegate.recently_killed_arc_processes_[kProcessName1] =
323 now - TabManagerDelegate::GetArcRespawnKillDelay() -
324 base::TimeDelta::FromSeconds(1);
325 EXPECT_FALSE(
326 tab_manager_delegate.IsRecentlyKilledArcProcess(kProcessName1, now));
327 EXPECT_FALSE(
328 tab_manager_delegate.IsRecentlyKilledArcProcess(kProcessName2, now));
329 }
330
331 TEST_F(TabManagerDelegateTest, DoNotKillRecentlyKilledArcProcesses) {
332 // Not owned.
333 MockMemoryStat* memory_stat = new MockMemoryStat();
334
335 // Instantiate the mock instance.
336 MockTabManagerDelegate tab_manager_delegate(memory_stat);
337 tab_manager_delegate.set_always_return_true_from_is_recently_killed(true);
338
339 std::vector<arc::ArcProcess> arc_processes;
340 arc_processes.emplace_back(
341 1, 10, "service", arc::mojom::ProcessState::SERVICE, kNotFocused, 500);
342
343 memory_stat->SetTargetMemoryToFreeKB(250000);
344 memory_stat->SetProcessPss(30, 10000);
345 TabStatsList tab_list;
346 tab_manager_delegate.LowMemoryKillImpl(tab_list, arc_processes);
347
348 auto killed_arc_processes = tab_manager_delegate.GetKilledArcProcesses();
349 EXPECT_EQ(0U, killed_arc_processes.size());
350 }
351
352 TEST_F(TabManagerDelegateTest, KillMultipleProcesses) {
353 // Not owned.
354 MockMemoryStat* memory_stat = new MockMemoryStat();
355
356 // Instantiate the mock instance.
357 MockTabManagerDelegate tab_manager_delegate(memory_stat);
358
359 std::vector<arc::ArcProcess> arc_processes;
360 arc_processes.emplace_back(1, 10, "focused", arc::mojom::ProcessState::TOP,
361 kIsFocused, 100);
362 arc_processes.emplace_back(2, 20, "visible1", arc::mojom::ProcessState::TOP,
363 kNotFocused, 200);
364 arc_processes.emplace_back(
365 3, 30, "service", arc::mojom::ProcessState::SERVICE, kNotFocused, 500);
366 arc_processes.emplace_back(4, 40, "visible2",
367 arc::mojom::ProcessState::IMPORTANT_FOREGROUND,
368 kNotFocused, 150);
369 arc_processes.emplace_back(5, 50, "not-visible",
370 arc::mojom::ProcessState::IMPORTANT_BACKGROUND,
371 kNotFocused, 300);
372 arc_processes.emplace_back(6, 60, "persistent",
373 arc::mojom::ProcessState::PERSISTENT, kNotFocused,
374 400);
375
376 TabStats tab1, tab2, tab3, tab4, tab5;
377 tab1.is_pinned = true;
378 tab1.renderer_handle = 11;
379 tab1.tab_contents_id = 1;
380
381 tab2.is_internal_page = true;
382 tab2.renderer_handle = 11;
383 tab2.tab_contents_id = 2;
384
385 tab3.is_pinned = true;
386 tab3.is_media = true;
387 tab3.renderer_handle = 12;
388 tab3.tab_contents_id = 3;
389
390 tab4.is_media = true;
391 tab4.renderer_handle = 12;
392 tab4.tab_contents_id = 4;
393
394 tab5.is_app = true;
395 tab5.renderer_handle = 12;
396 tab5.tab_contents_id = 5;
397 TabStatsList tab_list = {tab1, tab2, tab3, tab4, tab5};
398
399 // Sorted order (by GetSortedCandidates):
400 // app "focused" pid: 10 nspid 1
401 // app "persistent" pid: 60 nspid 6
402 // app "visible1" pid: 20 nspid 2
403 // app "visible2" pid: 40 nspid 4
404 // tab3 pid: 12 tab_contents_id 3
405 // tab4 pid: 12 tab_contents_id 4
406 // tab1 pid: 11 tab_contents_id 1
407 // tab5 pid: 12 tab_contents_id 5
408 // tab2 pid: 11 tab_contents_id 2
409 // app "not-visible" pid: 50 nspid 5
410 // app "service" pid: 30 nspid 3
411 memory_stat->SetTargetMemoryToFreeKB(250000);
412 // Entities to be killed.
413 memory_stat->SetProcessPss(30, 10000);
414 memory_stat->SetProcessPss(50, 5000);
415 memory_stat->SetProcessPss(11, 200000);
416 memory_stat->SetProcessPss(12, 30000);
417 // Should not be used.
418 memory_stat->SetProcessPss(60, 500000);
419 memory_stat->SetProcessPss(40, 50000);
420 memory_stat->SetProcessPss(20, 30000);
421 memory_stat->SetProcessPss(10, 100000);
422
423 tab_manager_delegate.LowMemoryKillImpl(tab_list, arc_processes);
424
425 auto killed_arc_processes = tab_manager_delegate.GetKilledArcProcesses();
426 auto killed_tabs = tab_manager_delegate.GetKilledTabs();
427
428 // Killed apps and their nspid.
429 ASSERT_EQ(2U, killed_arc_processes.size());
430 EXPECT_EQ(3, killed_arc_processes[0]);
431 EXPECT_EQ(5, killed_arc_processes[1]);
432 // Killed tabs and their content id.
433 // Note that process with pid 11 is counted twice. But so far I don't have a
434 // good way to estimate the memory freed if multiple tabs share one process.
435 ASSERT_EQ(3U, killed_tabs.size());
436 EXPECT_EQ(2, killed_tabs[0]);
437 EXPECT_EQ(5, killed_tabs[1]);
438 EXPECT_EQ(1, killed_tabs[2]);
439
440 // Check that killed apps are in the map.
441 const TabManagerDelegate::KilledArcProcessesMap& processes_map =
442 tab_manager_delegate.recently_killed_arc_processes_;
443 EXPECT_EQ(2U, processes_map.size());
444 EXPECT_EQ(1U, processes_map.count("service"));
445 EXPECT_EQ(1U, processes_map.count("not-visible"));
446 }
447
448 } // namespace memory
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698