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.
5 #include "chrome/browser/memory_details.h"
15 #include "base/bind.h"
16 #include "base/files/file_util.h"
17 #include "base/process/process_iterator.h"
18 #include "base/process/process_metrics.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "base/threading/scoped_blocking_call.h"
23 #include "build/build_config.h"
24 #include "chrome/common/chrome_constants.h"
25 #include "chrome/grit/chromium_strings.h"
26 #include "content/public/browser/browser_task_traits.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "content/public/common/process_type.h"
29 #include "ui/base/l10n/l10n_util.h"
31 using base::ProcessEntry;
39 typedef std::map<pid_t, Process> ProcessMap;
41 // Get information on all the processes running on the system.
42 ProcessMap GetProcesses() {
45 base::ProcessIterator process_iter(NULL);
46 while (const ProcessEntry* process_entry = process_iter.NextProcessEntry()) {
48 process.pid = process_entry->pid();
49 process.parent = process_entry->parent_pid();
50 map.insert(std::make_pair(process.pid, process));
55 // For each of a list of pids, collect memory information about that process.
56 ProcessData GetProcessDataMemoryInformation(
57 const std::vector<pid_t>& pids) {
58 ProcessData process_data;
59 for (pid_t pid : pids) {
60 ProcessMemoryInformation pmi;
63 pmi.num_processes = 1;
65 if (pmi.pid == base::GetCurrentProcId())
66 pmi.process_type = content::PROCESS_TYPE_BROWSER;
68 pmi.process_type = content::PROCESS_TYPE_UNKNOWN;
70 std::unique_ptr<base::ProcessMetrics> metrics(
71 base::ProcessMetrics::CreateProcessMetrics(pid));
72 pmi.num_open_fds = metrics->GetOpenFdCount();
73 pmi.open_fds_soft_limit = metrics->GetOpenFdSoftLimit();
75 process_data.processes.push_back(pmi);
80 // Find all children of the given process with pid |root|.
81 std::vector<pid_t> GetAllChildren(const ProcessMap& processes, pid_t root) {
82 std::vector<pid_t> children;
83 children.push_back(root);
85 std::set<pid_t> wavefront, next_wavefront;
86 wavefront.insert(root);
88 while (wavefront.size()) {
89 for (const auto& entry : processes) {
90 const Process& process = entry.second;
91 if (wavefront.count(process.parent)) {
92 children.push_back(process.pid);
93 next_wavefront.insert(process.pid);
98 wavefront.swap(next_wavefront);
105 MemoryDetails::MemoryDetails() {
108 ProcessData* MemoryDetails::ChromeBrowser() {
109 return &process_data_[0];
112 void MemoryDetails::CollectProcessData(
113 const std::vector<ProcessMemoryInformation>& child_info) {
114 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
115 base::BlockingType::MAY_BLOCK);
117 ProcessMap process_map = GetProcesses();
118 std::set<pid_t> browsers_found;
120 ProcessData current_browser =
121 GetProcessDataMemoryInformation(GetAllChildren(process_map, getpid()));
122 current_browser.name = l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME);
123 current_browser.process_name = base::ASCIIToUTF16("chrome");
125 for (auto i = current_browser.processes.begin();
126 i != current_browser.processes.end(); ++i) {
127 // Check if this is one of the child processes whose data we collected
128 // on the IO thread, and if so copy over that data.
129 for (size_t child = 0; child < child_info.size(); child++) {
130 if (child_info[child].pid != i->pid)
132 i->titles = child_info[child].titles;
133 i->process_type = child_info[child].process_type;
138 process_data_.push_back(current_browser);
140 #if defined(OS_CHROMEOS)
141 base::GetSwapInfo(&swap_info_);
144 // Finally return to the browser thread.
145 content::GetUIThreadTaskRunner({})->PostTask(
147 base::BindOnce(&MemoryDetails::CollectChildInfoOnUIThread, this));