blob: 250d58672b3410f2a97e77271df16dd431bde6e8 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_MEMORY_MEMORY_COORDINATOR_IMPL_H_
#define CONTENT_BROWSER_MEMORY_MEMORY_COORDINATOR_IMPL_H_
#include "base/callback.h"
#include "base/memory/memory_coordinator_client.h"
#include "base/memory/memory_pressure_monitor.h"
#include "base/memory/singleton.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/non_thread_safe.h"
#include "base/time/time.h"
#include "content/common/content_export.h"
#include "content/common/memory_coordinator.mojom.h"
#include "content/public/browser/memory_coordinator.h"
#include "content/public/browser/memory_coordinator_delegate.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
namespace content {
// NOTE: Memory coordinator is under development and not fully working.
class MemoryCoordinatorHandleImpl;
class MemoryCoordinatorImplTest;
class MemoryMonitor;
class MemoryStateUpdater;
class RenderProcessHost;
struct MemoryCoordinatorSingletonTraits;
// MemoryCoordinatorImpl is an implementation of MemoryCoordinator.
// The current implementation uses MemoryStateUpdater to update the global
// memory state. See comments in MemoryStateUpdater for details.
class CONTENT_EXPORT MemoryCoordinatorImpl : public MemoryCoordinator,
public NotificationObserver,
public base::NonThreadSafe {
public:
using MemoryState = base::MemoryState;
static MemoryCoordinatorImpl* GetInstance();
MemoryCoordinatorImpl(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
std::unique_ptr<MemoryMonitor> monitor);
~MemoryCoordinatorImpl() override;
MemoryMonitor* memory_monitor() { return memory_monitor_.get(); }
// Starts monitoring memory usage. After calling this method, memory
// coordinator will start dispatching state changes.
void Start();
// Creates a handle to the provided child process.
void CreateHandle(int render_process_id,
mojom::MemoryCoordinatorHandleRequest request);
// Dispatches a memory state change to the provided process. Returns true if
// the process is tracked by this coordinator and successfully dispatches,
// returns false otherwise.
bool SetChildMemoryState(int render_process_id, MemoryState memory_state);
// Returns the memory state of the specified render process. Returns UNKNOWN
// if the process is not tracked by this coordinator.
MemoryState GetChildMemoryState(int render_process_id) const;
// Records memory pressure notifications. Called by MemoryPressureMonitor.
// TODO(bashi): Remove this when MemoryPressureMonitor is retired.
void RecordMemoryPressure(
base::MemoryPressureMonitor::MemoryPressureLevel level);
// Returns the global memory state.
virtual MemoryState GetGlobalMemoryState() const;
// Returns the browser's current memory state. Note that the current state
// could be different from the global memory state as the browser won't be
// suspended.
MemoryState GetCurrentMemoryState() const;
// Sets the global memory state for testing.
void SetCurrentMemoryStateForTesting(MemoryState memory_state);
// MemoryCoordinator implementation:
MemoryState GetStateForProcess(base::ProcessHandle handle) override;
// NotificationObserver implementation:
void Observe(int type,
const NotificationSource& source,
const NotificationDetails& details) override;
// Overrides the global state to |new_state|. State update tasks won't be
// scheduled until |duration| is passed. This means that the global state
// remains the same until |duration| is passed or another call of this method.
void ForceSetGlobalState(base::MemoryState new_state,
base::TimeDelta duration);
// Changes the global state and notifies state changes to clients (lives in
// the browser) and child processes (renderers) if needed. Returns true when
// the state is actually changed.
bool ChangeStateIfNeeded(MemoryState prev_state, MemoryState next_state);
protected:
// Returns the RenderProcessHost which is correspond to the given id.
// Returns nullptr if there is no corresponding RenderProcessHost.
// This is a virtual method so that we can write tests without having
// actual RenderProcessHost.
virtual RenderProcessHost* GetRenderProcessHost(int render_process_id);
// Sets a delegate for testing.
void SetDelegateForTesting(
std::unique_ptr<MemoryCoordinatorDelegate> delegate);
// Adds the given ChildMemoryCoordinator as a child of this coordinator.
void AddChildForTesting(int dummy_render_process_id,
mojom::ChildMemoryCoordinatorPtr child);
// Callback invoked by mojo when the child connection goes down. Exposed
// for testing.
void OnConnectionError(int render_process_id);
// Returns true when a given renderer can be suspended.
bool CanSuspendRenderer(int render_process_id);
// Stores information about any known child processes.
struct ChildInfo {
// This object must be compatible with STL containers.
ChildInfo();
ChildInfo(const ChildInfo& rhs);
~ChildInfo();
MemoryState memory_state;
bool is_visible = false;
std::unique_ptr<MemoryCoordinatorHandleImpl> handle;
};
// A map from process ID (RenderProcessHost::GetID()) to child process info.
using ChildInfoMap = std::map<int, ChildInfo>;
ChildInfoMap& children() { return children_; }
private:
#if !defined(OS_MACOSX)
FRIEND_TEST_ALL_PREFIXES(MemoryCoordinatorImplBrowserTest, HandleAdded);
FRIEND_TEST_ALL_PREFIXES(MemoryCoordinatorImplBrowserTest,
CanSuspendRenderer);
FRIEND_TEST_ALL_PREFIXES(MemoryCoordinatorWithServiceWorkerTest,
CannotSuspendRendererWithServiceWorker);
#endif
FRIEND_TEST_ALL_PREFIXES(MemoryCoordinatorImplTest, CalculateNextState);
FRIEND_TEST_ALL_PREFIXES(MemoryCoordinatorImplTest, UpdateState);
FRIEND_TEST_ALL_PREFIXES(MemoryCoordinatorImplTest, SetMemoryStateForTesting);
FRIEND_TEST_ALL_PREFIXES(MemoryCoordinatorImplTest, ForceSetGlobalState);
friend struct MemoryCoordinatorSingletonTraits;
friend class MemoryCoordinatorHandleImpl;
// Called when ChildMemoryCoordinator calls AddChild().
void OnChildAdded(int render_process_id);
// Called by SetChildMemoryState() to determine a child memory state based on
// the current status of the child process.
MemoryState OverrideGlobalState(MemoryState memroy_state,
const ChildInfo& child);
// Helper function of CreateHandle and AddChildForTesting.
void CreateChildInfoMapEntry(
int render_process_id,
std::unique_ptr<MemoryCoordinatorHandleImpl> handle);
// Notifies a state change to in-process clients.
void NotifyStateToClients();
// Notifies a state change to child processes.
void NotifyStateToChildren();
// Records metrics. This is called when the global state is changed.
void RecordStateChange(MemoryState prev_state,
MemoryState next_state,
base::TimeDelta duration);
std::unique_ptr<MemoryCoordinatorDelegate> delegate_;
std::unique_ptr<MemoryMonitor> memory_monitor_;
std::unique_ptr<MemoryStateUpdater> state_updater_;
NotificationRegistrar notification_registrar_;
// The global memory state.
MemoryState current_state_ = MemoryState::NORMAL;
// The time tick of last global state change.
base::TimeTicks last_state_change_;
// Tracks child processes. An entry is added when a renderer connects to
// MemoryCoordinator and removed automatically when an underlying binding is
// disconnected.
ChildInfoMap children_;
DISALLOW_COPY_AND_ASSIGN(MemoryCoordinatorImpl);
};
} // namespace content
#endif // CONTENT_BROWSER_MEMORY_MEMORY_COORDINATOR_IMPL_H_