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 21 using base::ProcessEntry; 22 using base::ProcessId; 23 using content::BrowserThread; 24 25 namespace { 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. 30 void 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|. 48 void 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. 71 void 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 99 MemoryDetails::MemoryDetails() 100 : user_metrics_mode_(UPDATE_USER_METRICS), 101 memory_growth_tracker_(NULL) { 102 } 103 104 ProcessData* MemoryDetails::ChromeBrowser() { 105 return &process_data_[0]; 106 } 107 108 void 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