| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/memory_details.h" | 5 #include "chrome/browser/memory_details.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <set> | 8 #include <set> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 209 } | 209 } |
| 210 | 210 |
| 211 void MemoryDetails::CollectChildInfoOnUIThread() { | 211 void MemoryDetails::CollectChildInfoOnUIThread() { |
| 212 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 212 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 213 | 213 |
| 214 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) | 214 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
| 215 const pid_t zygote_pid = content::ZygoteHost::GetInstance()->GetPid(); | 215 const pid_t zygote_pid = content::ZygoteHost::GetInstance()->GetPid(); |
| 216 #endif | 216 #endif |
| 217 | 217 |
| 218 ProcessData* const chrome_browser = ChromeBrowser(); | 218 ProcessData* const chrome_browser = ChromeBrowser(); |
| 219 |
| 220 // First pass, collate the widgets by process ID. |
| 221 std::map<base::ProcessId, std::vector<RenderWidgetHost*>> widgets_by_pid; |
| 222 scoped_ptr<content::RenderWidgetHostIterator> widget_it( |
| 223 RenderWidgetHost::GetRenderWidgetHosts()); |
| 224 while (content::RenderWidgetHost* widget = widget_it->GetNextHost()) { |
| 225 // Ignore processes that don't have a connection, such as crashed tabs. |
| 226 if (!widget->GetProcess()->HasConnection()) |
| 227 continue; |
| 228 base::ProcessId pid = base::GetProcId(widget->GetProcess()->GetHandle()); |
| 229 widgets_by_pid[pid].push_back(widget); |
| 230 } |
| 231 |
| 219 // Get more information about the process. | 232 // Get more information about the process. |
| 220 for (size_t index = 0; index < chrome_browser->processes.size(); | 233 for (ProcessMemoryInformation& process : chrome_browser->processes) { |
| 221 index++) { | 234 // If there's at least one widget in the process, it is some kind of |
| 222 // Check if it's a renderer, if so get the list of page titles in it and | 235 // renderer process belonging to this browser. All these widgets will share |
| 223 // check if it's a diagnostics-related process. We skip about:memory pages. | 236 // a RenderProcessHost. |
| 224 // Iterate the RenderProcessHosts to find the tab contents. | 237 content::RenderProcessHost* render_process_host = nullptr; |
| 225 ProcessMemoryInformation& process = | 238 if (!widgets_by_pid[process.pid].empty()) { |
| 226 chrome_browser->processes[index]; | 239 // Mark it as a normal renderer process, if we don't refine it to some |
| 240 // other |renderer_type| later. |
| 241 process.process_type = content::PROCESS_TYPE_RENDERER; |
| 242 process.renderer_type = ProcessMemoryInformation::RENDERER_NORMAL; |
| 243 render_process_host = widgets_by_pid[process.pid].front()->GetProcess(); |
| 244 } |
| 227 | 245 |
| 228 scoped_ptr<content::RenderWidgetHostIterator> widgets( | |
| 229 RenderWidgetHost::GetRenderWidgetHosts()); | |
| 230 while (content::RenderWidgetHost* widget = widgets->GetNextHost()) { | |
| 231 content::RenderProcessHost* render_process_host = | |
| 232 widget->GetProcess(); | |
| 233 DCHECK(render_process_host); | |
| 234 // Ignore processes that don't have a connection, such as crashed tabs. | |
| 235 if (!render_process_host->HasConnection() || | |
| 236 process.pid != base::GetProcId(render_process_host->GetHandle())) { | |
| 237 continue; | |
| 238 } | |
| 239 | |
| 240 // The RenderProcessHost may host multiple WebContentses. Any | |
| 241 // of them which contain diagnostics information make the whole | |
| 242 // process be considered a diagnostics process. | |
| 243 RenderViewHost* host = RenderViewHost::From(widget); | |
| 244 if (!host) | |
| 245 continue; | |
| 246 | |
| 247 process.process_type = content::PROCESS_TYPE_RENDERER; | |
| 248 bool is_extension = false; | |
| 249 #if defined(ENABLE_EXTENSIONS) | 246 #if defined(ENABLE_EXTENSIONS) |
| 247 // Determine if this is an extension process. |
| 248 bool process_is_for_extensions = false; |
| 249 if (render_process_host) { |
| 250 content::BrowserContext* context = | 250 content::BrowserContext* context = |
| 251 render_process_host->GetBrowserContext(); | 251 render_process_host->GetBrowserContext(); |
| 252 extensions::ExtensionRegistry* extension_registry = | 252 extensions::ExtensionRegistry* extension_registry = |
| 253 extensions::ExtensionRegistry::Get(context); | 253 extensions::ExtensionRegistry::Get(context); |
| 254 extensions::ProcessMap* extension_process_map = | 254 extensions::ProcessMap* process_map = |
| 255 extensions::ProcessMap::Get(context); | 255 extensions::ProcessMap::Get(context); |
| 256 is_extension = extension_process_map->Contains( | 256 int rph_id = render_process_host->GetID(); |
| 257 host->GetProcess()->GetID()); | 257 process_is_for_extensions = process_map->Contains(rph_id); |
| 258 |
| 259 // For our purposes, don't count processes containing only hosted apps |
| 260 // as extension processes. See also: crbug.com/102533. |
| 261 for (auto& extension_id : process_map->GetExtensionsInProcess(rph_id)) { |
| 262 const Extension* extension = |
| 263 extension_registry->enabled_extensions().GetByID(extension_id); |
| 264 if (extension && !extension->is_hosted_app()) { |
| 265 process.renderer_type = ProcessMemoryInformation::RENDERER_EXTENSION; |
| 266 break; |
| 267 } |
| 268 } |
| 269 } |
| 258 #endif | 270 #endif |
| 259 | 271 |
| 260 WebContents* contents = WebContents::FromRenderViewHost(host); | 272 // Use the list of widgets to iterate over the WebContents instances whose |
| 261 GURL url; | 273 // main RenderFrameHosts are in |process|. Refine our determination of the |
| 262 if (contents) { | 274 // |process.renderer_type|, and record the page titles. |
| 263 url = contents->GetURL(); | 275 for (content::RenderWidgetHost* widget : widgets_by_pid[process.pid]) { |
| 264 SiteData* site_data = | 276 DCHECK_EQ(render_process_host, widget->GetProcess()); |
| 265 &chrome_browser->site_data[contents->GetBrowserContext()]; | 277 |
| 266 SiteDetails::CollectSiteInfo(contents, site_data); | 278 RenderViewHost* rvh = RenderViewHost::From(widget); |
| 279 if (!rvh) |
| 280 continue; |
| 281 |
| 282 WebContents* contents = WebContents::FromRenderViewHost(rvh); |
| 283 |
| 284 // Assume that an RVH without a web contents is an interstitial. |
| 285 if (!contents) { |
| 286 process.renderer_type = ProcessMemoryInformation::RENDERER_INTERSTITIAL; |
| 287 continue; |
| 267 } | 288 } |
| 289 |
| 290 // If this is a RVH for a subframe; skip it to avoid double-counting the |
| 291 // WebContents. |
| 292 if (rvh != contents->GetRenderViewHost()) |
| 293 continue; |
| 294 |
| 295 // The rest of this block will happen only once per WebContents. |
| 296 GURL page_url = contents->GetLastCommittedURL(); |
| 297 SiteData& site_data = |
| 298 chrome_browser->site_data[contents->GetBrowserContext()]; |
| 299 SiteDetails::CollectSiteInfo(contents, &site_data); |
| 300 |
| 301 bool is_webui = |
| 302 rvh->GetEnabledBindings() & content::BINDINGS_POLICY_WEB_UI; |
| 303 |
| 304 if (is_webui) { |
| 305 process.renderer_type = ProcessMemoryInformation::RENDERER_CHROME; |
| 306 } |
| 307 |
| 268 #if defined(ENABLE_EXTENSIONS) | 308 #if defined(ENABLE_EXTENSIONS) |
| 269 extensions::ViewType type = extensions::GetViewType(contents); | 309 if (!is_webui && process_is_for_extensions) { |
| 270 #endif | |
| 271 if (host->GetEnabledBindings() & content::BINDINGS_POLICY_WEB_UI) { | |
| 272 process.renderer_type = ProcessMemoryInformation::RENDERER_CHROME; | |
| 273 } else if (is_extension) { | |
| 274 #if defined(ENABLE_EXTENSIONS) | |
| 275 // For our purposes, don't count processes containing only hosted apps | |
| 276 // as extension processes. See also: crbug.com/102533. | |
| 277 std::set<std::string> extension_ids = | |
| 278 extension_process_map->GetExtensionsInProcess( | |
| 279 host->GetProcess()->GetID()); | |
| 280 for (std::set<std::string>::iterator iter = extension_ids.begin(); | |
| 281 iter != extension_ids.end(); ++iter) { | |
| 282 const Extension* extension = | |
| 283 extension_registry->enabled_extensions().GetByID(*iter); | |
| 284 if (extension && !extension->is_hosted_app()) { | |
| 285 process.renderer_type = | |
| 286 ProcessMemoryInformation::RENDERER_EXTENSION; | |
| 287 break; | |
| 288 } | |
| 289 } | |
| 290 #endif | |
| 291 } | |
| 292 #if defined(ENABLE_EXTENSIONS) | |
| 293 if (is_extension) { | |
| 294 const Extension* extension = | 310 const Extension* extension = |
| 295 extension_registry->enabled_extensions().GetByID(url.host()); | 311 extensions::ExtensionRegistry::Get( |
| 312 render_process_host->GetBrowserContext()) |
| 313 ->enabled_extensions() |
| 314 .GetByID(page_url.host()); |
| 296 if (extension) { | 315 if (extension) { |
| 297 base::string16 title = base::UTF8ToUTF16(extension->name()); | 316 base::string16 title = base::UTF8ToUTF16(extension->name()); |
| 298 process.titles.push_back(title); | 317 process.titles.push_back(title); |
| 299 process.renderer_type = | 318 process.renderer_type = |
| 300 ProcessMemoryInformation::RENDERER_EXTENSION; | 319 ProcessMemoryInformation::RENDERER_EXTENSION; |
| 301 continue; | 320 continue; |
| 302 } | 321 } |
| 303 } | 322 } |
| 304 #endif | |
| 305 | 323 |
| 306 if (!contents) { | 324 extensions::ViewType type = extensions::GetViewType(contents); |
| 307 process.renderer_type = | |
| 308 ProcessMemoryInformation::RENDERER_INTERSTITIAL; | |
| 309 continue; | |
| 310 } | |
| 311 | |
| 312 #if defined(ENABLE_EXTENSIONS) | |
| 313 if (type == extensions::VIEW_TYPE_BACKGROUND_CONTENTS) { | 325 if (type == extensions::VIEW_TYPE_BACKGROUND_CONTENTS) { |
| 314 process.titles.push_back(base::UTF8ToUTF16(url.spec())); | 326 process.titles.push_back(base::UTF8ToUTF16(page_url.spec())); |
| 315 process.renderer_type = | 327 process.renderer_type = |
| 316 ProcessMemoryInformation::RENDERER_BACKGROUND_APP; | 328 ProcessMemoryInformation::RENDERER_BACKGROUND_APP; |
| 317 continue; | 329 continue; |
| 318 } | 330 } |
| 319 #endif | 331 #endif |
| 320 | 332 |
| 321 // Since we have a WebContents and and the renderer type hasn't been | |
| 322 // set yet, it must be a normal tabbed renderer. | |
| 323 if (process.renderer_type == ProcessMemoryInformation::RENDERER_UNKNOWN) | |
| 324 process.renderer_type = ProcessMemoryInformation::RENDERER_NORMAL; | |
| 325 | |
| 326 base::string16 title = contents->GetTitle(); | 333 base::string16 title = contents->GetTitle(); |
| 327 if (!title.length()) | 334 if (!title.length()) |
| 328 title = l10n_util::GetStringUTF16(IDS_DEFAULT_TAB_TITLE); | 335 title = l10n_util::GetStringUTF16(IDS_DEFAULT_TAB_TITLE); |
| 329 process.titles.push_back(title); | 336 process.titles.push_back(title); |
| 330 | 337 |
| 338 // The presence of a single WebContents with a diagnostics page will make |
| 339 // the whole process be considered a diagnostics process. |
| 340 // |
| 331 // We need to check the pending entry as well as the virtual_url to | 341 // We need to check the pending entry as well as the virtual_url to |
| 332 // see if it's a chrome://memory URL (we don't want to count these in | 342 // see if it's a chrome://memory URL (we don't want to count these in |
| 333 // the total memory usage of the browser). | 343 // the total memory usage of the browser). |
| 334 // | 344 // |
| 335 // When we reach here, chrome://memory will be the pending entry since | 345 // When we reach here, chrome://memory will be the pending entry since |
| 336 // we haven't responded with any data such that it would be committed. | 346 // we haven't responded with any data such that it would be committed. |
| 337 // If you have another chrome://memory tab open (which would be | 347 // If you have another chrome://memory tab open (which would be |
| 338 // committed), we don't want to count it either, so we also check the | 348 // committed), we don't want to count it either, so we also check the |
| 339 // last committed entry. | 349 // last committed entry. |
| 340 // | 350 // |
| (...skipping 15 matching lines...) Expand all Loading... |
| 356 } | 366 } |
| 357 | 367 |
| 358 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) | 368 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
| 359 if (process.pid == zygote_pid) { | 369 if (process.pid == zygote_pid) { |
| 360 process.process_type = content::PROCESS_TYPE_ZYGOTE; | 370 process.process_type = content::PROCESS_TYPE_ZYGOTE; |
| 361 } | 371 } |
| 362 #endif | 372 #endif |
| 363 } | 373 } |
| 364 | 374 |
| 365 // Get rid of other Chrome processes that are from a different profile. | 375 // Get rid of other Chrome processes that are from a different profile. |
| 366 for (size_t index = 0; index < chrome_browser->processes.size(); | 376 auto is_unknown = [](ProcessMemoryInformation& process) { |
| 367 index++) { | 377 return process.process_type == content::PROCESS_TYPE_UNKNOWN; |
| 368 if (chrome_browser->processes[index].process_type == | 378 }; |
| 369 content::PROCESS_TYPE_UNKNOWN) { | 379 auto& vector = chrome_browser->processes; |
| 370 chrome_browser->processes.erase( | 380 vector.erase(std::remove_if(vector.begin(), vector.end(), is_unknown), |
| 371 chrome_browser->processes.begin() + index); | 381 vector.end()); |
| 372 index--; | |
| 373 } | |
| 374 } | |
| 375 | 382 |
| 376 OnDetailsAvailable(); | 383 OnDetailsAvailable(); |
| 377 } | 384 } |
| OLD | NEW |