blob: beb2d175d23f0321dda223e55eced1202fe210e6 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/342213636): Remove this and spanify to fix the errors.
#pragma allow_unsafe_buffers
#endif
#include "content/renderer/render_thread_impl.h"
#include <algorithm>
#include <atomic>
#include <limits>
#include <map>
#include <memory>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "base/allocator/partition_alloc_support.h"
#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/debug/crash_logging.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/discardable_memory_allocator.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/structured_shared_memory.h"
#include "base/message_loop/message_pump.h"
#include "base/message_loop/message_pump_type.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/histogram_macros_local.h"
#include "base/observer_list.h"
#include "base/path_service.h"
#include "base/process/process.h"
#include "base/process/process_metrics.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "base/task/bind_post_task.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/threading/simple_thread.h"
#include "base/threading/thread_restrictions.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/memory_pressure_level_proto.h"
#include "base/trace_event/trace_event.h"
#include "base/values.h"
#include "build/build_config.h"
#include "cc/base/histograms.h"
#include "cc/base/switches.h"
#include "cc/mojo_embedder/async_layer_tree_frame_sink.h"
#include "cc/raster/task_graph_runner.h"
#include "cc/tiles/image_decode_cache_utils.h"
#include "cc/trees/layer_tree_frame_sink.h"
#include "cc/trees/layer_tree_settings.h"
#include "cc/trees/raster_context_provider_wrapper.h"
#include "components/discardable_memory/client/client_discardable_shared_memory_manager.h"
#include "components/metrics/public/mojom/single_sample_metrics.mojom.h"
#include "components/metrics/single_sample_metrics.h"
#include "components/viz/common/features.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/switches.h"
#include "content/child/runtime_features.h"
#include "content/common/buildflags.h"
#include "content/common/content_constants_internal.h"
#include "content/common/content_switches_internal.h"
#include "content/common/features.h"
#include "content/common/main_frame_counter.h"
#include "content/common/process_visibility_tracker.h"
#include "content/common/pseudonymization_salt.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_constants.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_paths.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/gpu_stream_constants.h"
#include "content/public/common/url_constants.h"
#include "content/public/renderer/content_renderer_client.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_thread_observer.h"
#include "content/renderer/agent_scheduling_group.h"
#include "content/renderer/browser_exposed_renderer_interfaces.h"
#include "content/renderer/effective_connection_type_helper.h"
#include "content/renderer/media/media_factory.h"
#include "content/renderer/media/render_media_client.h"
#include "content/renderer/net_info_helper.h"
#include "content/renderer/render_process_impl.h"
#include "content/renderer/renderer_blink_platform_impl.h"
#include "content/renderer/service_worker/service_worker_context_client.h"
#include "content/renderer/variations_render_thread_observer.h"
#include "content/renderer/worker/embedded_shared_worker_stub.h"
#include "content/renderer/worker/worker_thread_registry.h"
#include "device/gamepad/public/cpp/gamepads.h"
#include "gin/public/debug.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/client/raster_interface.h"
#include "gpu/command_buffer/client/shared_memory_limits.h"
#include "gpu/config/gpu_driver_bug_workarounds.h"
#include "gpu/config/gpu_finch_features.h"
#include "gpu/config/gpu_switches.h"
#include "gpu/ipc/client/client_shared_image_interface.h"
#include "gpu/ipc/client/command_buffer_proxy_impl.h"
#include "gpu/ipc/client/gpu_channel_host.h"
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_channel_mojo.h"
#include "ipc/ipc_platform_file.h"
#include "media/base/decoder_factory.h"
#include "media/base/media.h"
#include "media/base/media_switches.h"
#include "media/media_buildflags.h"
#include "media/mojo/clients/mojo_codec_factory.h"
#include "media/mojo/clients/mojo_gpu_video_accelerator_factories.h"
#include "media/renderers/default_decoder_factory.h"
#include "media/video/gpu_video_accelerator_factories.h"
#include "mojo/public/cpp/bindings/binder_map.h"
#include "mojo/public/cpp/bindings/callback_helpers.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "net/base/net_errors.h"
#include "net/base/port_util.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/base/url_util.h"
#include "ppapi/buildflags/buildflags.h"
#include "services/network/public/cpp/network_switches.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "services/viz/public/cpp/gpu/context_provider_command_buffer.h"
#include "services/viz/public/cpp/gpu/gpu.h"
#include "skia/ext/font_utils.h"
#include "skia/ext/skia_memory_dump_provider.h"
#include "third_party/blink/public/common/origin_trials/origin_trials_settings_provider.h"
#include "third_party/blink/public/common/page/launching_process_state.h"
#include "third_party/blink/public/common/switches.h"
#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
#include "third_party/blink/public/mojom/origin_trials/origin_trials_settings.mojom.h"
#include "third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h"
#include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
#include "third_party/blink/public/platform/web_cache.h"
#include "third_party/blink/public/platform/web_image_generator.h"
#include "third_party/blink/public/platform/web_memory_pressure_listener.h"
#include "third_party/blink/public/platform/web_network_state_notifier.h"
#include "third_party/blink/public/platform/web_runtime_features.h"
#include "third_party/blink/public/platform/web_scoped_page_pauser.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_theme_engine.h"
#include "third_party/blink/public/web/blink.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_frame.h"
#include "third_party/blink/public/web/web_render_theme.h"
#include "third_party/blink/public/web/web_security_policy.h"
#include "third_party/blink/public/web/web_user_level_memory_pressure_signal_generator.h"
#include "third_party/blink/public/web/web_v8_features.h"
#include "third_party/blink/public/web/web_view.h"
#include "third_party/skia/include/core/SkFontMgr.h"
#include "third_party/skia/include/core/SkGraphics.h"
#include "ui/base/ui_base_switches.h"
#include "ui/base/ui_base_switches_util.h"
#include "ui/display/display_switches.h"
#include "v8/include/v8-extension.h"
#if BUILDFLAG(IS_ANDROID)
#include <cpu-features.h>
#include "content/renderer/media/android/stream_texture_factory.h"
#include "media/base/android/media_codec_util.h"
#endif
#if BUILDFLAG(IS_MAC)
#include "base/mac/mac_util.h"
#include "content/renderer/theme_helper_mac.h"
#endif
#if BUILDFLAG(IS_WIN)
#include <objbase.h>
#include <windows.h>
#include "content/renderer/media/win/dcomp_texture_factory.h"
#include "content/renderer/media/win/overlay_state_service_provider.h"
#include "media/base/win/mf_feature_checks.h"
#endif
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#include "content/child/sandboxed_process_thread_type_handler.h"
#endif
#ifdef ENABLE_VTUNE_JIT_INTERFACE
#include "v8/third_party/vtune/v8-vtune.h"
#endif
#if defined(ENABLE_IPC_FUZZER)
#include "content/common/external_ipc_dumper.h"
#include "mojo/public/cpp/bindings/message_dumper.h"
#endif
#if BUILDFLAG(IS_APPLE)
#include <malloc/malloc.h>
#else
#include <malloc.h>
#endif
#if BUILDFLAG(ENABLE_MOJO_VIDEO_DECODER)
#include "media/mojo/clients/mojo_codec_factory_mojo_decoder.h"
#include "media/mojo/mojom/interface_factory.mojom.h"
#endif
#if BUILDFLAG(IS_FUCHSIA)
#include "media/mojo/clients/mojo_codec_factory_fuchsia.h"
#include "media/mojo/mojom/fuchsia_media.mojom.h"
#endif
#if BUILDFLAG(CLANG_PROFILING_INSIDE_SANDBOX)
#include "base/test/clang_profiling.h"
#endif
namespace content {
namespace {
using ::base::PassKey;
using ::blink::WebDocument;
using ::blink::WebFrame;
using ::blink::WebNetworkStateNotifier;
using ::blink::WebRuntimeFeatures;
using ::blink::WebSecurityPolicy;
using ::blink::WebString;
using ::blink::WebView;
// Keep the global RenderThreadImpl in a TLS slot so it is impossible to access
// incorrectly from the wrong thread.
constinit thread_local RenderThreadImpl* render_thread = nullptr;
base::LazyInstance<scoped_refptr<base::SingleThreadTaskRunner>>::
DestructorAtExit g_main_task_runner = LAZY_INSTANCE_INITIALIZER;
// v8::MemoryPressureLevel should correspond to base::MemoryPressureListener.
static_assert(static_cast<v8::MemoryPressureLevel>(
base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) ==
v8::MemoryPressureLevel::kNone,
"none level not align");
static_assert(
static_cast<v8::MemoryPressureLevel>(
base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE) ==
v8::MemoryPressureLevel::kModerate,
"moderate level not align");
static_assert(
static_cast<v8::MemoryPressureLevel>(
base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) ==
v8::MemoryPressureLevel::kCritical,
"critical level not align");
// Feature to migrate the Media thread to a SequencedTaskRunner backed from
// the base::ThreadPool. Does not currently work on Fuchsia due to FIDL
// requiring thread affinity.
BASE_FEATURE(kUseThreadPoolForMediaTaskRunner,
"UseThreadPoolForMediaTaskRunner",
base::FEATURE_DISABLED_BY_DEFAULT);
// Updates the crash key for whether this renderer is foregrounded.
void UpdateForegroundCrashKey(bool foreground) {
static auto* const crash_key = base::debug::AllocateCrashKeyString(
"renderer_foreground", base::debug::CrashKeySize::Size32);
base::debug::SetCrashKeyString(crash_key, foreground ? "true" : "false");
}
scoped_refptr<viz::ContextProviderCommandBuffer> CreateOffscreenContext(
scoped_refptr<gpu::GpuChannelHost> gpu_channel_host,
const gpu::SharedMemoryLimits& limits,
bool support_locking,
bool support_gles2_interface,
bool support_raster_interface,
bool support_oop_rasterization,
bool support_grcontext,
bool automatic_flushes,
viz::command_buffer_metrics::ContextType type,
int32_t stream_id,
gpu::SchedulingPriority stream_priority) {
DCHECK(gpu_channel_host);
// This is used to create a few different offscreen contexts:
// - The shared main thread context, used by blink for 2D Canvas.
// - The compositor worker context, used for GPU raster.
// - The media context, used for accelerated video decoding.
// This is for an offscreen context, so the default framebuffer doesn't need
// alpha, depth, stencil, antialiasing.
gpu::ContextCreationAttribs attributes;
attributes.bind_generates_resource = false;
attributes.lose_context_when_out_of_memory = true;
attributes.enable_gles2_interface = support_gles2_interface;
attributes.enable_raster_interface = support_raster_interface;
attributes.enable_grcontext = support_grcontext;
// Using RasterDecoder for OOP-R backend, so we need support_raster_interface
// and !support_gles2_interface.
attributes.enable_oop_rasterization = support_oop_rasterization &&
support_raster_interface &&
!support_gles2_interface;
return base::MakeRefCounted<viz::ContextProviderCommandBuffer>(
std::move(gpu_channel_host), stream_id, stream_priority,
GURL("chrome://gpu/RenderThreadImpl::CreateOffscreenContext/" +
viz::command_buffer_metrics::ContextTypeToString(type)),
automatic_flushes, support_locking, limits, attributes, type);
}
// Hook that allows single-sample metric code from //components/metrics to
// connect from the renderer process to the browser process.
void CreateSingleSampleMetricsProvider(
mojo::SharedRemote<mojom::ChildProcessHost> process_host,
mojo::PendingReceiver<metrics::mojom::SingleSampleMetricsProvider>
receiver) {
process_host->BindHostReceiver(std::move(receiver));
}
static bool IsSingleProcess() {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kSingleProcess);
}
// Returns true if `process_priority` should be considered as backgrounded.
bool IsBackgrounded(std::optional<base::Process::Priority> process_priority) {
// Not backgrounded until we've received a state from the browser.
if (!process_priority.has_value()) {
return false;
}
switch (*process_priority) {
case base::Process::Priority::kBestEffort:
return true;
case base::Process::Priority::kUserVisible:
case base::Process::Priority::kUserBlocking:
return false;
}
}
perfetto::StaticString ProcessPriorityToString(
base::Process::Priority priority) {
switch (priority) {
case base::Process::Priority::kBestEffort:
return "Best effort";
case base::Process::Priority::kUserVisible:
return "User visible";
case base::Process::Priority::kUserBlocking:
return "User blocking";
}
NOTREACHED();
}
perfetto::StaticString ProcessVisibilityToString(
mojom::RenderProcessVisibleState visible_state) {
switch (visible_state) {
case mojom::RenderProcessVisibleState::kVisible:
return "Visible";
case mojom::RenderProcessVisibleState::kHidden:
return "Hidden";
}
NOTREACHED();
}
} // namespace
RenderThreadImpl::HistogramCustomizer::HistogramCustomizer() {
custom_histograms_.insert("V8.MemoryHeapSampleTotalCommitted");
}
RenderThreadImpl::HistogramCustomizer::~HistogramCustomizer() {}
void RenderThreadImpl::HistogramCustomizer::RenderViewNavigatedToHost(
const std::string& host,
size_t view_count) {
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableHistogramCustomizer)) {
return;
}
// Check if all RenderViews are displaying a page from the same host. If there
// is only one RenderView, the common host is this view's host. If there are
// many, check if this one shares the common host of the other
// RenderViews. It's ok to not detect some cases where the RenderViews share a
// common host. This information is only used for producing custom histograms.
if (view_count == 1)
SetCommonHost(host);
else if (host != common_host_)
SetCommonHost(std::string());
}
std::string RenderThreadImpl::HistogramCustomizer::ConvertToCustomHistogramName(
const char* histogram_name) const {
std::string name(histogram_name);
if (!common_host_histogram_suffix_.empty() &&
base::Contains(custom_histograms_, name)) {
name += common_host_histogram_suffix_;
}
return name;
}
void RenderThreadImpl::HistogramCustomizer::SetCommonHost(
const std::string& host) {
if (host != common_host_) {
common_host_ = host;
common_host_histogram_suffix_ = HostToCustomHistogramSuffix(host);
}
}
std::string RenderThreadImpl::HistogramCustomizer::HostToCustomHistogramSuffix(
const std::string& host) {
if (host == "mail.google.com")
return ".gmail";
if (host == "docs.google.com" || host == "drive.google.com")
return ".docs";
if (host == "plus.google.com")
return ".plus";
if (host == "inbox.google.com")
return ".inbox";
if (host == "calendar.google.com")
return ".calendar";
if (host == "www.youtube.com")
return ".youtube";
if (IsAlexaTop10NonGoogleSite(host))
return ".top10";
return std::string();
}
bool RenderThreadImpl::HistogramCustomizer::IsAlexaTop10NonGoogleSite(
const std::string& host) {
// The Top10 sites have different TLD and/or subdomains depending on the
// localization.
if (host == "sina.com.cn")
return true;
std::string sanitized_host =
net::registry_controlled_domains::GetDomainAndRegistry(
host, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
if (sanitized_host == "facebook.com")
return true;
if (sanitized_host == "baidu.com")
return true;
if (sanitized_host == "qq.com")
return true;
if (sanitized_host == "twitter.com")
return true;
if (sanitized_host == "taobao.com")
return true;
if (sanitized_host == "live.com")
return true;
if (!sanitized_host.empty()) {
std::vector<std::string_view> host_tokens = base::SplitStringPiece(
sanitized_host, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
if (host_tokens.size() >= 2) {
if ((host_tokens[0] == "yahoo") || (host_tokens[0] == "amazon") ||
(host_tokens[0] == "wikipedia")) {
return true;
}
}
}
return false;
}
// static
RenderThreadImpl* RenderThreadImpl::current() {
return render_thread;
}
// static
scoped_refptr<base::SingleThreadTaskRunner>
RenderThreadImpl::DeprecatedGetMainTaskRunner() {
return g_main_task_runner.Get();
}
// In single-process mode used for debugging, we don't pass a renderer client
// ID via command line because RenderThreadImpl lives in the same process as
// the browser
RenderThreadImpl::RenderThreadImpl(
const InProcessChildThreadParams& params,
int32_t client_id,
std::unique_ptr<blink::scheduler::WebThreadScheduler> scheduler)
: ChildThreadImpl(
base::DoNothing(),
Options::Builder()
.InBrowserProcess(params)
.ConnectToBrowser(true)
.IPCTaskRunner(scheduler->DeprecatedDefaultTaskRunner())
.ExposesInterfacesToBrowser()
.Build()),
main_thread_scheduler_(std::move(scheduler)),
client_id_(client_id) {
TRACE_EVENT0("startup", "RenderThreadImpl::Create");
TRACE_EVENT_BEGIN("renderer", "Unknown", process_priority_track_);
TRACE_EVENT_BEGIN("renderer", "Unknown", process_visibility_track_);
Init();
}
namespace {
int32_t GetClientIdFromCommandLine() {
DCHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kRendererClientId));
int32_t client_id;
base::StringToInt(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kRendererClientId),
&client_id);
return client_id;
}
} // anonymous namespace
// Multi-process mode.
RenderThreadImpl::RenderThreadImpl(
base::RepeatingClosure quit_closure,
std::unique_ptr<blink::scheduler::WebThreadScheduler> scheduler)
: ChildThreadImpl(
std::move(quit_closure),
Options::Builder()
.ConnectToBrowser(true)
.IPCTaskRunner(scheduler->DeprecatedDefaultTaskRunner())
.ExposesInterfacesToBrowser()
.SetUrgentMessageObserver(scheduler.get())
.Build()),
main_thread_scheduler_(std::move(scheduler)),
client_id_(GetClientIdFromCommandLine()) {
TRACE_EVENT0("startup", "RenderThreadImpl::Create");
TRACE_EVENT_BEGIN("renderer", "Unknown", process_priority_track_);
TRACE_EVENT_BEGIN("renderer", "Unknown", process_visibility_track_);
Init();
}
void RenderThreadImpl::Init() {
TRACE_EVENT0("startup", "RenderThreadImpl::Init");
SCOPED_UMA_HISTOGRAM_TIMER("Renderer.RenderThreadImpl.Init");
GetContentClient()->renderer()->PostIOThreadCreated(GetIOTaskRunner().get());
#if BUILDFLAG(USE_EXTERNAL_POPUP_MENU)
// On Mac and Android Java UI, the select popups are rendered by the browser.
blink::WebView::SetUseExternalPopupMenus(true);
#endif
render_thread = this;
g_main_task_runner.Get() = base::SingleThreadTaskRunner::GetCurrentDefault();
// Register this object as the main thread.
ChildProcess::current()->set_main_thread(this);
metrics::InitializeSingleSampleMetricsFactory(base::BindRepeating(
&CreateSingleSampleMetricsProvider, child_process_host()));
mojo::PendingRemote<viz::mojom::Gpu> remote_gpu;
BindHostReceiver(remote_gpu.InitWithNewPipeAndPassReceiver());
gpu_ = viz::Gpu::Create(std::move(remote_gpu), GetIOTaskRunner());
// Establish the GPU channel now, so its ready when needed and we don't have
// to wait on a sync call.
if (base::FeatureList::IsEnabled(features::kEarlyEstablishGpuChannel)) {
gpu_->EstablishGpuChannel(
base::BindOnce([](scoped_refptr<gpu::GpuChannelHost> host) {
if (host)
GetContentClient()->SetGpuInfo(host->gpu_info());
}));
}
// NOTE: Do not add interfaces to |binders| within this method. Instead,
// modify the definition of |ExposeRendererInterfacesToBrowser()| to ensure
// security review coverage.
mojo::BinderMap binders;
InitializeWebKit(&binders);
vc_manager_ = std::make_unique<blink::WebVideoCaptureImplManager>();
GetContentClient()->renderer()->RenderThreadStarted();
ExposeRendererInterfacesToBrowser(weak_factory_.GetWeakPtr(), &binders);
ExposeInterfacesToBrowser(std::move(binders));
url_loader_throttle_provider_ =
GetContentClient()->renderer()->CreateURLLoaderThrottleProvider(
blink::URLLoaderThrottleProviderType::kFrame);
GetAssociatedInterfaceRegistry()->AddInterface<mojom::Renderer>(
base::BindRepeating(&RenderThreadImpl::OnRendererInterfaceReceiver,
base::Unretained(this)));
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
#if defined(ENABLE_IPC_FUZZER)
if (command_line.HasSwitch(switches::kIpcDumpDirectory)) {
base::FilePath dump_directory =
command_line.GetSwitchValuePath(switches::kIpcDumpDirectory);
IPC::ChannelProxy::OutgoingMessageFilter* filter =
LoadExternalIPCDumper(dump_directory);
GetChannel()->set_outgoing_message_filter(filter);
mojo::MessageDumper::SetMessageDumpDirectory(dump_directory);
}
#endif
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
SandboxedProcessThreadTypeHandler::NotifyMainChildThreadCreated();
#endif
cc::SetClientNameForMetrics("Renderer");
is_threaded_animation_enabled_ =
!command_line.HasSwitch(switches::kDisableThreadedAnimation);
is_elastic_overscroll_enabled_ = switches::IsElasticOverscrollEnabled();
if (command_line.HasSwitch(switches::kDisableLCDText)) {
is_lcd_text_enabled_ = false;
} else if (command_line.HasSwitch(switches::kEnableLCDText)) {
is_lcd_text_enabled_ = true;
} else {
#if BUILDFLAG(IS_ANDROID)
is_lcd_text_enabled_ = false;
#elif BUILDFLAG(IS_MAC)
is_lcd_text_enabled_ = IsSubpixelAntialiasingAvailable();
#else
is_lcd_text_enabled_ = true;
#endif
}
if (command_line.HasSwitch(switches::kDisableGpuCompositing))
is_gpu_compositing_disabled_ = true;
// Note that under Linux, the media library will normally already have
// been initialized by the Zygote before this instance became a Renderer.
media::InitializeMediaLibrary();
memory_pressure_listener_ = std::make_unique<base::MemoryPressureListener>(
FROM_HERE,
base::BindRepeating(&RenderThreadImpl::OnMemoryPressure,
base::Unretained(this)),
base::BindRepeating(&RenderThreadImpl::OnSyncMemoryPressure,
base::Unretained(this)));
discardable_memory_allocator_ = CreateDiscardableMemoryAllocator();
// TODO(boliu): In single process, browser main loop should set up the
// discardable memory manager, and should skip this if kSingleProcess.
// See crbug.com/503724.
base::DiscardableMemoryAllocator::SetInstance(
discardable_memory_allocator_.get());
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
ChildProcess::current()->SetIOThreadType(base::ThreadType::kDisplayCritical);
#endif
process_foregrounded_count_ = 0;
if (!is_gpu_compositing_disabled_) {
BindHostReceiver(compositing_mode_reporter_.BindNewPipeAndPassReceiver());
compositing_mode_reporter_->AddCompositingModeWatcher(
compositing_mode_watcher_receiver_.BindNewPipeAndPassRemote());
}
variations_observer_ = std::make_unique<VariationsRenderThreadObserver>();
AddObserver(variations_observer_.get());
base::ThreadPool::PostTask(FROM_HERE,
base::BindOnce([] { skia::DefaultFontMgr(); }));
UpdateForegroundCrashKey(
/*foreground=*/!blink::kLaunchingProcessIsBackgrounded);
use_cached_routing_table_ =
base::FeatureList::IsEnabled(features::kFrameRoutingCache);
if (use_cached_routing_table_) {
RequestNewItemsForFrameRoutingCache();
}
blink::WebV8Features::InitializeMojoJSAllowedProtectedMemory();
}
RenderThreadImpl::~RenderThreadImpl() {
TRACE_EVENT_END("renderer", process_priority_track_);
TRACE_EVENT_END("renderer", process_visibility_track_);
// The destructor should not run in multi-process mode because Shutdown()
// terminates the process. The destructor only needs to clean up for tests.
CHECK(IsSingleProcess());
g_main_task_runner.Get() = nullptr;
// Need to make sure this reference is removed on the correct task runner;
if (video_frame_compositor_thread_ &&
video_frame_compositor_context_provider_) {
video_frame_compositor_thread_->task_runner()->ReleaseSoon(
FROM_HERE, std::move(video_frame_compositor_context_provider_));
}
}
void RenderThreadImpl::Shutdown() {
ChildThreadImpl::Shutdown();
// In a multi-process mode, we immediately exit the renderer.
// Historically we had a graceful shutdown sequence here but it was
// 1) a waste of performance and 2) a source of lots of complicated
// crashes caused by shutdown ordering. Immediate exit eliminates
// those problems.
blink::LogStatsDuringShutdown();
// In a single-process mode, we cannot call _exit(0) in Shutdown() because
// it will exit the process before the browser side is ready to exit.
if (!IsSingleProcess())
base::Process::TerminateCurrentProcessImmediately(0);
}
bool RenderThreadImpl::ShouldBeDestroyed() {
DCHECK(IsSingleProcess());
// In a single-process mode, it is unsafe to destruct this renderer thread
// because we haven't run the shutdown sequence. Hence we leak the render
// thread.
//
// In this case, we also need to disable at-exit callbacks because some of
// the at-exit callbacks are expected to run after the renderer thread
// has been destructed.
base::AtExitManager::DisableAllAtExitManagers();
return false;
}
IPC::SyncChannel* RenderThreadImpl::GetChannel() {
return channel();
}
std::string RenderThreadImpl::GetLocale() {
// The browser process should have passed the locale to the renderer via the
// --lang command line flag.
const base::CommandLine& parsed_command_line =
*base::CommandLine::ForCurrentProcess();
const std::string& lang =
parsed_command_line.GetSwitchValueASCII(switches::kLang);
DCHECK(!lang.empty());
return lang;
}
#if BUILDFLAG(CONTENT_ENABLE_LEGACY_IPC)
IPC::SyncMessageFilter* RenderThreadImpl::GetSyncMessageFilter() {
return sync_message_filter();
}
void RenderThreadImpl::AddRoute(int32_t routing_id, IPC::Listener* listener) {
ChildThreadImpl::GetRouter()->AddRoute(routing_id, listener);
}
void RenderThreadImpl::AttachTaskRunnerToRoute(
int32_t routing_id,
scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
GetChannel()->AddListenerTaskRunner(routing_id, std::move(task_runner));
}
void RenderThreadImpl::RemoveRoute(int32_t routing_id) {
ChildThreadImpl::GetRouter()->RemoveRoute(routing_id);
GetChannel()->RemoveListenerTaskRunner(routing_id);
}
void RenderThreadImpl::AddFilter(IPC::MessageFilter* filter) {
channel()->AddFilter(filter);
}
void RenderThreadImpl::RemoveFilter(IPC::MessageFilter* filter) {
channel()->RemoveFilter(filter);
}
#endif
mojom::RendererHost* RenderThreadImpl::GetRendererHost() {
if (!renderer_host_) {
DCHECK(GetChannel());
GetChannel()->GetRemoteAssociatedInterface(&renderer_host_);
}
return renderer_host_.get();
}
bool RenderThreadImpl::GenerateFrameRoutingID(
int32_t& routing_id,
blink::LocalFrameToken& frame_token,
base::UnguessableToken& devtools_frame_token,
blink::DocumentToken& document_token) {
if (!use_cached_routing_table_) {
mojom::FrameRoutingInfoPtr info;
if (!render_message_filter()->GenerateSingleFrameRoutingInfo(&info)) {
return false;
}
routing_id = info->routing_id;
frame_token = info->frame_token;
devtools_frame_token = info->devtools_frame_token;
document_token = info->document_token;
return true;
}
// If table is empty force a synchronous fetch.
if (cached_frame_routing_.empty()) {
std::vector<mojom::FrameRoutingInfoPtr> infos;
if (!render_message_filter()->GenerateFrameRoutingInfos(&infos)) {
return false;
}
for (auto& info : infos) {
cached_frame_routing_.push_back(std::move(info));
}
}
auto& front = cached_frame_routing_.front();
routing_id = front->routing_id;
frame_token = front->frame_token;
devtools_frame_token = front->devtools_frame_token;
document_token = front->document_token;
cached_frame_routing_.pop_front();
// If the table drops to 2 or less, request an asynchronous populate.
if (!cached_items_requested_ && cached_frame_routing_.size() <= 2) {
RequestNewItemsForFrameRoutingCache();
}
return true;
}
void RenderThreadImpl::RequestNewItemsForFrameRoutingCache() {
cached_items_requested_ = true;
render_message_filter()->GenerateFrameRoutingInfos(
base::BindOnce(&RenderThreadImpl::PopulateFrameRoutingCacheWithItems,
base::Unretained(this)));
}
void RenderThreadImpl::PopulateFrameRoutingCacheWithItems(
std::vector<mojom::FrameRoutingInfoPtr> infos) {
cached_items_requested_ = false;
for (auto& info : infos) {
cached_frame_routing_.push_back(std::move(info));
}
}
void RenderThreadImpl::AddObserver(RenderThreadObserver* observer) {
observers_.AddObserver(observer);
observer->RegisterMojoInterfaces(&associated_interfaces_);
}
void RenderThreadImpl::RemoveObserver(RenderThreadObserver* observer) {
observer->UnregisterMojoInterfaces(&associated_interfaces_);
observers_.RemoveObserver(observer);
}
void RenderThreadImpl::InitializeCompositorThread() {
blink_platform_impl_->CreateAndSetCompositorThread();
compositor_task_runner_ = blink_platform_impl_->CompositorThreadTaskRunner();
compositor_task_runner_->PostTask(FROM_HERE,
base::BindOnce(&base::DisallowBlocking));
GetContentClient()->renderer()->PostCompositorThreadCreated(
compositor_task_runner_.get());
}
void RenderThreadImpl::InitializeWebKit(mojo::BinderMap* binders) {
DCHECK(!blink_platform_impl_);
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
#ifdef ENABLE_VTUNE_JIT_INTERFACE
if (command_line.HasSwitch(switches::kEnableVtune))
gin::Debug::SetJitCodeEventHandler(vTune::GetVtuneCodeEventHandler());
#endif
blink_platform_impl_ =
std::make_unique<RendererBlinkPlatformImpl>(main_thread_scheduler_.get());
// This, among other things, enables any feature marked "test" in
// runtime_enabled_features. It is run before
// SetRuntimeFeaturesDefaultsAndUpdateFromArgs() so that command line
// arguments take precedence over (and can disable) "test" features.
GetContentClient()
->renderer()
->SetRuntimeFeaturesDefaultsBeforeBlinkInitialization();
SetRuntimeFeaturesDefaultsAndUpdateFromArgs(command_line);
blink::Initialize(blink_platform_impl_.get(), binders,
main_thread_scheduler_.get());
if (!command_line.HasSwitch(switches::kDisableThreadedCompositing))
InitializeCompositorThread();
RenderThreadImpl::RegisterSchemes();
RenderMediaClient::Initialize();
// Hook up blink's codecs so skia can call them. Since only the renderer
// processes should be doing image decoding, this is not done in the common
// skia initialization code for the GPU.
SkGraphics::SetImageGeneratorFromEncodedDataFactory(
blink::WebImageGenerator::CreateAsSkImageGenerator);
}
void RenderThreadImpl::InitializeRenderer(
const std::string& user_agent,
const blink::UserAgentMetadata& user_agent_metadata,
const std::vector<std::string>& cors_exempt_header_list,
blink::mojom::OriginTrialsSettingsPtr origin_trials_settings,
uint64_t trace_id) {
TRACE_EVENT("navigation", "RenderThreadImpl::InitializeRenderer",
perfetto::TerminatingFlow::Global(trace_id));
DCHECK(user_agent_.IsNull());
user_agent_ = WebString::FromUTF8(user_agent);
GetContentClient()->renderer()->DidSetUserAgent(user_agent);
user_agent_metadata_ = user_agent_metadata;
cors_exempt_header_list_ = cors_exempt_header_list;
std::vector<blink::WebString> web_cors_exempt_header_list(
cors_exempt_header_list.size());
std::ranges::transform(
cors_exempt_header_list, web_cors_exempt_header_list.begin(),
[](const auto& header) { return blink::WebString::FromLatin1(header); });
blink::SetCorsExemptHeaderList(web_cors_exempt_header_list);
// In single process mode, the settings have already been set by the browser.
if (!IsSingleProcess()) {
blink::OriginTrialsSettingsProvider::Get()->SetSettings(
std::move(origin_trials_settings));
}
}
void RenderThreadImpl::RegisterSchemes() {
// chrome:
WebString chrome_scheme(WebString::FromASCII(kChromeUIScheme));
WebSecurityPolicy::RegisterURLSchemeAsDisplayIsolated(chrome_scheme);
WebSecurityPolicy::RegisterURLSchemeAsNotAllowingJavascriptURLs(
chrome_scheme);
WebSecurityPolicy::RegisterURLSchemeAsWebUI(chrome_scheme);
// Service workers for chrome://
if (base::FeatureList::IsEnabled(
features::kEnableServiceWorkersForChromeScheme)) {
WebSecurityPolicy::RegisterURLSchemeAsAllowingServiceWorkers(chrome_scheme);
}
WebString chrome_untrusted_scheme(
WebString::FromASCII(kChromeUIUntrustedScheme));
// chrome-untrusted:
// Service workers for chrome-untrusted://
if (base::FeatureList::IsEnabled(
features::kEnableServiceWorkersForChromeUntrusted)) {
WebSecurityPolicy::RegisterURLSchemeAsAllowingServiceWorkers(
chrome_untrusted_scheme);
}
WebSecurityPolicy::RegisterURLSchemeAsNotAllowingJavascriptURLs(
chrome_untrusted_scheme);
WebSecurityPolicy::RegisterURLSchemeAsSupportingFetchAPI(
chrome_untrusted_scheme);
WebSecurityPolicy::RegisterURLSchemeAsAllowingWasmEvalCSP(
chrome_untrusted_scheme);
if (base::FeatureList::IsEnabled(features::kWebUICodeCache)) {
WebSecurityPolicy::RegisterURLSchemeAsCodeCacheWithHashing(chrome_scheme);
WebSecurityPolicy::RegisterURLSchemeAsCodeCacheWithHashing(
chrome_untrusted_scheme);
}
// devtools:
WebString devtools_scheme(WebString::FromASCII(kChromeDevToolsScheme));
WebSecurityPolicy::RegisterURLSchemeAsDisplayIsolated(devtools_scheme);
WebSecurityPolicy::RegisterURLSchemeAsSupportingFetchAPI(devtools_scheme);
WebSecurityPolicy::RegisterURLSchemeAsNotAllowingJavascriptURLs(
devtools_scheme);
// view-source:
WebString view_source_scheme(WebString::FromASCII(kViewSourceScheme));
WebSecurityPolicy::RegisterURLSchemeAsDisplayIsolated(view_source_scheme);
// chrome-error:
WebString error_scheme(WebString::FromASCII(kChromeErrorScheme));
WebSecurityPolicy::RegisterURLSchemeAsDisplayIsolated(error_scheme);
WebSecurityPolicy::RegisterURLSchemeAsNotAllowingJavascriptURLs(error_scheme);
WebSecurityPolicy::RegisterURLSchemeAsError(error_scheme);
// googlechrome:
WebString google_chrome_scheme(WebString::FromASCII(kGoogleChromeScheme));
WebSecurityPolicy::RegisterURLSchemeAsDisplayIsolated(google_chrome_scheme);
}
void RenderThreadImpl::RecordAction(const base::UserMetricsAction& action) {
GetRendererHost()->RecordUserMetricsAction(action.str_);
}
void RenderThreadImpl::RecordComputedAction(const std::string& action) {
GetRendererHost()->RecordUserMetricsAction(action);
}
int RenderThreadImpl::PostTaskToAllWebWorkers(base::RepeatingClosure closure) {
return WorkerThreadRegistry::Instance()->PostTaskToAllThreads(
std::move(closure));
}
media::GpuVideoAcceleratorFactories* RenderThreadImpl::GetGpuFactories() {
DCHECK(IsMainThread());
if (!gpu_factories_.empty()) {
if (!gpu_factories_.back()->CheckContextProviderLostOnMainThread())
return gpu_factories_.back().get();
GetMediaSequencedTaskRunner()->PostTask(
FROM_HERE,
base::BindOnce(&media::MojoGpuVideoAcceleratorFactories::DestroyContext,
base::Unretained(gpu_factories_.back().get())));
}
const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
scoped_refptr<gpu::GpuChannelHost> gpu_channel_host =
EstablishGpuChannelSync();
if (!gpu_channel_host)
return nullptr;
// Currently, VideoResourceUpdater can't convert hardware resources to
// software resources in software compositing mode. So, fall back to software
// video decoding if gpu compositing is off.
if (is_gpu_compositing_disabled_)
return nullptr;
// This context is only used to create textures and mailbox them, so
// use lower limits than the default.
gpu::SharedMemoryLimits limits = gpu::SharedMemoryLimits::ForMailboxContext();
bool support_locking = false;
bool support_gles2_interface = true;
bool support_raster_interface = false;
bool support_oop_rasterization = false;
bool support_grcontext = false;
bool automatic_flushes = false;
scoped_refptr<viz::ContextProviderCommandBuffer> media_context_provider =
CreateOffscreenContext(gpu_channel_host, limits, support_locking,
support_gles2_interface, support_raster_interface,
support_oop_rasterization, support_grcontext,
automatic_flushes,
viz::command_buffer_metrics::ContextType::MEDIA,
kGpuStreamIdMedia, kGpuStreamPriorityMedia);
const bool enable_video_decode_accelerator =
#if BUILDFLAG(IS_LINUX)
base::FeatureList::IsEnabled(media::kAcceleratedVideoDecodeLinux) &&
#endif // BUILDFLAG(IS_LINUX)
!cmd_line->HasSwitch(switches::kDisableAcceleratedVideoDecode) &&
(gpu_channel_host->gpu_feature_info()
.status_values[gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE] ==
gpu::kGpuFeatureStatusEnabled);
const bool enable_video_encode_accelerator =
#if BUILDFLAG(IS_LINUX)
base::FeatureList::IsEnabled(media::kAcceleratedVideoEncodeLinux) &&
#else
!cmd_line->HasSwitch(switches::kDisableAcceleratedVideoEncode) &&
#endif // BUILDFLAG(IS_LINUX)
(gpu_channel_host->gpu_feature_info()
.status_values[gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_ENCODE] ==
gpu::kGpuFeatureStatusEnabled);
const bool enable_gpu_memory_buffers =
!is_gpu_compositing_disabled_ &&
#if !BUILDFLAG(IS_ANDROID)
!cmd_line->HasSwitch(switches::kDisableGpuMemoryBufferVideoFrames);
#else
cmd_line->HasSwitch(switches::kEnableGpuMemoryBufferVideoFrames);
#endif
const bool enable_media_stream_gpu_memory_buffers = enable_gpu_memory_buffers;
bool enable_video_gpu_memory_buffers = enable_gpu_memory_buffers;
#if BUILDFLAG(IS_WIN)
enable_video_gpu_memory_buffers =
enable_video_gpu_memory_buffers &&
(cmd_line->HasSwitch(switches::kEnableGpuMemoryBufferVideoFrames) ||
gpu_channel_host->gpu_info().overlay_info.supports_overlays);
#endif // BUILDFLAG(IS_WIN)
auto codec_factory = CreateMediaMojoCodecFactory(
media_context_provider, enable_video_decode_accelerator,
enable_video_encode_accelerator);
gpu_factories_.push_back(media::MojoGpuVideoAcceleratorFactories::Create(
std::move(gpu_channel_host),
base::SingleThreadTaskRunner::GetCurrentDefault(),
GetMediaSequencedTaskRunner(), std::move(media_context_provider),
std::move(codec_factory), GetGpuMemoryBufferManager(),
enable_video_gpu_memory_buffers, enable_media_stream_gpu_memory_buffers,
enable_video_decode_accelerator, enable_video_encode_accelerator));
gpu_factories_.back()->SetRenderingColorSpace(rendering_color_space_);
return gpu_factories_.back().get();
}
scoped_refptr<viz::RasterContextProvider>
RenderThreadImpl::GetVideoFrameCompositorContextProvider(
scoped_refptr<viz::RasterContextProvider> unwanted_context_provider) {
auto video_frame_compositor_task_runner =
blink_platform_impl_->VideoFrameCompositorTaskRunner();
DCHECK(video_frame_compositor_task_runner);
if (video_frame_compositor_context_provider_ &&
video_frame_compositor_context_provider_ != unwanted_context_provider) {
return video_frame_compositor_context_provider_;
}
// Need to make sure these references are removed on the correct task runner;
if (video_frame_compositor_context_provider_) {
video_frame_compositor_task_runner->ReleaseSoon(
FROM_HERE, std::move(video_frame_compositor_context_provider_));
}
scoped_refptr<gpu::GpuChannelHost> gpu_channel_host =
EstablishGpuChannelSync();
if (!gpu_channel_host) {
return nullptr;
}
// This context is only used to create textures and mailbox them, so
// use lower limits than the default.
gpu::SharedMemoryLimits limits = gpu::SharedMemoryLimits::ForMailboxContext();
bool support_locking = false;
// Use RasterInterface always.
bool support_gles2_interface = false;
bool support_raster_interface = true;
bool support_oop_rasterization = false;
bool support_grcontext = false;
bool automatic_flushes = false;
video_frame_compositor_context_provider_ = CreateOffscreenContext(
gpu_channel_host, limits, support_locking, support_gles2_interface,
support_raster_interface, support_oop_rasterization, support_grcontext,
automatic_flushes,
viz::command_buffer_metrics::ContextType::RENDER_COMPOSITOR,
kGpuStreamIdMedia, kGpuStreamPriorityMedia);
return video_frame_compositor_context_provider_;
}
scoped_refptr<gpu::ClientSharedImageInterface>
RenderThreadImpl::GetRenderThreadSharedImageInterface() {
if (shared_image_interface_ &&
!shared_image_interface_->gpu_channel()->IsLost()) {
return shared_image_interface_;
}
shared_image_interface_.reset();
scoped_refptr<gpu::GpuChannelHost> gpu_channel_host =
EstablishGpuChannelSync();
if (!gpu_channel_host) {
return nullptr;
}
shared_image_interface_ =
gpu_channel_host->CreateClientSharedImageInterface();
return shared_image_interface_;
}
scoped_refptr<viz::ContextProviderCommandBuffer>
RenderThreadImpl::SharedMainThreadContextProvider() {
DCHECK(IsMainThread());
if (shared_main_thread_contexts_ &&
shared_main_thread_contexts_->RasterInterface()
->GetGraphicsResetStatusKHR() == GL_NO_ERROR)
return shared_main_thread_contexts_;
if (is_context_result_fatal_) {
return nullptr;
}
scoped_refptr<gpu::GpuChannelHost> gpu_channel_host(
EstablishGpuChannelSync());
if (!gpu_channel_host) {
shared_main_thread_contexts_ = nullptr;
return nullptr;
}
bool support_locking = false;
bool support_raster_interface = true;
bool support_oop_rasterization =
gpu_channel_host->gpu_feature_info()
.status_values[gpu::GPU_FEATURE_TYPE_CANVAS_OOP_RASTERIZATION] ==
gpu::kGpuFeatureStatusEnabled;
bool support_gles2_interface = false;
bool support_grcontext = !support_oop_rasterization;
// Enable automatic flushes to improve canvas throughput.
// See https://crbug.com/880901
bool automatic_flushes = true;
shared_main_thread_contexts_ = CreateOffscreenContext(
std::move(gpu_channel_host), gpu::SharedMemoryLimits(), support_locking,
support_gles2_interface, support_raster_interface,
support_oop_rasterization, support_grcontext, automatic_flushes,
viz::command_buffer_metrics::ContextType::RENDERER_MAIN_THREAD,
kGpuStreamIdDefault, kGpuStreamPriorityDefault);
auto result = shared_main_thread_contexts_->BindToCurrentSequence();
if (result != gpu::ContextResult::kSuccess) {
shared_main_thread_contexts_ = nullptr;
is_context_result_fatal_ = result == gpu::ContextResult::kFatalFailure;
}
return shared_main_thread_contexts_;
}
#if BUILDFLAG(IS_ANDROID)
scoped_refptr<StreamTextureFactory> RenderThreadImpl::GetStreamTexureFactory() {
DCHECK(IsMainThread());
if (!stream_texture_factory_ || stream_texture_factory_->IsLost()) {
scoped_refptr<gpu::GpuChannelHost> channel = EstablishGpuChannelSync();
if (!channel) {
stream_texture_factory_ = nullptr;
return nullptr;
}
stream_texture_factory_ = StreamTextureFactory::Create(std::move(channel));
}
return stream_texture_factory_;
}
bool RenderThreadImpl::EnableStreamTextureCopy() {
return GetContentClient()->UsingSynchronousCompositing();
}
#endif // BUILDFLAG(IS_ANDROID)
#if BUILDFLAG(IS_WIN)
scoped_refptr<DCOMPTextureFactory> RenderThreadImpl::GetDCOMPTextureFactory() {
DCHECK(IsMainThread());
if (!dcomp_texture_factory_.get() || dcomp_texture_factory_->IsLost()) {
scoped_refptr<gpu::GpuChannelHost> channel = EstablishGpuChannelSync();
if (!channel) {
dcomp_texture_factory_ = nullptr;
return nullptr;
}
dcomp_texture_factory_ = DCOMPTextureFactory::Create(
std::move(channel), GetMediaSequencedTaskRunner());
}
return dcomp_texture_factory_;
}
scoped_refptr<OverlayStateServiceProvider>
RenderThreadImpl::GetOverlayStateServiceProvider() {
DCHECK(IsMainThread());
// Only set 'overlay_state_service_provider_' if Media Foundation for clear
// is enabled.
if (media::SupportMediaFoundationClearPlayback()) {
if (!overlay_state_service_provider_ ||
overlay_state_service_provider_->IsLost()) {
scoped_refptr<gpu::GpuChannelHost> channel = EstablishGpuChannelSync();
if (!channel) {
overlay_state_service_provider_ = nullptr;
return nullptr;
}
overlay_state_service_provider_ =
base::MakeRefCounted<OverlayStateServiceProviderImpl>(
std::move(channel));
}
}
return overlay_state_service_provider_;
}
#endif // BUILDFLAG(IS_WIN)
base::WaitableEvent* RenderThreadImpl::GetShutdownEvent() {
return ChildProcess::current()->GetShutDownEvent();
}
int32_t RenderThreadImpl::GetClientId() {
return client_id_;
}
void RenderThreadImpl::SetRendererProcessType(
blink::scheduler::WebRendererProcessType type) {
main_thread_scheduler_->SetRendererProcessType(type);
}
blink::WebString RenderThreadImpl::GetUserAgent() {
DCHECK(!user_agent_.IsNull());
return user_agent_;
}
const blink::UserAgentMetadata& RenderThreadImpl::GetUserAgentMetadata() {
return user_agent_metadata_;
}
void RenderThreadImpl::WriteIntoTrace(
perfetto::TracedProto<perfetto::protos::pbzero::RenderProcessHost> proto) {
int id = GetClientId();
proto->set_id(id);
}
void RenderThreadImpl::OnAssociatedInterfaceRequest(
const std::string& name,
mojo::ScopedInterfaceEndpointHandle handle) {
if (!associated_interfaces_.TryBindInterface(name, &handle))
ChildThreadImpl::OnAssociatedInterfaceRequest(name, std::move(handle));
}
bool RenderThreadImpl::IsLcdTextEnabled() {
return is_lcd_text_enabled_;
}
bool RenderThreadImpl::IsElasticOverscrollEnabled() {
return is_elastic_overscroll_enabled_;
}
gpu::GpuMemoryBufferManager* RenderThreadImpl::GetGpuMemoryBufferManager() {
return gpu_->gpu_memory_buffer_manager();
}
blink::scheduler::WebThreadScheduler*
RenderThreadImpl::GetWebMainThreadScheduler() {
return main_thread_scheduler_.get();
}
bool RenderThreadImpl::IsThreadedAnimationEnabled() {
return is_threaded_animation_enabled_;
}
bool RenderThreadImpl::IsScrollAnimatorEnabled() {
return is_scroll_animator_enabled_;
}
void RenderThreadImpl::SetScrollAnimatorEnabled(
bool enable_scroll_animator,
base::PassKey<AgentSchedulingGroup>) {
is_scroll_animator_enabled_ = enable_scroll_animator;
}
bool RenderThreadImpl::IsMainThread() {
return !!current();
}
void RenderThreadImpl::OnChannelError() {
// In single-process mode, the renderer can't be restarted after shutdown.
// So, if we get a channel error, crash the whole process right now to get a
// more informative stack, since we will otherwise just crash later when we
// try to restart it.
CHECK(!IsSingleProcess());
ChildThreadImpl::OnChannelError();
}
void RenderThreadImpl::OnProcessFinalRelease() {
// Do not shutdown the process. The browser process is the only one
// responsible for renderer shutdown.
//
// Renderer process used to request self shutdown. It has been removed. It
// caused race conditions, where the browser process was reusing renderer
// processes that were shutting down.
// See https://crbug.com/535246 or https://crbug.com/873541/#c8.
NOTREACHED();
}
#if BUILDFLAG(CONTENT_ENABLE_LEGACY_IPC)
bool RenderThreadImpl::OnControlMessageReceived(const IPC::Message& msg) {
for (auto& observer : observers_) {
if (observer.OnControlMessageReceived(msg))
return true;
}
return false;
}
#endif
void RenderThreadImpl::SetProcessState(
base::Process::Priority process_priority,
mojom::RenderProcessVisibleState visible_state) {
DCHECK(process_priority_ != process_priority ||
visible_state_ != visible_state);
bool was_backgrounded = IsBackgrounded(process_priority_);
bool is_backgrounded = IsBackgrounded(process_priority);
if (base::FeatureList::IsEnabled(features::kRestrictThreadPoolInBackground)) {
if (process_priority == base::Process::Priority::kUserBlocking) {
restrict_thread_pool_.reset();
} else if (!restrict_thread_pool_) {
restrict_thread_pool_.emplace();
}
}
if (base::FeatureList::IsEnabled(features::kSetIsolatesPriority)) {
blink::WebV8Features::SetIsolatePriority(process_priority);
}
if (!process_priority_.has_value() || is_backgrounded != was_backgrounded) {
if (is_backgrounded) {
OnRendererBackgrounded();
} else {
OnRendererForegrounded();
}
}
if (visible_state != visible_state_) {
bool is_visible =
visible_state == mojom::RenderProcessVisibleState::kVisible;
if (!IsInBrowserProcess()) {
ProcessVisibilityTracker::GetInstance()->OnProcessVisibilityChanged(
is_visible);
}
if (is_visible)
OnRendererVisible();
else
OnRendererHidden();
}
if (process_priority_ != process_priority) {
TRACE_EVENT_END("renderer", process_priority_track_);
TRACE_EVENT_BEGIN("renderer", ProcessPriorityToString(process_priority),
process_priority_track_);
}
if (visible_state_ != visible_state) {
TRACE_EVENT_END("renderer", process_visibility_track_);
TRACE_EVENT_BEGIN("renderer", ProcessVisibilityToString(visible_state),
process_visibility_track_);
}
process_priority_ = process_priority;
visible_state_ = visible_state;
}
void RenderThreadImpl::SetBatterySaverMode(bool battery_saver_mode_enabled) {
blink::SetBatterySaverModeForAllIsolates(battery_saver_mode_enabled);
}
void RenderThreadImpl::SetIsLockedToSite() {
DCHECK(blink_platform_impl_);
blink_platform_impl_->SetIsLockedToSite();
}
#if BUILDFLAG(CLANG_PROFILING_INSIDE_SANDBOX)
void RenderThreadImpl::WriteClangProfilingProfile(
WriteClangProfilingProfileCallback callback) {
// This will write the profiling profile to the file that has been opened and
// passed to this renderer by the browser.
base::WriteClangProfilingProfile();
std::move(callback).Run();
}
#endif
void RenderThreadImpl::SetIsCrossOriginIsolated(bool value) {
blink::SetIsCrossOriginIsolated(value);
}
void RenderThreadImpl::SetIsWebSecurityDisabled(bool value) {
blink::SetIsWebSecurityDisabled(value);
}
void RenderThreadImpl::SetIsIsolatedContext(bool value) {
blink::SetIsIsolatedContext(value);
}
void RenderThreadImpl::CompositingModeFallbackToSoftware() {
gpu_->LoseChannel();
is_gpu_compositing_disabled_ = true;
}
bool RenderThreadImpl::IsGpuRemoteDisconnected() {
return gpu_->gpu_remote_disconnected();
}
scoped_refptr<gpu::GpuChannelHost> RenderThreadImpl::EstablishGpuChannelSync() {
TRACE_EVENT0("gpu", "RenderThreadImpl::EstablishGpuChannelSync");
scoped_refptr<gpu::GpuChannelHost> gpu_channel =
gpu_->EstablishGpuChannelSync();
if (gpu_channel)
GetContentClient()->SetGpuInfo(gpu_channel->gpu_info());
return gpu_channel;
}
void RenderThreadImpl::EstablishGpuChannel(
EstablishGpuChannelCallback callback) {
TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
"gpu", "RenderThreadImpl::EstablishGpuChannel", this);
gpu_->EstablishGpuChannel(base::BindOnce(
[](EstablishGpuChannelCallback callback, RenderThreadImpl* thread,
scoped_refptr<gpu::GpuChannelHost> host) {
TRACE_EVENT_NESTABLE_ASYNC_END0(
"gpu", "RenderThreadImpl::EstablishGpuChannel", thread);
if (host)
GetContentClient()->SetGpuInfo(host->gpu_info());
std::move(callback).Run(std::move(host));
},
// The GPU process can crash; in that case, run the callback with no host
// to signal the compositor to wait and try again.
mojo::WrapCallbackWithDefaultInvokeIfNotRun(std::move(callback), nullptr),
this));
}
blink::AssociatedInterfaceRegistry*
RenderThreadImpl::GetAssociatedInterfaceRegistry() {
return &associated_interfaces_;
}
mojom::RenderMessageFilter* RenderThreadImpl::render_message_filter() {
if (!render_message_filter_) {
blink::Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
render_message_filter_.BindNewPipeAndPassReceiver());
}
return render_message_filter_.get();
}
gpu::GpuChannelHost* RenderThreadImpl::GetGpuChannel() {
return gpu_->GetGpuChannel().get();
}
void RenderThreadImpl::CreateAgentSchedulingGroup(
mojo::PendingReceiver<IPC::mojom::ChannelBootstrap> bootstrap) {
agent_scheduling_groups_.emplace(
std::make_unique<AgentSchedulingGroup>(*this, std::move(bootstrap)));
}
void RenderThreadImpl::CreateAssociatedAgentSchedulingGroup(
mojo::PendingAssociatedReceiver<mojom::AgentSchedulingGroup>
agent_scheduling_group) {
agent_scheduling_groups_.emplace(std::make_unique<AgentSchedulingGroup>(
*this, std::move(agent_scheduling_group)));
}
void RenderThreadImpl::TransferSharedLastForegroundTime(
base::ReadOnlySharedMemoryRegion last_foreground_time_region) {
if (!last_foreground_time_mapping_.has_value()) {
last_foreground_time_mapping_ =
base::AtomicSharedMemory<base::TimeTicks>::MapReadOnlyRegion(
std::move(last_foreground_time_region));
}
if (!IsSingleProcess()) {
// The pointer will only be valid until `last_foreground_time_mapping_` is
// unmapped. In multi-process mode, that's on process exit, so it's safe to
// save the pointer and never reset it. In single-process mode, it's
// important that other threads not have a copy of the pointer after `this`
// is destroyed. But also, since base stores the pointer in a per-process
// global, in single-process-mode each RenderThreadImpl would overwrite it
// and the stored value would be wrong for most "renderers" anyway. So the
// easiest way to avoid accessing the pointer after it's unmapped is to
// never set it in the first place.
base::internal::SetSharedLastForegroundTimeForMetrics(
last_foreground_time_mapping_->ReadOnlyPtr());
}
}
void RenderThreadImpl::OnNetworkConnectionChanged(
net::NetworkChangeNotifier::ConnectionType type,
double max_bandwidth_mbps) {
bool online_status = type != net::NetworkChangeNotifier::CONNECTION_NONE;
WebNetworkStateNotifier::SetOnLine(online_status);
WebNetworkStateNotifier::SetWebConnection(
NetConnectionTypeToWebConnectionType(type), max_bandwidth_mbps);
if (url_loader_throttle_provider_)
url_loader_throttle_provider_->SetOnline(online_status);
}
void RenderThreadImpl::OnNetworkQualityChanged(
net::EffectiveConnectionType type,
base::TimeDelta http_rtt,
base::TimeDelta transport_rtt,
double downlink_throughput_kbps) {
LOCAL_HISTOGRAM_BOOLEAN("NQE.RenderThreadNotified", true);
WebNetworkStateNotifier::SetNetworkQuality(
EffectiveConnectionTypeToWebEffectiveConnectionType(type), http_rtt,
transport_rtt, downlink_throughput_kbps);
}
void RenderThreadImpl::SetWebKitSharedTimersSuspended(bool suspend) {
#if BUILDFLAG(IS_ANDROID)
if (suspend) {
main_thread_scheduler_->PauseTimersForAndroidWebView();
} else {
main_thread_scheduler_->ResumeTimersForAndroidWebView();
}
#else
NOTREACHED();
#endif
}
void RenderThreadImpl::UpdateScrollbarTheme(
mojom::UpdateScrollbarThemeParamsPtr params) {
#if BUILDFLAG(IS_MAC)
blink::WebScrollbarTheme::UpdateScrollbarsWithNSDefaults(
params->has_initial_button_delay
? std::make_optional(params->initial_button_delay)
: std::nullopt,
params->has_autoscroll_button_delay
? std::make_optional(params->autoscroll_button_delay)
: std::nullopt,
params->preferred_scroller_style, params->redraw,
params->jump_on_track_click);
#endif // BUILDFLAG(IS_MAC)
#if BUILDFLAG(IS_APPLE)
is_elastic_overscroll_enabled_ = params->scroll_view_rubber_banding;
#else
NOTREACHED();
#endif // BUILDFLAG(IS_APPLE)
}
void RenderThreadImpl::OnSystemColorsChanged(int32_t aqua_color_variant) {
#if BUILDFLAG(IS_MAC)
// Let blink know it should invalidate and recalculate styles for elements
// that rely on system colors, such as the accent and highlight colors.
blink::SystemColorsChanged();
#else
NOTREACHED();
#endif
}
void RenderThreadImpl::UpdateSystemColorInfo(
mojom::UpdateSystemColorInfoParamsPtr params) {
auto* native_theme = ui::NativeTheme::GetInstanceForWeb();
bool did_accent_color_change =
native_theme->user_color() != params->accent_color;
native_theme->set_user_color(params->accent_color);
if (did_accent_color_change) {
// Notify blink of accent color changes. These can affect CSS styles and
// thus require action beyond simply invalidating paint on local frames.
blink::SystemColorsChanged();
blink::ColorSchemeChanged();
}
}
void RenderThreadImpl::PurgePluginListCache(bool reload_pages) {
#if BUILDFLAG(ENABLE_PLUGINS)
blink::ResetPluginCache(reload_pages);
for (auto& observer : observers_)
observer.PluginListChanged();
#else
NOTREACHED();
#endif
}
void RenderThreadImpl::PurgeResourceCache(PurgeResourceCacheCallback callback) {
blink::WebCache::Clear();
std::move(callback).Run();
}
void RenderThreadImpl::OnMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
TRACE_EVENT(
"memory", "RenderThreadImpl::OnMemoryPressure",
[&](perfetto::EventContext ctx) {
auto* event = ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>();
auto* data = event->set_chrome_memory_pressure_notification();
data->set_level(base::trace_event::MemoryPressureLevelToTraceEnum(
memory_pressure_level));
});
if (blink_platform_impl_)
blink::WebMemoryPressureListener::OnMemoryPressure(memory_pressure_level);
if (memory_pressure_level ==
base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) {
discardable_memory_allocator_->ReleaseFreeMemory();
// Do not call into blink if it is not initialized.
if (blink_platform_impl_) {
// Purge Skia font cache, resource cache, and image filter.
SkGraphics::PurgeAllCaches();
blink::WebMemoryPressureListener::OnPurgeMemory();
}
}
}
scoped_refptr<base::SequencedTaskRunner>
RenderThreadImpl::GetMediaSequencedTaskRunner() {
DCHECK(main_thread_runner()->BelongsToCurrentThread());
if (base::FeatureList::IsEnabled(kUseThreadPoolForMediaTaskRunner)) {
if (!media_task_runner_) {
media_task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
base::TaskTraits{base::TaskPriority::USER_VISIBLE,
base::WithBaseSyncPrimitives(), base::MayBlock()});
}
return media_task_runner_;
}
if (!media_thread_) {
media_thread_ = std::make_unique<base::Thread>("Media");
#if BUILDFLAG(IS_FUCHSIA)
// Start IO thread on Fuchsia to make that thread usable for FIDL.
base::Thread::Options options(base::MessagePumpType::IO, 0);
// TODO(crbug.com/40250424): Use kDisplayCritical to address media latency
// on Fuchsia until alignment on new media thread types is achieved.
options.thread_type = base::ThreadType::kDisplayCritical;
#else
base::Thread::Options options;
#endif
media_thread_->StartWithOptions(std::move(options));
}
return media_thread_->task_runner();
}
scoped_refptr<cc::RasterContextProviderWrapper>
RenderThreadImpl::SharedCompositorWorkerContextProvider(
cc::RasterDarkModeFilter* dark_mode_filter) {
DCHECK(IsMainThread());
// Try to reuse existing shared worker context provider.
if (shared_worker_context_provider_wrapper_) {
// Note: If context is lost, delete reference after releasing the lock.
viz::RasterContextProvider::ScopedRasterContextLock lock(
shared_worker_context_provider_wrapper_->GetContext().get());
if (lock.RasterInterface()->GetGraphicsResetStatusKHR() == GL_NO_ERROR)
return shared_worker_context_provider_wrapper_;
}
scoped_refptr<gpu::GpuChannelHost> gpu_channel_host(
EstablishGpuChannelSync());
if (!gpu_channel_host) {
shared_worker_context_provider_wrapper_ = nullptr;
return shared_worker_context_provider_wrapper_;
}
bool support_locking = true;
// If the compositor worker context supports GPU rasterization then renderer
// tiles will be rasterized on the GPU.
bool support_gpu_rasterization =
gpu_channel_host->gpu_feature_info()
.status_values[gpu::GPU_FEATURE_TYPE_GPU_TILE_RASTERIZATION] ==
gpu::kGpuFeatureStatusEnabled;
bool support_gles2_interface = false;
bool support_raster_interface = true;
bool support_grcontext = false;
bool automatic_flushes = false;
auto shared_memory_limits =
support_gpu_rasterization ? gpu::SharedMemoryLimits::ForOOPRasterContext()
: gpu::SharedMemoryLimits();
scoped_refptr<viz::ContextProviderCommandBuffer>
shared_worker_context_provider = CreateOffscreenContext(
std::move(gpu_channel_host), shared_memory_limits, support_locking,
support_gles2_interface, support_raster_interface,
support_gpu_rasterization, support_grcontext, automatic_flushes,
viz::command_buffer_metrics::ContextType::RENDER_WORKER,
kGpuStreamIdWorker, kGpuStreamPriorityWorker);
auto result = shared_worker_context_provider->BindToCurrentSequence();
if (result != gpu::ContextResult::kSuccess)
return nullptr;
shared_worker_context_provider_wrapper_ =
base::MakeRefCounted<cc::RasterContextProviderWrapper>(
std::move(shared_worker_context_provider), dark_mode_filter,
cc::ImageDecodeCacheUtils::GetWorkingSetBytesForImageDecode(
/*for_renderer=*/true));
return shared_worker_context_provider_wrapper_;
}
bool RenderThreadImpl::RendererIsHidden() const {
return visible_state_ == mojom::RenderProcessVisibleState::kHidden;
}
void RenderThreadImpl::OnRendererHidden() {
if (!base::FeatureList::IsEnabled(features::kSetIsolatesPriority)) {
blink::WebV8Features::SetIsolatePriority(
base::Process::Priority::kBestEffort);
}
// TODO(rmcilroy): Remove IdleHandler and replace it with an IdleTask
// scheduled by the RendererScheduler - http://crbug.com/469210.
if (!GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden())
return;
main_thread_scheduler_->SetRendererHidden(true);
}
void RenderThreadImpl::OnRendererVisible() {
if (!base::FeatureList::IsEnabled(features::kSetIsolatesPriority)) {
blink::WebV8Features::SetIsolatePriority(
base::Process::Priority::kUserBlocking);
}
if (!GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden())
return;
main_thread_scheduler_->SetRendererHidden(false);
}
bool RenderThreadImpl::RendererIsBackgrounded() const {
return IsBackgrounded(process_priority_);
}
void RenderThreadImpl::OnRendererBackgrounded() {
UpdateForegroundCrashKey(/*foreground=*/false);
main_thread_scheduler_->SetRendererBackgrounded(true);
discardable_memory_allocator_->OnBackgrounded();
base::allocator::PartitionAllocSupport::Get()->OnBackgrounded();
blink::OnProcessBackgrounded();
}
void RenderThreadImpl::OnRendererForegrounded() {
UpdateForegroundCrashKey(/*foreground=*/true);
main_thread_scheduler_->SetRendererBackgrounded(false);
discardable_memory_allocator_->OnForegrounded();
base::allocator::PartitionAllocSupport::Get()->OnForegrounded(
MainFrameCounter::has_main_frame());
blink::OnProcessForegrounded();
process_foregrounded_count_++;
}
void RenderThreadImpl::OnSyncMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
v8::MemoryPressureLevel v8_memory_pressure_level =
static_cast<v8::MemoryPressureLevel>(memory_pressure_level);
#if !BUILDFLAG(ALLOW_CRITICAL_MEMORY_PRESSURE_HANDLING_IN_FOREGROUND)
// In order to reduce performance impact, translate critical level to
// moderate level for foreground renderer.
if (!RendererIsHidden() &&
v8_memory_pressure_level == v8::MemoryPressureLevel::kCritical)
v8_memory_pressure_level = v8::MemoryPressureLevel::kModerate;
#endif // !BUILDFLAG(ALLOW_CRITICAL_MEMORY_PRESSURE_HANDLING_IN_FOREGROUND)
if (base::FeatureList::IsEnabled(
features::kForwardMemoryPressureToBlinkIsolates)) {
blink::MemoryPressureNotificationToAllIsolates(v8_memory_pressure_level);
}
}
void RenderThreadImpl::OnRendererInterfaceReceiver(
mojo::PendingAssociatedReceiver<mojom::Renderer> receiver) {
DCHECK(!renderer_receiver_.is_bound());
renderer_receiver_.Bind(
std::move(receiver),
GetWebMainThreadScheduler()->DeprecatedDefaultTaskRunner());
}
void RenderThreadImpl::SetRenderingColorSpace(
const gfx::ColorSpace& color_space) {
DCHECK(IsMainThread());
rendering_color_space_ = color_space;
for (const auto& factories : gpu_factories_) {
if (factories)
factories->SetRenderingColorSpace(color_space);
}
}
gfx::ColorSpace RenderThreadImpl::GetRenderingColorSpace() {
DCHECK(IsMainThread());
return rendering_color_space_;
}
std::unique_ptr<media::MojoCodecFactory>
RenderThreadImpl::CreateMediaMojoCodecFactory(
scoped_refptr<viz::ContextProviderCommandBuffer> context_provider,
bool enable_video_decode_accelerator,
bool enable_video_encode_accelerator) {
mojo::PendingRemote<media::mojom::VideoEncodeAcceleratorProvider>
vea_provider;
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
if (base::FeatureList::IsEnabled(media::kUseOutOfProcessVideoEncoding)) {
BindHostReceiver(vea_provider.InitWithNewPipeAndPassReceiver());
} else {
gpu_->CreateVideoEncodeAcceleratorProvider(
vea_provider.InitWithNewPipeAndPassReceiver());
}
#else
gpu_->CreateVideoEncodeAcceleratorProvider(
vea_provider.InitWithNewPipeAndPassReceiver());
#endif
#if BUILDFLAG(ENABLE_MOJO_VIDEO_DECODER)
mojo::PendingRemote<media::mojom::InterfaceFactory> interface_factory;
BindHostReceiver(interface_factory.InitWithNewPipeAndPassReceiver());
return std::make_unique<media::MojoCodecFactoryMojoDecoder>(
GetMediaSequencedTaskRunner(), context_provider,
enable_video_decode_accelerator, enable_video_encode_accelerator,
std::move(vea_provider), std::move(interface_factory));
#elif BUILDFLAG(IS_FUCHSIA)
mojo::PendingRemote<media::mojom::FuchsiaMediaCodecProvider>
media_codec_provider;
BindHostReceiver(media_codec_provider.InitWithNewPipeAndPassReceiver());
return std::make_unique<media::MojoCodecFactoryFuchsia>(
GetMediaSequencedTaskRunner(), context_provider,
enable_video_decode_accelerator, enable_video_encode_accelerator,
std::move(vea_provider), std::move(media_codec_provider));
#else
return std::make_unique<media::MojoCodecFactoryDefault>(
GetMediaSequencedTaskRunner(), context_provider,
enable_video_decode_accelerator, enable_video_encode_accelerator,
std::move(vea_provider));
#endif
}
#if BUILDFLAG(IS_ANDROID)
void RenderThreadImpl::SetPrivateMemoryFootprint(
uint64_t private_memory_footprint_bytes) {
GetRendererHost()->SetPrivateMemoryFootprint(private_memory_footprint_bytes);
}
void RenderThreadImpl::OnMemoryPressureFromBrowserReceived(
base::MemoryPressureListener::MemoryPressureLevel level) {
// To avoid that the browser process requests a signal while a renderer
// is creating and blink has not been initialized yet, check
// |blink_platform_impl_| here.
if (!blink_platform_impl_) {
return;
}
blink::RequestUserLevelMemoryPressureSignal();
}
#endif
} // namespace content