| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "content/browser/memory/memory_coordinator_impl.h" | 5 #include "content/browser/memory/memory_coordinator_impl.h" |
| 6 | 6 |
| 7 #include "base/memory/memory_coordinator_client_registry.h" | 7 #include "base/memory/memory_coordinator_client_registry.h" |
| 8 #include "base/memory/memory_coordinator_proxy.h" | 8 #include "base/memory/memory_coordinator_proxy.h" |
| 9 #include "base/memory/memory_pressure_monitor.h" | 9 #include "base/memory/memory_pressure_monitor.h" |
| 10 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
| 11 #include "base/run_loop.h" | 11 #include "base/run_loop.h" |
| 12 #include "base/test/scoped_feature_list.h" | 12 #include "base/test/scoped_feature_list.h" |
| 13 #include "base/test/test_mock_time_task_runner.h" | 13 #include "base/test/test_mock_time_task_runner.h" |
| 14 #include "content/browser/memory/memory_monitor.h" | 14 #include "content/browser/memory/memory_monitor.h" |
| 15 #include "content/browser/memory/memory_state_updater.h" | 15 #include "content/browser/memory/memory_state_updater.h" |
| 16 #include "content/public/common/content_features.h" | 16 #include "content/public/common/content_features.h" |
| 17 #include "content/public/test/mock_render_process_host.h" |
| 18 #include "content/public/test/test_browser_context.h" |
| 17 #include "mojo/public/cpp/bindings/binding.h" | 19 #include "mojo/public/cpp/bindings/binding.h" |
| 18 #include "testing/gtest/include/gtest/gtest.h" | 20 #include "testing/gtest/include/gtest/gtest.h" |
| 19 | 21 |
| 20 namespace content { | 22 namespace content { |
| 21 | 23 |
| 22 namespace { | 24 namespace { |
| 23 | 25 |
| 24 void RunUntilIdle() { | 26 void RunUntilIdle() { |
| 25 base::RunLoop loop; | 27 base::RunLoop loop; |
| 26 loop.RunUntilIdle(); | 28 loop.RunUntilIdle(); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 76 | 78 |
| 77 // MemoryMonitor implementation | 79 // MemoryMonitor implementation |
| 78 int GetFreeMemoryUntilCriticalMB() override { return free_memory_; } | 80 int GetFreeMemoryUntilCriticalMB() override { return free_memory_; } |
| 79 | 81 |
| 80 private: | 82 private: |
| 81 int free_memory_ = 0; | 83 int free_memory_ = 0; |
| 82 | 84 |
| 83 DISALLOW_COPY_AND_ASSIGN(MockMemoryMonitor); | 85 DISALLOW_COPY_AND_ASSIGN(MockMemoryMonitor); |
| 84 }; | 86 }; |
| 85 | 87 |
| 88 class TestMemoryCoordinatorDelegate : public MemoryCoordinatorDelegate { |
| 89 public: |
| 90 TestMemoryCoordinatorDelegate() {} |
| 91 ~TestMemoryCoordinatorDelegate() override {} |
| 92 |
| 93 bool CanSuspendBackgroundedRenderer(int render_process_id) override { |
| 94 return true; |
| 95 } |
| 96 |
| 97 private: |
| 98 DISALLOW_COPY_AND_ASSIGN(TestMemoryCoordinatorDelegate); |
| 99 }; |
| 100 |
| 86 // A MemoryCoordinatorImpl that can be directly constructed. | 101 // A MemoryCoordinatorImpl that can be directly constructed. |
| 87 class TestMemoryCoordinatorImpl : public MemoryCoordinatorImpl { | 102 class TestMemoryCoordinatorImpl : public MemoryCoordinatorImpl { |
| 88 public: | 103 public: |
| 89 // Mojo machinery for wrapping a mock ChildMemoryCoordinator. | 104 // Mojo machinery for wrapping a mock ChildMemoryCoordinator. |
| 90 struct Child { | 105 struct Child { |
| 91 Child(mojom::ChildMemoryCoordinatorPtr* cmc_ptr) : cmc_binding(&cmc) { | 106 Child(mojom::ChildMemoryCoordinatorPtr* cmc_ptr) : cmc_binding(&cmc) { |
| 92 cmc_binding.Bind(mojo::GetProxy(cmc_ptr)); | 107 cmc_binding.Bind(mojo::GetProxy(cmc_ptr)); |
| 93 RunUntilIdle(); | 108 RunUntilIdle(); |
| 94 } | 109 } |
| 95 | 110 |
| 96 MockChildMemoryCoordinator cmc; | 111 MockChildMemoryCoordinator cmc; |
| 97 mojo::Binding<mojom::ChildMemoryCoordinator> cmc_binding; | 112 mojo::Binding<mojom::ChildMemoryCoordinator> cmc_binding; |
| 98 }; | 113 }; |
| 99 | 114 |
| 100 TestMemoryCoordinatorImpl( | 115 TestMemoryCoordinatorImpl( |
| 101 scoped_refptr<base::TestMockTimeTaskRunner> task_runner) | 116 scoped_refptr<base::TestMockTimeTaskRunner> task_runner) |
| 102 : MemoryCoordinatorImpl(task_runner, | 117 : MemoryCoordinatorImpl(task_runner, |
| 103 base::MakeUnique<MockMemoryMonitor>()) {} | 118 base::MakeUnique<MockMemoryMonitor>()) { |
| 119 SetDelegateForTesting(base::MakeUnique<TestMemoryCoordinatorDelegate>()); |
| 120 } |
| 121 |
| 104 ~TestMemoryCoordinatorImpl() override {} | 122 ~TestMemoryCoordinatorImpl() override {} |
| 105 | 123 |
| 106 using MemoryCoordinatorImpl::OnConnectionError; | 124 using MemoryCoordinatorImpl::OnConnectionError; |
| 107 using MemoryCoordinatorImpl::children; | 125 using MemoryCoordinatorImpl::children; |
| 108 | 126 |
| 109 MockChildMemoryCoordinator* CreateChildMemoryCoordinator( | 127 MockChildMemoryCoordinator* CreateChildMemoryCoordinator( |
| 110 int process_id) { | 128 int process_id) { |
| 111 mojom::ChildMemoryCoordinatorPtr cmc_ptr; | 129 mojom::ChildMemoryCoordinatorPtr cmc_ptr; |
| 112 children_.push_back(std::unique_ptr<Child>(new Child(&cmc_ptr))); | 130 children_.push_back(std::unique_ptr<Child>(new Child(&cmc_ptr))); |
| 113 AddChildForTesting(process_id, std::move(cmc_ptr)); | 131 AddChildForTesting(process_id, std::move(cmc_ptr)); |
| 132 render_process_hosts_[process_id] = |
| 133 base::MakeUnique<MockRenderProcessHost>(&browser_context_); |
| 114 return &children_.back()->cmc; | 134 return &children_.back()->cmc; |
| 115 } | 135 } |
| 116 | 136 |
| 137 RenderProcessHost* GetRenderProcessHost(int render_process_id) override { |
| 138 return GetMockRenderProcessHost(render_process_id); |
| 139 } |
| 140 |
| 141 MockRenderProcessHost* GetMockRenderProcessHost(int render_process_id) { |
| 142 auto iter = render_process_hosts_.find(render_process_id); |
| 143 if (iter == render_process_hosts_.end()) |
| 144 return nullptr; |
| 145 return iter->second.get(); |
| 146 } |
| 147 |
| 117 // Wrapper of MemoryCoordinator::SetMemoryState that also calls RunUntilIdle. | 148 // Wrapper of MemoryCoordinator::SetMemoryState that also calls RunUntilIdle. |
| 118 bool SetChildMemoryState( | 149 bool SetChildMemoryState( |
| 119 int render_process_id, MemoryState memory_state) { | 150 int render_process_id, MemoryState memory_state) { |
| 120 bool result = MemoryCoordinatorImpl::SetChildMemoryState( | 151 bool result = MemoryCoordinatorImpl::SetChildMemoryState( |
| 121 render_process_id, memory_state); | 152 render_process_id, memory_state); |
| 122 RunUntilIdle(); | 153 RunUntilIdle(); |
| 123 return result; | 154 return result; |
| 124 } | 155 } |
| 125 | 156 |
| 157 TestBrowserContext browser_context_; |
| 126 std::vector<std::unique_ptr<Child>> children_; | 158 std::vector<std::unique_ptr<Child>> children_; |
| 159 std::map<int, std::unique_ptr<MockRenderProcessHost>> render_process_hosts_; |
| 127 }; | 160 }; |
| 128 | 161 |
| 129 } // namespace | 162 } // namespace |
| 130 | 163 |
| 131 class MemoryCoordinatorImplTest : public testing::Test { | 164 class MemoryCoordinatorImplTest : public testing::Test { |
| 132 public: | 165 public: |
| 133 using MemoryState = base::MemoryState; | 166 using MemoryState = base::MemoryState; |
| 134 | 167 |
| 135 void SetUp() override { | 168 void SetUp() override { |
| 136 scoped_feature_list_.InitAndEnableFeature(features::kMemoryCoordinator); | 169 scoped_feature_list_.InitAndEnableFeature(features::kMemoryCoordinator); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 203 coordinator_->SetChildMemoryState(2, MemoryState::SUSPENDED)); | 236 coordinator_->SetChildMemoryState(2, MemoryState::SUSPENDED)); |
| 204 EXPECT_EQ(1, cmc2->on_state_change_calls()); | 237 EXPECT_EQ(1, cmc2->on_state_change_calls()); |
| 205 // Child processes are considered as visible (foreground) by default, | 238 // Child processes are considered as visible (foreground) by default, |
| 206 // and visible ones won't be suspended but throttled. | 239 // and visible ones won't be suspended but throttled. |
| 207 EXPECT_EQ(mojom::MemoryState::THROTTLED, cmc2->state()); | 240 EXPECT_EQ(mojom::MemoryState::THROTTLED, cmc2->state()); |
| 208 } | 241 } |
| 209 | 242 |
| 210 TEST_F(MemoryCoordinatorImplTest, SetChildMemoryState) { | 243 TEST_F(MemoryCoordinatorImplTest, SetChildMemoryState) { |
| 211 auto cmc = coordinator_->CreateChildMemoryCoordinator(1); | 244 auto cmc = coordinator_->CreateChildMemoryCoordinator(1); |
| 212 auto iter = coordinator_->children().find(1); | 245 auto iter = coordinator_->children().find(1); |
| 246 auto* render_process_host = coordinator_->GetMockRenderProcessHost(1); |
| 213 ASSERT_TRUE(iter != coordinator_->children().end()); | 247 ASSERT_TRUE(iter != coordinator_->children().end()); |
| 248 ASSERT_TRUE(render_process_host); |
| 214 | 249 |
| 215 // Foreground | 250 // Foreground |
| 216 iter->second.is_visible = true; | 251 iter->second.is_visible = true; |
| 252 render_process_host->set_is_process_backgrounded(false); |
| 217 EXPECT_TRUE(coordinator_->SetChildMemoryState(1, MemoryState::NORMAL)); | 253 EXPECT_TRUE(coordinator_->SetChildMemoryState(1, MemoryState::NORMAL)); |
| 218 EXPECT_EQ(mojom::MemoryState::NORMAL, cmc->state()); | 254 EXPECT_EQ(mojom::MemoryState::NORMAL, cmc->state()); |
| 219 EXPECT_TRUE( | 255 EXPECT_TRUE( |
| 220 coordinator_->SetChildMemoryState(1, MemoryState::THROTTLED)); | 256 coordinator_->SetChildMemoryState(1, MemoryState::THROTTLED)); |
| 221 EXPECT_EQ(mojom::MemoryState::THROTTLED, cmc->state()); | 257 EXPECT_EQ(mojom::MemoryState::THROTTLED, cmc->state()); |
| 222 EXPECT_TRUE( | 258 EXPECT_TRUE( |
| 223 coordinator_->SetChildMemoryState(1, MemoryState::SUSPENDED)); | 259 coordinator_->SetChildMemoryState(1, MemoryState::SUSPENDED)); |
| 224 EXPECT_EQ(mojom::MemoryState::THROTTLED, cmc->state()); | 260 EXPECT_EQ(mojom::MemoryState::THROTTLED, cmc->state()); |
| 225 | 261 |
| 226 // Background | 262 // Background |
| 227 iter->second.is_visible = false; | 263 iter->second.is_visible = false; |
| 264 render_process_host->set_is_process_backgrounded(true); |
| 228 EXPECT_TRUE(coordinator_->SetChildMemoryState(1, MemoryState::NORMAL)); | 265 EXPECT_TRUE(coordinator_->SetChildMemoryState(1, MemoryState::NORMAL)); |
| 229 #if defined(OS_ANDROID) | 266 #if defined(OS_ANDROID) |
| 230 EXPECT_EQ(mojom::MemoryState::THROTTLED, cmc->state()); | 267 EXPECT_EQ(mojom::MemoryState::THROTTLED, cmc->state()); |
| 231 #else | 268 #else |
| 232 EXPECT_EQ(mojom::MemoryState::NORMAL, cmc->state()); | 269 EXPECT_EQ(mojom::MemoryState::NORMAL, cmc->state()); |
| 233 #endif | 270 #endif |
| 234 EXPECT_TRUE( | 271 EXPECT_TRUE( |
| 235 coordinator_->SetChildMemoryState(1, MemoryState::THROTTLED)); | 272 coordinator_->SetChildMemoryState(1, MemoryState::THROTTLED)); |
| 236 EXPECT_EQ(mojom::MemoryState::THROTTLED, cmc->state()); | 273 EXPECT_EQ(mojom::MemoryState::THROTTLED, cmc->state()); |
| 237 EXPECT_TRUE( | 274 EXPECT_TRUE( |
| 238 coordinator_->SetChildMemoryState(1, MemoryState::SUSPENDED)); | 275 coordinator_->SetChildMemoryState(1, MemoryState::SUSPENDED)); |
| 239 EXPECT_EQ(mojom::MemoryState::SUSPENDED, cmc->state()); | 276 EXPECT_EQ(mojom::MemoryState::SUSPENDED, cmc->state()); |
| 277 |
| 278 // Background but there are workers |
| 279 render_process_host->IncrementServiceWorkerRefCount(); |
| 280 EXPECT_TRUE( |
| 281 coordinator_->SetChildMemoryState(1, MemoryState::THROTTLED)); |
| 282 EXPECT_EQ(mojom::MemoryState::THROTTLED, cmc->state()); |
| 283 EXPECT_FALSE( |
| 284 coordinator_->SetChildMemoryState(1, MemoryState::SUSPENDED)); |
| 285 EXPECT_EQ(mojom::MemoryState::THROTTLED, cmc->state()); |
| 286 render_process_host->DecrementSharedWorkerRefCount(); |
| 240 } | 287 } |
| 241 | 288 |
| 242 TEST_F(MemoryCoordinatorImplTest, CalculateNextState) { | 289 TEST_F(MemoryCoordinatorImplTest, CalculateNextState) { |
| 243 auto* state_updater = coordinator_->state_updater_.get(); | 290 auto* state_updater = coordinator_->state_updater_.get(); |
| 244 state_updater->expected_renderer_size_ = 10; | 291 state_updater->expected_renderer_size_ = 10; |
| 245 state_updater->new_renderers_until_throttled_ = 4; | 292 state_updater->new_renderers_until_throttled_ = 4; |
| 246 state_updater->new_renderers_until_suspended_ = 2; | 293 state_updater->new_renderers_until_suspended_ = 2; |
| 247 state_updater->new_renderers_back_to_normal_ = 5; | 294 state_updater->new_renderers_back_to_normal_ = 5; |
| 248 state_updater->new_renderers_back_to_throttled_ = 3; | 295 state_updater->new_renderers_back_to_throttled_ = 3; |
| 249 DCHECK(state_updater->ValidateParameters()); | 296 DCHECK(state_updater->ValidateParameters()); |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 417 // Also make sure that the state is updated based on free avaiable memory. | 464 // Also make sure that the state is updated based on free avaiable memory. |
| 418 // Since the global state has changed in the previous task, we have to wait | 465 // Since the global state has changed in the previous task, we have to wait |
| 419 // for |minimum_transition|. | 466 // for |minimum_transition|. |
| 420 GetMockMemoryMonitor()->SetFreeMemoryUntilCriticalMB(40); | 467 GetMockMemoryMonitor()->SetFreeMemoryUntilCriticalMB(40); |
| 421 task_runner_->FastForwardBy(minimum_transition); | 468 task_runner_->FastForwardBy(minimum_transition); |
| 422 task_runner_->RunUntilIdle(); | 469 task_runner_->RunUntilIdle(); |
| 423 EXPECT_EQ(base::MemoryState::THROTTLED, coordinator_->GetGlobalMemoryState()); | 470 EXPECT_EQ(base::MemoryState::THROTTLED, coordinator_->GetGlobalMemoryState()); |
| 424 } | 471 } |
| 425 | 472 |
| 426 } // namespace content | 473 } // namespace content |
| OLD | NEW |