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

Unified Diff: content/browser/memory/memory_coordinator_impl.cc

Issue 2579233002: Merge MemoryCoordinator and MemoryCoordinatorImpl into one class (Closed)
Patch Set: addressed comments Created 4 years 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 side-by-side diff with in-line comments
Download patch
Index: content/browser/memory/memory_coordinator_impl.cc
diff --git a/content/browser/memory/memory_coordinator_impl.cc b/content/browser/memory/memory_coordinator_impl.cc
index 5a24676c9386baf3b7a518f6f7c9240bfa6082e6..92a519f40df9f4f80a47a05a9ac16f523af4806b 100644
--- a/content/browser/memory/memory_coordinator_impl.cc
+++ b/content/browser/memory/memory_coordinator_impl.cc
@@ -4,18 +4,22 @@
#include "content/browser/memory/memory_coordinator_impl.h"
+#include "base/memory/memory_coordinator_client_registry.h"
#include "base/metrics/histogram_macros.h"
+#include "base/process/process_handle.h"
#include "base/process/process_metrics.h"
#include "base/strings/string_number_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
#include "content/browser/memory/memory_monitor.h"
#include "content/browser/memory/memory_state_updater.h"
+#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/common/content_features.h"
+#include "mojo/public/cpp/bindings/binding.h"
namespace content {
@@ -95,28 +99,72 @@ void RecordMetricsOnStateChange(base::MemoryState prev_state,
} // namespace
+// The implementation of MemoryCoordinatorHandle. See memory_coordinator.mojom
+// for the role of this class.
+class MemoryCoordinatorHandleImpl : public mojom::MemoryCoordinatorHandle {
+ public:
+ MemoryCoordinatorHandleImpl(mojom::MemoryCoordinatorHandleRequest request,
+ MemoryCoordinatorImpl* coordinator,
+ int render_process_id);
+ ~MemoryCoordinatorHandleImpl() override;
+
+ // mojom::MemoryCoordinatorHandle:
+ void AddChild(mojom::ChildMemoryCoordinatorPtr child) override;
+
+ mojom::ChildMemoryCoordinatorPtr& child() { return child_; }
+ mojo::Binding<mojom::MemoryCoordinatorHandle>& binding() { return binding_; }
+
+ private:
+ MemoryCoordinatorImpl* coordinator_;
+ int render_process_id_;
+ mojom::ChildMemoryCoordinatorPtr child_;
+ mojo::Binding<mojom::MemoryCoordinatorHandle> binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(MemoryCoordinatorHandleImpl);
+};
+
+MemoryCoordinatorHandleImpl::MemoryCoordinatorHandleImpl(
+ mojom::MemoryCoordinatorHandleRequest request,
+ MemoryCoordinatorImpl* coordinator,
+ int render_process_id)
+ : coordinator_(coordinator),
+ render_process_id_(render_process_id),
+ binding_(this, std::move(request)) {
+ DCHECK(coordinator_);
+}
+
+MemoryCoordinatorHandleImpl::~MemoryCoordinatorHandleImpl() {}
+
+void MemoryCoordinatorHandleImpl::AddChild(
+ mojom::ChildMemoryCoordinatorPtr child) {
+ DCHECK(!child_.is_bound());
+ child_ = std::move(child);
+ coordinator_->OnChildAdded(render_process_id_);
+}
+
// SingletonTraits for MemoryCoordinator. Returns MemoryCoordinatorImpl
// as an actual instance.
-struct MemoryCoordinatorSingletonTraits
- : public base::LeakySingletonTraits<MemoryCoordinator> {
- static MemoryCoordinator* New() {
+struct MemoryCoordinatorImplSingletonTraits
+ : public base::LeakySingletonTraits<MemoryCoordinatorImpl> {
+ static MemoryCoordinatorImpl* New() {
return new MemoryCoordinatorImpl(base::ThreadTaskRunnerHandle::Get(),
CreateMemoryMonitor());
}
};
// static
-MemoryCoordinator* MemoryCoordinator::GetInstance() {
+MemoryCoordinatorImpl* MemoryCoordinatorImpl::GetInstance() {
if (!base::FeatureList::IsEnabled(features::kMemoryCoordinator))
return nullptr;
- return base::Singleton<MemoryCoordinator,
- MemoryCoordinatorSingletonTraits>::get();
+ return base::Singleton<MemoryCoordinatorImpl,
+ MemoryCoordinatorImplSingletonTraits>::get();
}
MemoryCoordinatorImpl::MemoryCoordinatorImpl(
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
std::unique_ptr<MemoryMonitor> memory_monitor)
- : memory_monitor_(std::move(memory_monitor)),
+ : delegate_(GetContentClient()->browser()->GetMemoryCoordinatorDelegate()),
+ memory_monitor_(std::move(memory_monitor)),
state_updater_(base::MakeUnique<MemoryStateUpdater>(this, task_runner)) {
DCHECK(memory_monitor_.get());
}
@@ -134,10 +182,76 @@ void MemoryCoordinatorImpl::Start() {
state_updater_->ScheduleUpdateState(base::TimeDelta());
}
-void MemoryCoordinatorImpl::OnChildAdded(int render_process_id) {
- // Populate the global state as an initial state of a newly created process.
- auto new_state = ToMojomMemoryState(GetGlobalMemoryState());
- SetChildMemoryState(render_process_id, new_state);
+void MemoryCoordinatorImpl::CreateHandle(
+ int render_process_id,
+ mojom::MemoryCoordinatorHandleRequest request) {
+ std::unique_ptr<MemoryCoordinatorHandleImpl> handle(
+ new MemoryCoordinatorHandleImpl(std::move(request), this,
+ render_process_id));
+ handle->binding().set_connection_error_handler(
+ base::Bind(&MemoryCoordinatorImpl::OnConnectionError,
+ base::Unretained(this), render_process_id));
+ CreateChildInfoMapEntry(render_process_id, std::move(handle));
+}
+
+bool MemoryCoordinatorImpl::SetChildMemoryState(int render_process_id,
+ mojom::MemoryState memory_state) {
+ // Can't set an invalid memory state.
+ if (memory_state == mojom::MemoryState::UNKNOWN)
+ return false;
+
+ // Can't send a message to a child that doesn't exist.
+ auto iter = children_.find(render_process_id);
+ if (iter == children_.end())
+ return false;
+
+ // Can't send a message to a child that isn't bound.
+ if (!iter->second.handle->child().is_bound())
+ return false;
+
+ memory_state = OverrideGlobalState(memory_state, iter->second);
+
+ // A nop doesn't need to be sent, but is considered successful.
+ if (iter->second.memory_state == memory_state)
+ return true;
+
+ // Can't suspend the given renderer.
+ if (memory_state == mojom::MemoryState::SUSPENDED &&
+ !CanSuspendRenderer(render_process_id))
+ return false;
+
+ // Update the internal state and send the message.
+ iter->second.memory_state = memory_state;
+ iter->second.handle->child()->OnStateChange(memory_state);
+ return true;
+}
+
+mojom::MemoryState MemoryCoordinatorImpl::GetChildMemoryState(
+ int render_process_id) const {
+ auto iter = children_.find(render_process_id);
+ if (iter == children_.end())
+ return mojom::MemoryState::UNKNOWN;
+ return iter->second.memory_state;
+}
+
+void MemoryCoordinatorImpl::RecordMemoryPressure(
+ base::MemoryPressureMonitor::MemoryPressureLevel level) {
+ DCHECK(GetGlobalMemoryState() != base::MemoryState::UNKNOWN);
+ int state = static_cast<int>(GetGlobalMemoryState());
+ switch (level) {
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+ UMA_HISTOGRAM_ENUMERATION(
+ "Memory.Coordinator.StateOnModerateNotificationReceived",
+ state, base::kMemoryStateMax);
+ break;
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
+ UMA_HISTOGRAM_ENUMERATION(
+ "Memory.Coordinator.StateOnCriticalNotificationReceived",
+ state, base::kMemoryStateMax);
+ break;
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+ NOTREACHED();
+ }
}
base::MemoryState MemoryCoordinatorImpl::GetGlobalMemoryState() const {
@@ -202,6 +316,75 @@ bool MemoryCoordinatorImpl::ChangeStateIfNeeded(base::MemoryState prev_state,
return true;
}
+void MemoryCoordinatorImpl::AddChildForTesting(
+ int dummy_render_process_id, mojom::ChildMemoryCoordinatorPtr child) {
+ mojom::MemoryCoordinatorHandlePtr mch;
+ auto request = mojo::GetProxy(&mch);
+ std::unique_ptr<MemoryCoordinatorHandleImpl> handle(
+ new MemoryCoordinatorHandleImpl(std::move(request), this,
+ dummy_render_process_id));
+ handle->AddChild(std::move(child));
+ CreateChildInfoMapEntry(dummy_render_process_id, std::move(handle));
+}
+
+void MemoryCoordinatorImpl::OnConnectionError(int render_process_id) {
+ children_.erase(render_process_id);
+}
+
+bool MemoryCoordinatorImpl::CanSuspendRenderer(int render_process_id) {
+ // If there is no delegate (i.e. unittests), renderers are always suspendable.
+ if (!delegate_)
+ return true;
+ auto* render_process_host = RenderProcessHost::FromID(render_process_id);
+ if (!render_process_host || !render_process_host->IsProcessBackgrounded())
+ return false;
+ if (render_process_host->GetWorkerRefCount() > 0)
+ return false;
+ return delegate_->CanSuspendBackgroundedRenderer(render_process_id);
+}
+
+void MemoryCoordinatorImpl::OnChildAdded(int render_process_id) {
+ // Populate the global state as an initial state of a newly created process.
+ auto new_state = ToMojomMemoryState(GetGlobalMemoryState());
+ SetChildMemoryState(render_process_id, new_state);
+}
+
+mojom::MemoryState MemoryCoordinatorImpl::OverrideGlobalState(
+ mojom::MemoryState memory_state,
+ const ChildInfo& child) {
+ // We don't suspend foreground renderers. Throttle them instead.
+ if (child.is_visible && memory_state == mojom::MemoryState::SUSPENDED)
+ return mojom::MemoryState::THROTTLED;
+#if defined(OS_ANDROID)
+ // On Android, we throttle background renderers immediately.
+ // TODO(bashi): Create a specialized class of MemoryCoordinator for Android
+ // and move this ifdef to the class.
+ if (!child.is_visible && memory_state == mojom::MemoryState::NORMAL)
+ return mojom::MemoryState::THROTTLED;
+ // TODO(bashi): Suspend background renderers after a certain period of time.
+#endif // defined(OS_ANDROID)
+ return memory_state;
+}
+
+void MemoryCoordinatorImpl::SetDelegateForTesting(
+ std::unique_ptr<MemoryCoordinatorDelegate> delegate) {
+ CHECK(!delegate_);
+ delegate_ = std::move(delegate);
+}
+
+void MemoryCoordinatorImpl::CreateChildInfoMapEntry(
+ int render_process_id,
+ std::unique_ptr<MemoryCoordinatorHandleImpl> handle) {
+ auto& child_info = children_[render_process_id];
+ // Process always start with normal memory state.
+ // We'll set renderer's memory state to the current global state when the
+ // corresponding renderer process is ready to communicate. Renderer processes
+ // call AddChild() when they are ready.
+ child_info.memory_state = mojom::MemoryState::NORMAL;
+ child_info.is_visible = true;
+ child_info.handle = std::move(handle);
+}
+
void MemoryCoordinatorImpl::NotifyStateToClients() {
auto state = GetCurrentMemoryState();
base::MemoryCoordinatorClientRegistry::GetInstance()->Notify(state);
@@ -244,4 +427,12 @@ void MemoryCoordinatorImpl::RecordStateChange(MemoryState prev_state,
total_private_kb / 1024);
}
+MemoryCoordinatorImpl::ChildInfo::ChildInfo() {}
+
+MemoryCoordinatorImpl::ChildInfo::ChildInfo(const ChildInfo& rhs) {
+ // This is a nop, but exists for compatibility with STL containers.
+}
+
+MemoryCoordinatorImpl::ChildInfo::~ChildInfo() {}
+
} // namespace content
« no previous file with comments | « content/browser/memory/memory_coordinator_impl.h ('k') | content/browser/memory/memory_coordinator_impl_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698