// 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 #include #include #include #include #include #include #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/one_shot_background_sync_service_impl.h" #include "content/browser/background_sync/periodic_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/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/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_data_manager_impl.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/navigation_url_loader_impl.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/network_service_instance_impl.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/peer_connection_tracker_host.h" #include "content/browser/renderer_host/media/video_capture_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/background_tracing_manager_impl.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/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/system_connector.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 "content/public/common/web_preferences.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/database/database_tracker.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" #include "url/url_constants.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 #include #endif #if defined(OS_MACOSX) #include "content/browser/child_process_task_port_provider_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(ENABLE_WEBRTC) #include "content/browser/renderer_host/media/media_stream_track_metrics_host.h" #include "content/browser/renderer_host/p2p/socket_dispatcher_host.h" #include "content/browser/webrtc/webrtc_internals.h" #include "content/public/browser/webrtc_log.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 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; RenderProcessHostFactory* g_render_process_host_factory_ = nullptr; const char kSiteProcessMapKeyName[] = "content_site_process_map"; RenderProcessHost::AnalyzeHungRendererFunction g_analyze_hung_renderer = nullptr; 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 request_context, scoped_refptr 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 request_context, scoped_refptr 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); } // 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>::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 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 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( context->GetUserData(kSiteProcessMapKeyName)); if (existing_map) return existing_map; auto new_map = std::make_unique(); 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) { } ~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> 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::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( BrowserContext::GetDefaultStoragePartition(browser_context_)); StoragePartitionImpl* partition = static_cast( 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 void ForwardRequest(const char* service_name, mojo::InterfaceRequest request) { // TODO(beng): This should really be using the per-profile connector. GetSystemConnector()->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)) { 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 weak_factory_{this}; 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& 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& 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* foreground_processes, std::set* background_processes) { auto result = map_.find(site_instance->GetSiteURL()); if (result == map_.end()) return; std::map& 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); } } // Check whether |host| is associated with at least one URL for which // SiteInstance does not assign site URLs. This is used to disqualify |host| // from being reused if it has pending navigations to such URLs. bool ContainsNonReusableSiteForHost(RenderProcessHost* host) { for (auto iter : map_) { // If SiteInstance doesn't assign a site URL for the current entry (and it // isn't about:blank, which is allowed anywhere), check whether |host| is // on the list of processes the entry is associated with. // // TODO(alexmos): ShouldAssignSiteForURL() expects a full URL, whereas we // only have a site URL here. For now, this mismatch is ok since // ShouldAssignSiteForURL() only cares about schemes in practice, but // this should be cleaned up. if (!SiteInstanceImpl::ShouldAssignSiteForURL(iter.first) && !iter.first.IsAboutBlank() && base::Contains(iter.second, host->GetID())) return true; } return false; } 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& 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>; 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( 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( 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: using ProcessID = int; using SiteProcessIDPair = std::pair; using SiteProcessIDPairSet = std::set; 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) { SiteProcessIDPair site_process_pair = FindFreshestProcessForSite(site_instance); if (site_process_pair.first.is_empty()) return nullptr; RenderProcessHost* host = RenderProcessHost::FromID(site_process_pair.second); 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(site_process_pair); if (!HasProcess(host)) host->RemoveObserver(this); return host; } SiteProcessIDPair FindFreshestProcessForSite( SiteInstanceImpl* site_instance) const { const auto reversed_site_process_set = base::Reversed(site_process_set_); if (site_instance->IsDefaultSiteInstance()) { // See if we can find an entry that maps to a site associated with the // default SiteInstance. This allows the default SiteInstance to reuse a // service worker process for any site that has been associated with it. for (const auto& site_process_pair : reversed_site_process_set) { if (site_instance->IsSiteInDefaultSiteInstance(site_process_pair.first)) return site_process_pair; } } else { const GURL site_url(site_instance->GetSiteURL()); for (const auto& site_process_pair : reversed_site_process_set) { if (site_process_pair.first == site_url) return site_process_pair; } } return SiteProcessIDPair(); } // 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; } // 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 features = FeaturesFromSwitch(src, switch_name); if (!features.empty()) dest->AppendSwitchASCII(switch_name, base::JoinString(features, ",")); } std::set& GetCurrentCorbPluginExceptions() { static base::NoDestructor> 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::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::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::max(); return base::saturated_cast(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 { public: // |filter| is not owned by this object. explicit ConnectionFilterController(ConnectionFilterImpl* filter) : filter_(filter) {} void DisableFilter(); private: friend class base::RefCountedThreadSafe; 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 registry) : child_identity_(child_identity), registry_(std::move(registry)), controller_(new ConnectionFilterController(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 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 registry_; scoped_refptr controller_; base::Lock enabled_lock_; bool enabled_ GUARDED_BY(enabled_lock_) = true; base::WeakPtrFactory weak_factory_{this}; DISALLOW_COPY_AND_ASSIGN(ConnectionFilterImpl); }; void RenderProcessHostImpl::ConnectionFilterController::DisableFilter() { base::AutoLock lock(lock_); if (filter_) filter_->Disable(); } scoped_refptr 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::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( BrowserContext::GetStoragePartition(browser_context, site_instance)); } // If we've made a StoragePartition for guests (e.g., for the 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::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(this)), frame_sink_provider_(id_), shutdown_exit_code_(-1) { 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())); } // This instance of PushMessagingManager is only used from clients bound to // service workers (i.e. PushProvider), since frame-bound clients will rely on // DocumentInterfaceBroker instead. Therefore, pass an invalid frame ID here. push_messaging_manager_.reset(new PushMessagingManager( GetID(), /* render_frame_id= */ ChildProcessHost::kInvalidUniqueID, storage_partition_impl_->GetServiceWorkerContext())); AddObserver(indexed_db_factory_.get()); InitializeChannelProxy(); const int id = GetID(); const uint64_t tracing_id = ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId(id); gpu_client_.reset(new viz::GpuClient( std::make_unique(), 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( 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; #elif defined(OS_MACOSX) int flags = ChildProcessHost::CHILD_RENDERER; #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; // Don't grant further access to GPU if it is not allowed. GpuDataManagerImpl* gpu_data_manager = GpuDataManagerImpl::GetInstance(); DCHECK(gpu_data_manager); if (gpu_client_ && gpu_data_manager->GpuAccessAllowed(nullptr)) 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::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) && !defined(TOOLKIT_QT) // 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 cmd_line = std::make_unique(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( std::make_unique(), std::move(cmd_line), GetID(), this, std::move(mojo_invitation_), base::BindRepeating(&RenderProcessHostImpl::OnMojoError, id_)); channel_->Pause(); // In single process mode, browser-side tracing and memory will cover the // whole process including renderers. BackgroundTracingManagerImpl::ActivateForProcess(GetID(), child_process_.get()); fast_shutdown_started_ = false; } init_time_ = base::TimeTicks::Now(); return true; } void RenderProcessHostImpl::EnableSendQueue() { if (!channel_) InitializeChannelProxy(); } void RenderProcessHostImpl::InitializeChannelProxy() { scoped_refptr 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. connector = GetSystemConnector(); if (!connector && !ServiceManagerConnection::GetForProcess()) { // Additionally, some test code may not initialize the system Connector. // We initialize one that the ChildConnection below can use. // TODO(crbug.com/904240): Figure out why some unit tests fail when this // doesn't create a full ServiceManagerConnection. service_manager::mojom::ServicePtr unused_service; ServiceManagerConnection::SetForProcess(ServiceManagerConnection::Create( mojo::MakeRequest(&unused_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( 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 channel_factory = IPC::ChannelMojo::CreateServerFactory( std::move(pipe.handle0), io_task_runner, base::ThreadTaskRunnerHandle::Get()); child_process_.reset(); content::BindInterface( this, mojom::ChildProcessRequest(child_process_.BindNewPipeAndPassReceiver())); 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( 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 render_message_filter = base::MakeRefCounted( 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 blob_storage_context = ChromeBlobStorageContext::GetFor(browser_context); if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) { scoped_refptr request_context( storage_partition_impl_->GetURLRequestContext()); ResourceContext* resource_context = browser_context->GetResourceContext(); scoped_refptr 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()); } #if BUILDFLAG(ENABLE_WEBRTC) peer_connection_tracker_host_ = new PeerConnectionTrackerHost(GetID()); AddFilter(peer_connection_tracker_host_.get()); #endif #if BUILDFLAG(ENABLE_PLUGINS) AddFilter(new PepperRendererConnection(GetID())); #endif AddFilter(new BlobDispatcherHost(GetID(), blob_storage_context)); #if defined(OS_MACOSX) AddFilter(new TextInputClientMessageFilter()); #endif #if BUILDFLAG(ENABLE_WEBRTC) p2p_socket_dispatcher_host_ = std::make_unique(GetID()); #endif AddFilter(new ResolveProxyMsgHelper(GetID())); scoped_refptr service_worker_context( static_cast( storage_partition_impl_->GetServiceWorkerContext())); } void RenderProcessHostImpl::BindCacheStorage( blink::mojom::CacheStorageRequest request, const url::Origin& origin) { DCHECK_CURRENTLY_ON(BrowserThread::UI); storage_partition_impl_->GetCacheStorageContext()->AddBinding( 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_process_->CrashHungProcess(); } 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(); } 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(); 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(); AddUIThreadInterface( registry.get(), base::BindRepeating(&ForwardRequest, 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::CreateOneShotSyncService, base::Unretained( storage_partition_impl_->GetBackgroundSyncContext()))); AddUIThreadInterface( registry.get(), base::BindRepeating( &BackgroundSyncContextImpl::CreatePeriodicSyncService, 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)); AddUIThreadInterface( registry.get(), base::BindRepeating(&RenderProcessHostImpl::BindWebDatabaseHostImpl, base::Unretained(this))); 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()))); } 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})); #if BUILDFLAG(ENABLE_WEBRTC) registry->AddInterface(base::BindRepeating( &RenderProcessHostImpl::CreateMediaStreamTrackMetricsHost, base::Unretained(this))); #endif registry->AddInterface( base::BindRepeating(&metrics::CreateSingleSampleMetricsProvider)); AddUIThreadInterface( registry.get(), 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) if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) { AddUIThreadInterface( registry.get(), base::BindRepeating( &ChromeAppCacheService::CreateBackendForRequest, base::Unretained(storage_partition_impl_->GetAppCacheService()), GetID())); } else { registry->AddInterface(base::BindRepeating( &ChromeAppCacheService::CreateBackendForRequest, base::Unretained(storage_partition_impl_->GetAppCacheService()), GetID())); } #if BUILDFLAG(ENABLE_WEBRTC) AddUIThreadInterface( registry.get(), base::BindRepeating(&P2PSocketDispatcherHost::BindRequest, base::Unretained(p2p_socket_dispatcher_host_.get()))); #endif #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* 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))); #if BUILDFLAG(ENABLE_WEBRTC) AddUIThreadInterface( registry.get(), base::BindRepeating(&AecDumpManagerImpl::AddRequest, base::Unretained(&aec_dump_manager_))); #endif // ---- 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 connection_filter = std::make_unique( 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(id_); embedded_frame_sink_provider_ = std::make_unique( 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::BindWebDatabaseHostImpl( blink::mojom::WebDatabaseHostRequest request) { storage::DatabaseTracker* db_tracker = storage_partition_impl_->GetDatabaseTracker(); db_tracker->task_runner()->PostTask( FROM_HERE, base::BindOnce(&WebDatabaseHostImpl::Create, GetID(), base::WrapRefCounted(db_tracker), 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 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() { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(!is_keep_alive_ref_count_disabled_); ++keep_alive_ref_count_; if (keep_alive_ref_count_ == 1) GetRendererInterface()->SetSchedulerKeepActive(true); } void RenderProcessHostImpl::DecrementKeepAliveRefCount() { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(!is_keep_alive_ref_count_disabled_); DCHECK_GT(keep_alive_ref_count_, 0U); --keep_alive_ref_count_; if (keep_alive_ref_count_ == 0) { Cleanup(); GetRendererInterface()->SetSchedulerKeepActive(false); } } 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; // 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 request_initiator_site_lock; GURL process_lock = ChildProcessSecurityPolicyImpl::GetInstance()->GetOriginLock(GetID()); if (process_lock.is_valid()) { request_initiator_site_lock = SiteInstanceImpl::GetRequestInitiatorSiteLock(process_lock); } // Since this function is about to get deprecated (crbug.com/891872), it // should be fine to not add support for network isolation thus sending empty // key. CreateURLLoaderFactory(request_initiator_site_lock, nullptr /* preferences */, net::NetworkIsolationKey(), nullptr /* header_client */, std::move(request)); } void RenderProcessHostImpl::CreateURLLoaderFactory( const base::Optional& origin, const WebPreferences* preferences, const net::NetworkIsolationKey& network_isolation_key, 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); params->network_isolation_key = network_isolation_key; params->header_client = std::move(header_client); if (params->disable_web_security) { // --disable-web-security also disables Cross-Origin Read Blocking (CORB). params->is_corb_enabled = false; } else if (preferences && preferences->allow_universal_access_from_file_urls && origin.has_value() && origin->scheme() == url::kFileScheme) { // allow_universal_access_from_file_urls disables CORB (via // |is_corb_enabled|) and CORS (via |disable_web_security|) for requests // made from a file: |origin|. params->is_corb_enabled = false; params->disable_web_security = true; } else { params->is_corb_enabled = true; } 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( RenderProcessHostFactory* rph_factory) { g_render_process_host_factory_ = rph_factory; } // static 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( 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( 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( 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( 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; return true; } bool RenderProcessHostImpl::HostHasNotBeenUsed() { return IsUnused() && listeners_.IsEmpty() && keep_alive_ref_count_ == 0 && pending_views_ == 0; } void RenderProcessHostImpl::LockToOrigin( const IsolationContext& isolation_context, const GURL& lock_url) { ChildProcessSecurityPolicyImpl::GetInstance()->LockToOrigin( isolation_context, GetID(), lock_url); // Note that LockToOrigin is only called once per RenderProcessHostImpl (when // committing a navigation into an empty renderer). Therefore, the call to // NotifyRendererIfLockedToSite below is insufficient for setting up renderers // respawned after crashing - this is handled by another call to // NotifyRendererIfLockedToSite from OnProcessLaunched. NotifyRendererIfLockedToSite(); } void RenderProcessHostImpl::NotifyRendererIfLockedToSite() { GURL lock_url = ChildProcessSecurityPolicyImpl::GetInstance()->GetOriginLock(GetID()); if (!lock_url.is_valid()) return; if (!SiteInstanceImpl::IsOriginLockASite(lock_url)) return; GetRendererInterface()->SetIsLockedToSite(); } bool RenderProcessHostImpl::IsForGuestsOnly() { return is_for_guests_only_; } StoragePartition* RenderProcessHostImpl::GetStoragePartition() { return storage_partition_impl_; } static void AppendCompositorCommandLineFlags(base::CommandLine* command_line) { command_line->AppendSwitchASCII( switches::kNumRasterThreads, base::NumberToString(NumberOfRendererRasterThreads())); int msaa_sample_count = GpuRasterizationMSAASampleCount(); if (msaa_sample_count >= 0) { command_line->AppendSwitchASCII(switches::kGpuRasterizationMSAASampleCount, base::NumberToString(msaa_sample_count)); } if (IsZeroCopyUploadEnabled()) command_line->AppendSwitch(switches::kEnableZeroCopy); if (!IsPartialRasterEnabled()) command_line->AppendSwitch(switches::kDisablePartialRaster); if (IsGpuMemoryBufferCompositorResourcesEnabled()) { command_line->AppendSwitch( switches::kEnableGpuMemoryBufferCompositorResources); } if (IsMainFrameBeforeActivationEnabled()) command_line->AppendSwitch(cc::switches::kEnableMainFrameBeforeActivation); } void RenderProcessHostImpl::AppendRendererCommandLine( base::CommandLine* command_line) { // Pass the process type first, so it shows first in process listings. command_line->AppendSwitchASCII(switches::kProcessType, switches::kRendererProcess); #if defined(OS_WIN) command_line->AppendArg(switches::kPrefetchArgumentRenderer); #endif // defined(OS_WIN) // Now send any options from our own command line we want to propagate. const base::CommandLine& browser_command_line = *base::CommandLine::ForCurrentProcess(); PropagateBrowserCommandLineToRenderer(browser_command_line, command_line); // Pass on the browser locale. const std::string locale = GetContentClient()->browser()->GetApplicationLocale(); command_line->AppendSwitchASCII(switches::kLang, locale); // A non-empty RendererCmdPrefix implies that Zygote is disabled. if (!base::CommandLine::ForCurrentProcess() ->GetSwitchValueNative(switches::kRendererCmdPrefix) .empty()) { command_line->AppendSwitch(switches::kNoZygote); } GetContentClient()->browser()->AppendExtraCommandLineSwitches(command_line, GetID()); #if defined(OS_WIN) command_line->AppendSwitchASCII( switches::kDeviceScaleFactor, base::NumberToString(display::win::GetDPIScale())); #endif AppendCompositorCommandLineFlags(command_line); command_line->AppendSwitchASCII( service_manager::switches::kServiceRequestChannelToken, child_connection_->service_token()); command_line->AppendSwitchASCII(switches::kRendererClientId, std::to_string(GetID())); if (SiteIsolationPolicy::UseDedicatedProcessesForAllSites()) { // Disable V8 code mitigations if renderer processes are site-isolated. command_line->AppendSwitch(switches::kNoV8UntrustedCodeMitigations); } } void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer( const base::CommandLine& browser_cmd, base::CommandLine* renderer_cmd) { // Propagate the following switches to the renderer command line (along // with any associated values) if present in the browser command line. static const char* const kSwitchNames[] = { network::switches::kNoReferrers, network::switches::kExplicitlyAllowedPorts, service_manager::switches::kDisableInProcessStackTraces, service_manager::switches::kDisableSeccompFilterSandbox, service_manager::switches::kNoSandbox, #if defined(OS_MACOSX) // Allow this to be set when invoking the browser and relayed along. service_manager::switches::kEnableSandboxLogging, #endif switches::kAgcStartupMinVolume, switches::kAllowLoopbackInPeerConnection, switches::kAndroidFontsPath, switches::kAudioBufferSize, switches::kAutoplayPolicy, switches::kBlinkSettings, switches::kDefaultTileWidth, switches::kDefaultTileHeight, switches::kDisable2dCanvasImageChromium, switches::kDisableYUVImageDecoding, switches::kDisableAcceleratedVideoDecode, switches::kDisableBackgroundTimerThrottling, switches::kDisableBestEffortTasks, switches::kDisableBreakpad, switches::kDisablePreferCompositingToLCDText, switches::kDisableDatabases, switches::kDisableFileSystem, switches::kDisableFrameRateLimit, switches::kDisableGpuMemoryBufferVideoFrames, switches::kDisableImageAnimationResync, switches::kDisableLowResTiling, switches::kDisableHistogramCustomizer, switches::kDisableLCDText, switches::kDisableLogging, switches::kDisableMediaSuspend, switches::kDisableNotifications, switches::kDisableOopRasterization, switches::kDisableOriginTrialControlledBlinkFeatures, switches::kDisablePepper3DImageChromium, switches::kDisablePerfetto, switches::kDisablePermissionsAPI, switches::kDisablePresentationAPI, switches::kDisableRGBA4444Textures, switches::kDisableRTCSmoothnessAlgorithm, switches::kDisableSharedWorkers, switches::kDisableSkiaRuntimeOpts, switches::kDisableSpeechAPI, switches::kDisableThreadedCompositing, switches::kDisableThreadedScrolling, switches::kDisableTouchAdjustment, switches::kDisableTouchDragDrop, switches::kDisableV8IdleTasks, switches::kDisableWebGLImageChromium, switches::kDomAutomationController, switches::kEnableAccessibilityObjectModel, switches::kEnableAutomation, switches::kEnableExperimentalAccessibilityLanguageDetection, switches::kEnableExperimentalAccessibilityLabelsDebugging, switches::kEnableExperimentalWebPlatformFeatures, switches::kEnableGPUClientLogging, switches::kEnableGpuClientTracing, switches::kEnableGpuMemoryBufferVideoFrames, switches::kEnableGPUServiceLogging, switches::kEnableLowResTiling, switches::kEnableMediaSuspend, switches::kEnableLCDText, switches::kEnableLogging, switches::kEnableNetworkInformationDownlinkMax, switches::kEnableOopRasterization, switches::kEnablePluginPlaceholderTesting, switches::kEnablePreciseMemoryInfo, switches::kEnablePrintBrowser, switches::kEnablePreferCompositingToLCDText, switches::kEnableRGBA4444Textures, switches::kEnableSkiaBenchmarking, switches::kEnableSubresourceRedirect, switches::kEnableThreadedCompositing, switches::kEnableTouchDragDrop, switches::kEnableUnsafeWebGPU, switches::kEnableUseZoomForDSF, switches::kEnableViewport, switches::kEnableVtune, switches::kEnableWebBluetoothScanning, switches::kEnableWebGL2ComputeContext, switches::kEnableWebGLDraftExtensions, switches::kEnableWebGLImageChromium, switches::kEnableWebGLSwapChain, switches::kEnableWebVR, switches::kFileUrlPathAlias, switches::kForceDisplayColorProfile, switches::kForceDeviceScaleFactor, switches::kForceGpuMemAvailableMb, switches::kForceGpuRasterization, switches::kForceOverlayFullscreenVideo, switches::kForceVideoOverlays, switches::kFullMemoryCrashReport, switches::kIPCConnectionTimeout, switches::kJavaScriptFlags, switches::kLitePagesServerSubresourceHost, switches::kLogBestEffortTasks, switches::kLogFile, switches::kLoggingLevel, switches::kMaxActiveWebGLContexts, switches::kMaxUntiledLayerWidth, switches::kMaxUntiledLayerHeight, switches::kMSEAudioBufferSizeLimitMb, switches::kMSEVideoBufferSizeLimitMb, switches::kNetworkQuietTimeout, switches::kNoZygote, switches::kOverridePluginPowerSaverForTesting, switches::kPassiveListenersDefault, switches::kPpapiInProcess, switches::kProfilingAtStart, switches::kProfilingFile, switches::kProfilingFlush, switches::kRegisterPepperPlugins, switches::kRendererStartupDialog, switches::kReportVp9AsAnUnsupportedMimeType, switches::kShowLayoutShiftRegions, switches::kShowPaintRects, switches::kStatsCollectionController, switches::kSkiaFontCacheLimitMb, switches::kSkiaResourceCacheLimitMb, switches::kTestType, switches::kTouchEventFeatureDetection, switches::kTouchTextSelectionStrategy, switches::kTraceToConsole, switches::kUseFakeCodecForPeerConnection, switches::kUseFakeUIForMediaStream, // This flag needs to be propagated to the renderer process for // --in-process-webgl. switches::kUseGL, switches::kUseGpuInTests, switches::kUseMobileUserAgent, switches::kV, switches::kVideoThreads, switches::kVideoUnderflowThresholdMs, switches::kVModule, switches::kWebglAntialiasingMode, switches::kWebglMSAASampleCount, // Please keep these in alphabetical order. Compositor switches here should // also be added to chrome/browser/chromeos/login/chrome_restart_request.cc. cc::switches::kCCScrollAnimationDurationForTesting, cc::switches::kCheckDamageEarly, cc::switches::kDisableCheckerImaging, cc::switches::kDisableCompositedAntialiasing, cc::switches::kDisableThreadedAnimation, cc::switches::kEnableGpuBenchmarking, cc::switches::kShowCompositedLayerBorders, cc::switches::kShowFPSCounter, cc::switches::kShowLayerAnimationBounds, cc::switches::kShowPropertyChangedRects, cc::switches::kShowScreenSpaceRects, cc::switches::kShowSurfaceDamageRects, cc::switches::kSlowDownRasterScaleFactor, cc::switches::kBrowserControlsHideThreshold, cc::switches::kBrowserControlsShowThreshold, switches::kRunAllCompositorStagesBeforeDraw, switches::kUseVizHitTestSurfaceLayer, #if BUILDFLAG(ENABLE_PLUGINS) switches::kEnablePepperTesting, #endif #if BUILDFLAG(ENABLE_WEBRTC) switches::kDisableWebRtcHWDecoding, switches::kDisableWebRtcHWEncoding, switches::kEnableWebRtcSrtpAesGcm, switches::kEnableWebRtcSrtpEncryptedHeaders, switches::kEnableWebRtcStunOrigin, switches::kEnforceWebRtcIPPermissionCheck, switches::kWebRtcMaxCaptureFramerate, #endif switches::kEnableLowEndDeviceMode, switches::kDisableLowEndDeviceMode, switches::kDisallowNonExactResourceReuse, #if defined(OS_ANDROID) switches::kDisableMediaSessionAPI, switches::kEnableReachedCodeProfiler, switches::kRendererWaitForJavaDebugger, #endif #if defined(OS_WIN) service_manager::switches::kDisableWin32kLockDown, switches::kEnableWin7WebRtcHWH264Decoding, switches::kTrySupportedChannelLayouts, #endif #if defined(USE_OZONE) switches::kOzonePlatform, #endif #if defined(ENABLE_IPC_FUZZER) switches::kIpcDumpDirectory, switches::kIpcFuzzerTestcase, #endif }; renderer_cmd->CopySwitchesFrom(browser_cmd, kSwitchNames, base::size(kSwitchNames)); BrowserChildProcessHostImpl::CopyFeatureAndFieldTrialFlags(renderer_cmd); BrowserChildProcessHostImpl::CopyTraceStartupFlags(renderer_cmd); #if BUILDFLAG(ENABLE_WEBRTC) // Only run the Stun trials in the first renderer. if (!has_done_stun_trials && browser_cmd.HasSwitch(switches::kWebRtcStunProbeTrialParameter)) { has_done_stun_trials = true; renderer_cmd->AppendSwitchASCII( switches::kWebRtcStunProbeTrialParameter, browser_cmd.GetSwitchValueASCII( switches::kWebRtcStunProbeTrialParameter)); } #endif // Disable databases in incognito mode. if (GetBrowserContext()->IsOffTheRecord() && !browser_cmd.HasSwitch(switches::kDisableDatabases)) { renderer_cmd->AppendSwitch(switches::kDisableDatabases); } #if defined(OS_ANDROID) if (browser_cmd.HasSwitch(switches::kDisableGpuCompositing)) { renderer_cmd->AppendSwitch(switches::kDisableGpuCompositing); } #elif !defined(OS_CHROMEOS) // If gpu compositing is not being used, tell the renderer at startup. This // is inherently racey, as it may change while the renderer is being launched, // but the renderer will hear about the correct state eventually. This // optimizes the common case to avoid wasted work. if (ImageTransportFactory::GetInstance()->IsGpuCompositingDisabled()) renderer_cmd->AppendSwitch(switches::kDisableGpuCompositing); #endif // defined(OS_ANDROID) // Add kWaitForDebugger to let renderer process wait for a debugger. if (browser_cmd.HasSwitch(switches::kWaitForDebuggerChildren)) { // Look to pass-on the kWaitForDebugger flag. std::string value = browser_cmd.GetSwitchValueASCII(switches::kWaitForDebuggerChildren); if (value.empty() || value == switches::kRendererProcess) { renderer_cmd->AppendSwitch(switches::kWaitForDebugger); } } #if defined(OS_WIN) && !defined(OFFICIAL_BUILD) // Needed because we can't show the dialog from the sandbox. Don't pass // --no-sandbox in official builds because that would bypass the bad_flgs // prompt. if (renderer_cmd->HasSwitch(switches::kRendererStartupDialog) && !renderer_cmd->HasSwitch(service_manager::switches::kNoSandbox)) { renderer_cmd->AppendSwitch(service_manager::switches::kNoSandbox); } #endif CopyFeatureSwitch(browser_cmd, renderer_cmd, switches::kEnableBlinkFeatures); CopyFeatureSwitch(browser_cmd, renderer_cmd, switches::kDisableBlinkFeatures); } const base::Process& RenderProcessHostImpl::GetProcess() { if (run_renderer_in_process()) { // This is a sentinel object used for this process in single process mode. static const base::NoDestructor self( base::Process::Current()); return *self; } if (!child_process_launcher_.get() || child_process_launcher_->IsStarting()) { // This is a sentinel for "no process". static const base::NoDestructor null_process; return *null_process; } return child_process_launcher_->GetProcess(); } bool RenderProcessHostImpl::IsReady() { // The process launch result (that sets GetHandle()) and the channel // connection (that sets channel_connected_) can happen in either order. return GetProcess().Handle() && channel_connected_; } bool RenderProcessHostImpl::Shutdown(int exit_code) { if (run_renderer_in_process()) return false; // Single process mode never shuts down the renderer. if (!child_process_launcher_.get()) return false; shutdown_exit_code_ = exit_code; return child_process_launcher_->Terminate(exit_code); } bool RenderProcessHostImpl::FastShutdownIfPossible(size_t page_count, bool skip_unload_handlers) { // Do not shut down the process if there are active or pending views other // than the ones we're shutting down. if (page_count && page_count != (GetActiveViewCount() + pending_views_)) return false; if (run_renderer_in_process()) return false; // Single process mode never shuts down the renderer. if (!child_process_launcher_.get()) return false; // Render process hasn't started or is probably crashed. // Test if there's an unload listener. // NOTE: It's possible that an onunload listener may be installed // while we're shutting down, so there's a small race here. Given that // the window is small, it's unlikely that the web page has much // state that will be lost by not calling its unload handlers properly. if (!skip_unload_handlers && !SuddenTerminationAllowed()) return false; if (keep_alive_ref_count_ != 0) { if (keep_alive_start_time_.is_null()) keep_alive_start_time_ = base::TimeTicks::Now(); return false; } // Set this before ProcessDied() so observers can tell if the render process // died due to fast shutdown versus another cause. fast_shutdown_started_ = true; ProcessDied(false /* already_dead */, nullptr); return true; } bool RenderProcessHostImpl::Send(IPC::Message* msg) { TRACE_EVENT2("renderer_host", "RenderProcessHostImpl::Send", "class", IPC_MESSAGE_ID_CLASS(msg->type()), "line", IPC_MESSAGE_ID_LINE(msg->type())); std::unique_ptr message(msg); // |channel_| is only null after Cleanup(), at which point we don't care about // delivering any messages. if (!channel_) return false; #if !defined(OS_ANDROID) DCHECK(!message->is_sync()); #else if (message->is_sync()) { // If Init() hasn't been called yet since construction or the last // ProcessDied() we avoid blocking on sync IPC. if (!IsInitializedAndNotDead()) return false; // Likewise if we've done Init(), but process launch has not yet completed, // we avoid blocking on sync IPC. if (child_process_launcher_.get() && child_process_launcher_->IsStarting()) return false; } #endif // Allow tests to watch IPCs sent to the renderer. if (ipc_send_watcher_for_testing_) ipc_send_watcher_for_testing_.Run(*message); return channel_->Send(message.release()); } bool RenderProcessHostImpl::OnMessageReceived(const IPC::Message& msg) { // If we're about to be deleted, or have initiated the fast shutdown sequence, // we ignore incoming messages. if (deleting_soon_ || fast_shutdown_started_) return false; mark_child_process_activity_time(); if (msg.routing_id() == MSG_ROUTING_CONTROL) { // Dispatch control messages. IPC_BEGIN_MESSAGE_MAP(RenderProcessHostImpl, msg) IPC_MESSAGE_HANDLER(ViewHostMsg_UserMetricsRecordAction, OnUserMetricsRecordAction) IPC_MESSAGE_HANDLER(WidgetHostMsg_Close_ACK, OnCloseACK) // Adding single handlers for your service here is fine, but once your // service needs more than one handler, please extract them into a new // message filter and add that filter to CreateMessageFilters(). IPC_END_MESSAGE_MAP() return true; } // Dispatch incoming messages to the appropriate IPC::Listener. IPC::Listener* listener = listeners_.Lookup(msg.routing_id()); if (!listener) { if (msg.is_sync()) { // The listener has gone away, so we must respond or else the caller will // hang waiting for a reply. IPC::Message* reply = IPC::SyncMessage::GenerateReply(&msg); reply->set_reply_error(); Send(reply); } return true; } return listener->OnMessageReceived(msg); } void RenderProcessHostImpl::OnAssociatedInterfaceRequest( const std::string& interface_name, mojo::ScopedInterfaceEndpointHandle handle) { if (associated_interfaces_ && !associated_interfaces_->TryBindInterface(interface_name, &handle)) { LOG(ERROR) << "Request for unknown Channel-associated interface: " << interface_name; } } void RenderProcessHostImpl::OnChannelConnected(int32_t peer_pid) { channel_connected_ = true; #if defined(OS_MACOSX) ChildProcessTaskPortProvider::GetInstance()->OnChildProcessLaunched( peer_pid, child_process_.get()); #endif if (IsReady()) { DCHECK(!sent_render_process_ready_); sent_render_process_ready_ = true; // Send RenderProcessReady only if we already received the process handle. for (auto& observer : observers_) observer.RenderProcessReady(this); } #if BUILDFLAG(IPC_MESSAGE_LOG_ENABLED) child_process_->SetIPCLoggingEnabled(IPC::Logging::GetInstance()->Enabled()); #endif } void RenderProcessHostImpl::OnChannelError() { UMA_HISTOGRAM_BOOLEAN("BrowserRenderProcessHost.OnChannelError", true); ProcessDied(true /* already_dead */, nullptr); } void RenderProcessHostImpl::OnBadMessageReceived(const IPC::Message& message) { // Message de-serialization failed. We consider this a capital crime. Kill the // renderer if we have one. auto type = message.type(); LOG(ERROR) << "bad message " << type << " terminating renderer."; // The ReceivedBadMessage call below will trigger a DumpWithoutCrashing. Alias // enough information here so that we can determine what the bad message was. base::debug::Alias(&type); bad_message::ReceivedBadMessage(this, bad_message::RPH_DESERIALIZATION_FAILED); } BrowserContext* RenderProcessHostImpl::GetBrowserContext() { return browser_context_; } bool RenderProcessHostImpl::InSameStoragePartition( StoragePartition* partition) { return storage_partition_impl_ == partition; } int RenderProcessHostImpl::GetID() { return id_; } bool RenderProcessHostImpl::IsInitializedAndNotDead() { return is_initialized_ && !is_dead_; } void RenderProcessHostImpl::SetBlocked(bool blocked) { if (blocked == is_blocked_) return; is_blocked_ = blocked; blocked_state_changed_callback_list_.Notify(blocked); } bool RenderProcessHostImpl::IsBlocked() { return is_blocked_; } std::unique_ptr::Subscription> RenderProcessHostImpl::RegisterBlockStateChangedCallback( const base::RepeatingCallback& cb) { return blocked_state_changed_callback_list_.Add(cb); } void RenderProcessHostImpl::Cleanup() { DCHECK_CURRENTLY_ON(BrowserThread::UI); // Keep the one renderer thread around forever in single process mode. if (run_renderer_in_process()) return; // If within_process_died_observer_ is true, one of our observers performed an // action that caused us to die (e.g. http://crbug.com/339504). Therefore, // delay the destruction until all of the observer callbacks have been made, // and guarantee that the RenderProcessHostDestroyed observer callback is // always the last callback fired. if (within_process_died_observer_) { delayed_cleanup_needed_ = true; return; } delayed_cleanup_needed_ = false; // Records the time when the process starts kept alive by the ref count for // UMA. if (listeners_.IsEmpty() && keep_alive_ref_count_ > 0 && keep_alive_start_time_.is_null()) { keep_alive_start_time_ = base::TimeTicks::Now(); } // Until there are no other owners of this object, we can't delete ourselves. if (!listeners_.IsEmpty() || keep_alive_ref_count_ != 0) return; #if BUILDFLAG(ENABLE_WEBRTC) if (is_initialized_) { base::PostTaskWithTraits( FROM_HERE, {BrowserThread::IO}, base::BindOnce(&WebRtcLog::ClearLogMessageCallback, GetID())); } #endif if (!keep_alive_start_time_.is_null()) { UMA_HISTOGRAM_LONG_TIMES("BrowserRenderProcessHost.KeepAliveDuration", base::TimeTicks::Now() - keep_alive_start_time_); } // We cannot clean up twice; if this fails, there is an issue with our // control flow. DCHECK(!deleting_soon_); DCHECK_EQ(0, pending_views_); // If the process associated with this RenderProcessHost is still alive, // notify all observers that the process has exited cleanly, even though it // will be destroyed a bit later. Observers shouldn't rely on this process // anymore. if (IsInitializedAndNotDead()) { // Populates Android-only fields and closes the underlying base::Process. ChildProcessTerminationInfo info = child_process_launcher_->GetChildTerminationInfo( false /* already_dead */); info.status = base::TERMINATION_STATUS_NORMAL_TERMINATION; info.exit_code = 0; PopulateTerminationInfoRendererFields(&info); for (auto& observer : observers_) { observer.RenderProcessExited(this, info); } } for (auto& observer : observers_) observer.RenderProcessHostDestroyed(this); NotificationService::current()->Notify( NOTIFICATION_RENDERER_PROCESS_TERMINATED, Source(this), NotificationService::NoDetails()); if (connection_filter_id_ != ServiceManagerConnection::kInvalidConnectionFilterId) { ServiceManagerConnection* service_manager_connection = BrowserContext::GetServiceManagerConnectionFor(browser_context_); connection_filter_controller_->DisableFilter(); if (service_manager_connection) service_manager_connection->RemoveConnectionFilter(connection_filter_id_); connection_filter_id_ = ServiceManagerConnection::kInvalidConnectionFilterId; } #ifndef NDEBUG is_self_deleted_ = true; #endif base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this); deleting_soon_ = true; if (render_frame_message_filter_) { // RenderFrameMessageFilter is refcounted and can outlive the // ResourceContext. If the BrowserContext is shutting down, after // RenderProcessHostImpl cleanup a task will be posted to the IO thread // that destroys the ResourceContext. Therefore the ClearResourceContext // task must be posted now to ensure it gets ahead of the destruction of // the ResourceContext in the IOThread sequence. base::PostTaskWithTraits( FROM_HERE, {BrowserThread::IO}, base::BindOnce(&RenderFrameMessageFilter::ClearResourceContext, render_frame_message_filter_)); } // Destroy all mojo bindings and IPC channels that can cause calls to this // object, to avoid method invocations that trigger usages of profile. ResetIPC(); // Its important to remove the kSessionStorageHolder after the channel // has been reset to avoid deleting the underlying namespaces prior // to processing ipcs referring to them. DCHECK(!channel_); RemoveUserData(kSessionStorageHolderKey); // Remove ourself from the list of renderer processes so that we can't be // reused in between now and when the Delete task runs. UnregisterHost(GetID()); instance_weak_factory_ = std::make_unique>(this); } void RenderProcessHostImpl::PopulateTerminationInfoRendererFields( ChildProcessTerminationInfo* info) { info->renderer_has_visible_clients = VisibleClientCount() > 0; info->renderer_was_subframe = GetFrameDepth() > 0; } void RenderProcessHostImpl::AddPendingView() { const bool had_pending_views = pending_views_++; if (!had_pending_views) UpdateProcessPriority(); } void RenderProcessHostImpl::RemovePendingView() { DCHECK(pending_views_); --pending_views_; if (!pending_views_) UpdateProcessPriority(); } void RenderProcessHostImpl::AddPriorityClient(PriorityClient* priority_client) { DCHECK(!base::Contains(priority_clients_, priority_client)); priority_clients_.insert(priority_client); UpdateProcessPriorityInputs(); } void RenderProcessHostImpl::RemovePriorityClient( PriorityClient* priority_client) { DCHECK(base::Contains(priority_clients_, priority_client)); priority_clients_.erase(priority_client); UpdateProcessPriorityInputs(); } void RenderProcessHostImpl::SetSuddenTerminationAllowed(bool enabled) { sudden_termination_allowed_ = enabled; } bool RenderProcessHostImpl::SuddenTerminationAllowed() { return sudden_termination_allowed_; } base::TimeDelta RenderProcessHostImpl::GetChildProcessIdleTime() { return base::TimeTicks::Now() - child_process_activity_time_; } void RenderProcessHostImpl::FilterURL(bool empty_allowed, GURL* url) { FilterURL(this, empty_allowed, url); } #if BUILDFLAG(ENABLE_WEBRTC) void RenderProcessHostImpl::EnableAudioDebugRecordings( const base::FilePath& file_path) { DCHECK_CURRENTLY_ON(BrowserThread::UI); aec_dump_manager_.Start(file_path); } void RenderProcessHostImpl::DisableAudioDebugRecordings() { DCHECK_CURRENTLY_ON(BrowserThread::UI); aec_dump_manager_.Stop(); } RenderProcessHostImpl::WebRtcStopRtpDumpCallback RenderProcessHostImpl::StartRtpDump( bool incoming, bool outgoing, const WebRtcRtpPacketCallback& packet_callback) { p2p_socket_dispatcher_host_->StartRtpDump(incoming, outgoing, packet_callback); if (stop_rtp_dump_callback_.is_null()) { stop_rtp_dump_callback_ = base::Bind(&P2PSocketDispatcherHost::StopRtpDump, p2p_socket_dispatcher_host_->GetWeakPtr()); } return stop_rtp_dump_callback_; } void RenderProcessHostImpl::EnableWebRtcEventLogOutput(int lid, int output_period_ms) { Send(new PeerConnectionTracker_StartEventLog(lid, output_period_ms)); } void RenderProcessHostImpl::DisableWebRtcEventLogOutput(int lid) { Send(new PeerConnectionTracker_StopEventLog(lid)); } #endif // BUILDFLAG(ENABLE_WEBRTC) IPC::ChannelProxy* RenderProcessHostImpl::GetChannel() { return channel_.get(); } void RenderProcessHostImpl::AddFilter(BrowserMessageFilter* filter) { filter->RegisterAssociatedInterfaces(channel_.get()); channel_->AddFilter(filter->GetFilter()); } bool RenderProcessHostImpl::FastShutdownStarted() { return fast_shutdown_started_; } // static void RenderProcessHostImpl::RegisterHost(int host_id, RenderProcessHost* host) { g_all_hosts.Get().AddWithID(host, host_id); } // static void RenderProcessHostImpl::UnregisterHost(int host_id) { RenderProcessHost* host = g_all_hosts.Get().Lookup(host_id); if (!host) return; g_all_hosts.Get().Remove(host_id); // Look up the map of site to process for the given browser_context, // in case we need to remove this process from it. It will be registered // under any sites it rendered that use process-per-site mode. SiteProcessMap* map = GetSiteProcessMapForBrowserContext(host->GetBrowserContext()); map->RemoveProcess(host); } // static void RenderProcessHostImpl::FilterURL(RenderProcessHost* rph, bool empty_allowed, GURL* url) { ChildProcessSecurityPolicyImpl* policy = ChildProcessSecurityPolicyImpl::GetInstance(); if (empty_allowed && url->is_empty()) return; if (!url->is_valid()) { // Have to use about:blank for the denied case, instead of an empty GURL. // This is because the browser treats navigation to an empty GURL as a // navigation to the home page. This is often a privileged page // (chrome://newtab/) which is exactly what we don't want. *url = GURL(kBlockedURL); return; } if (!policy->CanRequestURL(rph->GetID(), *url)) { // If this renderer is not permitted to request this URL, we invalidate the // URL. This prevents us from storing the blocked URL and becoming confused // later. VLOG(1) << "Blocked URL " << url->spec(); *url = GURL(kBlockedURL); } } // static bool RenderProcessHostImpl::IsSuitableHost( RenderProcessHost* host, BrowserContext* browser_context, const IsolationContext& isolation_context, const GURL& site_url, const GURL& lock_url) { if (run_renderer_in_process()) { DCHECK_EQ(host->GetBrowserContext(), browser_context) << " Single-process mode does not support multiple browser contexts."; return true; } if (host->GetBrowserContext() != browser_context) return false; // Do not allow sharing of guest hosts. This is to prevent bugs where guest // and non-guest storage gets mixed. In the future, we might consider enabling // the sharing of guests, in this case this check should be removed and // InSameStoragePartition should handle the possible sharing. if (host->IsForGuestsOnly()) return false; // Check whether the given host and the intended site_url will be using the // same StoragePartition, since a RenderProcessHost can only support a single // StoragePartition. This is relevant for packaged apps. StoragePartition* dest_partition = BrowserContext::GetStoragePartitionForSite(browser_context, site_url); if (!host->InSameStoragePartition(dest_partition)) return false; // Check WebUI bindings and origin locks. Note that |lock_url| may differ // from |site_url| if an effective URL is used. auto* policy = ChildProcessSecurityPolicyImpl::GetInstance(); bool host_has_web_ui_bindings = policy->HasWebUIBindings(host->GetID()); GURL process_lock = policy->GetOriginLock(host->GetID()); if (host->HostHasNotBeenUsed()) { // If the host hasn't been used, it won't have the expected WebUI bindings // or origin locks just *yet* - skip the checks in this case. One example // where this case can happen is when the spare RenderProcessHost gets used. CHECK(!host_has_web_ui_bindings); CHECK(process_lock.is_empty()); } else { // WebUI checks. bool url_requires_web_ui_bindings = WebUIControllerFactoryRegistry::GetInstance()->UseWebUIBindingsForURL( browser_context, site_url); if (host_has_web_ui_bindings != url_requires_web_ui_bindings) return false; if (!process_lock.is_empty()) { // If this process is locked to a site, it cannot be reused for a // destination that doesn't require a dedicated process, even for the // same site. This can happen with dynamic isolated origins (see // https://crbug.com/950453). if (!SiteInstanceImpl::ShouldLockToOrigin(isolation_context, site_url)) return false; // If the destination requires a different process lock, this process // cannot be used. if (process_lock != lock_url) return false; } else { if (!host->IsUnused() && SiteInstanceImpl::ShouldLockToOrigin(isolation_context, site_url)) { // If this process has been used to host any other content, it cannot // be reused if the destination site requires a dedicated process and // should use a process locked to just that site. return false; } } } if (!GetContentClient()->browser()->IsSuitableHost(host, site_url)) return false; // If this site_url is going to require a dedicated process, then check // whether this process has a pending navigation to a URL for which // SiteInstance does not assign site URLs. If this is the case, it is not // safe to reuse this process for a navigation which itself assigns site URLs, // since in that case the latter navigation could lock this process before // the commit for the siteless URL arrives, resulting in a renderer kill. // See https://crbug.com/970046. if (SiteInstanceImpl::ShouldAssignSiteForURL(site_url) && SiteInstanceImpl::DoesSiteRequireDedicatedProcess(isolation_context, site_url)) { SiteProcessCountTracker* pending_tracker = static_cast( browser_context->GetUserData(kPendingSiteProcessCountTrackerKey)); bool has_disqualifying_pending_navigation = pending_tracker && pending_tracker->ContainsNonReusableSiteForHost(host); UMA_HISTOGRAM_BOOLEAN( "SiteIsolation.PendingSitelessNavigationDisallowsProcessReuse", has_disqualifying_pending_navigation); if (has_disqualifying_pending_navigation) return false; } return true; } // static void RenderProcessHost::WarmupSpareRenderProcessHost( content::BrowserContext* browser_context) { g_spare_render_process_host_manager.Get().WarmupSpareRenderProcessHost( browser_context); } // static bool RenderProcessHost::run_renderer_in_process() { return g_run_renderer_in_process; } // static void RenderProcessHost::SetRunRendererInProcess(bool value) { g_run_renderer_in_process = value; base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); if (value) { if (!command_line->HasSwitch(switches::kLang)) { // Modify the current process' command line to include the browser locale, // as the renderer expects this flag to be set. const std::string locale = GetContentClient()->browser()->GetApplicationLocale(); command_line->AppendSwitchASCII(switches::kLang, locale); } // TODO(piman): we should really send configuration through bools rather // than by parsing strings, i.e. sending an IPC rather than command line // args. crbug.com/314909 AppendCompositorCommandLineFlags(command_line); } } // static RenderProcessHost::iterator RenderProcessHost::AllHostsIterator() { DCHECK_CURRENTLY_ON(BrowserThread::UI); return iterator(g_all_hosts.Pointer()); } // static RenderProcessHost* RenderProcessHost::FromID(int render_process_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); return g_all_hosts.Get().Lookup(render_process_id); } // static RenderProcessHost* RenderProcessHost::FromRendererInstanceId( const base::Token& instance_id) { for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator()); !i.IsAtEnd(); i.Advance()) { RenderProcessHost* process = i.GetCurrentValue(); if (process->GetChildIdentity().instance_id() == instance_id) return process; } return nullptr; } // static bool RenderProcessHost::ShouldTryToUseExistingProcessHost( BrowserContext* browser_context, const GURL& url) { if (run_renderer_in_process()) return true; // NOTE: Sometimes it's necessary to create more render processes than // GetMaxRendererProcessCount(), for instance when we want to create // a renderer process for a browser context that has no existing // renderers. This is OK in moderation, since the // GetMaxRendererProcessCount() is conservative. if (g_all_hosts.Get().size() >= GetMaxRendererProcessCount()) return true; return GetContentClient()->browser()->ShouldTryToUseExistingProcessHost( browser_context, url); } // static RenderProcessHost* RenderProcessHostImpl::GetExistingProcessHost( SiteInstanceImpl* site_instance) { // First figure out which existing renderers we can use. std::vector suitable_renderers; suitable_renderers.reserve(g_all_hosts.Get().size()); iterator iter(AllHostsIterator()); while (!iter.IsAtEnd()) { if (iter.GetCurrentValue()->MayReuseHost() && RenderProcessHostImpl::IsSuitableHost( iter.GetCurrentValue(), site_instance->GetBrowserContext(), site_instance->GetIsolationContext(), site_instance->GetSiteURL(), site_instance->lock_url())) { // The spare is always considered before process reuse. DCHECK_NE(iter.GetCurrentValue(), g_spare_render_process_host_manager.Get() .spare_render_process_host()); suitable_renderers.push_back(iter.GetCurrentValue()); } iter.Advance(); } // Now pick a random suitable renderer, if we have any. if (!suitable_renderers.empty()) { int suitable_count = static_cast(suitable_renderers.size()); int random_index = base::RandInt(0, suitable_count - 1); return suitable_renderers[random_index]; } return nullptr; } // static bool RenderProcessHost::ShouldUseProcessPerSite(BrowserContext* browser_context, const GURL& url) { // Returns true if we should use the process-per-site model. This will be // the case if the --process-per-site switch is specified, or in // process-per-site-instance for particular sites (e.g., WebUI). // Note that --single-process is handled in ShouldTryToUseExistingProcessHost. const base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess(); if (command_line.HasSwitch(switches::kProcessPerSite)) return true; // Error pages should use process-per-site model, as it is useful to // consolidate them to minimize resource usage and there is no security // drawback to combining them all in the same process. if (url.SchemeIs(kChromeErrorScheme)) return true; // Otherwise let the content client decide, defaulting to false. return GetContentClient()->browser()->ShouldUseProcessPerSite(browser_context, url); } // static RenderProcessHost* RenderProcessHostImpl::GetSoleProcessHostForURL( BrowserContext* browser_context, const IsolationContext& isolation_context, const GURL& url) { GURL site_url = SiteInstanceImpl::GetSiteForURL(isolation_context, url); GURL lock_url = SiteInstanceImpl::DetermineProcessLockURL(isolation_context, url); return GetSoleProcessHostForSite(browser_context, isolation_context, site_url, lock_url); } // static RenderProcessHost* RenderProcessHostImpl::GetSoleProcessHostForSite( BrowserContext* browser_context, const IsolationContext& isolation_context, const GURL& site_url, const GURL& lock_url) { // Look up the map of site to process for the given browser_context. SiteProcessMap* map = GetSiteProcessMapForBrowserContext(browser_context); // See if we have an existing process with appropriate bindings for this site. // If not, the caller should create a new process and register it. Note that // IsSuitableHost expects a site URL rather than the full |url|. RenderProcessHost* host = map->FindProcess(site_url.possibly_invalid_spec()); if (host && (!host->MayReuseHost() || !IsSuitableHost(host, browser_context, isolation_context, site_url, lock_url))) { // The registered process does not have an appropriate set of bindings for // the url. Remove it from the map so we can register a better one. RecordAction( base::UserMetricsAction("BindingsMismatch_GetProcessHostPerSite")); map->RemoveProcess(host); host = nullptr; } return host; } void RenderProcessHostImpl::RegisterSoleProcessHostForSite( BrowserContext* browser_context, RenderProcessHost* process, SiteInstanceImpl* site_instance) { // Look up the map of site to process for the given browser_context. SiteProcessMap* map = GetSiteProcessMapForBrowserContext(browser_context); // Only register valid, non-empty sites. Empty or invalid sites will not // use process-per-site mode. We cannot check whether the process has // appropriate bindings here, because the bindings have not yet been granted. std::string site = site_instance->GetSiteURL().possibly_invalid_spec(); if (!site.empty()) map->RegisterProcess(site, process); } // static RenderProcessHost* RenderProcessHostImpl::GetProcessHostForSiteInstance( SiteInstanceImpl* site_instance) { const GURL site_url = site_instance->GetSiteURL(); SiteInstanceImpl::ProcessReusePolicy process_reuse_policy = site_instance->process_reuse_policy(); bool is_for_guests_only = site_url.SchemeIs(kGuestScheme); RenderProcessHost* render_process_host = nullptr; bool is_unmatched_service_worker = site_instance->is_for_service_worker(); BrowserContext* browser_context = site_instance->GetBrowserContext(); // First, attempt to reuse an existing RenderProcessHost if necessary. switch (process_reuse_policy) { case SiteInstanceImpl::ProcessReusePolicy::PROCESS_PER_SITE: render_process_host = GetSoleProcessHostForSite( browser_context, site_instance->GetIsolationContext(), site_url, site_instance->lock_url()); break; case SiteInstanceImpl::ProcessReusePolicy::REUSE_PENDING_OR_COMMITTED_SITE: render_process_host = FindReusableProcessHostForSiteInstance(site_instance); UMA_HISTOGRAM_BOOLEAN( "SiteIsolation.ReusePendingOrCommittedSite.CouldReuse", render_process_host != nullptr); if (render_process_host) is_unmatched_service_worker = false; break; default: break; } // If not, attempt to reuse an existing process with an unmatched service // worker for this site. Exclude cases where the policy is DEFAULT and the // site instance is for a service worker. We use DEFAULT when we have failed // to start the service worker before and want to use a new process. if (!render_process_host && !(process_reuse_policy == SiteInstanceImpl::ProcessReusePolicy::DEFAULT && site_instance->is_for_service_worker())) { render_process_host = UnmatchedServiceWorkerProcessTracker::MatchWithSite(site_instance); } // If a process hasn't been selected yet, check whether a default process // has been assigned for this browsing instance and use that. This is used // to group all SiteInstance that don't require a dedicated process into a // single process. This will only be set if // kProcessSharingWithStrictSiteInstances is enabled. if (!render_process_host) { render_process_host = site_instance->GetDefaultProcessIfUsable(); DCHECK(!render_process_host || base::FeatureList::IsEnabled( features::kProcessSharingWithStrictSiteInstances)); } // See if the spare RenderProcessHost can be used. SpareRenderProcessHostManager& spare_process_manager = g_spare_render_process_host_manager.Get(); bool spare_was_taken = false; if (!render_process_host) { render_process_host = spare_process_manager.MaybeTakeSpareRenderProcessHost( browser_context, site_instance, is_for_guests_only); spare_was_taken = (render_process_host != nullptr); } // If not (or if none found), see if we should reuse an existing process. if (!render_process_host && ShouldTryToUseExistingProcessHost(browser_context, site_url)) { render_process_host = GetExistingProcessHost(site_instance); } // If we found a process to reuse, sanity check that it is suitable for // hosting |site_url|. For example, if |site_url| requires a dedicated // process, we should never pick a process used by, or locked to, a different // site. if (render_process_host && !RenderProcessHostImpl::IsSuitableHost( render_process_host, browser_context, site_instance->GetIsolationContext(), site_url, site_instance->lock_url())) { ChildProcessSecurityPolicyImpl* policy = ChildProcessSecurityPolicyImpl::GetInstance(); base::debug::SetCrashKeyString(bad_message::GetRequestedSiteURLKey(), site_url.spec()); base::debug::SetCrashKeyString( bad_message::GetKilledProcessOriginLockKey(), policy->GetOriginLock(render_process_host->GetID()).spec()); CHECK(false) << "Unsuitable process reused for site " << site_url; } // Otherwise, create a new RenderProcessHost. if (!render_process_host) { // Pass a null StoragePartition. Tests with TestBrowserContext using a // RenderProcessHostFactory may not instantiate a StoragePartition, and // creating one here with GetStoragePartition() can run into cross-thread // issues as TestBrowserContext initialization is done on the main thread. render_process_host = CreateRenderProcessHost( browser_context, nullptr, site_instance, is_for_guests_only); } // It is important to call PrepareForFutureRequests *after* potentially // creating a process a few statements earlier - doing this avoids violating // the process limit. // // We should not warm-up another spare if the spare was not taken, because in // this case we might have created a new process - we want to avoid spawning // two processes at the same time. In this case the call to // PrepareForFutureRequests will be postponed until later (e.g. until the // navigation commits or a cross-site redirect happens). if (spare_was_taken) spare_process_manager.PrepareForFutureRequests(browser_context); if (is_unmatched_service_worker) { UnmatchedServiceWorkerProcessTracker::Register(render_process_host, site_instance); } // Make sure the chosen process is in the correct StoragePartition for the // SiteInstance. CHECK(render_process_host->InSameStoragePartition( BrowserContext::GetStoragePartition(browser_context, site_instance, false /* can_create */))); return render_process_host; } void RenderProcessHostImpl::CreateSharedRendererHistogramAllocator() { // Create a persistent memory segment for renderer histograms only if // they're active in the browser. if (!base::GlobalHistogramAllocator::Get()) { if (is_initialized_) { HistogramController::GetInstance()->SetHistogramMemory( this, base::WritableSharedMemoryRegion()); } return; } // Get handle to the renderer process. Stop if there is none. base::ProcessHandle destination = GetProcess().Handle(); if (destination == base::kNullProcessHandle) return; // Create persistent/shared memory and allow histograms to be stored in // it. Memory that is not actually used won't be physically mapped by the // system. RendererMetrics usage, as reported in UMA, peaked around 0.7MiB // as of 2016-12-20. base::WritableSharedMemoryRegion shm_region = base::WritableSharedMemoryRegion::Create(2 << 20); // 2 MiB base::WritableSharedMemoryMapping shm_mapping = shm_region.Map(); if (!shm_region.IsValid() || !shm_mapping.IsValid()) return; // If a renderer crashes before completing startup and gets restarted, this // method will get called a second time meaning that a metrics-allocator // already exists. We have to recreate it here because previously used // |shm_region| is gone. metrics_allocator_ = std::make_unique( std::move(shm_mapping), GetID(), "RendererMetrics"); HistogramController::GetInstance()->SetHistogramMemory( this, std::move(shm_region)); } void RenderProcessHostImpl::ProcessDied( bool already_dead, ChildProcessTerminationInfo* known_info) { // Our child process has died. If we didn't expect it, it's a crash. // In any case, we need to let everyone know it's gone. // The OnChannelError notification can fire multiple times due to nested sync // calls to a renderer. If we don't have a valid channel here it means we // already handled the error. // It should not be possible for us to be called re-entrantly. DCHECK(!within_process_died_observer_); // It should not be possible for a process death notification to come in while // we are dying. DCHECK(!deleting_soon_); // child_process_launcher_ can be NULL in single process mode or if fast // termination happened. ChildProcessTerminationInfo info; info.exit_code = 0; if (known_info) { info = *known_info; } else if (child_process_launcher_.get()) { info = child_process_launcher_->GetChildTerminationInfo(already_dead); if (already_dead && info.status == base::TERMINATION_STATUS_STILL_RUNNING) { // May be in case of IPC error, if it takes long time for renderer // to exit. Child process will be killed in any case during // child_process_launcher_.reset(). Make sure we will not broadcast // RenderProcessExited with status TERMINATION_STATUS_STILL_RUNNING, since // this will break WebContentsImpl logic. info.status = base::TERMINATION_STATUS_PROCESS_CRASHED; // TODO(siggi): Remove this once https://crbug.com/806661 is resolved. #if defined(OS_WIN) if (info.exit_code == WAIT_TIMEOUT && g_analyze_hung_renderer) g_analyze_hung_renderer(child_process_launcher_->GetProcess()); #endif } } PopulateTerminationInfoRendererFields(&info); child_process_launcher_.reset(); is_dead_ = true; // Make sure no IPCs or mojo calls from the old process get dispatched after // it has died. ResetIPC(); UpdateProcessPriority(); // RenderProcessExited relies on the exit code set during shutdown. if (shutdown_exit_code_ != -1) info.exit_code = shutdown_exit_code_; within_process_died_observer_ = true; for (auto& observer : observers_) observer.RenderProcessExited(this, info); NotificationService::current()->Notify( NOTIFICATION_RENDERER_PROCESS_CLOSED, Source(this), Details(&info)); within_process_died_observer_ = false; RemoveUserData(kSessionStorageHolderKey); // Initialize a new ChannelProxy in case this host is re-used for a new // process. This ensures that new messages can be sent on the host ASAP (even // before Init()) and they'll eventually reach the new process. // // Note that this may have already been called by one of the above observers EnableSendQueue(); // It's possible that one of the calls out to the observers might have caused // this object to be no longer needed. if (delayed_cleanup_needed_) Cleanup(); compositing_mode_reporter_.reset(); HistogramController::GetInstance()->NotifyChildDied(this); // This object is not deleted at this point and might be reused later. // TODO(darin): clean this up } void RenderProcessHostImpl::ResetIPC() { if (renderer_host_binding_.is_bound()) renderer_host_binding_.Unbind(); if (route_provider_binding_.is_bound()) route_provider_binding_.Close(); associated_interface_provider_bindings_.CloseAllBindings(); associated_interfaces_.reset(); // Destroy all embedded CompositorFrameSinks. embedded_frame_sink_provider_.reset(); for (auto binding_id : storage_partition_binding_ids_) { storage_partition_impl_->Unbind(binding_id); } // If RenderProcessHostImpl is reused, the next renderer will send a new // request for FrameSinkProvider so make sure frame_sink_provider_ is ready // for that. frame_sink_provider_.Unbind(); // It's important not to wait for the DeleteTask to delete the channel // proxy. Kill it off now. That way, in case the profile is going away, the // rest of the objects attached to this RenderProcessHost start going // away first, since deleting the channel proxy will post a // OnChannelClosed() to IPC::ChannelProxy::Context on the IO thread. ResetChannelProxy(); // The PermissionServiceContext holds PermissionSubscriptions originating from // service workers. These subscriptions observe the PermissionControllerImpl // that is owned by the Profile corresponding to |this|. At this point, IPC // are unbound so no new subscriptions can be made. Existing subscriptions // need to be released here, as the Profile, and with it, the // PermissionControllerImpl, can be destroyed anytime after // RenderProcessHostImpl::Cleanup() returns. permission_service_context_.reset(); } size_t RenderProcessHost::GetActiveViewCount() { size_t num_active_views = 0; std::unique_ptr widgets( RenderWidgetHost::GetRenderWidgetHosts()); while (RenderWidgetHost* widget = widgets->GetNextHost()) { // Count only RenderWidgetHosts in this process. if (widget->GetProcess()->GetID() == GetID()) num_active_views++; } return num_active_views; } void RenderProcessHost::PostTaskWhenProcessIsReady(base::OnceClosure task) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(!task.is_null()); new RenderProcessHostIsReadyObserver(this, std::move(task)); } // static void RenderProcessHost::SetHungRendererAnalysisFunction( AnalyzeHungRendererFunction analyze_hung_renderer) { g_analyze_hung_renderer = analyze_hung_renderer; } void RenderProcessHostImpl::ReleaseOnCloseACK( RenderProcessHost* host, const SessionStorageNamespaceMap& sessions, int widget_route_id) { DCHECK(host); if (sessions.empty()) return; SessionStorageHolder* holder = static_cast( host->GetUserData(kSessionStorageHolderKey)); if (!holder) { holder = new SessionStorageHolder(); host->SetUserData(kSessionStorageHolderKey, base::WrapUnique(holder)); } holder->Hold(sessions, widget_route_id); } void RenderProcessHostImpl::SuddenTerminationChanged(bool enabled) { SetSuddenTerminationAllowed(enabled); } void RenderProcessHostImpl::UpdateProcessPriorityInputs() { int32_t new_visible_widgets_count = 0; unsigned int new_frame_depth = kMaxFrameDepthForPriority; bool new_intersects_viewport = false; #if defined(OS_ANDROID) ChildProcessImportance new_effective_importance = ChildProcessImportance::NORMAL; #endif for (auto* client : priority_clients_) { Priority priority = client->GetPriority(); // Compute the lowest depth of widgets with highest visibility priority. // See comment on |frame_depth_| for more details. if (priority.is_hidden) { if (!new_visible_widgets_count) { new_frame_depth = std::min(new_frame_depth, priority.frame_depth); new_intersects_viewport = new_intersects_viewport || priority.intersects_viewport; } } else { if (new_visible_widgets_count) { new_frame_depth = std::min(new_frame_depth, priority.frame_depth); new_intersects_viewport = new_intersects_viewport || priority.intersects_viewport; } else { new_frame_depth = priority.frame_depth; new_intersects_viewport = priority.intersects_viewport; } new_visible_widgets_count++; } #if defined(OS_ANDROID) new_effective_importance = std::max(new_effective_importance, priority.importance); #endif } bool inputs_changed = new_visible_widgets_count != visible_clients_ || frame_depth_ != new_frame_depth || intersects_viewport_ != new_intersects_viewport; visible_clients_ = new_visible_widgets_count; frame_depth_ = new_frame_depth; intersects_viewport_ = new_intersects_viewport; #if defined(OS_ANDROID) inputs_changed = inputs_changed || new_effective_importance != effective_importance_; effective_importance_ = new_effective_importance; #endif if (inputs_changed) UpdateProcessPriority(); } void RenderProcessHostImpl::UpdateProcessPriority() { if (!run_renderer_in_process() && (!child_process_launcher_.get() || child_process_launcher_->IsStarting())) { // This path can be hit early (no-op) or on ProcessDied(). Reset |priority_| // to defaults in case this RenderProcessHostImpl is re-used. priority_.visible = !blink::kLaunchingProcessIsBackgrounded; priority_.boost_for_pending_views = true; return; } if (!has_recorded_media_stream_frame_depth_metric_ && !visible_clients_ && media_stream_count_) { UMA_HISTOGRAM_EXACT_LINEAR( "BrowserRenderProcessHost.InvisibleMediaStreamFrameDepth", frame_depth_, 50); has_recorded_media_stream_frame_depth_metric_ = true; } const ChildProcessLauncherPriority priority( visible_clients_ > 0 || base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableRendererBackgrounding), media_stream_count_ > 0, foreground_service_worker_count_ > 0, frame_depth_, intersects_viewport_, !!pending_views_ /* boost_for_pending_views */ #if defined(OS_ANDROID) , GetEffectiveImportance() #endif ); const bool background_state_changed = priority_.is_background() != priority.is_background(); const bool visibility_state_changed = priority_.visible != priority.visible; if (priority_ == priority) return; TRACE_EVENT2("renderer_host", "RenderProcessHostImpl::UpdateProcessPriority", "should_background", priority.is_background(), "has_pending_views", priority.boost_for_pending_views); priority_ = priority; bool allow_background_change = true; #if defined(OS_WIN) // The cbstext.dll loads as a global GetMessage hook in the browser process // and intercepts/unintercepts the kernel32 API SetPriorityClass in a // background thread. If the UI thread invokes this API just when it is // intercepted the stack is messed up on return from the interceptor // which causes random crashes in the browser process. Our hack for now // is to not invoke the SetPriorityClass API if the dll is loaded. if (GetModuleHandle(L"cbstext.dll")) allow_background_change = false; #endif // OS_WIN // Control the background state from the browser process, otherwise the task // telling the renderer to "unbackground" itself may be preempted by other // tasks executing at lowered priority ahead of it or simply by not being // swiftly scheduled by the OS per the low process priority // (http://crbug.com/398103). if (!run_renderer_in_process() && allow_background_change) { DCHECK(child_process_launcher_.get()); DCHECK(!child_process_launcher_->IsStarting()); // Make sure to keep the pid in the trace so we can tell which process is // being modified. TRACE_EVENT2( "renderer_host", "RenderProcessHostImpl::UpdateProcessPriority.SetProcessPriority", "pid", child_process_launcher_->GetProcess().Pid(), "priority_is_background", priority.is_background()); child_process_launcher_->SetProcessPriority(priority_); } // Notify the child process of the change in state. if ((background_state_changed && allow_background_change) || visibility_state_changed) { SendProcessStateToRenderer(); } } void RenderProcessHostImpl::SendProcessStateToRenderer() { mojom::RenderProcessState process_state; if (priority_.is_background()) process_state = mojom::RenderProcessState::kBackgrounded; else if (priority_.visible) process_state = mojom::RenderProcessState::kVisible; else process_state = mojom::RenderProcessState::kHidden; GetRendererInterface()->SetProcessState(process_state); } void RenderProcessHostImpl::OnProcessLaunched() { // No point doing anything, since this object will be destructed soon. We // especially don't want to send the RENDERER_PROCESS_CREATED notification, // since some clients might expect a RENDERER_PROCESS_TERMINATED afterwards to // properly cleanup. if (deleting_soon_) return; if (child_process_launcher_) { DCHECK(child_process_launcher_->GetProcess().IsValid()); // TODO(https://crbug.com/875933): This should be based on // |priority_.is_background()|, see similar check below. DCHECK_EQ(blink::kLaunchingProcessIsBackgrounded, !priority_.visible); // Unpause the channel now that the process is launched. We don't flush it // yet to ensure that any initialization messages sent here (e.g., things // done in response to NOTIFICATION_RENDER_PROCESS_CREATED; see below) // preempt already queued messages. channel_->Unpause(false /* flush */); if (child_connection_) { child_connection_->SetProcess( child_process_launcher_->GetProcess().Duplicate()); } // Not all platforms launch processes in the same backgrounded state. Make // sure |priority_.visible| reflects this platform's initial process // state. #if defined(OS_MACOSX) priority_.visible = !child_process_launcher_->GetProcess().IsProcessBackgrounded( ChildProcessTaskPortProvider::GetInstance()); #elif defined(OS_ANDROID) // Android child process priority works differently and cannot be queried // directly from base::Process. // TODO(https://crbug.com/875933): Fix initial priority on Android to // reflect |priority_.is_background()|. DCHECK_EQ(blink::kLaunchingProcessIsBackgrounded, !priority_.visible); #else priority_.visible = !child_process_launcher_->GetProcess().IsProcessBackgrounded(); #endif // defined(OS_MACOSX) // Only update the priority on startup if boosting is enabled (to avoid // reintroducing https://crbug.com/560446#c13 while pending views only // experimentally result in a boost). if (priority_.boost_for_pending_views) UpdateProcessPriority(); // Share histograms between the renderer and this process. CreateSharedRendererHistogramAllocator(); } // Pass bits of global renderer state to the renderer. GetRendererInterface()->SetUserAgent( GetContentClient()->browser()->GetUserAgent()); GetRendererInterface()->SetUserAgentMetadata( GetContentClient()->browser()->GetUserAgentMetadata()); NotifyRendererIfLockedToSite(); if (SiteIsolationPolicy::UseDedicatedProcessesForAllSites() && base::FeatureList::IsEnabled(features::kV8LowMemoryModeForSubframes)) { GetRendererInterface()->EnableV8LowMemoryMode(); } // NOTE: This needs to be before flushing queued messages, because // ExtensionService uses this notification to initialize the renderer process // with state that must be there before any JavaScript executes. // // The queued messages contain such things as "navigate". If this notification // was after, we can end up executing JavaScript before the initialization // happens. NotificationService::current()->Notify(NOTIFICATION_RENDERER_PROCESS_CREATED, Source(this), NotificationService::NoDetails()); if (child_process_launcher_) channel_->Flush(); if (IsReady()) { DCHECK(!sent_render_process_ready_); sent_render_process_ready_ = true; // Send RenderProcessReady only if the channel is already connected. for (auto& observer : observers_) observer.RenderProcessReady(this); } #if BUILDFLAG(ENABLE_WEBRTC) aec_dump_manager_.set_pid(GetProcess().Pid()); aec_dump_manager_.AutoStart(); #endif } void RenderProcessHostImpl::OnProcessLaunchFailed(int error_code) { // If this object will be destructed soon, then observers have already been // sent a RenderProcessHostDestroyed notification, and we must observe our // contract that says that will be the last call. if (deleting_soon_) return; ChildProcessTerminationInfo info; info.status = base::TERMINATION_STATUS_LAUNCH_FAILED; info.exit_code = error_code; PopulateTerminationInfoRendererFields(&info); ProcessDied(true, &info); } void RenderProcessHostImpl::OnUserMetricsRecordAction( const std::string& action) { base::RecordComputedAction(action); } void RenderProcessHostImpl::OnCloseACK(int closed_widget_route_id) { SessionStorageHolder* holder = static_cast(GetUserData(kSessionStorageHolderKey)); if (!holder) return; holder->Release(closed_widget_route_id); } // static RenderProcessHost* RenderProcessHostImpl::FindReusableProcessHostForSiteInstance( SiteInstanceImpl* site_instance) { BrowserContext* browser_context = site_instance->GetBrowserContext(); GURL site_url(site_instance->GetSiteURL()); if (!ShouldFindReusableProcessHostForSite(browser_context, site_url)) return nullptr; std::set eligible_foreground_hosts; std::set eligible_background_hosts; // First, add the RenderProcessHosts expecting a navigation to |site_url| to // the list of eligible RenderProcessHosts. SiteProcessCountTracker* pending_tracker = static_cast( browser_context->GetUserData(kPendingSiteProcessCountTrackerKey)); if (pending_tracker) { pending_tracker->FindRenderProcessesForSiteInstance( site_instance, &eligible_foreground_hosts, &eligible_background_hosts); } if (eligible_foreground_hosts.empty()) { // If needed, add the RenderProcessHosts hosting a frame for |site_url| to // the list of eligible RenderProcessHosts. SiteProcessCountTracker* committed_tracker = static_cast( browser_context->GetUserData(kCommittedSiteProcessCountTrackerKey)); if (committed_tracker) { committed_tracker->FindRenderProcessesForSiteInstance( site_instance, &eligible_foreground_hosts, &eligible_background_hosts); } } if (!eligible_foreground_hosts.empty()) { int index = base::RandInt(0, eligible_foreground_hosts.size() - 1); auto iterator = eligible_foreground_hosts.begin(); for (int i = 0; i < index; ++i) ++iterator; return *iterator; } if (!eligible_background_hosts.empty()) { int index = base::RandInt(0, eligible_background_hosts.size() - 1); auto iterator = eligible_background_hosts.begin(); for (int i = 0; i < index; ++i) ++iterator; return *iterator; } return nullptr; } #if BUILDFLAG(ENABLE_WEBRTC) void RenderProcessHostImpl::CreateMediaStreamTrackMetricsHost( blink::mojom::MediaStreamTrackMetricsHostRequest request) { DCHECK_CURRENTLY_ON(BrowserThread::IO); if (!media_stream_track_metrics_host_) media_stream_track_metrics_host_.reset(new MediaStreamTrackMetricsHost()); media_stream_track_metrics_host_->BindRequest(std::move(request)); } #endif // BUILDFLAG(ENABLE_WEBRTC) #if BUILDFLAG(ENABLE_MDNS) void RenderProcessHostImpl::CreateMdnsResponder( network::mojom::MdnsResponderRequest request) { GetStoragePartition()->GetNetworkContext()->CreateMdnsResponder( std::move(request)); } #endif // BUILDFLAG(ENABLE_MDNS) // static void RenderProcessHostImpl::OnMojoError(int render_process_id, const std::string& error) { LOG(ERROR) << "Terminating render process for bad Mojo message: " << error; // The ReceivedBadMessage call below will trigger a DumpWithoutCrashing. // Capture the error message in a crash key value. base::debug::ScopedCrashKeyString error_key_value( bad_message::GetMojoErrorCrashKey(), error); bad_message::ReceivedBadMessage(render_process_id, bad_message::RPH_MOJO_PROCESS_ERROR); } void RenderProcessHostImpl::GetBrowserHistogram( const std::string& name, BrowserHistogramCallback callback) { // Security: Only allow access to browser histograms when running in the // context of a test. bool using_stats_collection_controller = base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kStatsCollectionController); if (!using_stats_collection_controller) { std::move(callback).Run(std::string()); return; } base::HistogramBase* histogram = base::StatisticsRecorder::FindHistogram(name); std::string histogram_json; if (!histogram) { histogram_json = "{}"; } else { histogram->WriteJSON(&histogram_json, base::JSON_VERBOSITY_LEVEL_FULL); } std::move(callback).Run(histogram_json); } void RenderProcessHostImpl::SetBrowserPluginMessageFilterSubFilterForTesting( scoped_refptr message_filter) const { bp_message_filter_->SetSubFilterForTesting(std::move(message_filter)); } } // namespace content