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