Skip to content

Commit

Permalink
Make each render process provide its private memory footprint for bro…
Browse files Browse the repository at this point in the history
…wser process.

Because of the "hidepid=2" mount option for /proc on Android,
browser process cannot open /proc/{render process pid}/maps and
status, i.e. no such file or directory.
So add PrivateMemoryFootprintProvider, which uses MemoryUsageMonitor,
to third_party/blink/renderer/controller and provides the calculated
private memory footprint for browser process by using render_host.mojom.

Bug: 1393283

Change-Id: Ibb00262afc2ed0552e3f0c2ec5fb7449878b93c9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4124620
Reviewed-by: Arthur Sonzogni <arthursonzogni@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Kinuko Yasuda <kinuko@chromium.org>
Commit-Queue: Takashi Sakamoto <tasak@google.com>
Cr-Commit-Position: refs/heads/main@{#1096563}
  • Loading branch information
tasak authored and Chromium LUCI CQ committed Jan 25, 2023
1 parent 5630648 commit 9f5e410
Show file tree
Hide file tree
Showing 14 changed files with 195 additions and 3 deletions.
Expand Up @@ -3,7 +3,6 @@
// found in the LICENSE file.

#include "content/browser/memory_pressure/user_level_memory_pressure_signal_generator.h"
#include "base/task/sequenced_task_runner.h"

#if BUILDFLAG(IS_ANDROID)
#include <ctype.h>
Expand Down Expand Up @@ -199,6 +198,13 @@ uint64_t UserLevelMemoryPressureSignalGenerator::
add_process_private_footprint(base::Process::Current());

// Measure private memory footprints of GPU process and Utility processes.
// Since GPU process uses the same user id as the browser process (android),
// the browser process can measure the GPU's private memory footprint.
// However, regarding the utility processes, their user ids are different.
// So because of the hidepid=2 mount option, the browser process cannot
// measure the private memory footprints of the utility processes.
// TODO(crbug.com/1393283): measure the private memory footprints of
// the utility processes correctly.
for (content::BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
add_process_private_footprint(iter.GetData().GetProcess());
}
Expand All @@ -224,7 +230,14 @@ uint64_t UserLevelMemoryPressureSignalGenerator::
continue;
}

