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. 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 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: 66 explicit ChildProcessFilter(base::ProcessId parent_pid) 67 : parent_pids_(&parent_pid, (&parent_pid) + 1) {} 68 69 explicit ChildProcessFilter(const std::vector<base::ProcessId>& parent_pids) 70 : parent_pids_(parent_pids.begin(), parent_pids.end()) {} 71 72 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 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 131 size_t ChromeTestProcessMetrics::GetPagefileUsage() { 132 return process_metrics_->GetPagefileUsage(); 133 } 134 135 size_t ChromeTestProcessMetrics::GetWorkingSetSize() { 136 return process_metrics_->GetWorkingSetSize(); 137 } 138 139 #endif // !defined(OS_MACOSX) 140 141 ChromeTestProcessMetrics::~ChromeTestProcessMetrics() {} 142 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