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"
13 #include "base/apple/foundation_util.h"
14 #include "base/file_version_info.h"
15 #include "base/files/file_path.h"
16 #include "base/functional/bind.h"
17 #include "base/process/process_iterator.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "base/threading/scoped_blocking_call.h"
21 #include "base/threading/thread.h"
22 #include "chrome/common/chrome_constants.h"
23 #include "chrome/common/url_constants.h"
24 #include "chrome/grit/branded_strings.h"
25 #include "components/version_info/version_info.h"
26 #include "content/public/browser/browser_child_process_host.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"
34 // A helper for |CollectProcessData()|, collecting data on the Chrome/Chromium
35 // process with PID |pid|. The collected data is added to |processes|.
36 void CollectProcessDataForChromeProcess(
37 const std::vector<ProcessMemoryInformation>& child_info,
39 ProcessMemoryInformationList* processes) {
40 ProcessMemoryInformation info;
42 if (info.pid == base::GetCurrentProcId())
43 info.process_type = content::PROCESS_TYPE_BROWSER;
45 info.process_type = content::PROCESS_TYPE_UNKNOWN;
47 info.product_name = base::ASCIIToUTF16(version_info::GetProductName());
48 info.version = base::ASCIIToUTF16(version_info::GetVersionNumber());
50 // A PortProvider is not necessary to acquire information about the number
51 // of open file descriptors.
52 std::unique_ptr<base::ProcessMetrics> metrics(
53 base::ProcessMetrics::CreateProcessMetrics(pid, nullptr));
54 info.num_open_fds = metrics->GetOpenFdCount();
55 info.open_fds_soft_limit = metrics->GetOpenFdSoftLimit();
57 // Check if this is one of the child processes whose data was already
58 // collected and exists in |child_data|.
59 for (const ProcessMemoryInformation& child : child_info) {
60 if (child.pid == info.pid) {
61 info.titles = child.titles;
62 info.process_type = child.process_type;
67 processes->push_back(info);
72 MemoryDetails::MemoryDetails() {
73 const base::FilePath browser_process_path =
74 base::GetProcessExecutablePath(base::GetCurrentProcessHandle());
77 process.name = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
78 process.process_name =
79 base::UTF8ToUTF16(browser_process_path.BaseName().value());
80 process_data_.push_back(process);
83 ProcessData* MemoryDetails::ChromeBrowser() {
84 return &process_data_[0];
87 void MemoryDetails::CollectProcessData(
88 const std::vector<ProcessMemoryInformation>& child_info) {
89 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
90 base::BlockingType::MAY_BLOCK);
93 process_data_[0].processes.clear();
95 // First, we use |NamedProcessIterator| to get the PIDs of the processes we're
96 // interested in; we save our results to avoid extra calls to
97 // |NamedProcessIterator| (for performance reasons) and to avoid additional
98 // inconsistencies caused by racing. Then we run |/bin/ps| *once* to get
99 // information on those PIDs. Then we used our saved information to iterate
100 // over browsers, then over PIDs.
102 // Get PIDs of main browser processes.
103 std::vector<base::ProcessId> all_pids;
105 base::NamedProcessIterator process_it(
106 base::UTF16ToUTF8(process_data_[0].process_name), NULL);
108 while (const base::ProcessEntry* entry = process_it.NextProcessEntry()) {
109 all_pids.push_back(entry->pid());
113 // Get PIDs of the helper.
115 base::NamedProcessIterator helper_it(chrome::kHelperProcessExecutableName,
116 NULL, /*use_prefix_match=*/true);
117 while (const base::ProcessEntry* entry = helper_it.NextProcessEntry()) {
118 all_pids.push_back(entry->pid());
122 ProcessMemoryInformationList* chrome_processes = &process_data_[0].processes;
124 // Collect data about Chrome/Chromium.
125 for (const base::ProcessId& pid : all_pids)
126 CollectProcessDataForChromeProcess(child_info, pid, chrome_processes);
128 // Finally return to the browser thread.
129 content::GetUIThreadTaskRunner({})->PostTask(
131 base::BindOnce(&MemoryDetails::CollectChildInfoOnUIThread, this));