Home | History | Annotate | Download | only in browser
      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.
      4 
      5 #include "chrome/browser/memory_details.h"
      6 
      7 #include <set>
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/bind.h"
     12 #include "base/memory/scoped_ptr.h"
     13 #include "base/process/process_iterator.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "chrome/common/chrome_constants.h"
     16 #include "chrome/grit/chromium_strings.h"
     17 #include "content/public/browser/browser_thread.h"
     18 #include "content/public/common/process_type.h"
     19 #include "ui/base/l10n/l10n_util.h"
     20 
     21 using base::ProcessEntry;
     22 using base::ProcessId;
     23 using content::BrowserThread;
     24 
     25 namespace {
     26 
     27 // A helper for |CollectProcessData()| to include the chrome sandboxed
     28 // processes in android which are not running as a child of the browser
     29 // process.
     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) ==
     37             std::string::npos) {
     38       continue;
     39     }
     40     ProcessMemoryInformation info;
     41     info.pid = process_entry->pid();
     42     processes->push_back(info);
     43   }
     44 }
     45 
     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();
     51        ++i) {
     52     ProcessMemoryInformation pmi;
     53 
     54     pmi.pid = *i;
     55     pmi.num_processes = 1;
     56 
     57     if (pmi.pid == base::GetCurrentProcId())
     58       pmi.process_type = content::PROCESS_TYPE_BROWSER;
     59     else
     60       pmi.process_type = content::PROCESS_TYPE_UNKNOWN;
     61 
     62     scoped_ptr<base::ProcessMetrics> metrics(
     63         base::ProcessMetrics::CreateProcessMetrics(*i));
     64     metrics->GetWorkingSetKBytes(&pmi.working_set);
     65 
     66     out->processes.push_back(pmi);
     67   }
     68 }
     69 
     70 // Find all children of the given process.
     71 void GetAllChildren(const std::vector<ProcessEntry>& processes,
     72                     const std::set<ProcessId>& roots,
     73                     std::set<ProcessId>* out) {
     74   *out = roots;
     75 
     76   std::set<ProcessId> wavefront;
     77   for (std::set<ProcessId>::const_iterator i = roots.begin(); i != roots.end();
     78        ++i) {
     79     wavefront.insert(*i);
     80   }
     81 
     82   while (wavefront.size()) {
     83     std::set<ProcessId> next_wavefront;
     84     for (std::vector<ProcessEntry>::const_iterator i = processes.begin();
     85          i != processes.end(); ++i) {
     86       if (wavefront.count(i->parent_pid())) {
     87         out->insert(i->pid());
     88         next_wavefront.insert(i->pid());
     89       }
     90     }
     91 
     92     wavefront.clear();
     93     wavefront.swap(next_wavefront);
     94   }
     95 }
     96 
     97 }  // namespace
     98 
     99 MemoryDetails::MemoryDetails()
    100     : user_metrics_mode_(UPDATE_USER_METRICS),
    101       memory_growth_tracker_(NULL) {
    102 }
    103 
    104 ProcessData* MemoryDetails::ChromeBrowser() {
    105   return &process_data_[0];
    106 }
    107 
    108 void MemoryDetails::CollectProcessData(
    109     const std::vector<ProcessMemoryInformation>& chrome_processes) {
    110   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    111 
    112   std::vector<ProcessMemoryInformation> all_processes(chrome_processes);
    113   AddNonChildChromeProcesses(&all_processes);
    114 
    115   std::vector<ProcessEntry> processes;
    116   base::ProcessIterator process_iter(NULL);
    117   while (const ProcessEntry* process_entry = process_iter.NextProcessEntry()) {
    118     processes.push_back(*process_entry);
    119   }
    120 
    121   std::set<ProcessId> roots;
    122   roots.insert(base::GetCurrentProcId());
    123   for (std::vector<ProcessMemoryInformation>::const_iterator
    124        i = all_processes.begin(); i != all_processes.end(); ++i) {
    125     roots.insert(i->pid);
    126   }
    127 
    128   std::set<ProcessId> current_browser_processes;
    129   GetAllChildren(processes, roots, &current_browser_processes);
    130 
    131   ProcessData current_browser;
    132   GetProcessDataMemoryInformation(current_browser_processes, &current_browser);
    133   current_browser.name = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
    134   current_browser.process_name =
    135       base::ASCIIToUTF16(chrome::kBrowserProcessExecutableName);
    136   process_data_.push_back(current_browser);
    137 
    138   // Finally return to the browser thread.
    139   BrowserThread::PostTask(
    140       BrowserThread::UI, FROM_HERE,
    141       base::Bind(&MemoryDetails::CollectChildInfoOnUIThread, this));
    142 }
    143