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"
15 #include "base/files/file_util.h"
16 #include "base/functional/bind.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 "build/chromeos_buildflags.h"
25 #include "chrome/common/chrome_constants.h"
26 #include "chrome/grit/branded_strings.h"
27 #include "content/public/browser/browser_task_traits.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "content/public/common/process_type.h"
30 #include "ui/base/l10n/l10n_util.h"
32 using base::ProcessEntry;
40 typedef std::map<pid_t, Process> ProcessMap;
42 // Get information on all the processes running on the system.
43 ProcessMap GetProcesses() {
46 base::ProcessIterator process_iter(nullptr);
47 while (const ProcessEntry* process_entry = process_iter.NextProcessEntry()) {
49 process.pid = process_entry->pid();
50 process.parent = process_entry->parent_pid();
51 map.insert(std::make_pair(process.pid, process));
56 // For each of a list of pids, collect memory information about that process.
57 ProcessData GetProcessDataMemoryInformation(
58 const std::vector<pid_t>& pids) {
59 ProcessData process_data;
60 for (pid_t pid : pids) {
61 ProcessMemoryInformation pmi;
64 pmi.num_processes = 1;
66 if (pmi.pid == base::GetCurrentProcId())
67 pmi.process_type = content::PROCESS_TYPE_BROWSER;
69 pmi.process_type = content::PROCESS_TYPE_UNKNOWN;
71 std::unique_ptr<base::ProcessMetrics> metrics(
72 base::ProcessMetrics::CreateProcessMetrics(pid));
73 pmi.num_open_fds = metrics->GetOpenFdCount();
74 pmi.open_fds_soft_limit = metrics->GetOpenFdSoftLimit();
76 process_data.processes.push_back(pmi);
81 // Find all children of the given process with pid |root|.
82 std::vector<pid_t> GetAllChildren(const ProcessMap& processes, pid_t root) {
83 std::vector<pid_t> children;
84 children.push_back(root);
86 std::set<pid_t> wavefront, next_wavefront;
87 wavefront.insert(root);
89 while (wavefront.size()) {
90 for (const auto& entry : processes) {
91 const Process& process = entry.second;
92 if (wavefront.count(process.parent)) {
93 children.push_back(process.pid);
94 next_wavefront.insert(process.pid);
99 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>& child_info) {
115 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
116 base::BlockingType::MAY_BLOCK);
118 ProcessMap process_map = GetProcesses();
119 std::set<pid_t> browsers_found;
121 ProcessData current_browser =
122 GetProcessDataMemoryInformation(GetAllChildren(process_map, getpid()));
123 current_browser.name = l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME);
124 current_browser.process_name = u"chrome";
126 for (auto i = current_browser.processes.begin();
127 i != current_browser.processes.end(); ++i) {
128 // Check if this is one of the child processes whose data we collected
129 // on the IO thread, and if so copy over that data.
130 for (size_t child = 0; child < child_info.size(); child++) {
131 if (child_info[child].pid != i->pid)
133 i->titles = child_info[child].titles;
134 i->process_type = child_info[child].process_type;
139 process_data_.push_back(current_browser);
141 #if BUILDFLAG(IS_CHROMEOS_ASH)
142 base::GetSwapInfo(&swap_info_);
145 // Finally return to the browser thread.
146 content::GetUIThreadTaskRunner({})->PostTask(
148 base::BindOnce(&MemoryDetails::CollectChildInfoOnUIThread, this));