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