| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/memory/tab_manager_delegate_chromeos.h" | 5 #include "chrome/browser/memory/tab_manager_delegate_chromeos.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <map> | 8 #include <map> |
| 9 #include <string> | 9 #include <string> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 #include "components/arc/common/process.mojom.h" | 21 #include "components/arc/common/process.mojom.h" |
| 22 #include "components/arc/test/fake_arc_bridge_service.h" | 22 #include "components/arc/test/fake_arc_bridge_service.h" |
| 23 #include "components/exo/shell_surface.h" | 23 #include "components/exo/shell_surface.h" |
| 24 #include "testing/gtest/include/gtest/gtest.h" | 24 #include "testing/gtest/include/gtest/gtest.h" |
| 25 #include "ui/aura/window.h" | 25 #include "ui/aura/window.h" |
| 26 #include "ui/wm/public/activation_client.h" | 26 #include "ui/wm/public/activation_client.h" |
| 27 #include "url/gurl.h" | 27 #include "url/gurl.h" |
| 28 | 28 |
| 29 namespace memory { | 29 namespace memory { |
| 30 | 30 |
| 31 using TabManagerDelegateTest = testing::Test; |
| 32 |
| 31 namespace { | 33 namespace { |
| 32 | 34 constexpr bool kIsFocused = true; |
| 33 const char kExoShellSurfaceWindowName[] = "ExoShellSurface"; | 35 constexpr bool kNotFocused = false; |
| 34 const char kArcProcessNamePrefix[] = "org.chromium.arc."; | |
| 35 | |
| 36 } // namespace | 36 } // namespace |
| 37 | 37 |
| 38 class TabManagerDelegateTest : public ash::test::AshTestBase { | |
| 39 public: | |
| 40 TabManagerDelegateTest() : application_id_(kArcProcessNamePrefix) {} | |
| 41 ~TabManagerDelegateTest() override {} | |
| 42 | |
| 43 void SetUp() override { | |
| 44 AshTestBase::SetUp(); | |
| 45 | |
| 46 arc_window_ = CreateTestWindowInShellWithId(0); | |
| 47 arc_window_->SetName(kExoShellSurfaceWindowName); | |
| 48 exo::ShellSurface::SetApplicationId(arc_window_, | |
| 49 &application_id_); | |
| 50 } | |
| 51 | |
| 52 protected: | |
| 53 void ActivateArcWindow() { | |
| 54 GetActivationClient()->ActivateWindow(arc_window_); | |
| 55 } | |
| 56 void DeactivateArcWindow() { | |
| 57 GetActivationClient()->DeactivateWindow(arc_window_); | |
| 58 } | |
| 59 | |
| 60 private: | |
| 61 aura::client::ActivationClient* GetActivationClient() { | |
| 62 return aura::client::GetActivationClient( | |
| 63 ash::Shell::GetPrimaryRootWindow()); | |
| 64 } | |
| 65 | |
| 66 aura::Window* arc_window_; | |
| 67 std::string application_id_; | |
| 68 }; | |
| 69 | |
| 70 TEST_F(TabManagerDelegateTest, CandidatesSorted) { | 38 TEST_F(TabManagerDelegateTest, CandidatesSorted) { |
| 71 std::vector<arc::ArcProcess> arc_processes; | 39 std::vector<arc::ArcProcess> arc_processes; |
| 72 arc_processes.emplace_back(1, 10, "top", arc::mojom::ProcessState::TOP); | 40 arc_processes.emplace_back(1, 10, "focused", arc::mojom::ProcessState::TOP, |
| 73 arc_processes.emplace_back(2, 20, "foreground", | 41 kIsFocused, 100); |
| 74 arc::mojom::ProcessState::FOREGROUND_SERVICE); | 42 arc_processes.emplace_back(2, 20, "visible1", arc::mojom::ProcessState::TOP, |
| 75 arc_processes.emplace_back(3, 30, "service", | 43 kNotFocused, 200); |
| 76 arc::mojom::ProcessState::SERVICE); | 44 arc_processes.emplace_back( |
| 45 3, 30, "service", arc::mojom::ProcessState::SERVICE, kNotFocused, 500); |
| 46 arc_processes.emplace_back(4, 40, "visible2", arc::mojom::ProcessState::TOP, |
| 47 kNotFocused, 150); |
| 77 | 48 |
| 78 TabStats tab1, tab2, tab3, tab4, tab5; | 49 TabStats tab1, tab2, tab3, tab4, tab5; |
| 79 tab1.tab_contents_id = 100; | 50 tab1.tab_contents_id = 100; |
| 80 tab1.is_pinned = true; | 51 tab1.is_pinned = true; |
| 81 | 52 |
| 82 tab2.tab_contents_id = 200; | 53 tab2.tab_contents_id = 200; |
| 83 tab2.is_internal_page = true; | 54 tab2.is_internal_page = true; |
| 84 | 55 |
| 85 tab3.tab_contents_id = 300; | 56 tab3.tab_contents_id = 300; |
| 86 tab3.is_pinned = true; | 57 tab3.is_pinned = true; |
| 87 tab3.is_media = true; | 58 tab3.is_media = true; |
| 88 | 59 |
| 89 tab4.tab_contents_id = 400; | 60 tab4.tab_contents_id = 400; |
| 90 tab4.is_media = true; | 61 tab4.is_media = true; |
| 91 | 62 |
| 92 tab5.tab_contents_id = 500; | 63 tab5.tab_contents_id = 500; |
| 93 tab5.is_app = true; | 64 tab5.is_app = true; |
| 94 TabStatsList tab_list = { | 65 TabStatsList tab_list = { |
| 95 tab1, tab2, tab3, tab4, tab5 | 66 tab1, tab2, tab3, tab4, tab5 |
| 96 }; | 67 }; |
| 97 | 68 |
| 98 std::vector<TabManagerDelegate::Candidate> candidates; | 69 std::vector<TabManagerDelegate::Candidate> candidates; |
| 99 | 70 |
| 100 // Case 1: ARC window in the foreground. | |
| 101 ActivateArcWindow(); | |
| 102 candidates = TabManagerDelegate::GetSortedCandidates( | 71 candidates = TabManagerDelegate::GetSortedCandidates( |
| 103 tab_list, arc_processes); | 72 tab_list, arc_processes); |
| 104 EXPECT_EQ(8U, candidates.size()); | 73 EXPECT_EQ(9U, candidates.size()); |
| 105 | 74 |
| 106 EXPECT_EQ("service", candidates[0].app->process_name()); | 75 // focused app. |
| 107 EXPECT_EQ("foreground", candidates[1].app->process_name()); | 76 EXPECT_EQ("focused", candidates[0].app()->process_name()); |
| 77 // visible app 1, last_activity_time larger than visible app 2. |
| 78 EXPECT_EQ("visible1", candidates[1].app()->process_name()); |
| 79 // visible app 2, last_activity_time less than visible app 1. |
| 80 EXPECT_EQ("visible2", candidates[2].app()->process_name()); |
| 81 // pinned and media. |
| 82 EXPECT_EQ(300, candidates[3].tab()->tab_contents_id); |
| 83 // media. |
| 84 EXPECT_EQ(400, candidates[4].tab()->tab_contents_id); |
| 85 // pinned. |
| 86 EXPECT_EQ(100, candidates[5].tab()->tab_contents_id); |
| 87 // chrome app. |
| 88 EXPECT_EQ(500, candidates[6].tab()->tab_contents_id); |
| 108 // internal page. | 89 // internal page. |
| 109 EXPECT_EQ(200, candidates[2].tab->tab_contents_id); | 90 EXPECT_EQ(200, candidates[7].tab()->tab_contents_id); |
| 110 // chrome app. | 91 // background service. |
| 111 EXPECT_EQ(500, candidates[3].tab->tab_contents_id); | 92 EXPECT_EQ("service", candidates[8].app()->process_name()); |
| 112 // pinned. | |
| 113 EXPECT_EQ(100, candidates[4].tab->tab_contents_id); | |
| 114 // media. | |
| 115 EXPECT_EQ(400, candidates[5].tab->tab_contents_id); | |
| 116 // pinned and media. | |
| 117 EXPECT_EQ(300, candidates[6].tab->tab_contents_id); | |
| 118 // ARC window is the active window, so top app has highest priority. | |
| 119 EXPECT_EQ("top", candidates[7].app->process_name()); | |
| 120 | |
| 121 // Case 2: ARC window in the background. | |
| 122 DeactivateArcWindow(); | |
| 123 candidates = TabManagerDelegate::GetSortedCandidates( | |
| 124 tab_list, arc_processes); | |
| 125 EXPECT_EQ(8U, candidates.size()); | |
| 126 | |
| 127 EXPECT_EQ("service", candidates[0].app->process_name()); | |
| 128 EXPECT_EQ("foreground", candidates[1].app->process_name()); | |
| 129 // internal page. | |
| 130 EXPECT_EQ(200, candidates[2].tab->tab_contents_id); | |
| 131 | |
| 132 // Chrome app and android app are tied, so both orders are correct. | |
| 133 if (candidates[3].is_arc_app) { | |
| 134 EXPECT_EQ("top", candidates[3].app->process_name()); | |
| 135 // chrome app. | |
| 136 EXPECT_EQ(500, candidates[4].tab->tab_contents_id); | |
| 137 } else { | |
| 138 // chrome app. | |
| 139 EXPECT_EQ(500, candidates[3].tab->tab_contents_id); | |
| 140 EXPECT_EQ("top", candidates[4].app->process_name()); | |
| 141 } | |
| 142 | |
| 143 // pinned. | |
| 144 EXPECT_EQ(100, candidates[5].tab->tab_contents_id); | |
| 145 // media. | |
| 146 EXPECT_EQ(400, candidates[6].tab->tab_contents_id); | |
| 147 // pinned and media. | |
| 148 EXPECT_EQ(300, candidates[7].tab->tab_contents_id); | |
| 149 } | 93 } |
| 150 | 94 |
| 151 class MockTabManagerDelegate : public TabManagerDelegate { | 95 class MockTabManagerDelegate : public TabManagerDelegate { |
| 152 public: | 96 public: |
| 153 MockTabManagerDelegate(): TabManagerDelegate(nullptr) { | 97 MockTabManagerDelegate(): TabManagerDelegate(nullptr) { |
| 154 } | 98 } |
| 155 | 99 |
| 156 explicit MockTabManagerDelegate(TabManagerDelegate::MemoryStat* mem_stat) | 100 explicit MockTabManagerDelegate(TabManagerDelegate::MemoryStat* mem_stat) |
| 157 : TabManagerDelegate(nullptr, mem_stat) { | 101 : TabManagerDelegate(nullptr, mem_stat) { |
| 158 } | 102 } |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 | 163 |
| 220 private: | 164 private: |
| 221 int target_memory_to_free_kb_; | 165 int target_memory_to_free_kb_; |
| 222 std::map<base::ProcessHandle, int> process_pss_; | 166 std::map<base::ProcessHandle, int> process_pss_; |
| 223 }; | 167 }; |
| 224 | 168 |
| 225 TEST_F(TabManagerDelegateTest, SetOomScoreAdj) { | 169 TEST_F(TabManagerDelegateTest, SetOomScoreAdj) { |
| 226 arc::FakeArcBridgeService fake_arc_bridge_service; | 170 arc::FakeArcBridgeService fake_arc_bridge_service; |
| 227 MockTabManagerDelegate tab_manager_delegate; | 171 MockTabManagerDelegate tab_manager_delegate; |
| 228 | 172 |
| 229 ActivateArcWindow(); | |
| 230 std::vector<arc::ArcProcess> arc_processes; | 173 std::vector<arc::ArcProcess> arc_processes; |
| 231 arc_processes.emplace_back(1, 10, "top", arc::mojom::ProcessState::TOP); | 174 arc_processes.emplace_back(1, 10, "focused", arc::mojom::ProcessState::TOP, |
| 232 arc_processes.emplace_back(2, 20, "foreground", | 175 kIsFocused, 100); |
| 233 arc::mojom::ProcessState::FOREGROUND_SERVICE); | 176 arc_processes.emplace_back(2, 20, "visible1", arc::mojom::ProcessState::TOP, |
| 234 arc_processes.emplace_back(3, 30, "service", | 177 kNotFocused, 200); |
| 235 arc::mojom::ProcessState::SERVICE); | 178 arc_processes.emplace_back( |
| 179 3, 30, "service", arc::mojom::ProcessState::SERVICE, kNotFocused, 500); |
| 180 arc_processes.emplace_back(4, 40, "visible2", arc::mojom::ProcessState::TOP, |
| 181 kNotFocused, 150); |
| 236 | 182 |
| 237 TabStats tab1, tab2, tab3, tab4, tab5; | 183 TabStats tab1, tab2, tab3, tab4, tab5; |
| 238 tab1.is_pinned = true; | 184 tab1.is_pinned = true; |
| 239 tab1.renderer_handle = 11; | 185 tab1.renderer_handle = 11; |
| 240 | 186 |
| 241 tab2.is_internal_page = true; | 187 tab2.is_internal_page = true; |
| 242 tab2.renderer_handle = 11; | 188 tab2.renderer_handle = 11; |
| 243 | 189 |
| 244 tab3.is_pinned = true; | 190 tab3.is_pinned = true; |
| 245 tab3.is_media = true; | 191 tab3.is_media = true; |
| 246 tab3.renderer_handle = 12; | 192 tab3.renderer_handle = 12; |
| 247 | 193 |
| 248 tab4.is_media = true; | 194 tab4.is_media = true; |
| 249 tab4.renderer_handle = 12; | 195 tab4.renderer_handle = 12; |
| 250 | 196 |
| 251 tab5.is_app = true; | 197 tab5.is_app = true; |
| 252 tab5.renderer_handle = 12; | 198 tab5.renderer_handle = 12; |
| 253 TabStatsList tab_list = {tab1, tab2, tab3, tab4, tab5}; | 199 TabStatsList tab_list = {tab1, tab2, tab3, tab4, tab5}; |
| 254 | 200 |
| 255 // Sorted order: | 201 // Sorted order: |
| 256 // app "service" pid: 30 oom_socre_adj: 825 | 202 // app "focused" pid: 10 |
| 257 // app "foreground" pid: 20 oom_score_adj: 650 | 203 // app "visible1" pid: 20 |
| 258 // tab2 pid: 11 oom_socre_adj: 417 | 204 // app "visible2" pid: 40 |
| 259 // tab5 pid: 12 oom_score_adj: 358 | 205 // tab3 pid: 12 |
| 260 // tab1 pid: 11 oom_socre_adj: 417 | 206 // tab4 pid: 12 |
| 261 // tab4 pid: 12 oom_socre_adj: 358 | 207 // tab1 pid: 11 |
| 262 // tab3 pid: 12 oom_score_adj: 358 | 208 // tab5 pid: 12 |
| 263 // app "top" pid: 10 oom_score_adj: 300 | 209 // tab2 pid: 11 |
| 210 // app "service" pid: 30 |
| 264 tab_manager_delegate.AdjustOomPrioritiesImpl(tab_list, arc_processes); | 211 tab_manager_delegate.AdjustOomPrioritiesImpl(tab_list, arc_processes); |
| 265 auto& oom_score_map = tab_manager_delegate.oom_score_map_; | 212 auto& oom_score_map = tab_manager_delegate.oom_score_map_; |
| 266 | 213 |
| 267 EXPECT_EQ(5U, oom_score_map.size()); | 214 EXPECT_EQ(6U, oom_score_map.size()); |
| 268 | 215 |
| 269 // Higher priority part. | 216 // Higher priority part. |
| 270 EXPECT_EQ(300, oom_score_map[10]); | 217 EXPECT_EQ(300, oom_score_map[10]); |
| 271 EXPECT_EQ(358, oom_score_map[12]); | 218 EXPECT_EQ(344, oom_score_map[20]); |
| 272 EXPECT_EQ(417, oom_score_map[11]); | 219 EXPECT_EQ(388, oom_score_map[40]); |
| 220 EXPECT_EQ(431, oom_score_map[12]); |
| 221 EXPECT_EQ(475, oom_score_map[11]); |
| 273 | 222 |
| 274 // Lower priority part. | 223 // Lower priority part. |
| 275 EXPECT_EQ(650, oom_score_map[20]); | 224 EXPECT_EQ(650, oom_score_map[30]); |
| 276 EXPECT_EQ(825, oom_score_map[30]); | |
| 277 } | 225 } |
| 278 | 226 |
| 279 TEST_F(TabManagerDelegateTest, KillMultipleProcesses) { | 227 TEST_F(TabManagerDelegateTest, KillMultipleProcesses) { |
| 280 arc::FakeArcBridgeService fake_arc_bridge_service; | 228 arc::FakeArcBridgeService fake_arc_bridge_service; |
| 281 | 229 |
| 282 // Not owned. | 230 // Not owned. |
| 283 MockMemoryStat* memory_stat = new MockMemoryStat(); | 231 MockMemoryStat* memory_stat = new MockMemoryStat(); |
| 284 | 232 |
| 285 // Instantiate the mock instance. | 233 // Instantiate the mock instance. |
| 286 MockTabManagerDelegate tab_manager_delegate(memory_stat); | 234 MockTabManagerDelegate tab_manager_delegate(memory_stat); |
| 287 | 235 |
| 288 ActivateArcWindow(); | |
| 289 | |
| 290 std::vector<arc::ArcProcess> arc_processes; | 236 std::vector<arc::ArcProcess> arc_processes; |
| 291 arc_processes.emplace_back(10001, 100, "top", arc::mojom::ProcessState::TOP); | 237 arc_processes.emplace_back(1, 10, "focused", arc::mojom::ProcessState::TOP, |
| 292 arc_processes.emplace_back(10002, 200, "foreground", | 238 kIsFocused, 100); |
| 293 arc::mojom::ProcessState::FOREGROUND_SERVICE); | 239 arc_processes.emplace_back(2, 20, "visible1", arc::mojom::ProcessState::TOP, |
| 294 arc_processes.emplace_back(10003, 300, "service", | 240 kNotFocused, 200); |
| 295 arc::mojom::ProcessState::SERVICE); | 241 arc_processes.emplace_back( |
| 242 3, 30, "service", arc::mojom::ProcessState::SERVICE, kNotFocused, 500); |
| 243 arc_processes.emplace_back(4, 40, "visible2", arc::mojom::ProcessState::TOP, |
| 244 kNotFocused, 150); |
| 296 | 245 |
| 297 TabStats tab1, tab2, tab3, tab4, tab5; | 246 TabStats tab1, tab2, tab3, tab4, tab5; |
| 298 tab1.is_pinned = true; | 247 tab1.is_pinned = true; |
| 299 tab1.renderer_handle = 11; | 248 tab1.renderer_handle = 11; |
| 300 tab1.tab_contents_id = 1; | 249 tab1.tab_contents_id = 1; |
| 301 | 250 |
| 302 tab2.is_internal_page = true; | 251 tab2.is_internal_page = true; |
| 303 tab2.renderer_handle = 11; | 252 tab2.renderer_handle = 11; |
| 304 tab2.tab_contents_id = 2; | 253 tab2.tab_contents_id = 2; |
| 305 | 254 |
| 306 tab3.is_pinned = true; | 255 tab3.is_pinned = true; |
| 307 tab3.is_media = true; | 256 tab3.is_media = true; |
| 308 tab3.renderer_handle = 12; | 257 tab3.renderer_handle = 12; |
| 309 tab3.tab_contents_id = 3; | 258 tab3.tab_contents_id = 3; |
| 310 | 259 |
| 311 tab4.is_media = true; | 260 tab4.is_media = true; |
| 312 tab4.renderer_handle = 12; | 261 tab4.renderer_handle = 12; |
| 313 tab4.tab_contents_id = 4; | 262 tab4.tab_contents_id = 4; |
| 314 | 263 |
| 315 tab5.is_app = true; | 264 tab5.is_app = true; |
| 316 tab5.renderer_handle = 12; | 265 tab5.renderer_handle = 12; |
| 317 tab5.tab_contents_id = 5; | 266 tab5.tab_contents_id = 5; |
| 318 TabStatsList tab_list = {tab1, tab2, tab3, tab4, tab5}; | 267 TabStatsList tab_list = {tab1, tab2, tab3, tab4, tab5}; |
| 319 | 268 |
| 320 // Sorted order: | 269 // Sorted order: |
| 321 // app "service" pid: 30 | 270 // app "focused" pid: 10 nspid 1 |
| 322 // app "foreground" pid: 20 | 271 // app "visible1" pid: 20 nspid 2 |
| 323 // tab2 pid: 11 | 272 // app "visible2" pid: 40 nspid 4 |
| 324 // tab5 pid: 12 | 273 // tab3 pid: 12 tab_contents_id 3 |
| 325 // tab1 pid: 11 | 274 // tab4 pid: 12 tab_contents_id 4 |
| 326 // tab4 pid: 12 | 275 // tab1 pid: 11 tab_contents_id 1 |
| 327 // tab3 pid: 12 | 276 // tab5 pid: 12 tab_contents_id 5 |
| 328 // app "top" pid: 10 | 277 // tab2 pid: 11 tab_contents_id 2 |
| 278 // app "service" pid: 30 nspid 3 |
| 329 memory_stat->SetTargetMemoryToFreeKB(250000); | 279 memory_stat->SetTargetMemoryToFreeKB(250000); |
| 330 // The 3 entities to be killed. | 280 // Entities to be killed. |
| 331 memory_stat->SetProcessPss(300, 10000); | 281 memory_stat->SetProcessPss(30, 10000); |
| 332 memory_stat->SetProcessPss(200, 200000); | 282 memory_stat->SetProcessPss(11, 200000); |
| 333 memory_stat->SetProcessPss(11, 50000); | 283 memory_stat->SetProcessPss(12, 30000); |
| 334 // Should not be used. | 284 // Should not be used. |
| 335 memory_stat->SetProcessPss(100, 30000); | 285 memory_stat->SetProcessPss(40, 50000); |
| 336 memory_stat->SetProcessPss(12, 100000); | 286 memory_stat->SetProcessPss(20, 30000); |
| 287 memory_stat->SetProcessPss(10, 100000); |
| 337 | 288 |
| 338 tab_manager_delegate.LowMemoryKillImpl(tab_list, arc_processes); | 289 tab_manager_delegate.LowMemoryKillImpl(tab_list, arc_processes); |
| 339 | 290 |
| 340 auto killed_arc_processes = tab_manager_delegate.GetKilledArcProcesses(); | 291 auto killed_arc_processes = tab_manager_delegate.GetKilledArcProcesses(); |
| 341 auto killed_tabs = tab_manager_delegate.GetKilledTabs(); | 292 auto killed_tabs = tab_manager_delegate.GetKilledTabs(); |
| 342 | 293 |
| 343 EXPECT_EQ(2U, killed_arc_processes.size()); | 294 // Killed apps and their nspid. |
| 344 EXPECT_EQ(1U, killed_tabs.size()); | 295 EXPECT_EQ(1U, killed_arc_processes.size()); |
| 345 | 296 EXPECT_EQ(3, killed_arc_processes[0]); |
| 346 // nspid. | 297 // Killed tabs and their content id. |
| 347 EXPECT_EQ(10003, killed_arc_processes[0]); | 298 // Note that process with pid 11 is counted twice. But so far I don't have a |
| 348 EXPECT_EQ(10002, killed_arc_processes[1]); | 299 // good way to estimate the memory freed if multiple tabs share one process. |
| 349 // tab content id. | 300 EXPECT_EQ(3U, killed_tabs.size()); |
| 350 EXPECT_EQ(2, killed_tabs[0]); | 301 EXPECT_EQ(2, killed_tabs[0]); |
| 302 EXPECT_EQ(5, killed_tabs[1]); |
| 303 EXPECT_EQ(1, killed_tabs[2]); |
| 351 } | 304 } |
| 352 | 305 |
| 353 } // namespace memory | 306 } // namespace memory |
| OLD | NEW |