| 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/metrics/histogram_macros.h" | 8 #include "base/metrics/histogram_macros.h" |
| 9 #include "base/process/process_handle.h" | 9 #include "base/process/process_handle.h" |
| 10 #include "base/process/process_metrics.h" | 10 #include "base/process/process_metrics.h" |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 188 std::unique_ptr<MemoryCoordinatorHandleImpl> handle( | 188 std::unique_ptr<MemoryCoordinatorHandleImpl> handle( |
| 189 new MemoryCoordinatorHandleImpl(std::move(request), this, | 189 new MemoryCoordinatorHandleImpl(std::move(request), this, |
| 190 render_process_id)); | 190 render_process_id)); |
| 191 handle->binding().set_connection_error_handler( | 191 handle->binding().set_connection_error_handler( |
| 192 base::Bind(&MemoryCoordinatorImpl::OnConnectionError, | 192 base::Bind(&MemoryCoordinatorImpl::OnConnectionError, |
| 193 base::Unretained(this), render_process_id)); | 193 base::Unretained(this), render_process_id)); |
| 194 CreateChildInfoMapEntry(render_process_id, std::move(handle)); | 194 CreateChildInfoMapEntry(render_process_id, std::move(handle)); |
| 195 } | 195 } |
| 196 | 196 |
| 197 bool MemoryCoordinatorImpl::SetChildMemoryState(int render_process_id, | 197 bool MemoryCoordinatorImpl::SetChildMemoryState(int render_process_id, |
| 198 mojom::MemoryState memory_state) { | 198 MemoryState memory_state) { |
| 199 // Can't set an invalid memory state. | 199 // Can't set an invalid memory state. |
| 200 if (memory_state == mojom::MemoryState::UNKNOWN) | 200 if (memory_state == MemoryState::UNKNOWN) |
| 201 return false; | 201 return false; |
| 202 | 202 |
| 203 // Can't send a message to a child that doesn't exist. | 203 // Can't send a message to a child that doesn't exist. |
| 204 auto iter = children_.find(render_process_id); | 204 auto iter = children_.find(render_process_id); |
| 205 if (iter == children_.end()) | 205 if (iter == children_.end()) |
| 206 return false; | 206 return false; |
| 207 | 207 |
| 208 // Can't send a message to a child that isn't bound. | 208 // Can't send a message to a child that isn't bound. |
| 209 if (!iter->second.handle->child().is_bound()) | 209 if (!iter->second.handle->child().is_bound()) |
| 210 return false; | 210 return false; |
| 211 | 211 |
| 212 memory_state = OverrideGlobalState(memory_state, iter->second); | 212 memory_state = OverrideGlobalState(memory_state, iter->second); |
| 213 | 213 |
| 214 // A nop doesn't need to be sent, but is considered successful. | 214 // A nop doesn't need to be sent, but is considered successful. |
| 215 if (iter->second.memory_state == memory_state) | 215 if (iter->second.memory_state == memory_state) |
| 216 return true; | 216 return true; |
| 217 | 217 |
| 218 // Can't suspend the given renderer. | 218 // Can't suspend the given renderer. |
| 219 if (memory_state == mojom::MemoryState::SUSPENDED && | 219 if (memory_state == MemoryState::SUSPENDED && |
| 220 !CanSuspendRenderer(render_process_id)) | 220 !CanSuspendRenderer(render_process_id)) |
| 221 return false; | 221 return false; |
| 222 | 222 |
| 223 // Update the internal state and send the message. | 223 // Update the internal state and send the message. |
| 224 iter->second.memory_state = memory_state; | 224 iter->second.memory_state = memory_state; |
| 225 iter->second.handle->child()->OnStateChange(memory_state); | 225 iter->second.handle->child()->OnStateChange(ToMojomMemoryState(memory_state)); |
| 226 return true; | 226 return true; |
| 227 } | 227 } |
| 228 | 228 |
| 229 mojom::MemoryState MemoryCoordinatorImpl::GetChildMemoryState( | 229 base::MemoryState MemoryCoordinatorImpl::GetChildMemoryState( |
| 230 int render_process_id) const { | 230 int render_process_id) const { |
| 231 auto iter = children_.find(render_process_id); | 231 auto iter = children_.find(render_process_id); |
| 232 if (iter == children_.end()) | 232 if (iter == children_.end()) |
| 233 return mojom::MemoryState::UNKNOWN; | 233 return base::MemoryState::UNKNOWN; |
| 234 return iter->second.memory_state; | 234 return iter->second.memory_state; |
| 235 } | 235 } |
| 236 | 236 |
| 237 void MemoryCoordinatorImpl::RecordMemoryPressure( | 237 void MemoryCoordinatorImpl::RecordMemoryPressure( |
| 238 base::MemoryPressureMonitor::MemoryPressureLevel level) { | 238 base::MemoryPressureMonitor::MemoryPressureLevel level) { |
| 239 DCHECK(GetGlobalMemoryState() != base::MemoryState::UNKNOWN); | 239 DCHECK(GetGlobalMemoryState() != base::MemoryState::UNKNOWN); |
| 240 int state = static_cast<int>(GetGlobalMemoryState()); | 240 int state = static_cast<int>(GetGlobalMemoryState()); |
| 241 switch (level) { | 241 switch (level) { |
| 242 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE: | 242 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE: |
| 243 UMA_HISTOGRAM_ENUMERATION( | 243 UMA_HISTOGRAM_ENUMERATION( |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 285 const NotificationDetails& details) { | 285 const NotificationDetails& details) { |
| 286 DCHECK(type == NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED); | 286 DCHECK(type == NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED); |
| 287 RenderWidgetHost* render_widget_host = Source<RenderWidgetHost>(source).ptr(); | 287 RenderWidgetHost* render_widget_host = Source<RenderWidgetHost>(source).ptr(); |
| 288 RenderProcessHost* process = render_widget_host->GetProcess(); | 288 RenderProcessHost* process = render_widget_host->GetProcess(); |
| 289 if (!process) | 289 if (!process) |
| 290 return; | 290 return; |
| 291 auto iter = children().find(process->GetID()); | 291 auto iter = children().find(process->GetID()); |
| 292 if (iter == children().end()) | 292 if (iter == children().end()) |
| 293 return; | 293 return; |
| 294 iter->second.is_visible = *Details<bool>(details).ptr(); | 294 iter->second.is_visible = *Details<bool>(details).ptr(); |
| 295 auto new_state = ToMojomMemoryState(GetGlobalMemoryState()); | 295 auto new_state = GetGlobalMemoryState(); |
| 296 SetChildMemoryState(iter->first, new_state); | 296 SetChildMemoryState(iter->first, new_state); |
| 297 } | 297 } |
| 298 | 298 |
| 299 bool MemoryCoordinatorImpl::ChangeStateIfNeeded(base::MemoryState prev_state, | 299 bool MemoryCoordinatorImpl::ChangeStateIfNeeded(base::MemoryState prev_state, |
| 300 base::MemoryState next_state) { | 300 base::MemoryState next_state) { |
| 301 DCHECK(CalledOnValidThread()); | 301 DCHECK(CalledOnValidThread()); |
| 302 if (prev_state == next_state) | 302 if (prev_state == next_state) |
| 303 return false; | 303 return false; |
| 304 | 304 |
| 305 base::TimeTicks prev_last_state_change = last_state_change_; | 305 base::TimeTicks prev_last_state_change = last_state_change_; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 338 auto* render_process_host = RenderProcessHost::FromID(render_process_id); | 338 auto* render_process_host = RenderProcessHost::FromID(render_process_id); |
| 339 if (!render_process_host || !render_process_host->IsProcessBackgrounded()) | 339 if (!render_process_host || !render_process_host->IsProcessBackgrounded()) |
| 340 return false; | 340 return false; |
| 341 if (render_process_host->GetWorkerRefCount() > 0) | 341 if (render_process_host->GetWorkerRefCount() > 0) |
| 342 return false; | 342 return false; |
| 343 return delegate_->CanSuspendBackgroundedRenderer(render_process_id); | 343 return delegate_->CanSuspendBackgroundedRenderer(render_process_id); |
| 344 } | 344 } |
| 345 | 345 |
| 346 void MemoryCoordinatorImpl::OnChildAdded(int render_process_id) { | 346 void MemoryCoordinatorImpl::OnChildAdded(int render_process_id) { |
| 347 // Populate the global state as an initial state of a newly created process. | 347 // Populate the global state as an initial state of a newly created process. |
| 348 auto new_state = ToMojomMemoryState(GetGlobalMemoryState()); | 348 auto new_state = GetGlobalMemoryState(); |
| 349 SetChildMemoryState(render_process_id, new_state); | 349 SetChildMemoryState(render_process_id, new_state); |
| 350 } | 350 } |
| 351 | 351 |
| 352 mojom::MemoryState MemoryCoordinatorImpl::OverrideGlobalState( | 352 base::MemoryState MemoryCoordinatorImpl::OverrideGlobalState( |
| 353 mojom::MemoryState memory_state, | 353 MemoryState memory_state, |
| 354 const ChildInfo& child) { | 354 const ChildInfo& child) { |
| 355 // We don't suspend foreground renderers. Throttle them instead. | 355 // We don't suspend foreground renderers. Throttle them instead. |
| 356 if (child.is_visible && memory_state == mojom::MemoryState::SUSPENDED) | 356 if (child.is_visible && memory_state == MemoryState::SUSPENDED) |
| 357 return mojom::MemoryState::THROTTLED; | 357 return MemoryState::THROTTLED; |
| 358 #if defined(OS_ANDROID) | 358 #if defined(OS_ANDROID) |
| 359 // On Android, we throttle background renderers immediately. | 359 // On Android, we throttle background renderers immediately. |
| 360 // TODO(bashi): Create a specialized class of MemoryCoordinator for Android | 360 // TODO(bashi): Create a specialized class of MemoryCoordinator for Android |
| 361 // and move this ifdef to the class. | 361 // and move this ifdef to the class. |
| 362 if (!child.is_visible && memory_state == mojom::MemoryState::NORMAL) | 362 if (!child.is_visible && memory_state == MemoryState::NORMAL) |
| 363 return mojom::MemoryState::THROTTLED; | 363 return MemoryState::THROTTLED; |
| 364 // TODO(bashi): Suspend background renderers after a certain period of time. | 364 // TODO(bashi): Suspend background renderers after a certain period of time. |
| 365 #endif // defined(OS_ANDROID) | 365 #endif // defined(OS_ANDROID) |
| 366 return memory_state; | 366 return memory_state; |
| 367 } | 367 } |
| 368 | 368 |
| 369 void MemoryCoordinatorImpl::SetDelegateForTesting( | 369 void MemoryCoordinatorImpl::SetDelegateForTesting( |
| 370 std::unique_ptr<MemoryCoordinatorDelegate> delegate) { | 370 std::unique_ptr<MemoryCoordinatorDelegate> delegate) { |
| 371 CHECK(!delegate_); | 371 CHECK(!delegate_); |
| 372 delegate_ = std::move(delegate); | 372 delegate_ = std::move(delegate); |
| 373 } | 373 } |
| 374 | 374 |
| 375 void MemoryCoordinatorImpl::CreateChildInfoMapEntry( | 375 void MemoryCoordinatorImpl::CreateChildInfoMapEntry( |
| 376 int render_process_id, | 376 int render_process_id, |
| 377 std::unique_ptr<MemoryCoordinatorHandleImpl> handle) { | 377 std::unique_ptr<MemoryCoordinatorHandleImpl> handle) { |
| 378 auto& child_info = children_[render_process_id]; | 378 auto& child_info = children_[render_process_id]; |
| 379 // Process always start with normal memory state. | 379 // Process always start with normal memory state. |
| 380 // We'll set renderer's memory state to the current global state when the | 380 // We'll set renderer's memory state to the current global state when the |
| 381 // corresponding renderer process is ready to communicate. Renderer processes | 381 // corresponding renderer process is ready to communicate. Renderer processes |
| 382 // call AddChild() when they are ready. | 382 // call AddChild() when they are ready. |
| 383 child_info.memory_state = mojom::MemoryState::NORMAL; | 383 child_info.memory_state = MemoryState::NORMAL; |
| 384 child_info.is_visible = true; | 384 child_info.is_visible = true; |
| 385 child_info.handle = std::move(handle); | 385 child_info.handle = std::move(handle); |
| 386 } | 386 } |
| 387 | 387 |
| 388 void MemoryCoordinatorImpl::NotifyStateToClients() { | 388 void MemoryCoordinatorImpl::NotifyStateToClients() { |
| 389 auto state = GetCurrentMemoryState(); | 389 auto state = GetCurrentMemoryState(); |
| 390 base::MemoryCoordinatorClientRegistry::GetInstance()->Notify(state); | 390 base::MemoryCoordinatorClientRegistry::GetInstance()->Notify(state); |
| 391 } | 391 } |
| 392 | 392 |
| 393 void MemoryCoordinatorImpl::NotifyStateToChildren() { | 393 void MemoryCoordinatorImpl::NotifyStateToChildren() { |
| 394 auto mojo_state = ToMojomMemoryState(current_state_); | |
| 395 // It's OK to call SetChildMemoryState() unconditionally because it checks | 394 // It's OK to call SetChildMemoryState() unconditionally because it checks |
| 396 // whether this state transition is valid. | 395 // whether this state transition is valid. |
| 397 for (auto& iter : children()) | 396 for (auto& iter : children()) |
| 398 SetChildMemoryState(iter.first, mojo_state); | 397 SetChildMemoryState(iter.first, current_state_); |
| 399 } | 398 } |
| 400 | 399 |
| 401 void MemoryCoordinatorImpl::RecordStateChange(MemoryState prev_state, | 400 void MemoryCoordinatorImpl::RecordStateChange(MemoryState prev_state, |
| 402 MemoryState next_state, | 401 MemoryState next_state, |
| 403 base::TimeDelta duration) { | 402 base::TimeDelta duration) { |
| 404 size_t total_private_kb = 0; | 403 size_t total_private_kb = 0; |
| 405 | 404 |
| 406 // TODO(bashi): On MacOS we can't get process metrics for child processes and | 405 // TODO(bashi): On MacOS we can't get process metrics for child processes and |
| 407 // therefore can't calculate the total private memory. | 406 // therefore can't calculate the total private memory. |
| 408 #if !defined(OS_MACOSX) | 407 #if !defined(OS_MACOSX) |
| (...skipping 20 matching lines...) Expand all Loading... |
| 429 | 428 |
| 430 MemoryCoordinatorImpl::ChildInfo::ChildInfo() {} | 429 MemoryCoordinatorImpl::ChildInfo::ChildInfo() {} |
| 431 | 430 |
| 432 MemoryCoordinatorImpl::ChildInfo::ChildInfo(const ChildInfo& rhs) { | 431 MemoryCoordinatorImpl::ChildInfo::ChildInfo(const ChildInfo& rhs) { |
| 433 // This is a nop, but exists for compatibility with STL containers. | 432 // This is a nop, but exists for compatibility with STL containers. |
| 434 } | 433 } |
| 435 | 434 |
| 436 MemoryCoordinatorImpl::ChildInfo::~ChildInfo() {} | 435 MemoryCoordinatorImpl::ChildInfo::~ChildInfo() {} |
| 437 | 436 |
| 438 } // namespace content | 437 } // namespace content |
| OLD | NEW |