Chromium Code Reviews| Index: content/browser/renderer_host/render_process_host_impl.cc |
| diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc |
| index 4ac27dc3c34712a1d1a8ccf6caa4d6a90b1b7252..78503665c4dcb8012aca4922cdb4e17592aae2c6 100644 |
| --- a/content/browser/renderer_host/render_process_host_impl.cc |
| +++ b/content/browser/renderer_host/render_process_host_impl.cc |
| @@ -629,6 +629,104 @@ class RenderProcessHostIsReadyObserver : public RenderProcessHostObserver { |
| 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. |
| +const void* const kCommittedSiteProcessCountTrackerKey = |
| + "CommittedSiteProcessCountTrackerKey"; |
| +const void* const kPendingSiteProcessCountTrackerKey = |
| + "PendingSiteProcessCountTrackerKey"; |
| +class SiteProcessCountTracker : public base::SupportsUserData::Data, |
| + public RenderProcessHostObserver { |
| + public: |
| + SiteProcessCountTracker() {} |
| + ~SiteProcessCountTracker() override { DCHECK(map_.empty()); } |
| + |
| + void IncrementSiteProcessCount(const GURL& site_url, |
| + int render_process_host_id) { |
| + std::map<ProcessID, Count>& counts_per_process = map_[site_url]; |
| + ++counts_per_process[render_process_host_id]; |
| + |
| +#ifndef NDEBUG |
| + // In tests, observer the RenderProcessHost destrcution, to check that it is |
|
Charlie Reis
2017/05/24 17:18:37
nit: s/tests/debug builds/
nit: observe
nit: destr
clamy
2017/05/24 18:03:04
Done.
|
| + // properly removed from the map. |
| + RenderProcessHost* host = RenderProcessHost::FromID(render_process_host_id); |
| + if (!HasProcess(host)) |
| + host->AddObserver(this); |
| +#endif |
| + } |
| + |
| + void DecrementSiteProcessCount(const GURL& site_url, |
| + int render_process_host_id) { |
| + auto result = map_.find(site_url); |
| + DCHECK(result != map_.end()); |
| + std::map<ProcessID, Count>& counts_per_process = result->second; |
| + |
| + --counts_per_process[render_process_host_id]; |
| + DCHECK(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 FindRenderProcessesForSite( |
| + const GURL& site_url, |
| + std::set<RenderProcessHost*>* foreground_processes, |
| + std::set<RenderProcessHost*>* background_processes) { |
| + auto result = map_.find(site_url); |
| + if (result == map_.end()) |
| + return; |
| + |
| + std::map<ProcessID, Count>& counts_per_process = result->second; |
| + for (auto iter : counts_per_process) { |
| + RenderProcessHost* host = RenderProcessHost::FromID(iter.first); |
| + DCHECK(host); |
| + if (host->VisibleWidgetCount()) |
| + foreground_processes->insert(host); |
| + else |
| + background_processes->insert(host); |
| + } |
| + } |
| + |
| + private: |
| + void RenderProcessHostDestroyed(RenderProcessHost* host) override { |
| + host->RemoveObserver(this); |
|
Charlie Reis
2017/05/24 17:18:37
Shouldn't this be within the ifndef as well? We o
clamy
2017/05/24 18:03:04
Done.
|
| +#ifndef NDEBUG |
| + DCHECK(!HasProcess(host)); |
| +#endif |
| + } |
| + |
| + // Used in tests to ensure that RenderProcessHost don't persist in the map |
|
Charlie Reis
2017/05/24 17:18:37
nit: s/tests/debug builds/
clamy
2017/05/24 18:03:04
Done.
|
| + // after they've been destroyed. |
| + bool HasProcess(RenderProcessHost* process) { |
|
Charlie Reis
2017/05/24 17:18:37
I'd include this in the ifndef as well, given the
clamy
2017/05/24 18:03:04
Done.
|
| + for (auto iter : map_) { |
| + std::map<ProcessID, Count>& counts_per_process = iter.second; |
| + for (auto iter_process : counts_per_process) { |
| + if (iter_process.first == process->GetID()) |
| + return true; |
| + } |
| + } |
| + return false; |
| + } |
| + |
| + using ProcessID = int; |
| + using Count = int; |
| + using CountPerProcessPerSiteMap = std::map<GURL, std::map<ProcessID, Count>>; |
| + CountPerProcessPerSiteMap map_; |
| +}; |
| + |
| } // namespace |
| RendererMainThreadFactoryFunction g_renderer_main_thread_factory = NULL; |
| @@ -1748,6 +1846,78 @@ void RenderProcessHostImpl::set_render_process_host_factory( |
| g_render_process_host_factory_ = rph_factory; |
| } |
| +// static |
| +void RenderProcessHostImpl::AddFrameWithSite( |
| + BrowserContext* browser_context, |
| + RenderProcessHost* render_process_host, |
| + const GURL& site_url) { |
| + if (site_url.is_empty()) |
| + return; |
| + |
| + SiteProcessCountTracker* tracker = static_cast<SiteProcessCountTracker*>( |
| + browser_context->GetUserData(kCommittedSiteProcessCountTrackerKey)); |
| + if (!tracker) { |
| + tracker = new SiteProcessCountTracker(); |
| + browser_context->SetUserData(kCommittedSiteProcessCountTrackerKey, |
| + base::WrapUnique(tracker)); |
| + } |
| + tracker->IncrementSiteProcessCount(site_url, render_process_host->GetID()); |
| +} |
| + |
| +// static |
| +void RenderProcessHostImpl::RemoveFrameWithSite( |
| + BrowserContext* browser_context, |
| + RenderProcessHost* render_process_host, |
| + const GURL& site_url) { |
| + if (site_url.is_empty()) |
| + return; |
| + |
| + SiteProcessCountTracker* tracker = static_cast<SiteProcessCountTracker*>( |
| + browser_context->GetUserData(kCommittedSiteProcessCountTrackerKey)); |
| + if (!tracker) { |
| + tracker = new SiteProcessCountTracker(); |
| + browser_context->SetUserData(kCommittedSiteProcessCountTrackerKey, |
| + base::WrapUnique(tracker)); |
| + } |
| + tracker->DecrementSiteProcessCount(site_url, render_process_host->GetID()); |
| +} |
| + |
| +// static |
| +void RenderProcessHostImpl::AddExpectedNavigationToSite( |
| + BrowserContext* browser_context, |
| + RenderProcessHost* render_process_host, |
| + const GURL& site_url) { |
| + if (site_url.is_empty()) |
| + return; |
| + |
| + SiteProcessCountTracker* tracker = static_cast<SiteProcessCountTracker*>( |
| + browser_context->GetUserData(kPendingSiteProcessCountTrackerKey)); |
| + if (!tracker) { |
| + tracker = new SiteProcessCountTracker(); |
| + browser_context->SetUserData(kPendingSiteProcessCountTrackerKey, |
| + base::WrapUnique(tracker)); |
| + } |
| + tracker->IncrementSiteProcessCount(site_url, render_process_host->GetID()); |
| +} |
| + |
| +// static |
| +void RenderProcessHostImpl::RemoveExpectedNavigationToSite( |
| + BrowserContext* browser_context, |
| + RenderProcessHost* render_process_host, |
| + const GURL& site_url) { |
| + if (site_url.is_empty()) |
| + return; |
| + |
| + SiteProcessCountTracker* tracker = static_cast<SiteProcessCountTracker*>( |
| + browser_context->GetUserData(kPendingSiteProcessCountTrackerKey)); |
| + if (!tracker) { |
| + tracker = new SiteProcessCountTracker(); |
| + browser_context->SetUserData(kPendingSiteProcessCountTrackerKey, |
| + base::WrapUnique(tracker)); |
| + } |
| + tracker->DecrementSiteProcessCount(site_url, render_process_host->GetID()); |
| +} |
| + |
| bool RenderProcessHostImpl::IsForGuestsOnly() const { |
| return is_for_guests_only_; |
| } |
| @@ -2874,6 +3044,10 @@ RenderProcessHost* RenderProcessHostImpl::GetProcessHostForSiteInstance( |
| render_process_host = GetDefaultSubframeProcessHost( |
| browser_context, site_instance, is_for_guests_only); |
| break; |
| + case SiteInstanceImpl::ProcessReusePolicy::REUSE_PENDING_OR_COMMITTED_SITE: |
| + render_process_host = |
| + FindReusableProcessHostForSite(browser_context, site_url); |
| + break; |
| default: |
| break; |
| } |
| @@ -3266,6 +3440,57 @@ RenderProcessHost* RenderProcessHostImpl::GetDefaultSubframeProcessHost( |
| return holder->GetProcessHost(site_instance, is_for_guests_only); |
| } |
| +// static |
| +RenderProcessHost* RenderProcessHostImpl::FindReusableProcessHostForSite( |
| + BrowserContext* browser_context, |
| + const GURL& site_url) { |
| + if (site_url.is_empty()) |
| + return nullptr; |
| + |
| + std::set<RenderProcessHost*> eligible_foreground_hosts; |
| + std::set<RenderProcessHost*> eligible_background_hosts; |
| + |
| + // First, add the RenderProcessHosts expecting a navigation to |site_url| to |
| + // the list of eligible RenderProcessHosts. |
| + SiteProcessCountTracker* pending_tracker = |
| + static_cast<SiteProcessCountTracker*>( |
| + browser_context->GetUserData(kPendingSiteProcessCountTrackerKey)); |
| + if (pending_tracker) { |
| + pending_tracker->FindRenderProcessesForSite( |
| + site_url, &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<SiteProcessCountTracker*>( |
| + browser_context->GetUserData(kCommittedSiteProcessCountTrackerKey)); |
| + if (committed_tracker) { |
| + committed_tracker->FindRenderProcessesForSite( |
| + site_url, &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::OnRegisterAecDumpConsumer(int id) { |
| BrowserThread::PostTask( |