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* extension_process_map = |
255 extensions::ProcessMap::Get(context); | 255 extensions::ProcessMap::Get(context); |
256 is_extension = extension_process_map->Contains( | 256 process_is_for_extensions = |
257 host->GetProcess()->GetID()); | 257 extension_process_map->Contains(render_process_host->GetID()); |
258 | |
259 // For our purposes, don't count processes containing only hosted apps | |
260 // as extension processes. See also: crbug.com/102533. | |
261 std::set<std::string> extension_ids = | |
262 extension_process_map->GetExtensionsInProcess( | |
263 render_process_host->GetID()); | |
264 for (std::set<std::string>::iterator iter = extension_ids.begin(); | |
Lei Zhang
2015/10/30 07:17:48
convert to range-based for loop?
ncarter (slow)
2015/10/30 18:13:23
Done.
| |
265 iter != extension_ids.end(); ++iter) { | |
266 const Extension* extension = | |
267 extension_registry->enabled_extensions().GetByID(*iter); | |
268 if (extension && !extension->is_hosted_app()) { | |
269 process.renderer_type = ProcessMemoryInformation::RENDERER_EXTENSION; | |
270 break; | |
271 } | |
272 } | |
273 } | |
258 #endif | 274 #endif |
259 | 275 |
260 WebContents* contents = WebContents::FromRenderViewHost(host); | 276 // Use the list of widgets to iterate over the WebContents instances whose |
261 GURL url; | 277 // main RenderFrameHosts are in |process|. Refine our determination of the |
262 if (contents) { | 278 // |process.renderer_type|, and record the page titles. |
263 url = contents->GetURL(); | 279 for (content::RenderWidgetHost* widget : widgets_by_pid[process.pid]) { |
264 SiteData* site_data = | 280 DCHECK_EQ(render_process_host, widget->GetProcess()); |
265 &chrome_browser->site_data[contents->GetBrowserContext()]; | 281 |
266 SiteDetails::CollectSiteInfo(contents, site_data); | 282 RenderViewHost* rvh = RenderViewHost::From(widget); |
283 if (!rvh) | |
284 continue; | |
285 | |
286 WebContents* contents = WebContents::FromRenderViewHost(rvh); | |
287 | |
288 // Assume that an RVH without a web contents is an interstitial. | |
289 if (!contents) { | |
290 process.renderer_type = ProcessMemoryInformation::RENDERER_INTERSTITIAL; | |
291 continue; | |
267 } | 292 } |
293 | |
294 // If this is a RVH for a subframe; skip it to avoid double-counting the | |
295 // WebContents. | |
296 if (rvh != contents->GetRenderViewHost()) | |
297 continue; | |
298 | |
299 // The rest of this block will happen only once per WebContents. | |
300 GURL page_url = contents->GetLastCommittedURL(); | |
301 SiteData* site_data = | |
Lei Zhang
2015/10/30 07:17:49
Make this a reference and call SiteDetails::Collec
ncarter (slow)
2015/10/30 18:13:24
Done.
| |
302 &chrome_browser->site_data[contents->GetBrowserContext()]; | |
303 SiteDetails::CollectSiteInfo(contents, site_data); | |
304 | |
305 bool is_webui = | |
306 rvh->GetEnabledBindings() & content::BINDINGS_POLICY_WEB_UI; | |
307 | |
308 if (is_webui) { | |
309 process.renderer_type = ProcessMemoryInformation::RENDERER_CHROME; | |
310 } | |
311 | |
268 #if defined(ENABLE_EXTENSIONS) | 312 #if defined(ENABLE_EXTENSIONS) |
Lei Zhang
2015/10/30 07:17:49
I'm probably to blame for the #if ugliness in the
ncarter (slow)
2015/10/30 18:13:23
Thanks!
| |
269 extensions::ViewType type = extensions::GetViewType(contents); | 313 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 = | 314 const Extension* extension = |
295 extension_registry->enabled_extensions().GetByID(url.host()); | 315 extensions::ExtensionRegistry::Get( |
316 render_process_host->GetBrowserContext()) | |
317 ->enabled_extensions() | |
318 .GetByID(page_url.host()); | |
296 if (extension) { | 319 if (extension) { |
297 base::string16 title = base::UTF8ToUTF16(extension->name()); | 320 base::string16 title = base::UTF8ToUTF16(extension->name()); |
298 process.titles.push_back(title); | 321 process.titles.push_back(title); |
299 process.renderer_type = | 322 process.renderer_type = |
300 ProcessMemoryInformation::RENDERER_EXTENSION; | 323 ProcessMemoryInformation::RENDERER_EXTENSION; |
301 continue; | 324 continue; |
302 } | 325 } |
303 } | 326 } |
304 #endif | |
305 | 327 |
306 if (!contents) { | 328 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) { | 329 if (type == extensions::VIEW_TYPE_BACKGROUND_CONTENTS) { |
314 process.titles.push_back(base::UTF8ToUTF16(url.spec())); | 330 process.titles.push_back(base::UTF8ToUTF16(page_url.spec())); |
315 process.renderer_type = | 331 process.renderer_type = |
316 ProcessMemoryInformation::RENDERER_BACKGROUND_APP; | 332 ProcessMemoryInformation::RENDERER_BACKGROUND_APP; |
317 continue; | 333 continue; |
318 } | 334 } |
319 #endif | 335 #endif |
320 | 336 |
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(); | 337 base::string16 title = contents->GetTitle(); |
327 if (!title.length()) | 338 if (!title.length()) |
328 title = l10n_util::GetStringUTF16(IDS_DEFAULT_TAB_TITLE); | 339 title = l10n_util::GetStringUTF16(IDS_DEFAULT_TAB_TITLE); |
329 process.titles.push_back(title); | 340 process.titles.push_back(title); |
330 | 341 |
342 // The presence of a single WebContents with a diagnostics page will make | |
Lei Zhang
2015/10/30 07:17:49
typo continuing onto next line: make\nmake
ncarter (slow)
2015/10/30 18:13:24
Done.
| |
343 // make the whole process be considered a diagnostics process. | |
344 // | |
331 // We need to check the pending entry as well as the virtual_url to | 345 // 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 | 346 // see if it's a chrome://memory URL (we don't want to count these in |
333 // the total memory usage of the browser). | 347 // the total memory usage of the browser). |
334 // | 348 // |
335 // When we reach here, chrome://memory will be the pending entry since | 349 // 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. | 350 // 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 | 351 // 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 | 352 // committed), we don't want to count it either, so we also check the |
339 // last committed entry. | 353 // last committed entry. |
340 // | 354 // |
(...skipping 15 matching lines...) Expand all Loading... | |
356 } | 370 } |
357 | 371 |
358 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) | 372 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
359 if (process.pid == zygote_pid) { | 373 if (process.pid == zygote_pid) { |
360 process.process_type = content::PROCESS_TYPE_ZYGOTE; | 374 process.process_type = content::PROCESS_TYPE_ZYGOTE; |
361 } | 375 } |
362 #endif | 376 #endif |
363 } | 377 } |
364 | 378 |
365 // Get rid of other Chrome processes that are from a different profile. | 379 // Get rid of other Chrome processes that are from a different profile. |
366 for (size_t index = 0; index < chrome_browser->processes.size(); | 380 auto is_unknown = [](ProcessMemoryInformation& process) { |
367 index++) { | 381 return process.process_type == content::PROCESS_TYPE_UNKNOWN; |
368 if (chrome_browser->processes[index].process_type == | 382 }; |
369 content::PROCESS_TYPE_UNKNOWN) { | 383 auto& vector = chrome_browser->processes; |
370 chrome_browser->processes.erase( | 384 vector.erase(std::remove_if(vector.begin(), vector.end(), is_unknown), |
371 chrome_browser->processes.begin() + index); | 385 vector.end()); |
372 index--; | |
373 } | |
374 } | |
375 | 386 |
376 OnDetailsAvailable(); | 387 OnDetailsAvailable(); |
377 } | 388 } |
OLD | NEW |