Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2011 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/test/base/chrome_process_util.h"
      6 
      7 #include <set>
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/command_line.h"
     12 #include "base/process/kill.h"
     13 #include "base/process/process_iterator.h"
     14 #include "base/time/time.h"
     15 #include "chrome/common/chrome_constants.h"
     16 #include "chrome/test/base/test_switches.h"
     17 #include "content/public/common/result_codes.h"
     18 
     19 using base::TimeDelta;
     20 using base::TimeTicks;
     21 
     22 namespace {
     23 
     24 // Returns the executable name of the current Chrome browser process.
     25 const base::FilePath::CharType* GetRunningBrowserExecutableName() {
     26   const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
     27   if (cmd_line->HasSwitch(switches::kEnableChromiumBranding))
     28     return chrome::kBrowserProcessExecutableNameChromium;
     29   return chrome::kBrowserProcessExecutableName;
     30 }
     31 
     32 // Returns the executable name of the current Chrome helper process.
     33 std::vector<base::FilePath::StringType> GetRunningHelperExecutableNames() {
     34   base::FilePath::StringType name;
     35   const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
     36   if (cmd_line->HasSwitch(switches::kEnableChromiumBranding)) {
     37     name = chrome::kHelperProcessExecutableNameChromium;
     38   } else {
     39     name = chrome::kHelperProcessExecutableName;
     40   }
     41 
     42   std::vector<base::FilePath::StringType> names;
     43   names.push_back(name);
     44 
     45 #if defined(OS_MACOSX)
     46   // The helper might show up as these different flavors depending on the
     47   // executable flags required.
     48   for (const char* const* suffix = chrome::kHelperFlavorSuffixes;
     49        *suffix;
     50        ++suffix) {
     51     std::string flavor_name(name);
     52     flavor_name.append(1, ' ');
     53     flavor_name.append(*suffix);
     54     names.push_back(flavor_name);
     55   }
     56 #endif
     57 
     58   return names;
     59 }
     60 
     61 }  // namespace
     62 
     63 void TerminateAllChromeProcesses(const ChromeProcessList& process_pids) {
     64   ChromeProcessList::const_iterator it;
     65   for (it = process_pids.begin(); it != process_pids.end(); ++it) {
     66     base::ProcessHandle handle;
     67     if (!base::OpenProcessHandle(*it, &handle)) {
     68       // Ignore processes for which we can't open the handle. We don't
     69       // guarantee that all processes will terminate, only try to do so.
     70       continue;
     71     }
     72 
     73     base::KillProcess(handle, content::RESULT_CODE_KILLED, true);
     74     base::CloseProcessHandle(handle);
     75   }
     76 }
     77 
     78 class ChildProcessFilter : public base::ProcessFilter {
     79  public:
     80   explicit ChildProcessFilter(base::ProcessId parent_pid)
     81       : parent_pids_(&parent_pid, (&parent_pid) + 1) {}
     82 
     83   explicit ChildProcessFilter(const std::vector<base::ProcessId>& parent_pids)
     84       : parent_pids_(parent_pids.begin(), parent_pids.end()) {}
     85 
     86   virtual bool Includes(const base::ProcessEntry& entry) const OVERRIDE {
     87     return parent_pids_.find(entry.parent_pid()) != parent_pids_.end();
     88   }
     89 
     90  private:
     91   const std::set<base::ProcessId> parent_pids_;
     92 
     93   DISALLOW_COPY_AND_ASSIGN(ChildProcessFilter);
     94 };
     95 
     96 ChromeProcessList GetRunningChromeProcesses(base::ProcessId browser_pid) {
     97   const base::FilePath::CharType* executable_name =
     98       GetRunningBrowserExecutableName();
     99   ChromeProcessList result;
    100   if (browser_pid == static_cast<base::ProcessId>(-1))
    101     return result;
    102 
    103   ChildProcessFilter filter(browser_pid);
    104   base::NamedProcessIterator it(executable_name, &filter);
    105   while (const base::ProcessEntry* process_entry = it.NextProcessEntry()) {
    106     result.push_back(process_entry->pid());
    107   }
    108 
    109 #if defined(OS_POSIX) && !defined(OS_MACOSX)
    110   // On Unix we might be running with a zygote process for the renderers.
    111   // Because of that we sweep the list of processes again and pick those which
    112   // are children of one of the processes that we've already seen.
    113   {
    114     ChildProcessFilter filter(result);
    115     base::NamedProcessIterator it(executable_name, &filter);
    116     while (const base::ProcessEntry* process_entry = it.NextProcessEntry())
    117       result.push_back(process_entry->pid());
    118   }
    119 #endif  // defined(OS_POSIX) && !defined(OS_MACOSX)
    120 
    121 #if defined(OS_POSIX)
    122   // On Mac OS X we run the subprocesses with a different bundle, and
    123   // on Linux via /proc/self/exe, so they end up with a different
    124   // name.  We must collect them in a second pass.
    125   {
    126     std::vector<base::FilePath::StringType> names =
    127         GetRunningHelperExecutableNames();
    128     for (size_t i = 0; i < names.size(); ++i) {
    129       base::FilePath::StringType name = names[i];
    130       ChildProcessFilter filter(browser_pid);
    131       base::NamedProcessIterator it(name, &filter);
    132       while (const base::ProcessEntry* process_entry = it.NextProcessEntry())
    133         result.push_back(process_entry->pid());
    134     }
    135   }
    136 #endif  // defined(OS_POSIX)
    137 
    138   result.push_back(browser_pid);
    139 
    140   return result;
    141 }
    142 
    143 #if !defined(OS_MACOSX)
    144 
    145 size_t ChromeTestProcessMetrics::GetPagefileUsage() {
    146   return process_metrics_->GetPagefileUsage();
    147 }
    148 
    149 size_t ChromeTestProcessMetrics::GetWorkingSetSize() {
    150   return process_metrics_->GetWorkingSetSize();
    151 }
    152 
    153 #endif  // !defined(OS_MACOSX)
    154 
    155 ChromeTestProcessMetrics::~ChromeTestProcessMetrics() {}
    156 
    157 ChromeTestProcessMetrics::ChromeTestProcessMetrics(
    158     base::ProcessHandle process) {
    159 #if !defined(OS_MACOSX)
    160   process_metrics_.reset(
    161       base::ProcessMetrics::CreateProcessMetrics(process));
    162 #else
    163   process_metrics_.reset(
    164       base::ProcessMetrics::CreateProcessMetrics(process, NULL));
    165 #endif
    166   process_handle_ = process;
    167 }
    168