1 // Copyright 2012 The Chromium Authors
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"
12 #include "base/functional/bind.h"
13 #include "base/process/process_iterator.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/threading/scoped_blocking_call.h"
16 #include "chrome/common/chrome_constants.h"
17 #include "chrome/grit/branded_strings.h"
18 #include "content/public/browser/browser_task_traits.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/common/process_type.h"
21 #include "ui/base/l10n/l10n_util.h"
23 using base::ProcessEntry;
24 using base::ProcessId;
27 // A helper for |CollectProcessData()| to include the chrome sandboxed
28 // processes in android which are not running as a child of the browser
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) ==
40 ProcessMemoryInformation info;
41 info.pid = process_entry->pid();
42 processes->push_back(info);
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();
52 ProcessMemoryInformation pmi;
55 pmi.num_processes = 1;
57 base::ProcessId current_pid = base::GetCurrentProcId();
58 if (pmi.pid == current_pid)
59 pmi.process_type = content::PROCESS_TYPE_BROWSER;
61 pmi.process_type = content::PROCESS_TYPE_UNKNOWN;
63 std::unique_ptr<base::ProcessMetrics> metrics(
64 base::ProcessMetrics::CreateProcessMetrics(*i));
66 // TODO(ssid): Reading "/proc/fd" only works for current process. For child
67 // processes, the values need to be computed by the process itself.
68 if (pmi.pid == current_pid) {
69 pmi.num_open_fds = metrics->GetOpenFdCount();
70 pmi.open_fds_soft_limit = metrics->GetOpenFdSoftLimit();
73 out->processes.push_back(pmi);
77 // Find all children of the given process.
78 void GetAllChildren(const std::vector<ProcessEntry>& processes,
79 const std::set<ProcessId>& roots,
80 std::set<ProcessId>* out) {
83 std::set<ProcessId> wavefront;
84 for (std::set<ProcessId>::const_iterator i = roots.begin(); i != roots.end();
89 while (wavefront.size()) {
90 std::set<ProcessId> next_wavefront;
91 for (std::vector<ProcessEntry>::const_iterator i = processes.begin();
92 i != processes.end(); ++i) {
93 if (wavefront.count(i->parent_pid())) {
94 out->insert(i->pid());
95 next_wavefront.insert(i->pid());
100 wavefront.swap(next_wavefront);
106 MemoryDetails::MemoryDetails() {
109 ProcessData* MemoryDetails::ChromeBrowser() {
110 return &process_data_[0];
113 void MemoryDetails::CollectProcessData(
114 const std::vector<ProcessMemoryInformation>& chrome_processes) {
115 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
116 base::BlockingType::WILL_BLOCK);
118 std::vector<ProcessMemoryInformation> all_processes(chrome_processes);
119 AddNonChildChromeProcesses(&all_processes);
121 std::vector<ProcessEntry> processes;
122 base::ProcessIterator process_iter(NULL);
123 while (const ProcessEntry* process_entry = process_iter.NextProcessEntry()) {
124 processes.push_back(*process_entry);
127 std::set<ProcessId> roots;
128 roots.insert(base::GetCurrentProcId());
129 for (std::vector<ProcessMemoryInformation>::const_iterator
130 i = all_processes.begin(); i != all_processes.end(); ++i) {
131 roots.insert(i->pid);
134 std::set<ProcessId> current_browser_processes;
135 GetAllChildren(processes, roots, ¤t_browser_processes);
137 ProcessData current_browser;
138 GetProcessDataMemoryInformation(current_browser_processes, ¤t_browser);
139 current_browser.name = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
140 current_browser.process_name =
141 base::ASCIIToUTF16(chrome::kBrowserProcessExecutableName);
142 process_data_.push_back(current_browser);
144 // Finally return to the browser thread.
145 content::GetUIThreadTaskRunner({})->PostTask(
147 base::BindOnce(&MemoryDetails::CollectChildInfoOnUIThread, this));