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 3// found in the LICENSE file. 4 5#include "chrome/browser/memory_details.h" 6 7#include <set> 8#include <string> 9#include <vector> 10 11#include "base/bind.h" 12#include "base/memory/scoped_ptr.h" 13#include "base/process/process_iterator.h" 14#include "base/strings/utf_string_conversions.h" 15#include "chrome/common/chrome_constants.h" 16#include "chrome/grit/chromium_strings.h" 17#include "content/public/browser/browser_thread.h" 18#include "content/public/common/process_type.h" 19#include "ui/base/l10n/l10n_util.h" 20 21using base::ProcessEntry; 22using base::ProcessId; 23using content::BrowserThread; 24 25namespace { 26 27// A helper for |CollectProcessData()| to include the chrome sandboxed 28// processes in android which are not running as a child of the browser 29// process. 30void AddNonChildChromeProcesses( 31 std::vector<ProcessMemoryInformation>* processes) { 32 base::ProcessIterator process_iter(NULL); 33 while (const ProcessEntry* process_entry = process_iter.NextProcessEntry()) { 34 const std::vector<std::string>& cmd_args = process_entry->cmd_line_args(); 35 if (cmd_args.empty() || 36 cmd_args[0].find(chrome::kHelperProcessExecutableName) == 37 std::string::npos) { 38 continue; 39 } 40 ProcessMemoryInformation info; 41 info.pid = process_entry->pid(); 42 processes->push_back(info); 43 } 44} 45 46// For each of the pids, collect memory information about that process 47// and append a record to |out|. 48void GetProcessDataMemoryInformation( 49 const std::set<ProcessId>& pids, ProcessData* out) { 50 for (std::set<ProcessId>::const_iterator i = pids.begin(); i != pids.end(); 51 ++i) { 52 ProcessMemoryInformation pmi; 53 54 pmi.pid = *i; 55 pmi.num_processes = 1; 56 57 if (pmi.pid == base::GetCurrentProcId()) 58 pmi.process_type = content::PROCESS_TYPE_BROWSER; 59 else 60 pmi.process_type = content::PROCESS_TYPE_UNKNOWN; 61 62 scoped_ptr<base::ProcessMetrics> metrics( 63 base::ProcessMetrics::CreateProcessMetrics(*i)); 64 metrics->GetWorkingSetKBytes(&pmi.working_set); 65 66 out->processes.push_back(pmi); 67 } 68} 69 70// Find all children of the given process. 71void GetAllChildren(const std::vector<ProcessEntry>& processes, 72 const std::set<ProcessId>& roots, 73 std::set<ProcessId>* out) { 74 *out = roots; 75 76 std::set<ProcessId> wavefront; 77 for (std::set<ProcessId>::const_iterator i = roots.begin(); i != roots.end(); 78 ++i) { 79 wavefront.insert(*i); 80 } 81 82 while (wavefront.size()) { 83 std::set<ProcessId> next_wavefront; 84 for (std::vector<ProcessEntry>::const_iterator i = processes.begin(); 85 i != processes.end(); ++i) { 86 if (wavefront.count(i->parent_pid())) { 87 out->insert(i->pid()); 88 next_wavefront.insert(i->pid()); 89 } 90 } 91 92 wavefront.clear(); 93 wavefront.swap(next_wavefront); 94 } 95} 96 97} // namespace 98 99MemoryDetails::MemoryDetails() 100 : user_metrics_mode_(UPDATE_USER_METRICS), 101 memory_growth_tracker_(NULL) { 102} 103 104ProcessData* MemoryDetails::ChromeBrowser() { 105 return &process_data_[0]; 106} 107 108void MemoryDetails::CollectProcessData( 109 const std::vector<ProcessMemoryInformation>& chrome_processes) { 110 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 111 112 std::vector<ProcessMemoryInformation> all_processes(chrome_processes); 113 AddNonChildChromeProcesses(&all_processes); 114 115 std::vector<ProcessEntry> processes; 116 base::ProcessIterator process_iter(NULL); 117 while (const ProcessEntry* process_entry = process_iter.NextProcessEntry()) { 118 processes.push_back(*process_entry); 119 } 120 121 std::set<ProcessId> roots; 122 roots.insert(base::GetCurrentProcId()); 123 for (std::vector<ProcessMemoryInformation>::const_iterator 124 i = all_processes.begin(); i != all_processes.end(); ++i) { 125 roots.insert(i->pid); 126 } 127 128 std::set<ProcessId> current_browser_processes; 129 GetAllChildren(processes, roots, ¤t_browser_processes); 130 131 ProcessData current_browser; 132 GetProcessDataMemoryInformation(current_browser_processes, ¤t_browser); 133 current_browser.name = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME); 134 current_browser.process_name = 135 base::ASCIIToUTF16(chrome::kBrowserProcessExecutableName); 136 process_data_.push_back(current_browser); 137 138 // Finally return to the browser thread. 139 BrowserThread::PostTask( 140 BrowserThread::UI, FROM_HERE, 141 base::Bind(&MemoryDetails::CollectChildInfoOnUIThread, this)); 142} 143