1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
|
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_RENDERER_HOST_SPARE_RENDER_PROCESS_HOST_MANAGER_IMPL_H_
#define CONTENT_BROWSER_RENDERER_HOST_SPARE_RENDER_PROCESS_HOST_MANAGER_IMPL_H_
#include <optional>
#include "base/memory/memory_pressure_listener.h"
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "base/timer/elapsed_timer.h"
#include "base/timer/timer.h"
#include "components/performance_manager/scenario_api/performance_scenario_observer.h"
#include "content/common/content_export.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/process_allocation_context.h"
#include "content/public/browser/render_process_host_observer.h"
#include "content/public/browser/spare_render_process_host_manager.h"
#if BUILDFLAG(IS_ANDROID)
#include "base/android/application_status_listener.h"
#endif
namespace content {
class BrowserContext;
class SiteInstanceImpl;
class RenderProcessHost;
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
//
// LINT.IfChange(SpareRendererDispatchResult)
enum class SpareRendererDispatchResult {
kUsed = 0,
kTimeout = 1,
kOverridden = 2,
kDestroyedNotEnabled = 3,
kDestroyedProcessLimit = 4,
kProcessExited = 5,
kProcessHostDestroyed = 6,
kMemoryPressure = 7,
kKillAfterBackgrounded = 8,
kMaxValue = kKillAfterBackgrounded
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/browser/enums.xml:SpareRendererDispatchResult)
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
//
// LINT.IfChange(NoSpareRendererReason)
enum class NoSpareRendererReason {
kNotYetCreated = 0,
kTakenByPreviousNavigation = 1,
kTimeout = 2,
kNotEnabled = 3,
kProcessLimit = 4,
kMemoryPressure = 5,
kProcessExited = 6,
kProcessHostDestroyed = 7,
kNotYetCreatedFirstLaunch = 8,
kNotYetCreatedAfterWarmup = 9,
kOnceBackgrounded = 10,
kMaxValue = kOnceBackgrounded
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/browser/enums.xml:NoSpareRendererReason)
class CONTENT_EXPORT SpareRenderProcessHostManagerImpl
: public SpareRenderProcessHostManager,
public RenderProcessHostObserver,
public performance_scenarios::PerformanceScenarioObserver {
public:
SpareRenderProcessHostManagerImpl();
~SpareRenderProcessHostManagerImpl() override;
SpareRenderProcessHostManagerImpl(
const SpareRenderProcessHostManagerImpl& other) = delete;
SpareRenderProcessHostManagerImpl& operator=(
const SpareRenderProcessHostManagerImpl& other) = delete;
static SpareRenderProcessHostManagerImpl& Get();
// SpareRenderProcessHostManager:
void AddObserver(Observer* observer) override;
void RemoveObserver(Observer* observer) override;
RenderProcessHost* WarmupSpare(BrowserContext* browser_context) override;
const std::vector<RenderProcessHost*>& GetSpares() override;
std::vector<ChildProcessId> GetSpareIds() override;
void CleanupSparesForTesting() override;
// Start a spare renderer immediately, only if there is none.
// If the timeout is given, the spare render process will not be created
// if there is a delayed creation which indicates no timeout.
//
// The created spare render process will be destroyed after the timeout
// if it is given and accepted. Otherwise, the spare renderer will be kept
// until used by some navigation or cleared for memory pressure.
//
// The general rule for the timeout update is to always keep the value with
// a larger timeout. The timeout will be accepted when:
// * There is no spare render process or the spare render process was created
// for a different browser context.
// * The current timeout will be fired before the specified timeout.
// If the function is called again without a timeout, the current timeout will
// be cancelled. If the function is called again with a timeout firing after
// the current timeout, the timeout will be updated.
//
// Returns a RenderProcessHost if a new one is created.
RenderProcessHost* WarmupSpare(BrowserContext* browser_context,
std::optional<base::TimeDelta> timeout);
// RenderProcessHostImpl should call
// SpareRenderProcessHostManager::MaybeTakeSpare when creating a new RPH. In
// this implementation, the spare renderer is bound to a BrowserContext and
// its default StoragePartition. If MaybeTakeSpare is called with a
// BrowserContext that does not match, the spare renderer is discarded. Only
// the default StoragePartition will be able to use a spare renderer. The
// spare renderer will also not be used as a guest renderer (flags_ contains
// kForGuestsOnly).
RenderProcessHost* MaybeTakeSpare(
BrowserContext* browser_context,
SiteInstanceImpl* site_instance,
const ProcessAllocationContext& allocation_context);
// Prepares for future requests (with an assumption that a future navigation
// might require a new process for |browser_context|).
//
// Note that depending on the caller PrepareForFutureRequests can be called
// after a spare RPH has either been 1) matched and taken or 2) mismatched and
// ignored or 3) matched and ignored.
//
// The creation of new spare renderer will be delayed by `delay` if present.
// This is used to mitigate resource contention.
void PrepareForFutureRequests(BrowserContext* browser_context,
std::optional<base::TimeDelta> delay);
// Gracefully remove and cleanup all existing spare RenderProcessHost.
//
// Passing std::nullopt as dispatch_result is for test only.
void CleanupSpares(
std::optional<SpareRendererDispatchResult> dispatch_result);
// Gracefully removes and cleanups any extra spare RenderProcessHost beyond
// the first one. This is always a nop if the kMultipleSpareRPHs feature is
// disabled.
void CleanupExtraSpares(
std::optional<SpareRendererDispatchResult> dispatch_result);
void SetDeferTimerTaskRunnerForTesting(
scoped_refptr<base::SequencedTaskRunner> task_runner);
void SetIsBrowserIdleForTesting(bool is_browser_idle);
bool HasSpareRenderer() { return !spare_rphs_.empty(); }
private:
// Release ownership of a spare renderer. Called when the spare has either
// been 1) claimed to be used in a navigation or 2) shutdown somewhere else.
void ReleaseSpare(RenderProcessHost* host,
SpareRendererDispatchResult dispatch_result);
// RenderProcessHostObserver:
void RenderProcessReady(RenderProcessHost* host) override;
void RenderProcessExited(RenderProcessHost* host,
const ChildProcessTerminationInfo& info) override;
void RenderProcessHostDestroyed(RenderProcessHost* host) override;
// performance_scenarios::PerformanceScenarioObserver:
void OnLoadingScenarioChanged(
performance_scenarios::ScenarioScope scope,
performance_scenarios::LoadingScenario old_scenario,
performance_scenarios::LoadingScenario new_scenario) override;
void SetIsBrowserIdle(bool is_browser_idle);
// Start a spare renderer at a later time if there isn't one.
// This is to avoid resource contention between existing renderers and a
// new spare renderer.
void DeferredWarmupSpare(BrowserContext* browser_context,
base::TimeDelta delay,
std::optional<base::TimeDelta> timeout);
void StartDestroyTimer(std::optional<base::TimeDelta> timeout);
bool DestroyTimerWillFireBefore(base::TimeDelta timeout);
void OnMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
// When the system is under memory pressure, this function is called every 5
// minutes to determine when it ends.
void CheckIfMemoryPressureEnded();
// Returns true if an extra spare should be created.
bool ShouldCreateExtraSpare() const;
// Creates an extra spare, if ShouldCreateExtraSpare() returns true. This
// function is responsible for the creation of all the extra spares.
// `WarmupSpare()` is still responsible for creating the first one.
void MaybeCreateExtraSpare();
// Records heartbeat metrics for the spare RPHs. Called every 2 minutes.
void OnMetricsHeartbeatTimerFired();
#if BUILDFLAG(IS_ANDROID)
void OnApplicationStateChange(base::android::ApplicationState state);
#endif
// Checks various conditions that could prevent an embedder from using the
// spare.
std::optional<ContentBrowserClient::SpareProcessRefusedByEmbedderReason>
DoesEmbedderAllowSpareUsage(BrowserContext* browser_context,
SiteInstanceImpl* site_instance);
base::MemoryPressureListener memory_pressure_listener_;
// If this timer is running, then the system is under memory pressure.
// TODO(380805024): Remove the polling timer when possible.
base::RepeatingTimer check_memory_pressure_timer_;
// The clients who want to know when the spare render process host has
// changed.
base::ObserverList<Observer> observer_list_;
// All spare RPHs. RPH instances are self-owned, hence the raw pointers.
std::vector<RenderProcessHost*> spare_rphs_;
// The timer used to track the startup time of the spare renderer process.
// The elapsed time will be tracked even if the spare renderer is destroyed
// for memory pressure or timeout.
std::unique_ptr<base::ElapsedTimer> process_startup_timer_;
// The timer used to track the delay of spare renderer creation.
std::unique_ptr<base::ElapsedTimer> delay_timer_;
// The timer used to track the time from the last spare renderer creation to
// the next call to MaybeTakeSpare(). Note that the created spare renderer
// might have already been deleted at the time MaybeTakeSpare() runs, but we
// still want to record it so that we can potentially adjust the timeout of
// the spare renderer.
std::unique_ptr<base::ElapsedTimer> spare_renderer_maybe_take_timer_;
base::OneShotTimer deferred_warmup_timer_;
base::OneShotTimer deferred_destroy_timer_;
// The reason for there being no spare render process present.
NoSpareRendererReason no_spare_renderer_reason_ =
NoSpareRendererReason::kNotYetCreatedFirstLaunch;
// The process allocation context for the previous successful
// MaybeTakeSpare() function call.
std::optional<ProcessAllocationContext> previous_taken_context_;
// Indicates if the browser is not currently loading content.
bool is_browser_idle_ = true;
base::RepeatingTimer metrics_heartbeat_timer_;
#if BUILDFLAG(IS_ANDROID)
std::unique_ptr<base::android::ApplicationStatusListener>
app_status_listener_;
bool is_app_backgroud_;
#endif
};
} // namespace content
#endif // CONTENT_BROWSER_RENDERER_HOST_SPARE_RENDER_PROCESS_HOST_MANAGER_IMPL_H_
|