blob: 0e9f6e57eac4c1fd1eaf8dd1c86ac1153d1a44b4 [file] [log] [blame]
// Copyright 2012 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.
// Represents the browser side of the browser <--> renderer communication
// channel. There will be one RenderProcessHost per renderer process.
#include "content/browser/renderer_host/render_process_host_impl.h"
#include <algorithm>
#include <limits>
#include <map>
#include <set>
#include <unordered_map>
#include <utility>
#include <vector>
#include "base/base_switches.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/containers/adapters.h"
#include "base/debug/alias.h"
#include "base/debug/crash_logging.h"
#include "base/debug/dump_without_crashing.h"
#include "base/feature_list.h"
#include "base/files/file.h"
#include "base/lazy_instance.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/memory_pressure_monitor.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/shared_memory_mapping.h"
#include "base/memory/writable_shared_memory_region.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_base.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/persistent_histogram_allocator.h"
#include "base/metrics/persistent_memory_allocator.h"
#include "base/metrics/statistics_recorder.h"
#include "base/metrics/user_metrics.h"
#include "base/no_destructor.h"
#include "base/numerics/ranges.h"
#include "base/numerics/safe_conversions.h"
#include "base/process/process_handle.h"
#include "base/rand_util.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/supports_user_data.h"
#include "base/synchronization/lock.h"
#include "base/system/sys_info.h"
#include "base/task/post_task.h"
#include "base/thread_annotations.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "base/token.h"
#include "base/trace_event/memory_allocator_dump.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/memory_dump_provider.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "cc/base/switches.h"
#include "components/metrics/single_sample_metrics.h"
#include "components/tracing/common/tracing_switches.h"
#include "components/viz/common/switches.h"
#include "components/viz/host/gpu_client.h"
#include "content/browser/appcache/chrome_appcache_service.h"
#include "content/browser/background_fetch/background_fetch_context.h"
#include "content/browser/background_fetch/background_fetch_service_impl.h"
#include "content/browser/background_sync/background_sync_service_impl.h"
#include "content/browser/bad_message.h"
#include "content/browser/blob_storage/blob_dispatcher_host.h"
#include "content/browser/blob_storage/blob_registry_wrapper.h"
#include "content/browser/blob_storage/chrome_blob_storage_context.h"
#include "content/browser/broadcast_channel/broadcast_channel_provider.h"
#include "content/browser/browser_child_process_host_impl.h"
#include "content/browser/browser_main.h"
#include "content/browser/browser_main_loop.h"
#include "content/browser/browser_plugin/browser_plugin_message_filter.h"
#include "content/browser/cache_storage/cache_storage_context_impl.h"
#include "content/browser/cache_storage/cache_storage_dispatcher_host.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/code_cache/generated_code_cache.h"
#include "content/browser/code_cache/generated_code_cache_context.h"
#include "content/browser/compositor/surface_utils.h"
#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
#include "content/browser/dom_storage/dom_storage_message_filter.h"
#include "content/browser/field_trial_recorder.h"
#include "content/browser/fileapi/file_system_manager_impl.h"
#include "content/browser/font_unique_name_lookup/font_unique_name_lookup_service.h"
#include "content/browser/frame_host/render_frame_message_filter.h"
#include "content/browser/gpu/browser_gpu_client_delegate.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/browser/gpu/gpu_process_host.h"
#include "content/browser/gpu/shader_cache_factory.h"
#include "content/browser/histogram_controller.h"
#include "content/browser/indexed_db/indexed_db_context_impl.h"
#include "content/browser/indexed_db/indexed_db_dispatcher_host.h"
#include "content/browser/loader/resource_message_filter.h"
#include "content/browser/loader/url_loader_factory_impl.h"
#include "content/browser/media/capture/audio_mirroring_manager.h"
#include "content/browser/media/media_internals.h"
#include "content/browser/media/midi_host.h"
#include "content/browser/mime_registry_impl.h"
#include "content/browser/navigation_subresource_loader_params.h"
#include "content/browser/payments/payment_manager.h"
#include "content/browser/permissions/permission_service_context.h"
#include "content/browser/permissions/permission_service_impl.h"
#include "content/browser/push_messaging/push_messaging_manager.h"
#include "content/browser/renderer_host/clipboard_host_impl.h"
#include "content/browser/renderer_host/code_cache_host_impl.h"
#include "content/browser/renderer_host/embedded_frame_sink_provider_impl.h"
#include "content/browser/renderer_host/file_utilities_host_impl.h"
#include "content/browser/renderer_host/media/media_stream_manager.h"
#include "content/browser/renderer_host/media/media_stream_track_metrics_host.h"
#include "content/browser/renderer_host/media/peer_connection_tracker_host.h"
#include "content/browser/renderer_host/media/video_capture_host.h"
#include "content/browser/renderer_host/p2p/socket_dispatcher_host.h"
#include "content/browser/renderer_host/pepper/pepper_message_filter.h"
#include "content/browser/renderer_host/pepper/pepper_renderer_connection.h"
#include "content/browser/renderer_host/plugin_registry_impl.h"
#include "content/browser/renderer_host/render_message_filter.h"
#include "content/browser/renderer_host/render_widget_helper.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/text_input_client_message_filter.h"
#include "content/browser/renderer_host/web_database_host_impl.h"
#include "content/browser/resolve_proxy_msg_helper.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/site_instance_impl.h"
#include "content/browser/storage_partition_impl.h"
#include "content/browser/streams/stream_context.h"
#include "content/browser/tracing/trace_message_filter.h"
#include "content/browser/webrtc/webrtc_internals.h"
#include "content/browser/websockets/websocket_manager.h"
#include "content/browser/webui/web_ui_controller_factory_registry.h"
#include "content/common/child_process_host_impl.h"
#include "content/common/content_switches_internal.h"
#include "content/common/frame_messages.h"
#include "content/common/in_process_child_thread_params.h"
#include "content/common/media/aec_dump_messages.h"
#include "content/common/media/peer_connection_tracker_messages.h"
#include "content/common/resource_messages.h"
#include "content/common/service_manager/child_connection.h"
#include "content/common/service_manager/service_manager_connection_impl.h"
#include "content/common/service_worker/service_worker_utils.h"
#include "content/common/view_messages.h"
#include "content/common/widget_messages.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_or_resource_context.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/network_service_instance.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_process_host_factory.h"
#include "content/public/browser/render_process_host_observer.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/render_widget_host_iterator.h"
#include "content/public/browser/resource_context.h"
#include "content/public/browser/site_isolation_policy.h"
#include "content/public/browser/webrtc_log.h"
#include "content/public/common/bind_interface_helpers.h"
#include "content/public/common/child_process_host.h"
#include "content/public/common/connection_filter.h"
#include "content/public/common/content_constants.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/process_type.h"
#include "content/public/common/resource_type.h"
#include "content/public/common/result_codes.h"
#include "content/public/common/sandboxed_process_launcher_delegate.h"
#include "content/public/common/service_names.mojom.h"
#include "content/public/common/url_constants.h"
#include "device/gamepad/gamepad_haptics_manager.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/gpu_switches.h"
#include "gpu/command_buffer/common/context_creation_attribs.h"
#include "gpu/command_buffer/service/gpu_switches.h"
#include "gpu/ipc/host/gpu_memory_buffer_support.h"
#include "ipc/ipc.mojom.h"
#include "ipc/ipc_channel.h"
#include "ipc/ipc_channel_mojo.h"
#include "ipc/ipc_logging.h"
#include "media/audio/audio_manager.h"
#include "media/base/media_switches.h"
#include "media/media_buildflags.h"
#include "media/webrtc/webrtc_switches.h"
#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "net/url_request/url_request_context_getter.h"
#include "ppapi/buildflags/buildflags.h"
#include "services/device/public/mojom/battery_monitor.mojom.h"
#include "services/device/public/mojom/constants.mojom.h"
#include "services/network/cross_origin_read_blocking.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/network_switches.h"
#include "services/network/public/mojom/network_service.mojom.h"
#include "services/service_manager/embedder/switches.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "services/service_manager/sandbox/switches.h"
#include "services/service_manager/zygote/common/zygote_buildflags.h"
#include "storage/browser/fileapi/sandbox_file_system_backend.h"
#include "third_party/blink/public/common/page/launching_process_state.h"
#include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
#include "third_party/blink/public/public_buildflags.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/accessibility/accessibility_switches.h"
#include "ui/base/ui_base_switches.h"
#include "ui/base/ui_base_switches_util.h"
#include "ui/display/display_switches.h"
#include "ui/gl/gl_switches.h"
#include "ui/native_theme/native_theme_features.h"
#if defined(OS_ANDROID)
#include "content/public/browser/android/java_interfaces.h"
#include "ipc/ipc_sync_channel.h"
#include "media/audio/android/audio_manager_android.h"
#else
#include "content/browser/compositor/image_transport_factory.h"
#endif
#if defined(OS_LINUX)
#include <sys/resource.h>
#include <sys/time.h>
#endif
#if defined(OS_MACOSX)
#include "content/browser/mach_broker_mac.h"
#endif
#if defined(OS_WIN)
#include "base/win/scoped_com_initializer.h"
#include "base/win/windows_version.h"
#include "sandbox/win/src/sandbox_policy.h"
#include "services/service_manager/sandbox/win/sandbox_win.h"
#include "ui/display/win/dpi.h"
#endif
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
#include "content/browser/media/key_system_support_impl.h"
#endif
#if BUILDFLAG(ENABLE_PLUGINS)
#include "content/browser/plugin_service_impl.h"
#include "ppapi/shared_impl/ppapi_switches.h" // nogncheck
#endif
#if BUILDFLAG(ENABLE_REPORTING)
#include "content/browser/net/reporting_service_proxy.h"
#endif
#if BUILDFLAG(USE_MINIKIN_HYPHENATION)
#include "content/browser/hyphenation/hyphenation_impl.h"
#endif
#if defined(USE_OZONE)
#include "ui/ozone/public/ozone_switches.h"
#endif
#if BUILDFLAG(USE_ZYGOTE_HANDLE)
#include "services/service_manager/zygote/common/zygote_handle.h" // nogncheck
#endif
#if defined(OS_WIN)
#define NumberToStringType base::NumberToString16
#else
#define NumberToStringType base::NumberToString
#endif
namespace content {
namespace {
// Stores the maximum number of renderer processes the content module can
// create. Only applies if it is set to a non-zero value.
size_t g_max_renderer_count_override = 0;
bool g_run_renderer_in_process = false;
RendererMainThreadFactoryFunction g_renderer_main_thread_factory = nullptr;
base::Thread* g_in_process_thread;
const RenderProcessHostFactory* g_render_process_host_factory_ = nullptr;
const char kSiteProcessMapKeyName[] = "content_site_process_map";
RenderProcessHost::AnalyzeHungRendererFunction g_analyze_hung_renderer =
nullptr;
const base::FilePath::CharType kAecDumpFileNameAddition[] =
FILE_PATH_LITERAL("aec_dump");
void CacheShaderInfo(int32_t id, base::FilePath path) {
if (GetShaderCacheFactorySingleton())
GetShaderCacheFactorySingleton()->SetCacheInfo(id, path);
}
void RemoveShaderInfo(int32_t id) {
if (GetShaderCacheFactorySingleton())
GetShaderCacheFactorySingleton()->RemoveCacheInfo(id);
}
net::URLRequestContext* GetRequestContext(
scoped_refptr<net::URLRequestContextGetter> request_context,
scoped_refptr<net::URLRequestContextGetter> media_request_context,
ResourceType resource_type) {
// If the request has resource type of ResourceType::kMedia, we use a request
// context specific to media for handling it because these resources have
// specific needs for caching.
if (resource_type == ResourceType::kMedia)
return media_request_context->GetURLRequestContext();
return request_context->GetURLRequestContext();
}
void GetContexts(
ResourceContext* resource_context,
scoped_refptr<net::URLRequestContextGetter> request_context,
scoped_refptr<net::URLRequestContextGetter> media_request_context,
ResourceType resource_type,
ResourceContext** resource_context_out,
net::URLRequestContext** request_context_out) {
*resource_context_out = resource_context;
*request_context_out =
GetRequestContext(request_context, media_request_context, resource_type);
}
// Creates a file used for handing over to the renderer.
IPC::PlatformFileForTransit CreateFileForProcess(base::FilePath file_path) {
base::File dump_file(file_path,
base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_APPEND);
if (!dump_file.IsValid()) {
VLOG(1) << "Could not open AEC dump file, error="
<< dump_file.error_details();
return IPC::InvalidPlatformFileForTransit();
}
return IPC::TakePlatformFileForTransit(std::move(dump_file));
}
// Allow us to only run the trial in the first renderer.
bool has_done_stun_trials = false;
// the global list of all renderer processes
base::LazyInstance<base::IDMap<RenderProcessHost*>>::Leaky g_all_hosts =
LAZY_INSTANCE_INITIALIZER;
// Map of site to process, to ensure we only have one RenderProcessHost per
// site in process-per-site mode. Each map is specific to a BrowserContext.
class SiteProcessMap : public base::SupportsUserData::Data {
public:
typedef std::unordered_map<std::string, RenderProcessHost*> SiteToProcessMap;
SiteProcessMap() {}
void RegisterProcess(const std::string& site, RenderProcessHost* process) {
// There could already exist a site to process mapping due to races between
// two WebContents with blank SiteInstances. If that occurs, keeping the
// existing entry and not overwriting it is a predictable behavior that is
// safe.
auto i = map_.find(site);
if (i == map_.end())
map_[site] = process;
}
RenderProcessHost* FindProcess(const std::string& site) {
auto i = map_.find(site);
if (i != map_.end())
return i->second;
return nullptr;
}
void RemoveProcess(RenderProcessHost* host) {
// Find all instances of this process in the map, then separately remove
// them.
std::set<std::string> sites;
for (SiteToProcessMap::const_iterator i = map_.begin(); i != map_.end();
++i) {
if (i->second == host)
sites.insert(i->first);
}
for (auto i = sites.begin(); i != sites.end(); ++i) {
auto iter = map_.find(*i);
if (iter != map_.end()) {
DCHECK_EQ(iter->second, host);
map_.erase(iter);
}
}
}
private:
SiteToProcessMap map_;
};
// Find the SiteProcessMap specific to the given context.
SiteProcessMap* GetSiteProcessMapForBrowserContext(BrowserContext* context) {
DCHECK(context);
SiteProcessMap* existing_map = static_cast<SiteProcessMap*>(
context->GetUserData(kSiteProcessMapKeyName));
if (existing_map)
return existing_map;
auto new_map = std::make_unique<SiteProcessMap>();
auto* new_map_ptr = new_map.get();
context->SetUserData(kSiteProcessMapKeyName, std::move(new_map));
return new_map_ptr;
}
// NOTE: changes to this class need to be reviewed by the security team.
class RendererSandboxedProcessLauncherDelegate
: public SandboxedProcessLauncherDelegate {
public:
RendererSandboxedProcessLauncherDelegate() {}
~RendererSandboxedProcessLauncherDelegate() override {}
#if defined(OS_WIN)
bool PreSpawnTarget(sandbox::TargetPolicy* policy) override {
service_manager::SandboxWin::AddBaseHandleClosePolicy(policy);
const base::string16& sid =
GetContentClient()->browser()->GetAppContainerSidForSandboxType(
GetSandboxType());
if (!sid.empty())
service_manager::SandboxWin::AddAppContainerPolicy(policy, sid.c_str());
return GetContentClient()->browser()->PreSpawnRenderer(policy);
}
#endif // OS_WIN
#if BUILDFLAG(USE_ZYGOTE_HANDLE)
service_manager::ZygoteHandle GetZygote() override {
const base::CommandLine& browser_command_line =
*base::CommandLine::ForCurrentProcess();
base::CommandLine::StringType renderer_prefix =
browser_command_line.GetSwitchValueNative(switches::kRendererCmdPrefix);
if (!renderer_prefix.empty())
return nullptr;
return service_manager::GetGenericZygote();
}
#endif // BUILDFLAG(USE_ZYGOTE_HANDLE)
service_manager::SandboxType GetSandboxType() override {
return service_manager::SANDBOX_TYPE_RENDERER;
}
};
const char kSessionStorageHolderKey[] = "kSessionStorageHolderKey";
class SessionStorageHolder : public base::SupportsUserData::Data {
public:
SessionStorageHolder()
: session_storage_namespaces_awaiting_close_(
new std::map<int, SessionStorageNamespaceMap>) {
}
~SessionStorageHolder() override {
// Its important to delete the map on the IO thread to avoid deleting
// the underlying namespaces prior to processing ipcs referring to them.
BrowserThread::DeleteSoon(
BrowserThread::IO, FROM_HERE,
session_storage_namespaces_awaiting_close_.release());
}
void Hold(const SessionStorageNamespaceMap& sessions, int widget_route_id) {
(*session_storage_namespaces_awaiting_close_)[widget_route_id] = sessions;
}
void Release(int old_route_id) {
session_storage_namespaces_awaiting_close_->erase(old_route_id);
}
private:
std::unique_ptr<std::map<int, SessionStorageNamespaceMap>>
session_storage_namespaces_awaiting_close_;
DISALLOW_COPY_AND_ASSIGN(SessionStorageHolder);
};
// This class manages spare RenderProcessHosts.
//
// There is a singleton instance of this class which manages a single spare
// renderer (g_spare_render_process_host_manager, below). This class
// encapsulates the implementation of
// RenderProcessHost::WarmupSpareRenderProcessHost()
//
// RenderProcessHostImpl should call
// SpareRenderProcessHostManager::MaybeTakeSpareRenderProcessHost when creating
// a new RPH. In this implementation, the spare renderer is bound to a
// BrowserContext and its default StoragePartition. If
// MaybeTakeSpareRenderProcessHost 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 (is_for_guests_ == true).
//
// It is safe to call WarmupSpareRenderProcessHost multiple times, although if
// called in a context where the spare renderer is not likely to be used
// performance may suffer due to the unnecessary RPH creation.
class SpareRenderProcessHostManager : public RenderProcessHostObserver {
public:
SpareRenderProcessHostManager() {}
void WarmupSpareRenderProcessHost(BrowserContext* browser_context) {
if (spare_render_process_host_ &&
spare_render_process_host_->GetBrowserContext() == browser_context) {
DCHECK_EQ(BrowserContext::GetDefaultStoragePartition(browser_context),
spare_render_process_host_->GetStoragePartition());
return; // Nothing to warm up.
}
CleanupSpareRenderProcessHost();
// Don't create a spare renderer if we're using --single-process or if we've
// got too many processes. See also ShouldTryToUseExistingProcessHost in
// this file.
if (RenderProcessHost::run_renderer_in_process() ||
g_all_hosts.Get().size() >=
RenderProcessHostImpl::GetMaxRendererProcessCount())
return;
// Don't create a spare renderer when the system is under load. This is
// currently approximated by only looking at the memory pressure. See also
// https://crbug.com/852905.
auto* memory_monitor = base::MemoryPressureMonitor::Get();
if (memory_monitor &&
memory_monitor->GetCurrentPressureLevel() >=
base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE)
return;
spare_render_process_host_ = RenderProcessHostImpl::CreateRenderProcessHost(
browser_context, nullptr /* storage_partition_impl */,
nullptr /* site_instance */, false /* is_for_guests_only */);
spare_render_process_host_->AddObserver(this);
spare_render_process_host_->Init();
}
RenderProcessHost* MaybeTakeSpareRenderProcessHost(
BrowserContext* browser_context,
SiteInstanceImpl* site_instance,
bool is_for_guests_only) {
// Give embedder a chance to disable using a spare RenderProcessHost for
// certain SiteInstances. Some navigations, such as to NTP or extensions,
// require passing command-line flags to the renderer process at process
// launch time, but this cannot be done for spare RenderProcessHosts, which
// are started before it is known which navigation might use them. So, a
// spare RenderProcessHost should not be used in such cases.
bool embedder_allows_spare_usage =
GetContentClient()->browser()->ShouldUseSpareRenderProcessHost(
browser_context, site_instance->GetSiteURL());
bool site_instance_allows_spare_usage =
site_instance->CanAssociateWithSpareProcess();
// Get the StoragePartition for |site_instance|. Note that this might be
// different than the default StoragePartition for |browser_context|.
StoragePartition* site_storage =
BrowserContext::GetStoragePartition(browser_context, site_instance);
// Log UMA metrics.
using SpareProcessMaybeTakeAction =
RenderProcessHostImpl::SpareProcessMaybeTakeAction;
SpareProcessMaybeTakeAction action =
SpareProcessMaybeTakeAction::kNoSparePresent;
if (!spare_render_process_host_)
action = SpareProcessMaybeTakeAction::kNoSparePresent;
else if (browser_context != spare_render_process_host_->GetBrowserContext())
action = SpareProcessMaybeTakeAction::kMismatchedBrowserContext;
else if (site_storage != spare_render_process_host_->GetStoragePartition())
action = SpareProcessMaybeTakeAction::kMismatchedStoragePartition;
else if (!embedder_allows_spare_usage)
action = SpareProcessMaybeTakeAction::kRefusedByEmbedder;
else if (!site_instance_allows_spare_usage)
action = SpareProcessMaybeTakeAction::kRefusedBySiteInstance;
else
action = SpareProcessMaybeTakeAction::kSpareTaken;
UMA_HISTOGRAM_ENUMERATION(
"BrowserRenderProcessHost.SpareProcessMaybeTakeAction", action);
// Decide whether to take or drop the spare process.
RenderProcessHost* returned_process = nullptr;
if (spare_render_process_host_ &&
browser_context == spare_render_process_host_->GetBrowserContext() &&
site_storage == spare_render_process_host_->GetStoragePartition() &&
!is_for_guests_only && embedder_allows_spare_usage &&
site_instance_allows_spare_usage) {
CHECK(spare_render_process_host_->HostHasNotBeenUsed());
// If the spare process ends up getting killed, the spare manager should
// discard the spare RPH, so if one exists, it should always be live here.
CHECK(spare_render_process_host_->IsInitializedAndNotDead());
DCHECK_EQ(SpareProcessMaybeTakeAction::kSpareTaken, action);
returned_process = spare_render_process_host_;
ReleaseSpareRenderProcessHost(spare_render_process_host_);
} else if (!RenderProcessHostImpl::IsSpareProcessKeptAtAllTimes()) {
// If the spare shouldn't be kept around, then discard it as soon as we
// find that the current spare was mismatched.
CleanupSpareRenderProcessHost();
} else if (g_all_hosts.Get().size() >=
RenderProcessHostImpl::GetMaxRendererProcessCount()) {
// Drop the spare if we are at a process limit and the spare wasn't taken.
// This helps avoid process reuse.
CleanupSpareRenderProcessHost();
}
return returned_process;
}
// 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 the spare_render_process_host_ has either been 1) matched and taken
// or 2) mismatched and ignored or 3) matched and ignored.
void PrepareForFutureRequests(BrowserContext* browser_context) {
if (RenderProcessHostImpl::IsSpareProcessKeptAtAllTimes()) {
// Always keep around a spare process for the most recently requested
// |browser_context|.
WarmupSpareRenderProcessHost(browser_context);
} else {
// Discard the ignored (probably non-matching) spare so as not to waste
// resources.
CleanupSpareRenderProcessHost();
}
}
// Gracefully remove and cleanup a spare RenderProcessHost if it exists.
void CleanupSpareRenderProcessHost() {
if (spare_render_process_host_) {
// Stop observing the process, to avoid getting notifications as a
// consequence of the Cleanup call below - such notification could call
// back into CleanupSpareRenderProcessHost leading to stack overflow.
spare_render_process_host_->RemoveObserver(this);
// Make sure the RenderProcessHost object gets destroyed.
if (!spare_render_process_host_->IsKeepAliveRefCountDisabled())
spare_render_process_host_->Cleanup();
// Drop reference to the RenderProcessHost object.
spare_render_process_host_ = nullptr;
}
}
RenderProcessHost* spare_render_process_host() {
return spare_render_process_host_;
}
private:
// Release ownership of |host| as a possible spare renderer. Called when
// |host| has either been 1) claimed to be used in a navigation or 2) shutdown
// somewhere else.
void ReleaseSpareRenderProcessHost(RenderProcessHost* host) {
if (spare_render_process_host_ && spare_render_process_host_ == host) {
spare_render_process_host_->RemoveObserver(this);
spare_render_process_host_ = nullptr;
}
}
void RenderProcessExited(RenderProcessHost* host,
const ChildProcessTerminationInfo& info) override {
if (host == spare_render_process_host_)
CleanupSpareRenderProcessHost();
}
void RenderProcessHostDestroyed(RenderProcessHost* host) override {
ReleaseSpareRenderProcessHost(host);
}
// This is a bare pointer, because RenderProcessHost manages the lifetime of
// all its instances; see g_all_hosts, above.
RenderProcessHost* spare_render_process_host_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(SpareRenderProcessHostManager);
};
base::LazyInstance<SpareRenderProcessHostManager>::Leaky
g_spare_render_process_host_manager = LAZY_INSTANCE_INITIALIZER;
const void* const kDefaultSubframeProcessHostHolderKey =
&kDefaultSubframeProcessHostHolderKey;
class DefaultSubframeProcessHostHolder : public base::SupportsUserData::Data,
public RenderProcessHostObserver {
public:
explicit DefaultSubframeProcessHostHolder(BrowserContext* browser_context)
: browser_context_(browser_context) {}
~DefaultSubframeProcessHostHolder() override {}
// Gets the correct render process to use for this SiteInstance.
RenderProcessHost* GetProcessHost(SiteInstance* site_instance,
bool is_for_guests_only) {
StoragePartitionImpl* default_partition =
static_cast<StoragePartitionImpl*>(
BrowserContext::GetDefaultStoragePartition(browser_context_));
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
BrowserContext::GetStoragePartition(browser_context_, site_instance));
// Is this the default storage partition? If it isn't, then just give it its
// own non-shared process.
if (partition != default_partition || is_for_guests_only) {
RenderProcessHost* host = RenderProcessHostImpl::CreateRenderProcessHost(
browser_context_, partition, site_instance, is_for_guests_only);
host->SetIsNeverSuitableForReuse();
return host;
}
// If we already have a shared host for the default storage partition, use
// it.
if (host_)
return host_;
host_ = RenderProcessHostImpl::CreateRenderProcessHost(
browser_context_, partition, site_instance,
false /* is for guests only */);
host_->SetIsNeverSuitableForReuse();
host_->AddObserver(this);
return host_;
}
// Implementation of RenderProcessHostObserver.
void RenderProcessHostDestroyed(RenderProcessHost* host) override {
DCHECK_EQ(host_, host);
host_->RemoveObserver(this);
host_ = nullptr;
}
private:
BrowserContext* browser_context_;
// The default subframe render process used for the default storage partition
// of this BrowserContext.
RenderProcessHost* host_ = nullptr;
};
// Forwards service requests to Service Manager since the renderer cannot launch
// out-of-process services on is own.
template <typename Interface>
void ForwardRequest(const char* service_name,
mojo::InterfaceRequest<Interface> request) {
// TODO(beng): This should really be using the per-profile connector.
service_manager::Connector* connector =
ServiceManagerConnection::GetForProcess()->GetConnector();
connector->BindInterface(service_name, std::move(request));
}
class RenderProcessHostIsReadyObserver : public RenderProcessHostObserver {
public:
RenderProcessHostIsReadyObserver(RenderProcessHost* render_process_host,
base::OnceClosure task)
: render_process_host_(render_process_host),
task_(std::move(task)),
weak_factory_(this) {
render_process_host_->AddObserver(this);
if (render_process_host_->IsReady())
PostTask();
}
~RenderProcessHostIsReadyObserver() override {
render_process_host_->RemoveObserver(this);
}
void RenderProcessReady(RenderProcessHost* host) override { PostTask(); }
void RenderProcessHostDestroyed(RenderProcessHost* host) override {
delete this;
}
private:
void PostTask() {
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::UI},
base::BindOnce(&RenderProcessHostIsReadyObserver::CallTask,
weak_factory_.GetWeakPtr()));
}
void CallTask() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (render_process_host_->IsReady())
std::move(task_).Run();
delete this;
}
RenderProcessHost* render_process_host_;
base::OnceClosure task_;
base::WeakPtrFactory<RenderProcessHostIsReadyObserver> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(RenderProcessHostIsReadyObserver);
};
// The following class is used to track the sites each RenderProcessHost is
// hosting frames for and expecting navigations to. There are two of them per
// BrowserContext: one for frames and one for navigations.
//
// For each site, the SiteProcessCountTracker keeps a map of counts per
// RenderProcessHost, which represents the number of frames/navigations
// for this site that are associated with the RenderProcessHost. This allows to
// quickly lookup a list of RenderProcessHost that can be used by a particular
// SiteInstance. On the other hand, it does not allow to quickly lookup which
// sites are hosted by a RenderProcessHost. This class is meant to help reusing
// RenderProcessHosts among SiteInstances, not to perform security checks for a
// RenderProcessHost.
//
// TODO(alexmos): Currently, the tracking in this class and in
// UnmatchedServiceWorkerProcessTracker is associated with a BrowserContext,
// but it needs to also consider StoragePartitions, so that process reuse is
// allowed only within the same StoragePartition. For now, the tracking is
// done only for the default StoragePartition. See https://crbug.com/752667.
const void* const kCommittedSiteProcessCountTrackerKey =
"CommittedSiteProcessCountTrackerKey";
const void* const kPendingSiteProcessCountTrackerKey =
"PendingSiteProcessCountTrackerKey";
class SiteProcessCountTracker : public base::SupportsUserData::Data,
public RenderProcessHostObserver {
public:
SiteProcessCountTracker() {}
~SiteProcessCountTracker() override { DCHECK(map_.empty()); }
void IncrementSiteProcessCount(const GURL& site_url,
int render_process_host_id) {
std::map<ProcessID, Count>& counts_per_process = map_[site_url];
++counts_per_process[render_process_host_id];
#ifndef NDEBUG
// In debug builds, observe the RenderProcessHost destruction, to check
// that it is properly removed from the map.
RenderProcessHost* host = RenderProcessHost::FromID(render_process_host_id);
if (!HasProcess(host))
host->AddObserver(this);
#endif
}
void DecrementSiteProcessCount(const GURL& site_url,
int render_process_host_id) {
auto result = map_.find(site_url);
DCHECK(result != map_.end());
std::map<ProcessID, Count>& counts_per_process = result->second;
--counts_per_process[render_process_host_id];
DCHECK_GE(counts_per_process[render_process_host_id], 0);
if (counts_per_process[render_process_host_id] == 0)
counts_per_process.erase(render_process_host_id);
if (counts_per_process.empty())
map_.erase(site_url);
}
void FindRenderProcessesForSiteInstance(
SiteInstanceImpl* site_instance,
std::set<RenderProcessHost*>* foreground_processes,
std::set<RenderProcessHost*>* background_processes) {
auto result = map_.find(site_instance->GetSiteURL());
if (result == map_.end())
return;
std::map<ProcessID, Count>& counts_per_process = result->second;
for (auto iter : counts_per_process) {
RenderProcessHost* host = RenderProcessHost::FromID(iter.first);
if (!host) {
// TODO(clamy): This shouldn't happen but we are getting reports from
// the field that this is happening. We need to figure out why some
// RenderProcessHosts are not taken out of the map when they're
// destroyed.
NOTREACHED();
continue;
}
// It's possible that |host| has become unsuitable for hosting
// |site_url|, for example if it was reused by a navigation to a
// different site, and |site_url| requires a dedicated process. Do not
// allow such hosts to be reused. See https://crbug.com/780661.
if (!host->MayReuseHost() ||
!RenderProcessHostImpl::IsSuitableHost(
host, host->GetBrowserContext(),
site_instance->GetIsolationContext(), site_instance->GetSiteURL(),
site_instance->lock_url())) {
continue;
}
if (host->VisibleClientCount())
foreground_processes->insert(host);
else
background_processes->insert(host);
}
}
private:
void RenderProcessHostDestroyed(RenderProcessHost* host) override {
#ifndef NDEBUG
host->RemoveObserver(this);
DCHECK(!HasProcess(host));
#endif
}
#ifndef NDEBUG
// Used in debug builds to ensure that RenderProcessHost don't persist in the
// map after they've been destroyed.
bool HasProcess(RenderProcessHost* process) {
for (auto iter : map_) {
std::map<ProcessID, Count>& counts_per_process = iter.second;
for (auto iter_process : counts_per_process) {
if (iter_process.first == process->GetID())
return true;
}
}
return false;
}
#endif
using ProcessID = int;
using Count = int;
using CountPerProcessPerSiteMap = std::map<GURL, std::map<ProcessID, Count>>;
CountPerProcessPerSiteMap map_;
};
bool ShouldUseSiteProcessTracking(BrowserContext* browser_context,
StoragePartition* dest_partition,
const GURL& site_url) {
// TODO(alexmos): Sites should be tracked separately for each
// StoragePartition. For now, track them only in the default one.
StoragePartition* default_partition =
BrowserContext::GetDefaultStoragePartition(browser_context);
if (dest_partition != default_partition)
return false;
return true;
}
bool ShouldTrackProcessForSite(BrowserContext* browser_context,
RenderProcessHost* render_process_host,
const GURL& site_url) {
if (site_url.is_empty())
return false;
return ShouldUseSiteProcessTracking(
browser_context, render_process_host->GetStoragePartition(), site_url);
}
bool ShouldFindReusableProcessHostForSite(BrowserContext* browser_context,
const GURL& site_url) {
if (site_url.is_empty())
return false;
return ShouldUseSiteProcessTracking(
browser_context,
BrowserContext::GetStoragePartitionForSite(browser_context, site_url),
site_url);
}
const void* const kUnmatchedServiceWorkerProcessTrackerKey =
"UnmatchedServiceWorkerProcessTrackerKey";
// This class tracks 'unmatched' service worker processes. When a service worker
// is started after a navigation to the site, SiteProcessCountTracker that is
// implemented above is used to find the matching renderer process which is used
// for the navigation. But a service worker may be started before a navigation
// (ex: Push notification -> show the page of the notification).
// This class tracks processes with 'unmatched' service workers until the
// processes are reused for a navigation to a matching site. After a single
// matching navigation is put into the process, all service workers for that
// site in that process are considered 'matched.'
//
// TODO(alexmos): Currently, the tracking in this class and in
// SiteProcessCountTracker is associated with a BrowserContext, but it needs to
// also consider StoragePartitions, so that process reuse is allowed only
// within the same StoragePartition. For now, the tracking is done only for
// the default StoragePartition. See https://crbug.com/752667.
class UnmatchedServiceWorkerProcessTracker
: public base::SupportsUserData::Data,
public RenderProcessHostObserver {
public:
// Registers |render_process_host| as having an unmatched service worker for
// |site_instance|.
static void Register(RenderProcessHost* render_process_host,
SiteInstanceImpl* site_instance) {
BrowserContext* browser_context = site_instance->GetBrowserContext();
DCHECK(!site_instance->GetSiteURL().is_empty());
if (!ShouldTrackProcessForSite(browser_context, render_process_host,
site_instance->GetSiteURL()))
return;
UnmatchedServiceWorkerProcessTracker* tracker =
static_cast<UnmatchedServiceWorkerProcessTracker*>(
browser_context->GetUserData(
kUnmatchedServiceWorkerProcessTrackerKey));
if (!tracker) {
tracker = new UnmatchedServiceWorkerProcessTracker();
browser_context->SetUserData(kUnmatchedServiceWorkerProcessTrackerKey,
base::WrapUnique(tracker));
}
tracker->RegisterProcessForSite(render_process_host, site_instance);
}
// Find a process with an unmatched service worker for |site_instance| and
// removes the process from the tracker if it exists.
static RenderProcessHost* MatchWithSite(SiteInstanceImpl* site_instance) {
BrowserContext* browser_context = site_instance->GetBrowserContext();
if (!ShouldFindReusableProcessHostForSite(browser_context,
site_instance->GetSiteURL()))
return nullptr;
UnmatchedServiceWorkerProcessTracker* tracker =
static_cast<UnmatchedServiceWorkerProcessTracker*>(
browser_context->GetUserData(
kUnmatchedServiceWorkerProcessTrackerKey));
if (!tracker)
return nullptr;
return tracker->TakeFreshestProcessForSite(site_instance);
}
UnmatchedServiceWorkerProcessTracker() {}
~UnmatchedServiceWorkerProcessTracker() override {
DCHECK(site_process_set_.empty());
}
// Implementation of RenderProcessHostObserver.
void RenderProcessHostDestroyed(RenderProcessHost* host) override {
DCHECK(HasProcess(host));
int process_id = host->GetID();
for (auto it = site_process_set_.begin(); it != site_process_set_.end();) {
if (it->second == process_id) {
it = site_process_set_.erase(it);
} else {
++it;
}
}
host->RemoveObserver(this);
}
private:
void RegisterProcessForSite(RenderProcessHost* host,
SiteInstanceImpl* site_instance) {
if (!HasProcess(host))
host->AddObserver(this);
site_process_set_.insert(
SiteProcessIDPair(site_instance->GetSiteURL(), host->GetID()));
}
RenderProcessHost* TakeFreshestProcessForSite(
SiteInstanceImpl* site_instance) {
RenderProcessHost* host = FindFreshestProcessForSite(site_instance);
if (!host)
return nullptr;
// It's possible that |host| is currently unsuitable for hosting
// |site_url|, for example if it was used for a ServiceWorker for a
// nonexistent extension URL. See https://crbug.com/782349 and
// https://crbug.com/780661.
GURL site_url(site_instance->GetSiteURL());
if (!host->MayReuseHost() || !RenderProcessHostImpl::IsSuitableHost(
host, host->GetBrowserContext(),
site_instance->GetIsolationContext(),
site_url, site_instance->lock_url()))
return nullptr;
site_process_set_.erase(SiteProcessIDPair(site_url, host->GetID()));
if (!HasProcess(host))
host->RemoveObserver(this);
return host;
}
RenderProcessHost* FindFreshestProcessForSite(
SiteInstanceImpl* site_instance) const {
GURL site_url(site_instance->GetSiteURL());
for (const auto& site_process_pair : base::Reversed(site_process_set_)) {
if (site_process_pair.first == site_url)
return RenderProcessHost::FromID(site_process_pair.second);
}
return nullptr;
}
// Returns true if this tracker contains the process ID |host->GetID()|.
bool HasProcess(RenderProcessHost* host) const {
int process_id = host->GetID();
for (const auto& site_process_id : site_process_set_) {
if (site_process_id.second == process_id)
return true;
}
return false;
}
using ProcessID = int;
using SiteProcessIDPair = std::pair<GURL, ProcessID>;
using SiteProcessIDPairSet = std::set<SiteProcessIDPair>;
// Use std::set because duplicates don't need to be tracked separately (eg.,
// service workers for the same site in the same process). It is sorted in the
// order of insertion.
SiteProcessIDPairSet site_process_set_;
};
void CopyFeatureSwitch(const base::CommandLine& src,
base::CommandLine* dest,
const char* switch_name) {
std::vector<std::string> features = FeaturesFromSwitch(src, switch_name);
if (!features.empty())
dest->AppendSwitchASCII(switch_name, base::JoinString(features, ","));
}
std::set<int>& GetCurrentCorbPluginExceptions() {
static base::NoDestructor<std::set<int>> s_data;
return *s_data;
}
void OnNetworkServiceCrashForCorb() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
network::mojom::NetworkService* network_service = GetNetworkService();
for (int process_id : GetCurrentCorbPluginExceptions())
network_service->AddCorbExceptionForPlugin(process_id);
}
RenderProcessHostImpl::StoragePartitionServiceRequestHandler&
GetStoragePartitionServiceRequestHandler() {
static base::NoDestructor<
RenderProcessHostImpl::StoragePartitionServiceRequestHandler>
instance;
return *instance;
}
RenderProcessHostImpl::BroadcastChannelProviderRequestHandler&
GetBroadcastChannelProviderRequestHandler() {
static base::NoDestructor<
RenderProcessHostImpl::BroadcastChannelProviderRequestHandler>
instance;
return *instance;
}
void RemoveCorbExceptionForPluginOnIOThread(int process_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
// Without NetworkService the exception list is stored directly in the browser
// process.
if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
network::CrossOriginReadBlocking::RemoveExceptionForPlugin(process_id);
}
// This is the entry point (i.e. this is called on the UI thread *before*
// we post a task for RemoveCorbExceptionForPluginOnIOThread).
void RemoveCorbExceptionForPluginOnUIThread(int process_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
GetCurrentCorbPluginExceptions().erase(process_id);
GetNetworkService()->RemoveCorbExceptionForPlugin(process_id);
} else {
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::IO},
base::BindOnce(&RemoveCorbExceptionForPluginOnIOThread, process_id));
}
}
void AddCorbExceptionForPluginOnUIThread(int process_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RenderProcessHost* process = RenderProcessHostImpl::FromID(process_id);
if (!process) {
// In this case the exception won't be added via NetworkService (because of
// the early return below), but we need to proactively do clean-up on IO
// thread.
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::IO},
base::BindOnce(&RemoveCorbExceptionForPluginOnIOThread, process_id));
return;
}
process->CleanupCorbExceptionForPluginUponDestruction();
if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
static base::NoDestructor<
std::unique_ptr<base::CallbackList<void()>::Subscription>>
s_crash_handler_subscription;
if (!*s_crash_handler_subscription) {
*s_crash_handler_subscription = RegisterNetworkServiceCrashHandler(
base::BindRepeating(&OnNetworkServiceCrashForCorb));
}
GetCurrentCorbPluginExceptions().insert(process_id);
GetNetworkService()->AddCorbExceptionForPlugin(process_id);
}
}
// This is the entry point (i.e. this is called on the IO thread *before*
// we post a task for AddCorbExceptionForPluginOnUIThread).
void AddCorbExceptionForPluginOnIOThread(int process_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
// Without NetworkService the exception list is stored directly in the browser
// process.
if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
network::CrossOriginReadBlocking::AddExceptionForPlugin(process_id);
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::UI},
base::BindOnce(&AddCorbExceptionForPluginOnUIThread, process_id));
}
#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
static constexpr size_t kUnknownPlatformProcessLimit = 0;
// Returns the process limit from the system. Use |kUnknownPlatformProcessLimit|
// to indicate failure and std::numeric_limits<size_t>::max() to indicate
// unlimited.
size_t GetPlatformProcessLimit() {
#if defined(OS_LINUX)
struct rlimit limit;
if (getrlimit(RLIMIT_NPROC, &limit) != 0)
return kUnknownPlatformProcessLimit;
if (limit.rlim_cur == RLIM_INFINITY)
return std::numeric_limits<size_t>::max();
return base::saturated_cast<size_t>(limit.rlim_cur);
#else
// TODO(https://crbug.com/104689): Implement on other platforms.
return kUnknownPlatformProcessLimit;
#endif // defined(OS_LINUX)
}
#endif // !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
} // namespace
// Held by the RPH and used to control an (unowned) ConnectionFilterImpl from
// any thread.
class RenderProcessHostImpl::ConnectionFilterController
: public base::RefCountedThreadSafe<ConnectionFilterController> {
public:
// |filter| is not owned by this object.
explicit ConnectionFilterController(ConnectionFilterImpl* filter)
: filter_(filter) {}
void DisableFilter();
private:
friend class base::RefCountedThreadSafe<ConnectionFilterController>;
friend class ConnectionFilterImpl;
~ConnectionFilterController() {}
void Detach() {
base::AutoLock lock(lock_);
filter_ = nullptr;
}
base::Lock lock_;
ConnectionFilterImpl* filter_ PT_GUARDED_BY(lock_);
};
// Held by the RPH's BrowserContext's ServiceManagerConnection, ownership
// transferred back to RPH upon RPH destruction.
class RenderProcessHostImpl::ConnectionFilterImpl : public ConnectionFilter {
public:
ConnectionFilterImpl(
const service_manager::Identity& child_identity,
std::unique_ptr<service_manager::BinderRegistry> registry)
: child_identity_(child_identity),
registry_(std::move(registry)),
controller_(new ConnectionFilterController(this)),
weak_factory_(this) {
// Registration of this filter may race with browser shutdown, in which case
// it's possible for this filter to be destroyed on the main thread. This
// is fine as long as the filter hasn't been used on the IO thread yet. We
// detach the ThreadChecker initially and the first use of the filter will
// bind it.
thread_checker_.DetachFromThread();
}
~ConnectionFilterImpl() override {
DCHECK(thread_checker_.CalledOnValidThread());
controller_->Detach();
}
scoped_refptr<ConnectionFilterController> controller() { return controller_; }
void Disable() {
base::AutoLock lock(enabled_lock_);
enabled_ = false;
}
private:
// ConnectionFilter:
void OnBindInterface(const service_manager::BindSourceInfo& source_info,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle* interface_pipe,
service_manager::Connector* connector) override {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK_CURRENTLY_ON(BrowserThread::IO);
// We only fulfill connections from the renderer we host.
if (source_info.identity != child_identity_)
return;
base::AutoLock lock(enabled_lock_);
if (!enabled_)
return;
registry_->TryBindInterface(interface_name, interface_pipe);
}
base::ThreadChecker thread_checker_;
service_manager::Identity child_identity_;
std::unique_ptr<service_manager::BinderRegistry> registry_;
scoped_refptr<ConnectionFilterController> controller_;
base::Lock enabled_lock_;
bool enabled_ GUARDED_BY(enabled_lock_) = true;
base::WeakPtrFactory<ConnectionFilterImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ConnectionFilterImpl);
};
void RenderProcessHostImpl::ConnectionFilterController::DisableFilter() {
base::AutoLock lock(lock_);
if (filter_)
filter_->Disable();
}
scoped_refptr<base::SingleThreadTaskRunner>
RenderProcessHostImpl::GetInProcessRendererThreadTaskRunnerForTesting() {
return g_in_process_thread->task_runner();
}
#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
// static
size_t RenderProcessHostImpl::GetPlatformMaxRendererProcessCount() {
// Set the limit to half of the system limit to leave room for other programs.
size_t limit = GetPlatformProcessLimit() / 2;
// If the system limit is unavailable, use a fallback value instead.
if (limit == kUnknownPlatformProcessLimit) {
static constexpr size_t kMaxRendererProcessCount = 82;
limit = kMaxRendererProcessCount;
}
return limit;
}
#endif
// static
size_t RenderProcessHost::GetMaxRendererProcessCount() {
if (g_max_renderer_count_override)
return g_max_renderer_count_override;
#if defined(OS_ANDROID)
// On Android we don't maintain a limit of renderer process hosts - we are
// happy with keeping a lot of these, as long as the number of live renderer
// processes remains reasonable, and on Android the OS takes care of that.
return std::numeric_limits<size_t>::max();
#elif defined(OS_CHROMEOS)
// On Chrome OS new renderer processes are very cheap and there's no OS
// driven constraint on the number of processes, and the effectiveness
// of the tab discarder is very poor when we have tabs sharing a
// renderer process. So, set a high limit, and based on UMA stats
// for CrOS the 99.9th percentile of Tabs.MaxTabsInADay is around 100.
return 100;
#else
// On other platforms, calculate the maximum number of renderer process hosts
// according to the amount of installed memory as reported by the OS, along
// with some hard-coded limits. The calculation assumes that the renderers
// will use up to half of the installed RAM and assumes that each WebContents
// uses |kEstimatedWebContentsMemoryUsage| MB. If this assumption changes, the
// ThirtyFourTabs test needs to be adjusted to match the expected number of
// processes.
//
// Using the above assumptions, with the given amounts of installed memory
// below on a 64-bit CPU, the maximum renderer count based on available RAM
// alone will be as follows:
//
// 128 MB -> 1
// 512 MB -> 4
// 1024 MB -> 8
// 4096 MB -> 34
// 16384 MB -> 136
//
// Then the calculated value will be clamped by |kMinRendererProcessCount| and
// GetPlatformMaxRendererProcessCount().
static size_t max_count = 0;
if (!max_count) {
static constexpr size_t kEstimatedWebContentsMemoryUsage =
#if defined(ARCH_CPU_64_BITS)
60; // In MB
#else
40; // In MB
#endif
max_count = base::SysInfo::AmountOfPhysicalMemoryMB() / 2;
max_count /= kEstimatedWebContentsMemoryUsage;
static constexpr size_t kMinRendererProcessCount = 3;
static const size_t kMaxRendererProcessCount =
RenderProcessHostImpl::GetPlatformMaxRendererProcessCount();
DCHECK_LE(kMinRendererProcessCount, kMaxRendererProcessCount);
max_count = base::ClampToRange(max_count, kMinRendererProcessCount,
kMaxRendererProcessCount);
}
return max_count;
#endif
}
// static
void RenderProcessHost::SetMaxRendererProcessCount(size_t count) {
g_max_renderer_count_override = count;
if (g_all_hosts.Get().size() > count)
g_spare_render_process_host_manager.Get().CleanupSpareRenderProcessHost();
}
// static
int RenderProcessHost::GetCurrentRenderProcessCountForTesting() {
RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator();
int count = 0;
while (!it.IsAtEnd()) {
RenderProcessHost* host = it.GetCurrentValue();
if (host->IsInitializedAndNotDead() &&
host != RenderProcessHostImpl::GetSpareRenderProcessHostForTesting()) {
count++;
}
it.Advance();
}
return count;
}
// static
RenderProcessHost* RenderProcessHostImpl::CreateRenderProcessHost(
BrowserContext* browser_context,
StoragePartitionImpl* storage_partition_impl,
SiteInstance* site_instance,
bool is_for_guests_only) {
if (g_render_process_host_factory_) {
return g_render_process_host_factory_->CreateRenderProcessHost(
browser_context, site_instance);
}
if (!storage_partition_impl) {
storage_partition_impl = static_cast<StoragePartitionImpl*>(
BrowserContext::GetStoragePartition(browser_context, site_instance));
}
// If we've made a StoragePartition for guests (e.g., for the <webview> tag),
// stash the Site URL on it. This way, when we start a service worker inside
// this storage partition, we can create the appropriate SiteInstance for
// finding a process (e.g., we will try to start a worker from
// "https://example.com/sw.js" but need to use the site URL
// "chrome-guest://blahblah" to get a process in the guest's
// StoragePartition.)
if (is_for_guests_only && site_instance &&
storage_partition_impl->site_for_service_worker().is_empty()) {
storage_partition_impl->set_site_for_service_worker(
site_instance->GetSiteURL());
}
return new RenderProcessHostImpl(browser_context, storage_partition_impl,
is_for_guests_only);
}
// static
const unsigned int RenderProcessHostImpl::kMaxFrameDepthForPriority =
std::numeric_limits<unsigned int>::max();
RenderProcessHostImpl::RenderProcessHostImpl(
BrowserContext* browser_context,
StoragePartitionImpl* storage_partition_impl,
bool is_for_guests_only)
: fast_shutdown_started_(false),
deleting_soon_(false),
#ifndef NDEBUG
is_self_deleted_(false),
#endif
pending_views_(0),
keep_alive_ref_count_(0),
is_keep_alive_ref_count_disabled_(false),
route_provider_binding_(this),
visible_clients_(0),
priority_(!blink::kLaunchingProcessIsBackgrounded,
false /* has_media_stream */,
false /* has_foreground_service_worker */,
frame_depth_,
false /* intersects_viewport */,
true /* boost_for_pending_views */
#if defined(OS_ANDROID)
,
ChildProcessImportance::NORMAL
#endif
),
id_(ChildProcessHostImpl::GenerateChildProcessUniqueId()),
browser_context_(browser_context),
storage_partition_impl_(storage_partition_impl),
sudden_termination_allowed_(true),
is_blocked_(false),
is_for_guests_only_(is_for_guests_only),
is_unused_(true),
delayed_cleanup_needed_(false),
within_process_died_observer_(false),
permission_service_context_(new PermissionServiceContext(this)),
indexed_db_factory_(
new IndexedDBDispatcherHost(
id_,
storage_partition_impl_->GetIndexedDBContext(),
ChromeBlobStorageContext::GetFor(browser_context_)),
base::OnTaskRunnerDeleter(
storage_partition_impl_->GetIndexedDBContext()->TaskRunner())),
channel_connected_(false),
sent_render_process_ready_(false),
renderer_host_binding_(this),
instance_weak_factory_(
new base::WeakPtrFactory<RenderProcessHostImpl>(this)),
frame_sink_provider_(id_),
shutdown_exit_code_(-1),
weak_factory_(this) {
for (size_t i = 0; i < kNumKeepAliveClients; i++)
keep_alive_client_count_[i] = 0;
widget_helper_ = new RenderWidgetHelper();
ChildProcessSecurityPolicyImpl::GetInstance()->Add(GetID(), browser_context);
CHECK(!BrowserMainRunner::ExitedMainMessageLoop());
RegisterHost(GetID(), this);
g_all_hosts.Get().set_check_on_null_data(true);
// Initialize |child_process_activity_time_| to a reasonable value.
mark_child_process_activity_time();
if (!GetBrowserContext()->IsOffTheRecord() &&
!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableGpuShaderDiskCache)) {
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::IO},
base::BindOnce(&CacheShaderInfo, GetID(),
storage_partition_impl_->GetPath()));
}
push_messaging_manager_.reset(new PushMessagingManager(
GetID(), storage_partition_impl_->GetServiceWorkerContext()));
AddObserver(indexed_db_factory_.get());
#if defined(OS_MACOSX)
AddObserver(MachBroker::GetInstance());
#endif
InitializeChannelProxy();
const int id = GetID();
const uint64_t tracing_id =
ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId(id);
gpu_client_.reset(new viz::GpuClient(
std::make_unique<BrowserGpuClientDelegate>(), id, tracing_id,
base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO})));
}
// static
void RenderProcessHostImpl::ShutDownInProcessRenderer() {
DCHECK(g_run_renderer_in_process);
switch (g_all_hosts.Pointer()->size()) {
case 0:
return;
case 1: {
RenderProcessHostImpl* host = static_cast<RenderProcessHostImpl*>(
AllHostsIterator().GetCurrentValue());
for (auto& observer : host->observers_)
observer.RenderProcessHostDestroyed(host);
#ifndef NDEBUG
host->is_self_deleted_ = true;
#endif
delete host;
return;
}
default:
NOTREACHED() << "There should be only one RenderProcessHost when running "
<< "in-process.";
}
}
void RenderProcessHostImpl::RegisterRendererMainThreadFactory(
RendererMainThreadFactoryFunction create) {
g_renderer_main_thread_factory = create;
}
void RenderProcessHostImpl::SetStoragePartitionServiceRequestHandlerForTesting(
StoragePartitionServiceRequestHandler handler) {
GetStoragePartitionServiceRequestHandler() = handler;
}
void RenderProcessHostImpl::SetBroadcastChannelProviderRequestHandlerForTesting(
BroadcastChannelProviderRequestHandler handler) {
GetBroadcastChannelProviderRequestHandler() = handler;
}
RenderProcessHostImpl::~RenderProcessHostImpl() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
#ifndef NDEBUG
DCHECK(is_self_deleted_)
<< "RenderProcessHostImpl is destroyed by something other than itself";
#endif
// Make sure to clean up the in-process renderer before the channel, otherwise
// it may still run and have its IPCs fail, causing asserts.
in_process_renderer_.reset();
g_in_process_thread = nullptr;
ChildProcessSecurityPolicyImpl::GetInstance()->Remove(GetID());
is_dead_ = true;
UnregisterHost(GetID());
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableGpuShaderDiskCache)) {
base::PostTaskWithTraits(FROM_HERE, {BrowserThread::IO},
base::BindOnce(&RemoveShaderInfo, GetID()));
}
if (cleanup_corb_exception_for_plugin_upon_destruction_)
RemoveCorbExceptionForPluginOnUIThread(GetID());
}
bool RenderProcessHostImpl::Init() {
// calling Init() more than once does nothing, this makes it more convenient
// for the view host which may not be sure in some cases
if (IsInitializedAndNotDead())
return true;
base::CommandLine::StringType renderer_prefix;
// A command prefix is something prepended to the command line of the spawned
// process.
const base::CommandLine& browser_command_line =
*base::CommandLine::ForCurrentProcess();
renderer_prefix =
browser_command_line.GetSwitchValueNative(switches::kRendererCmdPrefix);
#if defined(OS_LINUX)
int flags = renderer_prefix.empty() ? ChildProcessHost::CHILD_ALLOW_SELF
: ChildProcessHost::CHILD_NORMAL;
#else
int flags = ChildProcessHost::CHILD_NORMAL;
#endif
// Find the renderer before creating the channel so if this fails early we
// return without creating the channel.
base::FilePath renderer_path = ChildProcessHost::GetChildPath(flags);
if (renderer_path.empty())
return false;
is_initialized_ = true;
is_dead_ = false;
sent_render_process_ready_ = false;
if (gpu_client_)
gpu_client_->PreEstablishGpuChannel();
// We may reach Init() during process death notification (e.g.
// RenderProcessExited on some observer). In this case the Channel may be
// null, so we re-initialize it here.
if (!channel_)
InitializeChannelProxy();
// Unpause the Channel briefly. This will be paused again below if we launch a
// real child process. Note that messages may be sent in the short window
// between now and then (e.g. in response to RenderProcessWillLaunch) and we
// depend on those messages being sent right away.
//
// |channel_| must always be non-null here: either it was initialized in
// the constructor, or in the most recent call to ProcessDied().
channel_->Unpause(false /* flush */);
// Call the embedder first so that their IPC filters have priority.
service_manager::mojom::ServiceRequest service_request;
GetContentClient()->browser()->RenderProcessWillLaunch(this,
&service_request);
if (service_request.is_pending()) {
GetRendererInterface()->CreateEmbedderRendererService(
std::move(service_request));
}
#if defined(OS_ANDROID)
// Initialize the java audio manager so that media session tests will pass.
// See internal b/29872494.
static_cast<media::AudioManagerAndroid*>(media::AudioManager::Get())->
InitializeIfNeeded();
#endif // defined(OS_ANDROID)
CreateMessageFilters();
RegisterMojoInterfaces();
if (run_renderer_in_process()) {
DCHECK(g_renderer_main_thread_factory);
// Crank up a thread and run the initialization there. With the way that
// messages flow between the browser and renderer, this thread is required
// to prevent a deadlock in single-process mode. Since the primordial
// thread in the renderer process runs the WebKit code and can sometimes
// make blocking calls to the UI thread (i.e. this thread), they need to run
// on separate threads.
in_process_renderer_.reset(
g_renderer_main_thread_factory(InProcessChildThreadParams(
base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO}),
&mojo_invitation_, child_connection_->service_token())));
base::Thread::Options options;
#if defined(OS_WIN) && !defined(OS_MACOSX)
// In-process plugins require this to be a UI message loop.
options.message_loop_type = base::MessageLoop::TYPE_UI;
#else
// We can't have multiple UI loops on Linux and Android, so we don't support
// in-process plugins.
options.message_loop_type = base::MessageLoop::TYPE_DEFAULT;
#endif
// As for execution sequence, this callback should have no any dependency
// on starting in-process-render-thread.
// So put it here to trigger ChannelMojo initialization earlier to enable
// in-process-render-thread using ChannelMojo there.
OnProcessLaunched(); // Fake a callback that the process is ready.
in_process_renderer_->StartWithOptions(options);
g_in_process_thread = in_process_renderer_.get();
// Make sure any queued messages on the channel are flushed in the case
// where we aren't launching a child process.
channel_->Flush();
} else {
// Build command line for renderer. We call AppendRendererCommandLine()
// first so the process type argument will appear first.
std::unique_ptr<base::CommandLine> cmd_line =
std::make_unique<base::CommandLine>(renderer_path);
if (!renderer_prefix.empty())
cmd_line->PrependWrapper(renderer_prefix);
AppendRendererCommandLine(cmd_line.get());
// Spawn the child process asynchronously to avoid blocking the UI thread.
// As long as there's no renderer prefix, we can use the zygote process
// at this stage.
child_process_launcher_ = std::make_unique<ChildProcessLauncher>(
std::make_unique<RendererSandboxedProcessLauncherDelegate>(),
std::move(cmd_line), GetID(), this, std::move(mojo_invitation_),
base::BindRepeating(&RenderProcessHostImpl::OnMojoError, id_));
channel_->Pause();
fast_shutdown_started_ = false;
}
init_time_ = base::TimeTicks::Now();
return true;
}
void RenderProcessHostImpl::EnableSendQueue() {
if (!channel_)
InitializeChannelProxy();
}
void RenderProcessHostImpl::InitializeChannelProxy() {
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner =
base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO});
// Acquire a Connector which will route connections to a new instance of the
// renderer service.
service_manager::Connector* connector =
BrowserContext::GetConnectorFor(browser_context_);
if (!connector) {
// Note that some embedders (e.g. Android WebView) may not initialize a
// Connector per BrowserContext. In those cases we fall back to the
// browser-wide Connector.
if (!ServiceManagerConnection::GetForProcess()) {
// Additionally, some test code may not initialize the process-wide
// ServiceManagerConnection prior to this point. This class of test code
// doesn't care about render processes, so we can initialize a dummy
// connection.
ServiceManagerConnection::SetForProcess(ServiceManagerConnection::Create(
mojo::MakeRequest(&test_service_), io_task_runner));
}
connector = ServiceManagerConnection::GetForProcess()->GetConnector();
}
// Establish a ServiceManager connection for the new render service instance.
mojo_invitation_ = {};
child_connection_ = std::make_unique<ChildConnection>(
service_manager::Identity(
mojom::kRendererServiceName,
BrowserContext::GetServiceInstanceGroupFor(GetBrowserContext()),
base::Token::CreateRandom(), base::Token::CreateRandom()),
&mojo_invitation_, connector, io_task_runner);
// Send an interface request to bootstrap the IPC::Channel. Note that this
// request will happily sit on the pipe until the process is launched and
// connected to the ServiceManager. We take the other end immediately and
// plug it into a new ChannelProxy.
mojo::MessagePipe pipe;
BindInterface(IPC::mojom::ChannelBootstrap::Name_, std::move(pipe.handle1));
std::unique_ptr<IPC::ChannelFactory> channel_factory =
IPC::ChannelMojo::CreateServerFactory(
std::move(pipe.handle0), io_task_runner,
base::ThreadTaskRunnerHandle::Get());
content::BindInterface(this, &child_control_interface_);
ResetChannelProxy();
// Do NOT expand ifdef or run time condition checks here! Synchronous
// IPCs from browser process are banned. It is only narrowly allowed
// for Android WebView to maintain backward compatibility.
// See crbug.com/526842 for details.
#if defined(OS_ANDROID)
if (GetContentClient()->UsingSynchronousCompositing()) {
// Android never performs a clean shutdown, so we pass nullptr for
// shudown_event to indicate that we never intend to signal a shutdown.
channel_ =
IPC::SyncChannel::Create(this, io_task_runner.get(),
base::ThreadTaskRunnerHandle::Get(), nullptr);
}
#endif // OS_ANDROID
if (!channel_) {
channel_ = std::make_unique<IPC::ChannelProxy>(
this, io_task_runner.get(), base::ThreadTaskRunnerHandle::Get());
}
channel_->Init(std::move(channel_factory), true /* create_pipe_now */);
// Note that Channel send is effectively paused and unpaused at various points
// during startup, and existing code relies on a fragile relative message
// ordering resulting from some early messages being queued until process
// launch while others are sent immediately. See https://goo.gl/REW75h for
// details.
//
// We acquire a few associated interface proxies here -- before the channel is
// paused -- to ensure that subsequent initialization messages on those
// interfaces behave properly. Specifically, this avoids the risk of an
// interface being requested while the Channel is paused, which could
// effectively and undesirably block the transmission of a subsequent message
// on that interface while the Channel is unpaused.
//
// See OnProcessLaunched() for some additional details of this somewhat
// surprising behavior.
channel_->GetRemoteAssociatedInterface(&remote_route_provider_);
channel_->GetRemoteAssociatedInterface(&renderer_interface_);
// We start the Channel in a paused state. It will be briefly unpaused again
// in Init() if applicable, before process launch is initiated.
channel_->Pause();
}
void RenderProcessHostImpl::ResetChannelProxy() {
if (!channel_)
return;
channel_.reset();
channel_connected_ = false;
}
void RenderProcessHostImpl::CreateMessageFilters() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
MediaInternals* media_internals = MediaInternals::GetInstance();
// Add BrowserPluginMessageFilter to ensure it gets the first stab at messages
// from guests.
bp_message_filter_ = new BrowserPluginMessageFilter(GetID());
AddFilter(bp_message_filter_.get());
scoped_refptr<RenderMessageFilter> render_message_filter =
base::MakeRefCounted<RenderMessageFilter>(
GetID(), GetBrowserContext(), widget_helper_.get(), media_internals);
AddFilter(render_message_filter.get());
render_frame_message_filter_ = new RenderFrameMessageFilter(
GetID(),
#if BUILDFLAG(ENABLE_PLUGINS)
PluginServiceImpl::GetInstance(),
#else
nullptr,
#endif
GetBrowserContext(), storage_partition_impl_, widget_helper_.get());
AddFilter(render_frame_message_filter_.get());
BrowserContext* browser_context = GetBrowserContext();
// Several filters need the Blob storage context, so fetch it in advance.
scoped_refptr<ChromeBlobStorageContext> blob_storage_context =
ChromeBlobStorageContext::GetFor(browser_context);
if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
scoped_refptr<net::URLRequestContextGetter> request_context(
storage_partition_impl_->GetURLRequestContext());
ResourceContext* resource_context = browser_context->GetResourceContext();
scoped_refptr<net::URLRequestContextGetter> media_request_context(
GetStoragePartition()->GetMediaURLRequestContext());
ResourceMessageFilter::GetContextsCallback get_contexts_callback(
base::Bind(&GetContexts, resource_context, request_context,
media_request_context));
resource_message_filter_ = new ResourceMessageFilter(
GetID(), storage_partition_impl_->GetAppCacheService(),
blob_storage_context.get(),
storage_partition_impl_->GetFileSystemContext(),
storage_partition_impl_->GetPrefetchURLLoaderService(),
std::move(get_contexts_callback),
base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO}));
AddFilter(resource_message_filter_.get());
}
AddFilter(new DOMStorageMessageFilter(
storage_partition_impl_->GetDOMStorageContext()));
peer_connection_tracker_host_ = new PeerConnectionTrackerHost(GetID());
AddFilter(peer_connection_tracker_host_.get());
#if BUILDFLAG(ENABLE_PLUGINS)
AddFilter(new PepperRendererConnection(GetID()));
#endif
AddFilter(new BlobDispatcherHost(GetID(), blob_storage_context));
#if defined(OS_MACOSX)
AddFilter(new TextInputClientMessageFilter());
#endif
p2p_socket_dispatcher_host_ =
std::make_unique<P2PSocketDispatcherHost>(GetID());
AddFilter(new TraceMessageFilter(GetID()));
AddFilter(new ResolveProxyMsgHelper(GetID()));
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context(
static_cast<ServiceWorkerContextWrapper*>(
storage_partition_impl_->GetServiceWorkerContext()));
}
void RenderProcessHostImpl::BindCacheStorage(
blink::mojom::CacheStorageRequest request,
const url::Origin& origin) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!cache_storage_dispatcher_host_) {
cache_storage_dispatcher_host_ =
base::MakeRefCounted<CacheStorageDispatcherHost>();
cache_storage_dispatcher_host_->Init(
storage_partition_impl_->GetCacheStorageContext());
}
// Send the binding to IO thread, because Cache Storage handles Mojo IPC on IO
// thread entirely.
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::IO},
base::BindOnce(&CacheStorageDispatcherHost::AddBinding,
cache_storage_dispatcher_host_, std::move(request),
origin));
}
void RenderProcessHostImpl::BindIndexedDB(
blink::mojom::IDBFactoryRequest request,
const url::Origin& origin) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (origin.opaque()) {
// Opaque origins aren't valid for IndexedDB access, so we won't bind
// |request| to |indexed_db_factory_|. Return early here which will cause
// |request| to be freed. When |request| is freed, we expect the pipe on
// the client will be closed.
return;
}
// Send the binding to IDB sequenced task runner to let IndexedDB handle Mojo
// IPC there. |indexed_db_factory_| is being invoked on the IDB task runner,
// and |this| owns |indexed_db_factory_| via a unique_ptr with an IDB task
// runner deleter, so if |this| is destroyed immediately after this call,
// the IDB task runner deleter's task will be run after the next call,
// guaranteeing that the usage of base::Unretained(indexed_db_factory_.get())
// here is safe.
indexed_db_factory_->context()->TaskRunner()->PostTask(
FROM_HERE, base::BindOnce(&IndexedDBDispatcherHost::AddBinding,
base::Unretained(indexed_db_factory_.get()),
std::move(request), origin));
}
void RenderProcessHostImpl::ForceCrash() {
child_connection_->ForceCrash();
}
void RenderProcessHostImpl::BindFileSystemManager(
blink::mojom::FileSystemManagerRequest request) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::IO},
base::BindOnce(&FileSystemManagerImpl::BindRequest,
base::Unretained(file_system_manager_impl_.get()),
std::move(request)));
}
void RenderProcessHostImpl::CancelProcessShutdownDelayForUnload() {
if (IsKeepAliveRefCountDisabled())
return;
DecrementKeepAliveRefCount(RenderProcessHost::KeepAliveClientType::kUnload);
}
void RenderProcessHostImpl::DelayProcessShutdownForUnload(
const base::TimeDelta& timeout) {
// No need to delay shutdown if the process is already shutting down.
if (IsKeepAliveRefCountDisabled() || deleting_soon_ || fast_shutdown_started_)
return;
IncrementKeepAliveRefCount(RenderProcessHost::KeepAliveClientType::kUnload);
base::PostDelayedTaskWithTraits(
FROM_HERE, {BrowserThread::UI},
base::BindOnce(
&RenderProcessHostImpl::CancelProcessShutdownDelayForUnload,
weak_factory_.GetWeakPtr()),
timeout);
}
// static
void RenderProcessHostImpl::AddCorbExceptionForPlugin(int process_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
AddCorbExceptionForPluginOnIOThread(process_id);
}
void RenderProcessHostImpl::CleanupCorbExceptionForPluginUponDestruction() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
cleanup_corb_exception_for_plugin_upon_destruction_ = true;
}
void RenderProcessHostImpl::RegisterMojoInterfaces() {
auto registry = std::make_unique<service_manager::BinderRegistry>();
AddUIThreadInterface(
registry.get(),
base::BindRepeating(&ForwardRequest<device::mojom::BatteryMonitor>,
device::mojom::kServiceName));
AddUIThreadInterface(
registry.get(),
base::BindRepeating(
&RenderProcessHostImpl::CreateEmbeddedFrameSinkProvider,
base::Unretained(this)));
AddUIThreadInterface(
registry.get(),
base::BindRepeating(&RenderProcessHostImpl::BindFrameSinkProvider,
base::Unretained(this)));
AddUIThreadInterface(
registry.get(),
base::BindRepeating(&RenderProcessHostImpl::BindCompositingModeReporter,
base::Unretained(this)));
AddUIThreadInterface(
registry.get(),
base::BindRepeating(
&BackgroundSyncContextImpl::CreateService,
base::Unretained(
storage_partition_impl_->GetBackgroundSyncContext())));
AddUIThreadInterface(
registry.get(),
base::BindRepeating(&RenderProcessHostImpl::CreateStoragePartitionService,
base::Unretained(this)));
AddUIThreadInterface(
registry.get(),
base::BindRepeating(
&RenderProcessHostImpl::CreateBroadcastChannelProvider,
base::Unretained(this)));
AddUIThreadInterface(registry.get(),
base::BindRepeating(&ClipboardHostImpl::Create));
registry->AddInterface(
base::BindRepeating(&MimeRegistryImpl::Create),
base::CreateSequencedTaskRunnerWithTraits(
{base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
base::TaskPriority::USER_BLOCKING}));
#if BUILDFLAG(USE_MINIKIN_HYPHENATION)
registry->AddInterface(
base::BindRepeating(&hyphenation::HyphenationImpl::Create),
hyphenation::HyphenationImpl::GetTaskRunner());
#endif
#if defined(OS_ANDROID)
if (base::FeatureList::IsEnabled(features::kFontSrcLocalMatching)) {
registry->AddInterface(
base::BindRepeating(&FontUniqueNameLookupService::Create),
FontUniqueNameLookupService::GetTaskRunner());
}
#endif
registry->AddInterface(
base::BindRepeating(&device::GamepadHapticsManager::Create));
registry->AddInterface(
base::BindRepeating(&PushMessagingManager::BindRequest,
base::Unretained(push_messaging_manager_.get())));
file_system_manager_impl_.reset(new FileSystemManagerImpl(
GetID(), storage_partition_impl_->GetFileSystemContext(),
ChromeBlobStorageContext::GetFor(GetBrowserContext())));
// This interface is still exposed by the RenderProcessHost's registry so
// that it can be accessed by PepperFileSystemHost. Blink accesses this
// interface through RenderFrameHost/RendererInterfaceBinders.
// TODO(https://crbug.com/873661): Make PepperFileSystemHost access this with
// the RenderFrameHost's registry, and remove this registration.
registry->AddInterface(
base::BindRepeating(&FileSystemManagerImpl::BindRequest,
base::Unretained(file_system_manager_impl_.get())));
registry->AddInterface(base::BindRepeating(
&MidiHost::BindRequest, GetID(),
base::Unretained(BrowserMainLoop::GetInstance()->midi_service())));
if (gpu_client_) {
// |gpu_client_| outlives the registry, because its destruction is posted to
// IO thread from the destructor of |this|.
registry->AddInterface(base::BindRepeating(
&viz::GpuClient::Add, base::Unretained(gpu_client_.get())));
}
registry->AddInterface(
base::BindRepeating(
&WebDatabaseHostImpl::Create, GetID(),
base::WrapRefCounted(storage_partition_impl_->GetDatabaseTracker())),
storage_partition_impl_->GetDatabaseTracker()->task_runner());
MediaStreamManager* media_stream_manager =
BrowserMainLoop::GetInstance()->media_stream_manager();
registry->AddInterface(base::BindRepeating(&VideoCaptureHost::Create, GetID(),
media_stream_manager));
registry->AddInterface(
base::BindRepeating(&FileUtilitiesHostImpl::Create, GetID()),
base::CreateSequencedTaskRunnerWithTraits(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE}));
registry->AddInterface(base::BindRepeating(
&RenderProcessHostImpl::CreateMediaStreamTrackMetricsHost,
base::Unretained(this)));
registry->AddInterface(
base::BindRepeating(&metrics::CreateSingleSampleMetricsProvider));
registry->AddInterface(base::BindRepeating(
&CodeCacheHostImpl::Create, GetID(),
base::RetainedRef(storage_partition_impl_->GetCacheStorageContext()),
base::RetainedRef(
storage_partition_impl_->GetGeneratedCodeCacheContext())));
#if BUILDFLAG(ENABLE_REPORTING)
AddUIThreadInterface(
registry.get(),
base::BindRepeating(&CreateReportingServiceProxy, GetID()));
#endif // BUILDFLAG(ENABLE_REPORTING)
registry->AddInterface(base::BindRepeating(
&ChromeAppCacheService::CreateBackend,
base::Unretained(storage_partition_impl_->GetAppCacheService()),
GetID()));
AddUIThreadInterface(
registry.get(),
base::BindRepeating(&P2PSocketDispatcherHost::BindRequest,
base::Unretained(p2p_socket_dispatcher_host_.get())));
#if BUILDFLAG(ENABLE_MDNS)
AddUIThreadInterface(
registry.get(),
base::BindRepeating(&RenderProcessHostImpl::CreateMdnsResponder,
base::Unretained(this)));
#endif // BUILDFLAG(ENABLE_MDNS)
AddUIThreadInterface(registry.get(),
base::BindRepeating(&FieldTrialRecorder::Create));
associated_interfaces_ =
std::make_unique<blink::AssociatedInterfaceRegistry>();
blink::AssociatedInterfaceRegistry* associated_registry =
associated_interfaces_.get();
associated_registry->AddInterface(base::BindRepeating(
&RenderProcessHostImpl::BindRouteProvider, base::Unretained(this)));
associated_registry->AddInterface(base::BindRepeating(
&RenderProcessHostImpl::CreateRendererHost, base::Unretained(this)));
if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
AddUIThreadInterface(
registry.get(),
base::BindRepeating(
&RenderProcessHostImpl::CreateURLLoaderFactoryForRendererProcess,
base::Unretained(this)));
}
registry->AddInterface(
base::BindRepeating(&BlobRegistryWrapper::Bind,
storage_partition_impl_->GetBlobRegistry(), GetID()));
#if BUILDFLAG(ENABLE_PLUGINS)
// Initialization can happen more than once (in the case of a child process
// crash), but we don't want to lose the plugin registry in this case.
if (!plugin_registry_) {
plugin_registry_.reset(
new PluginRegistryImpl(GetBrowserContext()->GetResourceContext()));
}
registry->AddInterface(base::BindRepeating(
&PluginRegistryImpl::Bind, base::Unretained(plugin_registry_.get())));
#endif
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
registry->AddInterface(base::BindRepeating(&KeySystemSupportImpl::Create));
#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
AddUIThreadInterface(
registry.get(),
base::BindRepeating(&RenderProcessHostImpl::BindVideoDecoderService,
base::Unretained(this)));
// ---- Please do not register interfaces below this line ------
//
// This call should be done after registering all interfaces above, so that
// embedder can override any interfaces. The fact that registry calls
// the last registration for the name allows us to easily override interfaces.
GetContentClient()->browser()->ExposeInterfacesToRenderer(
registry.get(), associated_interfaces_.get(), this);
ServiceManagerConnection* service_manager_connection =
BrowserContext::GetServiceManagerConnectionFor(browser_context_);
if (connection_filter_id_ !=
ServiceManagerConnection::kInvalidConnectionFilterId) {
connection_filter_controller_->DisableFilter();
service_manager_connection->RemoveConnectionFilter(connection_filter_id_);
}
std::unique_ptr<ConnectionFilterImpl> connection_filter =
std::make_unique<ConnectionFilterImpl>(
child_connection_->child_identity(), std::move(registry));
connection_filter_controller_ = connection_filter->controller();
connection_filter_id_ = service_manager_connection->AddConnectionFilter(
std::move(connection_filter));
}
void RenderProcessHostImpl::BindRouteProvider(
mojom::RouteProviderAssociatedRequest request) {
if (route_provider_binding_.is_bound())
return;
route_provider_binding_.Bind(std::move(request));
}
void RenderProcessHostImpl::GetRoute(
int32_t routing_id,
blink::mojom::AssociatedInterfaceProviderAssociatedRequest request) {
DCHECK(request.is_pending());
associated_interface_provider_bindings_.AddBinding(
this, std::move(request), routing_id);
}
void RenderProcessHostImpl::GetAssociatedInterface(
const std::string& name,
blink::mojom::AssociatedInterfaceAssociatedRequest request) {
int32_t routing_id =
associated_interface_provider_bindings_.dispatch_context();
IPC::Listener* listener = listeners_.Lookup(routing_id);
if (listener)
listener->OnAssociatedInterfaceRequest(name, request.PassHandle());
}
void RenderProcessHostImpl::CreateEmbeddedFrameSinkProvider(
blink::mojom::EmbeddedFrameSinkProviderRequest request) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!embedded_frame_sink_provider_) {
// The client id gets converted to a uint32_t in FrameSinkId.
uint32_t renderer_client_id = base::checked_cast<uint32_t>(id_);
embedded_frame_sink_provider_ =
std::make_unique<EmbeddedFrameSinkProviderImpl>(
GetHostFrameSinkManager(), renderer_client_id);
}
embedded_frame_sink_provider_->Add(std::move(request));
}
void RenderProcessHostImpl::BindFrameSinkProvider(
mojom::FrameSinkProviderRequest request) {
frame_sink_provider_.Bind(std::move(request));
}
void RenderProcessHostImpl::BindCompositingModeReporter(
viz::mojom::CompositingModeReporterRequest request) {
BrowserMainLoop::GetInstance()->GetCompositingModeReporter(
std::move(request));
}
void RenderProcessHostImpl::CreateStoragePartitionService(
blink::mojom::StoragePartitionServiceRequest request) {
if (!GetStoragePartitionServiceRequestHandler().is_null()) {
GetStoragePartitionServiceRequestHandler().Run(this, std::move(request));
return;
}
storage_partition_binding_ids_.insert(
storage_partition_impl_->Bind(id_, std::move(request)));
}
void RenderProcessHostImpl::CreateBroadcastChannelProvider(
blink::mojom::BroadcastChannelProviderRequest request) {
if (!GetBroadcastChannelProviderRequestHandler().is_null()) {
GetBroadcastChannelProviderRequestHandler().Run(this, std::move(request));
return;
}
storage_partition_impl_->GetBroadcastChannelProvider()->Connect(
id_, std::move(request));
}
void RenderProcessHostImpl::BindVideoDecoderService(
media::mojom::InterfaceFactoryRequest request) {
if (!video_decoder_proxy_)
video_decoder_proxy_.reset(new VideoDecoderProxy());
video_decoder_proxy_->Add(std::move(request));
}
void RenderProcessHostImpl::CreateRendererHost(
mojom::RendererHostAssociatedRequest request) {
renderer_host_binding_.Bind(std::move(request));
}
int RenderProcessHostImpl::GetNextRoutingID() {
return widget_helper_->GetNextRoutingID();
}
void RenderProcessHostImpl::BindInterface(
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) {
child_connection_->BindInterface(interface_name, std::move(interface_pipe));
}
const service_manager::Identity& RenderProcessHostImpl::GetChildIdentity() {
// GetChildIdentity should only be called if the RPH is (or soon will be)
// backed by an actual renderer process. This helps prevent leaks similar to
// the ones raised in https://crbug.com/813045.
DCHECK(IsInitializedAndNotDead());
return child_connection_->child_identity();
}
std::unique_ptr<base::PersistentMemoryAllocator>
RenderProcessHostImpl::TakeMetricsAllocator() {
return std::move(metrics_allocator_);
}
const base::TimeTicks&
RenderProcessHostImpl::GetInitTimeForNavigationMetrics() {
return init_time_;
}
bool RenderProcessHostImpl::IsProcessBackgrounded() {
return priority_.is_background();
}
void RenderProcessHostImpl::IncrementKeepAliveRefCount(
RenderProcessHost::KeepAliveClientType client) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!is_keep_alive_ref_count_disabled_);
base::TimeTicks now = base::TimeTicks::Now();
size_t client_type = static_cast<size_t>(client);
keep_alive_client_count_[client_type]++;
if (keep_alive_client_count_[client_type] == 1)
keep_alive_client_start_time_[client_type] = now;
++keep_alive_ref_count_;
if (keep_alive_ref_count_ == 1) {
GetRendererInterface()->SetSchedulerKeepActive(true);
}
}
void RenderProcessHostImpl::DecrementKeepAliveRefCount(
RenderProcessHost::KeepAliveClientType client) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!is_keep_alive_ref_count_disabled_);
DCHECK_GT(keep_alive_ref_count_, 0U);
base::TimeTicks now = base::TimeTicks::Now();
size_t client_type = static_cast<size_t>(client);
keep_alive_client_count_[client_type]--;
if (keep_alive_client_count_[client_type] == 0) {
RecordKeepAliveDuration(client, keep_alive_client_start_time_[client_type],
now);
}
--keep_alive_ref_count_;
if (keep_alive_ref_count_ == 0) {
Cleanup();
GetRendererInterface()->SetSchedulerKeepActive(false);
}
}
void RenderProcessHostImpl::RecordKeepAliveDuration(
RenderProcessHost::KeepAliveClientType client,
base::TimeTicks start,
base::TimeTicks end) {
switch (client) {
case RenderProcessHost::KeepAliveClientType::kServiceWorker:
UMA_HISTOGRAM_LONG_TIMES(
"BrowserRenderProcessHost.KeepAliveDuration.ServiceWorker",
end - start);
break;
case RenderProcessHost::KeepAliveClientType::kSharedWorker:
UMA_HISTOGRAM_LONG_TIMES(
"BrowserRenderProcessHost.KeepAliveDuration.SharedWorker",
end - start);
break;
case RenderProcessHost::KeepAliveClientType::kFetch:
UMA_HISTOGRAM_LONG_TIMES(
"BrowserRenderProcessHost.KeepAliveDuration.Fetch", end - start);
break;
case RenderProcessHost::KeepAliveClientType::kUnload:
UMA_HISTOGRAM_LONG_TIMES(
"BrowserRenderProcessHost.KeepAliveDuration.Unload", end - start);
break;
}
}
void RenderProcessHostImpl::DisableKeepAliveRefCount() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (is_keep_alive_ref_count_disabled_)
return;
is_keep_alive_ref_count_disabled_ = true;
keep_alive_ref_count_ = 0;
base::TimeTicks now = base::TimeTicks::Now();
for (size_t i = 0; i < kNumKeepAliveClients; i++) {
if (keep_alive_client_count_[i] > 0) {
RecordKeepAliveDuration(
static_cast<RenderProcessHost::KeepAliveClientType>(i),
keep_alive_client_start_time_[i], now);
keep_alive_client_count_[i] = 0;
}
}
// Cleaning up will also remove this from the SpareRenderProcessHostManager.
// (in this case |keep_alive_ref_count_| would be 0 even before).
Cleanup();
}
bool RenderProcessHostImpl::IsKeepAliveRefCountDisabled() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
return is_keep_alive_ref_count_disabled_;
}
void RenderProcessHostImpl::Resume() {}
mojom::Renderer* RenderProcessHostImpl::GetRendererInterface() {
return renderer_interface_.get();
}
void RenderProcessHostImpl::CreateURLLoaderFactoryForRendererProcess(
network::mojom::URLLoaderFactoryRequest request) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::Optional<url::Origin> request_initiator_site_lock;
GURL process_lock =
ChildProcessSecurityPolicyImpl::GetInstance()->GetOriginLock(GetID());
if (process_lock.is_valid()) {
request_initiator_site_lock =
SiteInstanceImpl::GetRequestInitiatorSiteLock(process_lock);
}
CreateURLLoaderFactory(request_initiator_site_lock,
nullptr /* header_client */, std::move(request));
}
void RenderProcessHostImpl::CreateURLLoaderFactory(
const base::Optional<url::Origin>& origin,
network::mojom::TrustedURLLoaderHeaderClientPtrInfo header_client,
network::mojom::URLLoaderFactoryRequest request) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// "chrome-guest://..." is never used as a |request_initiator|. Therefore
// it doesn't make sense to associate a URLLoaderFactory with a
// chrome-guest-based |origin|.
DCHECK(!origin.has_value() || origin.value().scheme() != kGuestScheme);
if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::IO},
base::BindOnce(&ResourceMessageFilter::Clone, resource_message_filter_,
std::move(request)));
return;
}
network::mojom::NetworkContext* network_context =
storage_partition_impl_->GetNetworkContext();
network::mojom::URLLoaderFactoryPtrInfo embedder_provided_factory;
if (origin.has_value()) {
embedder_provided_factory =
GetContentClient()->browser()->CreateURLLoaderFactoryForNetworkRequests(
this, network_context, &header_client, origin.value());
}
if (embedder_provided_factory) {
mojo::FuseInterface(std::move(request),
std::move(embedder_provided_factory));
} else {
network::mojom::URLLoaderFactoryParamsPtr params =
network::mojom::URLLoaderFactoryParams::New();
params->process_id = GetID();
params->request_initiator_site_lock = origin;
params->disable_web_security =
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableWebSecurity);
SiteIsolationPolicy::PopulateURLLoaderFactoryParamsPtrForCORB(params.get());
params->header_client = std::move(header_client);
network_context->CreateURLLoaderFactory(std::move(request),
std::move(params));
}
}
void RenderProcessHostImpl::SetIsNeverSuitableForReuse() {
is_never_suitable_for_reuse_ = true;
}
bool RenderProcessHostImpl::MayReuseHost() {
if (is_never_suitable_for_reuse_)
return false;
return GetContentClient()->browser()->MayReuseHost(this);
}
bool RenderProcessHostImpl::IsUnused() {
return is_unused_;
}
void RenderProcessHostImpl::SetIsUsed() {
is_unused_ = false;
}
mojom::RouteProvider* RenderProcessHostImpl::GetRemoteRouteProvider() {
return remote_route_provider_.get();
}
void RenderProcessHostImpl::AddRoute(int32_t routing_id,
IPC::Listener* listener) {
CHECK(!listeners_.Lookup(routing_id)) << "Found Routing ID Conflict: "
<< routing_id;
listeners_.AddWithID(listener, routing_id);
}
void RenderProcessHostImpl::RemoveRoute(int32_t routing_id) {
DCHECK(listeners_.Lookup(routing_id) != nullptr);
listeners_.Remove(routing_id);
Cleanup();
}
void RenderProcessHostImpl::AddObserver(RenderProcessHostObserver* observer) {
observers_.AddObserver(observer);
}
void RenderProcessHostImpl::RemoveObserver(
RenderProcessHostObserver* observer) {
observers_.RemoveObserver(observer);
}
void RenderProcessHostImpl::ShutdownForBadMessage(
CrashReportMode crash_report_mode) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kDisableKillAfterBadIPC))
return;
if (run_renderer_in_process()) {
// In single process mode it is better if we don't suicide but just
// crash.
CHECK(false);
}
// We kill the renderer but don't include a NOTREACHED, because we want the
// browser to try to survive when it gets illegal messages from the renderer.
Shutdown(RESULT_CODE_KILLED_BAD_MESSAGE);
if (crash_report_mode == CrashReportMode::GENERATE_CRASH_DUMP) {
// Set crash keys to understand renderer kills related to site isolation.
auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
std::string lock_url = policy->GetOriginLock(GetID()).spec();
base::debug::SetCrashKeyString(bad_message::GetKilledProcessOriginLockKey(),
lock_url.empty() ? "(none)" : lock_url);
std::string site_isolation_mode;
if (SiteIsolationPolicy::UseDedicatedProcessesForAllSites())
site_isolation_mode += "spp ";
if (SiteIsolationPolicy::AreIsolatedOriginsEnabled())
site_isolation_mode += "io ";
if (SiteIsolationPolicy::IsStrictOriginIsolationEnabled())
site_isolation_mode += "soi ";
if (site_isolation_mode.empty())
site_isolation_mode = "(none)";
static auto* isolation_mode_key = base::debug::AllocateCrashKeyString(
"site_isolation_mode", base::debug::CrashKeySize::Size32);
base::debug::SetCrashKeyString(isolation_mode_key, site_isolation_mode);
// Report a crash, since none will be generated by the killed renderer.
base::debug::DumpWithoutCrashing();
}
// Log the renderer kill to the histogram tracking all kills.
BrowserChildProcessHostImpl::HistogramBadMessageTerminated(
PROCESS_TYPE_RENDERER);
}
void RenderProcessHostImpl::UpdateClientPriority(PriorityClient* client) {
DCHECK(client);
DCHECK_EQ(1u, priority_clients_.count(client));
UpdateProcessPriorityInputs();
}
int RenderProcessHostImpl::VisibleClientCount() {
return visible_clients_;
}
unsigned int RenderProcessHostImpl::GetFrameDepth() {
return frame_depth_;
}
bool RenderProcessHostImpl::GetIntersectsViewport() {
return intersects_viewport_;
}
#if defined(OS_ANDROID)
ChildProcessImportance RenderProcessHostImpl::GetEffectiveImportance() {
return effective_importance_;
}
void RenderProcessHostImpl::DumpProcessStack() {
if (child_process_launcher_)
child_process_launcher_->DumpProcessStack();
}
#endif
RendererAudioOutputStreamFactoryContext*
RenderProcessHostImpl::GetRendererAudioOutputStreamFactoryContext() {
if (!audio_output_stream_factory_context_) {
media::AudioManager* audio_manager =
BrowserMainLoop::GetInstance()->audio_manager();
DCHECK(audio_manager) << "AudioManager is not instantiated: running the "
"audio service out of process?";
MediaStreamManager* media_stream_manager =
BrowserMainLoop::GetInstance()->media_stream_manager();
media::AudioSystem* audio_system =
BrowserMainLoop::GetInstance()->audio_system();
audio_output_stream_factory_context_.reset(
new RendererAudioOutputStreamFactoryContextImpl(
GetID(), audio_system, audio_manager, media_stream_manager));
}
return audio_output_stream_factory_context_.get();
}
void RenderProcessHostImpl::OnMediaStreamAdded() {
++media_stream_count_;
UpdateProcessPriority();
}
void RenderProcessHostImpl::OnMediaStreamRemoved() {
DCHECK_GT(media_stream_count_, 0);
--media_stream_count_;
UpdateProcessPriority();
}
void RenderProcessHostImpl::OnForegroundServiceWorkerAdded() {
foreground_service_worker_count_ += 1;
UpdateProcessPriority();
}
void RenderProcessHostImpl::OnForegroundServiceWorkerRemoved() {
DCHECK_GT(foreground_service_worker_count_, 0);
foreground_service_worker_count_ -= 1;
UpdateProcessPriority();
}
// static
void RenderProcessHostImpl::set_render_process_host_factory_for_testing(
const RenderProcessHostFactory* rph_factory) {
g_render_process_host_factory_ = rph_factory;
}
// static
const RenderProcessHostFactory*
RenderProcessHostImpl::get_render_process_host_factory_for_testing() {
return g_render_process_host_factory_;
}
// static
void RenderProcessHostImpl::AddFrameWithSite(
BrowserContext* browser_context,
RenderProcessHost* render_process_host,
const GURL& site_url) {
if (!ShouldTrackProcessForSite(browser_context, render_process_host,
site_url))
return;
SiteProcessCountTracker* tracker = static_cast<SiteProcessCountTracker*>(
browser_context->GetUserData(kCommittedSiteProcessCountTrackerKey));
if (!tracker) {
tracker = new SiteProcessCountTracker();
browser_context->SetUserData(kCommittedSiteProcessCountTrackerKey,
base::WrapUnique(tracker));
}
tracker->IncrementSiteProcessCount(site_url, render_process_host->GetID());
}
// static
void RenderProcessHostImpl::RemoveFrameWithSite(
BrowserContext* browser_context,
RenderProcessHost* render_process_host,
const GURL& site_url) {
if (!ShouldTrackProcessForSite(browser_context, render_process_host,
site_url))
return;
SiteProcessCountTracker* tracker = static_cast<SiteProcessCountTracker*>(
browser_context->GetUserData(kCommittedSiteProcessCountTrackerKey));
if (!tracker) {
tracker = new SiteProcessCountTracker();
browser_context->SetUserData(kCommittedSiteProcessCountTrackerKey,
base::WrapUnique(tracker));
}
tracker->DecrementSiteProcessCount(site_url, render_process_host->GetID());
}
// static
void RenderProcessHostImpl::AddExpectedNavigationToSite(
BrowserContext* browser_context,
RenderProcessHost* render_process_host,
const GURL& site_url) {
if (!ShouldTrackProcessForSite(browser_context, render_process_host,
site_url))
return;
SiteProcessCountTracker* tracker = static_cast<SiteProcessCountTracker*>(
browser_context->GetUserData(kPendingSiteProcessCountTrackerKey));
if (!tracker) {
tracker = new SiteProcessCountTracker();
browser_context->SetUserData(kPendingSiteProcessCountTrackerKey,
base::WrapUnique(tracker));
}
tracker->IncrementSiteProcessCount(site_url, render_process_host->GetID());
}
// static
void RenderProcessHostImpl::RemoveExpectedNavigationToSite(
BrowserContext* browser_context,
RenderProcessHost* render_process_host,
const GURL& site_url) {
if (!ShouldTrackProcessForSite(browser_context, render_process_host,
site_url))
return;
SiteProcessCountTracker* tracker = static_cast<SiteProcessCountTracker*>(
browser_context->GetUserData(kPendingSiteProcessCountTrackerKey));
if (!tracker) {
tracker = new SiteProcessCountTracker();
browser_context->SetUserData(kPendingSiteProcessCountTrackerKey,
base::WrapUnique(tracker));
}
tracker->DecrementSiteProcessCount(site_url, render_process_host->GetID());
}
// static
void RenderProcessHostImpl::NotifySpareManagerAboutRecentlyUsedBrowserContext(
BrowserContext* browser_context) {
g_spare_render_process_host_manager.Get().PrepareForFutureRequests(
browser_context);
}
// static
RenderProcessHost*
RenderProcessHostImpl::GetSpareRenderProcessHostForTesting() {
return g_spare_render_process_host_manager.Get().spare_render_process_host();
}
// static
void RenderProcessHostImpl::DiscardSpareRenderProcessHostForTesting() {
g_spare_render_process_host_manager.Get().CleanupSpareRenderProcessHost();
}
// static
bool RenderProcessHostImpl::IsSpareProcessKeptAtAllTimes() {
if (!SiteIsolationPolicy::UseDedicatedProcessesForAllSites())
return false;
if (!base::FeatureList::IsEnabled(features::kSpareRendererForSitePerProcess))
return false;
// Spare renderer actually hurts performance on low-memory devices. See
// https://crbug.com/843775 for more details.
//
// The comparison below is using 1077 rather than 1024 because 1) this helps
// ensure that devices with exactly 1GB of RAM won't get included because of
// inaccuracies or off-by-one errors and 2) this is the bucket boundary in
// Memory.Stats.Win.TotalPhys2.
if (base::SysInfo::AmountOfPhysicalMemoryMB() <= 1077)
return false;