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