Index: chrome/browser/memory_details.cc |
diff --git a/chrome/browser/memory_details.cc b/chrome/browser/memory_details.cc |
index fbf669df4f29a3cfcb225535bc60878d2b9483b5..b210f92597e57fe45fabff785ec7533ec143cbfb 100644 |
--- a/chrome/browser/memory_details.cc |
+++ b/chrome/browser/memory_details.cc |
@@ -216,83 +216,102 @@ void MemoryDetails::CollectChildInfoOnUIThread() { |
#endif |
ProcessData* const chrome_browser = ChromeBrowser(); |
- // Get more information about the process. |
- for (size_t index = 0; index < chrome_browser->processes.size(); |
- index++) { |
- // Check if it's a renderer, if so get the list of page titles in it and |
- // check if it's a diagnostics-related process. We skip about:memory pages. |
- // Iterate the RenderProcessHosts to find the tab contents. |
- ProcessMemoryInformation& process = |
- chrome_browser->processes[index]; |
- |
- scoped_ptr<content::RenderWidgetHostIterator> widgets( |
- RenderWidgetHost::GetRenderWidgetHosts()); |
- while (content::RenderWidgetHost* widget = widgets->GetNextHost()) { |
- content::RenderProcessHost* render_process_host = |
- widget->GetProcess(); |
- DCHECK(render_process_host); |
- // Ignore processes that don't have a connection, such as crashed tabs. |
- if (!render_process_host->HasConnection() || |
- process.pid != base::GetProcId(render_process_host->GetHandle())) { |
- continue; |
- } |
- // The RenderProcessHost may host multiple WebContentses. Any |
- // of them which contain diagnostics information make the whole |
- // process be considered a diagnostics process. |
- RenderViewHost* host = RenderViewHost::From(widget); |
- if (!host) |
- continue; |
+ // First pass, collate the widgets by process ID. |
+ std::map<base::ProcessId, std::vector<RenderWidgetHost*>> widgets_by_pid; |
+ scoped_ptr<content::RenderWidgetHostIterator> widget_it( |
+ RenderWidgetHost::GetRenderWidgetHosts()); |
+ while (content::RenderWidgetHost* widget = widget_it->GetNextHost()) { |
+ // Ignore processes that don't have a connection, such as crashed tabs. |
+ if (!widget->GetProcess()->HasConnection()) |
+ continue; |
+ base::ProcessId pid = base::GetProcId(widget->GetProcess()->GetHandle()); |
+ widgets_by_pid[pid].push_back(widget); |
+ } |
+ // Get more information about the process. |
+ for (ProcessMemoryInformation& process : chrome_browser->processes) { |
+ // If there's at least one widget in the process, it is some kind of |
+ // renderer process belonging to this browser. All these widgets will share |
+ // a RenderProcessHost. |
+ content::RenderProcessHost* render_process_host = nullptr; |
+ if (!widgets_by_pid[process.pid].empty()) { |
+ // Mark it as a normal renderer process, if we don't refine it to some |
+ // other |renderer_type| later. |
process.process_type = content::PROCESS_TYPE_RENDERER; |
- bool is_extension = false; |
+ process.renderer_type = ProcessMemoryInformation::RENDERER_NORMAL; |
+ render_process_host = widgets_by_pid[process.pid].front()->GetProcess(); |
+ } |
+ |
#if defined(ENABLE_EXTENSIONS) |
+ // Determine if this is an extension process. |
+ bool process_is_for_extensions = false; |
+ if (render_process_host) { |
content::BrowserContext* context = |
render_process_host->GetBrowserContext(); |
extensions::ExtensionRegistry* extension_registry = |
extensions::ExtensionRegistry::Get(context); |
- extensions::ProcessMap* extension_process_map = |
+ extensions::ProcessMap* process_map = |
extensions::ProcessMap::Get(context); |
- is_extension = extension_process_map->Contains( |
- host->GetProcess()->GetID()); |
-#endif |
+ int rph_id = render_process_host->GetID(); |
+ process_is_for_extensions = process_map->Contains(rph_id); |
- WebContents* contents = WebContents::FromRenderViewHost(host); |
- GURL url; |
- if (contents) { |
- url = contents->GetURL(); |
- SiteData* site_data = |
- &chrome_browser->site_data[contents->GetBrowserContext()]; |
- SiteDetails::CollectSiteInfo(contents, site_data); |
+ // For our purposes, don't count processes containing only hosted apps |
+ // as extension processes. See also: crbug.com/102533. |
+ for (auto& extension_id : process_map->GetExtensionsInProcess(rph_id)) { |
+ const Extension* extension = |
+ extension_registry->enabled_extensions().GetByID(extension_id); |
+ if (extension && !extension->is_hosted_app()) { |
+ process.renderer_type = ProcessMemoryInformation::RENDERER_EXTENSION; |
+ break; |
+ } |
} |
-#if defined(ENABLE_EXTENSIONS) |
- extensions::ViewType type = extensions::GetViewType(contents); |
+ } |
#endif |
- if (host->GetEnabledBindings() & content::BINDINGS_POLICY_WEB_UI) { |
+ |
+ // Use the list of widgets to iterate over the WebContents instances whose |
+ // main RenderFrameHosts are in |process|. Refine our determination of the |
+ // |process.renderer_type|, and record the page titles. |
+ for (content::RenderWidgetHost* widget : widgets_by_pid[process.pid]) { |
+ DCHECK_EQ(render_process_host, widget->GetProcess()); |
+ |
+ RenderViewHost* rvh = RenderViewHost::From(widget); |
+ if (!rvh) |
+ continue; |
+ |
+ WebContents* contents = WebContents::FromRenderViewHost(rvh); |
+ |
+ // Assume that an RVH without a web contents is an interstitial. |
+ if (!contents) { |
+ process.renderer_type = ProcessMemoryInformation::RENDERER_INTERSTITIAL; |
+ continue; |
+ } |
+ |
+ // If this is a RVH for a subframe; skip it to avoid double-counting the |
+ // WebContents. |
+ if (rvh != contents->GetRenderViewHost()) |
+ continue; |
+ |
+ // The rest of this block will happen only once per WebContents. |
+ GURL page_url = contents->GetLastCommittedURL(); |
+ SiteData& site_data = |
+ chrome_browser->site_data[contents->GetBrowserContext()]; |
+ SiteDetails::CollectSiteInfo(contents, &site_data); |
+ |
+ bool is_webui = |
+ rvh->GetEnabledBindings() & content::BINDINGS_POLICY_WEB_UI; |
+ |
+ if (is_webui) { |
process.renderer_type = ProcessMemoryInformation::RENDERER_CHROME; |
- } else if (is_extension) { |
-#if defined(ENABLE_EXTENSIONS) |
- // For our purposes, don't count processes containing only hosted apps |
- // as extension processes. See also: crbug.com/102533. |
- std::set<std::string> extension_ids = |
- extension_process_map->GetExtensionsInProcess( |
- host->GetProcess()->GetID()); |
- for (std::set<std::string>::iterator iter = extension_ids.begin(); |
- iter != extension_ids.end(); ++iter) { |
- const Extension* extension = |
- extension_registry->enabled_extensions().GetByID(*iter); |
- if (extension && !extension->is_hosted_app()) { |
- process.renderer_type = |
- ProcessMemoryInformation::RENDERER_EXTENSION; |
- break; |
- } |
- } |
-#endif |
} |
+ |
#if defined(ENABLE_EXTENSIONS) |
- if (is_extension) { |
+ if (!is_webui && process_is_for_extensions) { |
const Extension* extension = |
- extension_registry->enabled_extensions().GetByID(url.host()); |
+ extensions::ExtensionRegistry::Get( |
+ render_process_host->GetBrowserContext()) |
+ ->enabled_extensions() |
+ .GetByID(page_url.host()); |
if (extension) { |
base::string16 title = base::UTF8ToUTF16(extension->name()); |
process.titles.push_back(title); |
@@ -301,33 +320,24 @@ void MemoryDetails::CollectChildInfoOnUIThread() { |
continue; |
} |
} |
-#endif |
- |
- if (!contents) { |
- process.renderer_type = |
- ProcessMemoryInformation::RENDERER_INTERSTITIAL; |
- continue; |
- } |
-#if defined(ENABLE_EXTENSIONS) |
+ extensions::ViewType type = extensions::GetViewType(contents); |
if (type == extensions::VIEW_TYPE_BACKGROUND_CONTENTS) { |
- process.titles.push_back(base::UTF8ToUTF16(url.spec())); |
+ process.titles.push_back(base::UTF8ToUTF16(page_url.spec())); |
process.renderer_type = |
ProcessMemoryInformation::RENDERER_BACKGROUND_APP; |
continue; |
} |
#endif |
- // Since we have a WebContents and and the renderer type hasn't been |
- // set yet, it must be a normal tabbed renderer. |
- if (process.renderer_type == ProcessMemoryInformation::RENDERER_UNKNOWN) |
- process.renderer_type = ProcessMemoryInformation::RENDERER_NORMAL; |
- |
base::string16 title = contents->GetTitle(); |
if (!title.length()) |
title = l10n_util::GetStringUTF16(IDS_DEFAULT_TAB_TITLE); |
process.titles.push_back(title); |
+ // The presence of a single WebContents with a diagnostics page will make |
+ // the whole process be considered a diagnostics process. |
+ // |
// We need to check the pending entry as well as the virtual_url to |
// see if it's a chrome://memory URL (we don't want to count these in |
// the total memory usage of the browser). |
@@ -363,15 +373,12 @@ void MemoryDetails::CollectChildInfoOnUIThread() { |
} |
// Get rid of other Chrome processes that are from a different profile. |
- for (size_t index = 0; index < chrome_browser->processes.size(); |
- index++) { |
- if (chrome_browser->processes[index].process_type == |
- content::PROCESS_TYPE_UNKNOWN) { |
- chrome_browser->processes.erase( |
- chrome_browser->processes.begin() + index); |
- index--; |
- } |
- } |
+ auto is_unknown = [](ProcessMemoryInformation& process) { |
+ return process.process_type == content::PROCESS_TYPE_UNKNOWN; |
+ }; |
+ auto& vector = chrome_browser->processes; |
+ vector.erase(std::remove_if(vector.begin(), vector.end(), is_unknown), |
+ vector.end()); |
OnDetailsAvailable(); |
} |