total_private_footprint_bytes += GetPrivateFootprint(process).value_or(0);
// Because of the "hidepid=2" mount option for /proc on Android,
// the browser process cannot open /proc/{render process pid}/maps and
// status, i.e. no such file or directory. So each renderer process
// provides its private memory footprint for the browser process and
// the browser process gets the (cached) value via RenderProcessHostImpl.
total_private_footprint_bytes +=
static_cast<content::RenderProcessHostImpl*>(host)
->GetPrivateMemoryFootprint();
}
return total_private_footprint_bytes;
}
Expand Down Expand Up @@ -267,7 +280,7 @@ void UserLevelMemoryPressureSignalGenerator::NotifyMemoryPressure() {

namespace {

// TODO(crbug.com/1393282): if this feature is approved, refactor the duplicate
// TODO(crbug.com/1393283): if this feature is approved, refactor the duplicate
// code under //third_party/blink/renderer/controller. If not approved,
// remove the code as soon as possible.
absl::optional<uint64_t> CalculateProcessMemoryFootprint(
Expand Down
7 changes: 7 additions & 0 deletions content/browser/renderer_host/render_process_host_impl.cc
Expand Up @@ -4888,6 +4888,13 @@ void RenderProcessHostImpl::RecordUserMetricsAction(const std::string& action) {
base::RecordComputedAction(action);
}

#if BUILDFLAG(IS_ANDROID)
void RenderProcessHostImpl::SetPrivateMemoryFootprint(
uint64_t private_memory_footprint_bytes) {
private_memory_footprint_bytes_ = private_memory_footprint_bytes;
}
#endif

void RenderProcessHostImpl::UpdateProcessPriorityInputs() {
int32_t new_visible_widgets_count = 0;
unsigned int new_frame_depth = kMaxFrameDepthForPriority;
Expand Down
13 changes: 13 additions & 0 deletions content/browser/renderer_host/render_process_host_impl.h
Expand Up @@ -744,6 +744,10 @@ class CONTENT_EXPORT RenderProcessHostImpl
// Notifies the renderer process of memory pressure level.
void NotifyMemoryPressureToRenderer(
base::MemoryPressureListener::MemoryPressureLevel level);

uint64_t GetPrivateMemoryFootprint() const {
return private_memory_footprint_bytes_;
}
#endif

protected:
Expand Down Expand Up @@ -826,6 +830,10 @@ class CONTENT_EXPORT RenderProcessHostImpl
BrowserHistogramCallback callback) override;
void SuddenTerminationChanged(bool enabled) override;
void RecordUserMetricsAction(const std::string& action) override;
#if BUILDFLAG(IS_ANDROID)
void SetPrivateMemoryFootprint(
uint64_t private_memory_footprint_bytes) override;
#endif

void CreateEmbeddedFrameSinkProvider(
mojo::PendingReceiver<blink::mojom::EmbeddedFrameSinkProvider> receiver);
Expand Down Expand Up @@ -1237,6 +1245,11 @@ class CONTENT_EXPORT RenderProcessHostImpl
scoped_refptr<PepperRendererConnection> pepper_renderer_connection_;
#endif

#if BUILDFLAG(IS_ANDROID)
// The private memory footprint of the render process.
uint64_t private_memory_footprint_bytes_ = 0u;
#endif

// IOThreadHostImpl owns some IO-thread state associated with this
// RenderProcessHostImpl. This is mainly to allow various IPCs from the
// renderer to be handled on the IO thread without a hop to the UI thread.
Expand Down
18 changes: 18 additions & 0 deletions content/common/renderer_host.mojom
Expand Up @@ -21,4 +21,22 @@ interface RendererHost {

// Sends a string to be recorded by UserMetrics.
RecordUserMetricsAction(string action);

// Provides this render process' private memory footprint to the browser.
// Used by the UserLevelMemoryPressureSignalGenerator.
//
// In case of compromised renderer process:
// - Reporting small values make it less likely for a memory pressure signal
// to be sent. This isn't a big deal, it only increase the changes the OS to
// start killing the renderer process.
// - Reporting large values makes Chrome to dispatch memory pressure
// signal needlessly. There is a 10 minutes wait in between them. It is not
// particularly worrying.
//
// TODO(https://crbug.com/1393283): if the
// UserLevelMemoryPressureSignalGenerator is approved, investigate a
// possibility to gather data inside the browser process, via e.g.
// getProcessMemoryInfo.
[EnableIf=is_android]
SetPrivateMemoryFootprint(uint64 private_memory_footprint_bytes);
};
5 changes: 5 additions & 0 deletions content/public/test/render_view_test.cc
Expand Up @@ -228,6 +228,11 @@ class RendererBlinkPlatformImplTestOverrideImpl
// Get rid of the dependency to the sandbox, which is not available in
// RenderViewTest.
blink::WebSandboxSupport* GetSandboxSupport() override { return nullptr; }

#if BUILDFLAG(IS_ANDROID)
void SetPrivateMemoryFootprint(
uint64_t private_memory_footprint_bytes) override {}
#endif
};

class RenderFrameWasShownWaiter : public RenderFrameObserver {
Expand Down
7 changes: 7 additions & 0 deletions content/renderer/render_thread_impl.cc
Expand Up @@ -1878,4 +1878,11 @@ std::unique_ptr<CodecFactory> RenderThreadImpl::CreateMediaCodecFactory(
#endif
}

#if BUILDFLAG(IS_ANDROID)
void RenderThreadImpl::SetPrivateMemoryFootprint(
uint64_t private_memory_footprint_bytes) {
GetRendererHost()->SetPrivateMemoryFootprint(private_memory_footprint_bytes);
}
#endif

} // namespace content
5 changes: 5 additions & 0 deletions content/renderer/render_thread_impl.h
Expand Up @@ -386,6 +386,11 @@ class CONTENT_EXPORT RenderThreadImpl
run_loop_start_time_ = run_loop_start_time;
}

#if BUILDFLAG(IS_ANDROID)
// Provide private memory footprint for browser process.
void SetPrivateMemoryFootprint(uint64_t private_memory_footprint_bytes);
#endif

private:
friend class RenderThreadImplBrowserTest;
friend class AgentSchedulingGroup;
Expand Down
9 changes: 9 additions & 0 deletions content/renderer/renderer_blink_platform_impl.cc
Expand Up @@ -1054,4 +1054,13 @@ RendererBlinkPlatformImpl::VideoFrameCompositorTaskRunner() {
return compositor_task_runner;
}

#if BUILDFLAG(IS_ANDROID)
void RendererBlinkPlatformImpl::SetPrivateMemoryFootprint(
uint64_t private_memory_footprint_bytes) {
auto* render_thread = RenderThreadImpl::current();
CHECK(render_thread);
render_thread->SetPrivateMemoryFootprint(private_memory_footprint_bytes);
}
#endif

} // namespace content
4 changes: 4 additions & 0 deletions content/renderer/renderer_blink_platform_impl.h
Expand Up @@ -230,6 +230,10 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl {
override;
scoped_refptr<base::SingleThreadTaskRunner> VideoFrameCompositorTaskRunner()
override;
#if BUILDFLAG(IS_ANDROID)
void SetPrivateMemoryFootprint(
uint64_t private_memory_footprint_bytes) override;
#endif

// Tells this platform that the renderer is locked to a site (i.e., a scheme
// plus eTLD+1, such as https://google.com), or to a more specific origin.
Expand Down
6 changes: 6 additions & 0 deletions third_party/blink/public/platform/platform.h
Expand Up @@ -793,6 +793,12 @@ class BLINK_PLATFORM_EXPORT Platform {
return attribution_reporting::mojom::OsSupport::kDisabled;
}

#if BUILDFLAG(IS_ANDROID)
// User Level Memory Pressure Signal Generator ------------------
virtual void SetPrivateMemoryFootprint(
uint64_t private_memory_footprint_bytes) {}
#endif

private:
static void InitializeMainThreadCommon(
Platform* platform,
Expand Down
2 changes: 2 additions & 0 deletions third_party/blink/renderer/controller/BUILD.gn
Expand Up @@ -74,6 +74,8 @@ component("controller") {
"memory_usage_monitor_posix.h",
"oom_intervention_impl.cc",
"oom_intervention_impl.h",
"private_memory_footprint_provider.cc",
"private_memory_footprint_provider.h",
]
public_deps = [ "//third_party/blink/public/mojom:memory_usage_monitor_linux_mojo_bindings_blink" ]
}
Expand Down
7 changes: 7 additions & 0 deletions third_party/blink/renderer/controller/blink_initializer.cc
Expand Up @@ -70,6 +70,7 @@
#if BUILDFLAG(IS_ANDROID)
#include "third_party/blink/renderer/controller/crash_memory_metrics_reporter_impl.h"
#include "third_party/blink/renderer/controller/oom_intervention_impl.h"
#include "third_party/blink/renderer/controller/private_memory_footprint_provider.h"
#endif

#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
Expand Down Expand Up @@ -248,6 +249,12 @@ void BlinkInitializer::RegisterMemoryWatchers() {
// navigation.
HighestPmfReporter::Initialize(main_thread_task_runner);
#endif

#if BUILDFLAG(IS_ANDROID)
// Initialize PrivateMemoryFootprintProvider to start providing the value
// for the browser process.
PrivateMemoryFootprintProvider::Initialize(main_thread_task_runner);
#endif
}

void BlinkInitializer::InitLocalFrame(LocalFrame& frame) const {
Expand Down
@@ -0,0 +1,44 @@
// 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.

#include "third_party/blink/renderer/controller/private_memory_footprint_provider.h"

#include "base/task/task_runner.h"
#include "base/time/default_tick_clock.h"
#include "third_party/blink/public/platform/platform.h"

namespace blink {

void PrivateMemoryFootprintProvider::Initialize(
scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
DEFINE_STATIC_LOCAL(PrivateMemoryFootprintProvider, provider,
(std::move(task_runner)));
(void)provider;
}

PrivateMemoryFootprintProvider::PrivateMemoryFootprintProvider(
scoped_refptr<base::SingleThreadTaskRunner> task_runner)
: PrivateMemoryFootprintProvider(std::move(task_runner),
base::DefaultTickClock::GetInstance()) {}

PrivateMemoryFootprintProvider::PrivateMemoryFootprintProvider(
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
const base::TickClock* clock)
: task_runner_(std::move(task_runner)), clock_(clock) {
MemoryUsageMonitor::Instance().AddObserver(this);
}

void PrivateMemoryFootprintProvider::OnMemoryPing(MemoryUsage usage) {
DCHECK(IsMainThread());
SetPrivateMemoryFootprint(
static_cast<uint64_t>(usage.private_footprint_bytes));
}

void PrivateMemoryFootprintProvider::SetPrivateMemoryFootprint(
uint64_t private_memory_footprint_bytes) {
Platform::Current()->SetPrivateMemoryFootprint(
private_memory_footprint_bytes);
}

} // namespace blink
@@ -0,0 +1,52 @@
// 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 THIRD_PARTY_BLINK_RENDERER_CONTROLLER_PRIVATE_MEMORY_FOOTPRINT_PROVIDER_H_
#define THIRD_PARTY_BLINK_RENDERER_CONTROLLER_PRIVATE_MEMORY_FOOTPRINT_PROVIDER_H_

#include "base/time/time.h"
#include "third_party/blink/renderer/controller/controller_export.h"
#include "third_party/blink/renderer/controller/memory_usage_monitor.h"
#include "third_party/blink/renderer/platform/timer.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"

namespace base {
class SingleThreadTaskRunner;
class TickClock;
} // namespace base

namespace blink {

// Provides this renderer process' private memory footprint for browser process.
class CONTROLLER_EXPORT PrivateMemoryFootprintProvider
: public MemoryUsageMonitor::Observer {
USING_FAST_MALLOC(PrivateMemoryFootprintProvider);

public:
// Initializes the shared instance. Has no effect if called more than once.
static void Initialize(
scoped_refptr<base::SingleThreadTaskRunner> task_runner);

private:
explicit PrivateMemoryFootprintProvider(
scoped_refptr<base::SingleThreadTaskRunner> task_runner);

PrivateMemoryFootprintProvider(
scoped_refptr<base::SingleThreadTaskRunner> task_runner_for_testing,
const base::TickClock* clock);

// MemoryUsageMonitor::Observer:
void OnMemoryPing(MemoryUsage) override;

// Use mojom to provide private memory footprint for this RendererHost in
// the browser process.
void SetPrivateMemoryFootprint(uint64_t private_memory_footprint_bytes);

scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
const base::TickClock* clock_;
};

} // namespace blink

#endif // THIRD_PARTY_BLINK_RENDERER_CONTROLLER_PMF_REPORTER_H_

0 comments on commit 9f5e410

Please sign in to comment.