| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/public/test/mock_render_process_host.h" |
| |
| #include <algorithm> |
| #include <tuple> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/containers/contains.h" |
| #include "base/functional/bind.h" |
| #include "base/functional/callback_helpers.h" |
| #include "base/lazy_instance.h" |
| #include "base/location.h" |
| #include "base/notimplemented.h" |
| #include "base/process/process_handle.h" |
| #include "base/task/single_thread_task_runner.h" |
| #include "base/time/time.h" |
| #include "build/build_config.h" |
| #include "content/browser/child_process_host_impl.h" |
| #include "content/browser/child_process_security_policy_impl.h" |
| #include "content/browser/file_system_access/file_system_access_error.h" |
| #include "content/browser/process_lock.h" |
| #include "content/browser/renderer_host/render_process_host_impl.h" |
| #include "content/browser/renderer_host/render_view_host_impl.h" |
| #include "content/browser/renderer_host/render_widget_host_impl.h" |
| #include "content/browser/renderer_host/spare_render_process_host_manager_impl.h" |
| #include "content/common/renderer.mojom.h" |
| #include "content/public/browser/android/child_process_importance.h" |
| #include "content/public/browser/browser_context.h" |
| #include "content/public/browser/global_request_id.h" |
| #include "content/public/browser/render_process_host_priority_client.h" |
| #include "content/public/browser/render_widget_host_iterator.h" |
| #include "content/public/browser/site_instance.h" |
| #include "content/test/fake_network_url_loader_factory.h" |
| #include "media/media_buildflags.h" |
| #include "services/network/public/mojom/url_loader_factory.mojom.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| StoragePartitionConfig GetOrCreateStoragePartitionConfig( |
| BrowserContext* browser_context, |
| SiteInstance* site_instance) { |
| if (site_instance) { |
| SiteInstanceImpl* site_instance_impl = |
| static_cast<SiteInstanceImpl*>(site_instance); |
| return site_instance_impl->GetSiteInfo().storage_partition_config(); |
| } |
| return StoragePartitionConfig::CreateDefault(browser_context); |
| } |
| |
| } // namespace |
| |
| MockRenderProcessHost::MockRenderProcessHost(BrowserContext* browser_context, |
| bool is_for_guests_only) |
| : MockRenderProcessHost( |
| browser_context, |
| StoragePartitionConfig::CreateDefault(browser_context), |
| is_for_guests_only) {} |
| |
| MockRenderProcessHost::MockRenderProcessHost( |
| BrowserContext* browser_context, |
| const StoragePartitionConfig& storage_partition_config, |
| bool is_for_guests_only) |
| : bad_msg_count_(0), |
| id_(ChildProcessHostImpl::GenerateChildProcessUniqueId()), |
| has_connection_(false), |
| browser_context_(browser_context), |
| storage_partition_config_(storage_partition_config), |
| prev_routing_id_(0), |
| shutdown_requested_(false), |
| fast_shutdown_started_(false), |
| deletion_callback_called_(false), |
| is_for_guests_only_(is_for_guests_only), |
| priority_(base::Process::Priority::kUserBlocking), |
| is_unused_(true), |
| pending_view_count_(0), |
| worker_ref_count_(0), |
| pending_reuse_ref_count_(0), |
| foreground_service_worker_count_(0) { |
| // Child process security operations can't be unit tested unless we add |
| // ourselves as an existing child process. |
| ChildProcessSecurityPolicyImpl::GetInstance()->Add(GetDeprecatedID(), |
| browser_context); |
| |
| RenderProcessHostImpl::RegisterHost(GetDeprecatedID(), this); |
| } |
| |
| MockRenderProcessHost::~MockRenderProcessHost() { |
| ChildProcessSecurityPolicyImpl::GetInstance()->Remove(GetDeprecatedID()); |
| // In unit tests, Cleanup() might not have been called. |
| if (!deletion_callback_called_) { |
| for (auto& observer : observers_) |
| observer.RenderProcessHostDestroyed(this); |
| RenderProcessHostImpl::UnregisterHost(GetDeprecatedID()); |
| } |
| } |
| |
| void MockRenderProcessHost::SimulateCrash() { |
| SimulateRenderProcessExit(base::TERMINATION_STATUS_PROCESS_CRASHED, 0); |
| } |
| |
| void MockRenderProcessHost::SimulateRenderProcessExit( |
| base::TerminationStatus status, |
| int exit_code) { |
| has_connection_ = false; |
| ChildProcessTerminationInfo termination_info; |
| termination_info.status = status; |
| termination_info.exit_code = exit_code; |
| #if BUILDFLAG(IS_ANDROID) |
| termination_info.renderer_has_visible_clients = VisibleClientCount() > 0; |
| #endif |
| |
| within_process_died_observer_ = true; |
| for (auto& observer : observers_) |
| observer.RenderProcessExited(this, termination_info); |
| within_process_died_observer_ = false; |
| |
| if (delayed_cleanup_) { |
| Cleanup(); |
| } |
| } |
| |
| void MockRenderProcessHost::SimulateReady() { |
| is_ready_ = true; |
| for (auto& observer : observers_) |
| observer.RenderProcessReady(this); |
| } |
| |
| bool MockRenderProcessHost::Init() { |
| has_connection_ = true; |
| return true; |
| } |
| |
| void MockRenderProcessHost::EnableSendQueue() {} |
| |
| int MockRenderProcessHost::GetNextRoutingID() { |
| return ++prev_routing_id_; |
| } |
| |
| void MockRenderProcessHost::AddRoute(int32_t routing_id, |
| IPC::Listener* listener) { |
| listeners_.AddWithID(listener, routing_id); |
| } |
| |
| void MockRenderProcessHost::RemoveRoute(int32_t routing_id) { |
| DCHECK(listeners_.Lookup(routing_id) != nullptr); |
| listeners_.Remove(routing_id); |
| Cleanup(); |
| } |
| |
| void MockRenderProcessHost::AddObserver(RenderProcessHostObserver* observer) { |
| observers_.AddObserver(observer); |
| } |
| |
| void MockRenderProcessHost::RemoveObserver( |
| RenderProcessHostObserver* observer) { |
| observers_.RemoveObserver(observer); |
| } |
| |
| void MockRenderProcessHost::ShutdownForBadMessage( |
| CrashReportMode crash_report_mode) { |
| ++bad_msg_count_; |
| shutdown_requested_ = true; |
| } |
| |
| void MockRenderProcessHost::UpdateClientPriority( |
| RenderProcessHostPriorityClient* client) {} |
| |
| int MockRenderProcessHost::VisibleClientCount() { |
| int count = 0; |
| for (RenderProcessHostPriorityClient* client : priority_clients_) { |
| const RenderProcessHostPriorityClient::Priority priority = |
| client->GetPriority(); |
| if (!priority.is_hidden) { |
| count++; |
| } |
| } |
| return count; |
| } |
| |
| unsigned int MockRenderProcessHost::GetFrameDepth() { |
| NOTIMPLEMENTED(); |
| return 0u; |
| } |
| |
| bool MockRenderProcessHost::GetIntersectsViewport() { |
| NOTIMPLEMENTED(); |
| return true; |
| } |
| |
| bool MockRenderProcessHost::IsForGuestsOnly() { |
| return is_for_guests_only_; |
| } |
| |
| bool MockRenderProcessHost::IsJitDisabled() { |
| return false; |
| } |
| |
| bool MockRenderProcessHost::AreV8OptimizationsDisabled() { |
| return false; |
| } |
| |
| bool MockRenderProcessHost::DisallowV8FeatureFlagOverrides() { |
| return false; |
| } |
| |
| bool MockRenderProcessHost::IsPdf() { |
| return false; |
| } |
| |
| void MockRenderProcessHost::OnMediaStreamAdded() {} |
| |
| void MockRenderProcessHost::OnMediaStreamRemoved() {} |
| |
| void MockRenderProcessHost::OnForegroundServiceWorkerAdded() { |
| foreground_service_worker_count_ += 1; |
| } |
| |
| void MockRenderProcessHost::OnForegroundServiceWorkerRemoved() { |
| DCHECK_GT(foreground_service_worker_count_, 0); |
| foreground_service_worker_count_ -= 1; |
| } |
| |
| void MockRenderProcessHost::OnBoostForLoadingAdded() {} |
| |
| void MockRenderProcessHost::OnBoostForLoadingRemoved() {} |
| |
| void MockRenderProcessHost::OnImmersiveXrSessionStarted() {} |
| |
| void MockRenderProcessHost::OnImmersiveXrSessionStopped() {} |
| |
| StoragePartition* MockRenderProcessHost::GetStoragePartition() { |
| return browser_context_->GetStoragePartition(storage_partition_config_); |
| } |
| |
| void MockRenderProcessHost::AddWord(const std::u16string& word) {} |
| |
| bool MockRenderProcessHost::Shutdown(int exit_code) { |
| shutdown_requested_ = true; |
| return true; |
| } |
| |
| bool MockRenderProcessHost::ShutdownRequested() { |
| return shutdown_requested_; |
| } |
| |
| bool MockRenderProcessHost::FastShutdownIfPossible(size_t page_count, |
| bool skip_unload_handlers, |
| bool ignore_workers, |
| bool ignore_keep_alive) { |
| if (GetActiveViewCount() != page_count) |
| return false; |
| // We aren't actually going to do anything, but set |fast_shutdown_started_| |
| // to true so that tests know we've been called. |
| fast_shutdown_started_ = true; |
| return true; |
| } |
| |
| bool MockRenderProcessHost::FastShutdownStarted() { |
| return fast_shutdown_started_; |
| } |
| |
| const base::Process& MockRenderProcessHost::GetProcess() { |
| // Return the current-process handle for the IPC::GetPlatformFileForTransit |
| // function. |
| if (process.IsValid()) |
| return process; |
| |
| static const base::Process current_process(base::Process::Current()); |
| return current_process; |
| } |
| |
| bool MockRenderProcessHost::IsReady() { |
| return is_ready_; |
| } |
| |
| bool MockRenderProcessHost::Send(IPC::Message* msg) { |
| delete msg; |
| return true; |
| } |
| |
| ChildProcessId MockRenderProcessHost::GetID() const { |
| return id_; |
| } |
| |
| int MockRenderProcessHost::GetDeprecatedID() const { |
| return id_.GetUnsafeValue(); |
| } |
| |
| base::SafeRef<RenderProcessHost> MockRenderProcessHost::GetSafeRef() const { |
| return weak_ptr_factory_.GetSafeRef(); |
| } |
| |
| bool MockRenderProcessHost::IsInitializedAndNotDead() { |
| return has_connection_; |
| } |
| |
| bool MockRenderProcessHost::IsDeletingSoon() { |
| return deletion_callback_called_; |
| } |
| |
| void MockRenderProcessHost::SetBlocked(bool blocked) {} |
| |
| bool MockRenderProcessHost::IsBlocked() { |
| return false; |
| } |
| |
| base::CallbackListSubscription |
| MockRenderProcessHost::RegisterBlockStateChangedCallback( |
| const BlockStateChangedCallback& cb) { |
| return {}; |
| } |
| |
| void MockRenderProcessHost::Cleanup() { |
| if (within_process_died_observer_) { |
| delayed_cleanup_ = true; |
| return; |
| } |
| delayed_cleanup_ = false; |
| |
| if (listeners_.IsEmpty() && !deletion_callback_called_ && |
| !pending_view_count_) { |
| if (IsInitializedAndNotDead()) { |
| ChildProcessTerminationInfo termination_info; |
| termination_info.status = base::TERMINATION_STATUS_NORMAL_TERMINATION; |
| termination_info.exit_code = 0; |
| #if BUILDFLAG(IS_ANDROID) |
| termination_info.renderer_has_visible_clients = VisibleClientCount() > 0; |
| #endif |
| for (auto& observer : observers_) |
| observer.RenderProcessExited(this, termination_info); |
| } |
| |
| for (auto& observer : observers_) |
| observer.RenderProcessHostDestroyed(this); |
| RenderProcessHostImpl::UnregisterHost(GetDeprecatedID()); |
| has_connection_ = false; |
| deletion_callback_called_ = true; |
| } |
| } |
| |
| void MockRenderProcessHost::AddPendingView() { |
| ++pending_view_count_; |
| } |
| |
| void MockRenderProcessHost::RemovePendingView() { |
| CHECK(pending_view_count_); |
| --pending_view_count_; |
| Cleanup(); |
| } |
| |
| void MockRenderProcessHost::AddPriorityClient( |
| RenderProcessHostPriorityClient* priority_client) { |
| priority_clients_.insert(priority_client); |
| } |
| |
| void MockRenderProcessHost::RemovePriorityClient( |
| RenderProcessHostPriorityClient* priority_client) { |
| priority_clients_.erase(priority_client); |
| } |
| |
| #if !BUILDFLAG(IS_ANDROID) |
| void MockRenderProcessHost::SetPriorityOverride( |
| base::Process::Priority priority) {} |
| |
| bool MockRenderProcessHost::HasPriorityOverride() { |
| return false; |
| } |
| |
| void MockRenderProcessHost::ClearPriorityOverride() {} |
| #endif // !BUILDFLAG(IS_ANDROID) |
| |
| void MockRenderProcessHost::GraduateSpareToNormalRendererPriority() {} |
| |
| #if BUILDFLAG(IS_ANDROID) |
| ChildProcessImportance MockRenderProcessHost::GetEffectiveImportance() { |
| NOTIMPLEMENTED(); |
| return ChildProcessImportance::NORMAL; |
| } |
| |
| base::android::ChildBindingState |
| MockRenderProcessHost::GetEffectiveChildBindingState() { |
| NOTIMPLEMENTED(); |
| return base::android::ChildBindingState::UNBOUND; |
| } |
| |
| void MockRenderProcessHost::DumpProcessStack() {} |
| #endif |
| |
| void MockRenderProcessHost::SetSuddenTerminationAllowed(bool allowed) {} |
| |
| BrowserContext* MockRenderProcessHost::GetBrowserContext() { |
| return browser_context_; |
| } |
| |
| bool MockRenderProcessHost::InSameStoragePartition( |
| StoragePartition* partition) { |
| return GetStoragePartition() == partition; |
| } |
| |
| IPC::ChannelProxy* MockRenderProcessHost::GetChannel() { |
| return nullptr; |
| } |
| |
| base::TimeDelta MockRenderProcessHost::GetChildProcessIdleTime() { |
| return base::Milliseconds(0); |
| } |
| |
| void MockRenderProcessHost::BindReceiver( |
| mojo::GenericPendingReceiver receiver) { |
| auto it = binder_overrides_.find(*receiver.interface_name()); |
| if (it != binder_overrides_.end()) |
| it->second.Run(receiver.PassPipe()); |
| } |
| |
| std::unique_ptr<base::PersistentMemoryAllocator> |
| MockRenderProcessHost::TakeMetricsAllocator() { |
| return nullptr; |
| } |
| |
| const base::TimeTicks& MockRenderProcessHost::GetLastInitTime() { |
| static base::TimeTicks dummy_time = base::TimeTicks::Now(); |
| return dummy_time; |
| } |
| |
| base::Process::Priority MockRenderProcessHost::GetPriority() const { |
| return priority_; |
| } |
| |
| std::string MockRenderProcessHost::GetKeepAliveDurations() const { |
| return std::string("MockRenderProcessHost: durations not tracked."); |
| } |
| |
| size_t MockRenderProcessHost::GetShutdownDelayRefCount() const { |
| return 0; |
| } |
| |
| int MockRenderProcessHost::GetRenderFrameHostCount() const { |
| return render_frame_host_id_set_.size(); |
| } |
| |
| void MockRenderProcessHost::RegisterRenderFrameHost( |
| const GlobalRenderFrameHostId& render_frame_host_id, |
| bool is_outermost_main_frame) { |
| render_frame_host_id_set_.insert(render_frame_host_id); |
| } |
| |
| void MockRenderProcessHost::UnregisterRenderFrameHost( |
| const GlobalRenderFrameHostId& render_frame_host_id, |
| bool is_outermost_main_frame) { |
| render_frame_host_id_set_.erase(render_frame_host_id); |
| } |
| |
| void MockRenderProcessHost::ForEachRenderFrameHost( |
| base::FunctionRef<void(RenderFrameHost*)> on_render_frame_host) { |
| // TODO(crbug.com/40487508): Clean up MockRenderProcessHost usage and merge |
| // this implementation with RenderProcessHostImpl::ForEachRenderFrameHost(). |
| for (auto rfh_id : render_frame_host_id_set_) { |
| RenderFrameHostImpl* rfh = RenderFrameHostImpl::FromID(rfh_id); |
| // Note that some RenderFrameHosts in the set may not be found by FromID if |
| // we get here during their destructor (e.g., while deleting their subframe |
| // RenderFrameHosts). |
| if (!rfh) { |
| continue; |
| } |
| |
| // Speculative RFHs are not exposed to //content embedders, so we have to |
| // explicitly check them here to avoid leaks. |
| if (rfh->lifecycle_state() == |
| RenderFrameHostImpl::LifecycleStateImpl::kSpeculative) { |
| continue; |
| } |
| on_render_frame_host(rfh); |
| } |
| } |
| |
| void MockRenderProcessHost::IncrementWorkerRefCount() { |
| ++worker_ref_count_; |
| } |
| |
| void MockRenderProcessHost::DecrementWorkerRefCount() { |
| DCHECK_GT(worker_ref_count_, 0); |
| --worker_ref_count_; |
| } |
| |
| void MockRenderProcessHost::IncrementPendingReuseRefCount() { |
| ++pending_reuse_ref_count_; |
| } |
| |
| void MockRenderProcessHost::DecrementPendingReuseRefCount() { |
| DCHECK_GT(pending_reuse_ref_count_, 0); |
| --pending_reuse_ref_count_; |
| } |
| |
| int MockRenderProcessHost::GetPendingReuseRefCountForTesting() const { |
| return pending_reuse_ref_count_; |
| } |
| |
| size_t MockRenderProcessHost::GetWorkerRefCount() const { |
| return worker_ref_count_; |
| } |
| |
| void MockRenderProcessHost::DisableRefCounts() { |
| worker_ref_count_ = 0; |
| pending_reuse_ref_count_ = 0; |
| |
| // RenderProcessHost::DisableRefCounts() virtual method gets called as part of |
| // BrowserContext::NotifyWillBeDestroyed(...). Normally |
| // MockRenderProcessHost::DisableRefCounts() doesn't call Cleanup, because the |
| // MockRenderProcessHost might be owned by a test. However, when the |
| // MockRenderProcessHost is the spare RenderProcessHost, we know that it is |
| // owned by the SpareRenderProcessHostManager and we need to delete the spare |
| // to avoid reports/DCHECKs about memory leaks. |
| if (IsSpare()) { |
| Cleanup(); |
| } |
| } |
| |
| bool MockRenderProcessHost::AreRefCountsDisabled() { |
| return false; |
| } |
| |
| mojom::Renderer* MockRenderProcessHost::GetRendererInterface() { |
| if (!renderer_interface_) { |
| renderer_interface_ = |
| std::make_unique<mojo::AssociatedRemote<mojom::Renderer>>(); |
| std::ignore = |
| renderer_interface_->BindNewEndpointAndPassDedicatedReceiver(); |
| } |
| return renderer_interface_->get(); |
| } |
| |
| bool MockRenderProcessHost::MayReuseHost() { |
| return true; |
| } |
| |
| bool MockRenderProcessHost::IsUnused() { |
| return is_unused_; |
| } |
| |
| void MockRenderProcessHost::SetIsUsed() { |
| is_unused_ = false; |
| } |
| |
| bool MockRenderProcessHost::HostHasNotBeenUsed() { |
| return IsUnused() && listeners_.IsEmpty(); |
| } |
| |
| bool MockRenderProcessHost::IsSpare() const { |
| return base::Contains(SpareRenderProcessHostManagerImpl::Get().GetSpares(), |
| this); |
| } |
| |
| void MockRenderProcessHost::SetProcessLock( |
| const IsolationContext& isolation_context, |
| const ProcessLock& process_lock) { |
| ChildProcessSecurityPolicyImpl::GetInstance()->LockProcess( |
| isolation_context, GetDeprecatedID(), !IsUnused(), process_lock); |
| if (process_lock.IsASiteOrOrigin()) |
| is_renderer_locked_to_site_ = true; |
| } |
| |
| ProcessLock MockRenderProcessHost::GetProcessLock() const { |
| return ChildProcessSecurityPolicyImpl::GetInstance()->GetProcessLock( |
| GetDeprecatedID()); |
| } |
| |
| bool MockRenderProcessHost::IsProcessLockedToSiteForTesting() { |
| return GetProcessLock().IsLockedToSite(); |
| } |
| |
| void MockRenderProcessHost::BindCacheStorage( |
| const network::CrossOriginEmbedderPolicy&, |
| mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>, |
| const network::DocumentIsolationPolicy&, |
| mojo::PendingRemote<network::mojom::DocumentIsolationPolicyReporter>, |
| const storage::BucketLocator& bucket_locator, |
| mojo::PendingReceiver<blink::mojom::CacheStorage> receiver) { |
| cache_storage_receiver_ = std::move(receiver); |
| } |
| |
| void MockRenderProcessHost::BindIndexedDB( |
| const blink::StorageKey& storage_key, |
| BucketContext& bucket_context, |
| mojo::PendingReceiver<blink::mojom::IDBFactory> receiver) { |
| idb_factory_receiver_ = std::move(receiver); |
| } |
| |
| void MockRenderProcessHost::GetSandboxedFileSystemForBucket( |
| const storage::BucketLocator& bucket, |
| const std::vector<std::string>& directory_path_components, |
| blink::mojom::FileSystemAccessManager::GetSandboxedFileSystemCallback |
| callback) { |
| std::move(callback).Run(file_system_access_error::Ok(), {}); |
| } |
| |
| std::string |
| MockRenderProcessHost::GetInfoForBrowserContextDestructionCrashReporting() { |
| return std::string(); |
| } |
| |
| void MockRenderProcessHost::WriteIntoTrace( |
| perfetto::TracedProto<TraceProto> proto) const { |
| proto->set_id(GetDeprecatedID()); |
| } |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| void MockRenderProcessHost::ReinitializeLogging( |
| uint32_t logging_dest, |
| base::ScopedFD log_file_descriptor) { |
| NOTIMPLEMENTED(); |
| } |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| |
| uint64_t MockRenderProcessHost::GetPrivateMemoryFootprint() { |
| return 0; |
| } |
| |
| RenderProcessHost::FilterURLResult MockRenderProcessHost::FilterURL( |
| bool empty_allowed, |
| GURL* url) { |
| return RenderProcessHostImpl::FilterURL(this, empty_allowed, url); |
| } |
| |
| void MockRenderProcessHost::EnableAudioDebugRecordings( |
| const base::FilePath& file) {} |
| |
| void MockRenderProcessHost::DisableAudioDebugRecordings() {} |
| |
| RenderProcessHost::WebRtcStopRtpDumpCallback |
| MockRenderProcessHost::StartRtpDump(bool incoming, |
| bool outgoing, |
| WebRtcRtpPacketCallback packet_callback) { |
| return base::NullCallback(); |
| } |
| |
| bool MockRenderProcessHost::OnMessageReceived(const IPC::Message& msg) { |
| IPC::Listener* listener = listeners_.Lookup(msg.routing_id()); |
| if (listener) |
| return listener->OnMessageReceived(msg); |
| return false; |
| } |
| |
| void MockRenderProcessHost::OnChannelConnected(int32_t peer_pid) {} |
| |
| void MockRenderProcessHost::OverrideBinderForTesting( |
| const std::string& interface_name, |
| const InterfaceBinder& binder) { |
| binder_overrides_[interface_name] = binder; |
| } |
| |
| void MockRenderProcessHost::OverrideRendererInterfaceForTesting( |
| std::unique_ptr<mojo::AssociatedRemote<mojom::Renderer>> |
| renderer_interface) { |
| renderer_interface_ = std::move(renderer_interface); |
| } |
| |
| MockRenderProcessHostFactory::MockRenderProcessHostFactory() = default; |
| |
| MockRenderProcessHostFactory::~MockRenderProcessHostFactory() = default; |
| |
| RenderProcessHost* MockRenderProcessHostFactory::CreateRenderProcessHost( |
| BrowserContext* browser_context, |
| SiteInstance* site_instance) { |
| processes_.push_back(BuildRenderProcessHost(browser_context, site_instance)); |
| return processes_.back().get(); |
| } |
| |
| void MockRenderProcessHostFactory::Remove(MockRenderProcessHost* host) const { |
| for (auto it = processes_.begin(); it != processes_.end(); ++it) { |
| if (it->get() == host) { |
| processes_.erase(it); |
| break; |
| } |
| } |
| } |
| |
| std::unique_ptr<MockRenderProcessHost> |
| MockRenderProcessHostFactory::BuildRenderProcessHost( |
| BrowserContext* browser_context, |
| SiteInstance* site_instance) { |
| const bool is_for_guests_only = site_instance && site_instance->IsGuest(); |
| StoragePartitionConfig storage_partition_config = |
| GetOrCreateStoragePartitionConfig(browser_context, site_instance); |
| return std::make_unique<MockRenderProcessHost>( |
| browser_context, storage_partition_config, is_for_guests_only); |
| } |
| |
| } // namespace content |