123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "chrome/browser/memory_details.h"
- #include <memory>
- #include <set>
- #include <string>
- #include <vector>
- #include "base/bind.h"
- #include "base/process/process_iterator.h"
- #include "base/strings/utf_string_conversions.h"
- #include "base/threading/scoped_blocking_call.h"
- #include "chrome/common/chrome_constants.h"
- #include "chrome/grit/chromium_strings.h"
- #include "content/public/browser/browser_task_traits.h"
- #include "content/public/browser/browser_thread.h"
- #include "content/public/common/process_type.h"
- #include "ui/base/l10n/l10n_util.h"
- using base::ProcessEntry;
- using base::ProcessId;
- namespace {
- // A helper for |CollectProcessData()| to include the chrome sandboxed
- // processes in android which are not running as a child of the browser
- // process.
- void AddNonChildChromeProcesses(
- std::vector<ProcessMemoryInformation>* processes) {
- base::ProcessIterator process_iter(NULL);
- while (const ProcessEntry* process_entry = process_iter.NextProcessEntry()) {
- const std::vector<std::string>& cmd_args = process_entry->cmd_line_args();
- if (cmd_args.empty() ||
- cmd_args[0].find(chrome::kHelperProcessExecutableName) ==
- std::string::npos) {
- continue;
- }
- ProcessMemoryInformation info;
- info.pid = process_entry->pid();
- processes->push_back(info);
- }
- }
- // For each of the pids, collect memory information about that process
- // and append a record to |out|.
- void GetProcessDataMemoryInformation(
- const std::set<ProcessId>& pids, ProcessData* out) {
- for (std::set<ProcessId>::const_iterator i = pids.begin(); i != pids.end();
- ++i) {
- ProcessMemoryInformation pmi;
- pmi.pid = *i;
- pmi.num_processes = 1;
- base::ProcessId current_pid = base::GetCurrentProcId();
- if (pmi.pid == current_pid)
- pmi.process_type = content::PROCESS_TYPE_BROWSER;
- else
- pmi.process_type = content::PROCESS_TYPE_UNKNOWN;
- std::unique_ptr<base::ProcessMetrics> metrics(
- base::ProcessMetrics::CreateProcessMetrics(*i));
- // TODO(ssid): Reading "/proc/fd" only works for current process. For child
- // processes, the values need to be computed by the process itself.
- if (pmi.pid == current_pid) {
- pmi.num_open_fds = metrics->GetOpenFdCount();
- pmi.open_fds_soft_limit = metrics->GetOpenFdSoftLimit();
- }
- out->processes.push_back(pmi);
- }
- }
- // Find all children of the given process.
- void GetAllChildren(const std::vector<ProcessEntry>& processes,
- const std::set<ProcessId>& roots,
- std::set<ProcessId>* out) {
- *out = roots;
- std::set<ProcessId> wavefront;
- for (std::set<ProcessId>::const_iterator i = roots.begin(); i != roots.end();
- ++i) {
- wavefront.insert(*i);
- }
- while (wavefront.size()) {
- std::set<ProcessId> next_wavefront;
- for (std::vector<ProcessEntry>::const_iterator i = processes.begin();
- i != processes.end(); ++i) {
- if (wavefront.count(i->parent_pid())) {
- out->insert(i->pid());
- next_wavefront.insert(i->pid());
- }
- }
- wavefront.clear();
- wavefront.swap(next_wavefront);
- }
- }
- } // namespace
- MemoryDetails::MemoryDetails() {
- }
- ProcessData* MemoryDetails::ChromeBrowser() {
- return &process_data_[0];
- }
- void MemoryDetails::CollectProcessData(
- const std::vector<ProcessMemoryInformation>& chrome_processes) {
- base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
- base::BlockingType::WILL_BLOCK);
- std::vector<ProcessMemoryInformation> all_processes(chrome_processes);
- AddNonChildChromeProcesses(&all_processes);
- std::vector<ProcessEntry> processes;
- base::ProcessIterator process_iter(NULL);
- while (const ProcessEntry* process_entry = process_iter.NextProcessEntry()) {
- processes.push_back(*process_entry);
- }
- std::set<ProcessId> roots;
- roots.insert(base::GetCurrentProcId());
- for (std::vector<ProcessMemoryInformation>::const_iterator
- i = all_processes.begin(); i != all_processes.end(); ++i) {
- roots.insert(i->pid);
- }
- std::set<ProcessId> current_browser_processes;
- GetAllChildren(processes, roots, ¤t_browser_processes);
- ProcessData current_browser;
- GetProcessDataMemoryInformation(current_browser_processes, ¤t_browser);
- current_browser.name = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
- current_browser.process_name =
- base::ASCIIToUTF16(chrome::kBrowserProcessExecutableName);
- process_data_.push_back(current_browser);
- // Finally return to the browser thread.
- content::GetUIThreadTaskRunner({})->PostTask(
- FROM_HERE,
- base::BindOnce(&MemoryDetails::CollectChildInfoOnUIThread, this));
- }
|