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