| OLD | NEW |
| (Empty) |
| 1 // Copyright 2008-2009 Google Inc. | |
| 2 // | |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
| 4 // you may not use this file except in compliance with the License. | |
| 5 // You may obtain a copy of the License at | |
| 6 // | |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | |
| 8 // | |
| 9 // Unless required by applicable law or agreed to in writing, software | |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 12 // See the License for the specific language governing permissions and | |
| 13 // limitations under the License. | |
| 14 // ======================================================================== | |
| 15 | |
| 16 #include "omaha/tools/goopdump/process_monitor.h" | |
| 17 | |
| 18 #include <tlhelp32.h> | |
| 19 #include <map> | |
| 20 #include <vector> | |
| 21 | |
| 22 #include "omaha/common/debug.h" | |
| 23 #include "omaha/common/error.h" | |
| 24 #include "omaha/common/logging.h" | |
| 25 #include "omaha/tools/goopdump/process_commandline.h" | |
| 26 | |
| 27 namespace omaha { | |
| 28 | |
| 29 ProcessMonitor::ProcessMonitor() : is_running_(false), callback_(NULL) { | |
| 30 } | |
| 31 | |
| 32 ProcessMonitor::~ProcessMonitor() { | |
| 33 } | |
| 34 | |
| 35 HRESULT ProcessMonitor::Start(ProcessMonitorCallbackInterface* callback, | |
| 36 const TCHAR* process_name_pattern) { | |
| 37 std::vector<CString> patterns; | |
| 38 patterns.push_back(CString(process_name_pattern)); | |
| 39 return StartWithPatterns(callback, patterns); | |
| 40 } | |
| 41 | |
| 42 HRESULT ProcessMonitor::StartWithPatterns( | |
| 43 ProcessMonitorCallbackInterface* callback, | |
| 44 const std::vector<CString>& process_name_patterns) { | |
| 45 SingleLock lock(&lock_); | |
| 46 | |
| 47 if (is_running_) { | |
| 48 return E_UNEXPECTED; | |
| 49 } | |
| 50 | |
| 51 EnableDebugPrivilege(); | |
| 52 | |
| 53 std::vector<CString>::const_iterator it = process_name_patterns.begin(); | |
| 54 for (; it != process_name_patterns.end(); ++it) { | |
| 55 CString pattern = *it; | |
| 56 pattern.MakeLower(); | |
| 57 process_name_patterns_.push_back(pattern); | |
| 58 } | |
| 59 | |
| 60 callback_ = callback; | |
| 61 | |
| 62 reset(event_thread_exit_, ::CreateEvent(NULL, FALSE, FALSE, NULL)); | |
| 63 if (!valid(event_thread_exit_)) { | |
| 64 return HRESULTFromLastError(); | |
| 65 } | |
| 66 | |
| 67 reset(monitor_thread_, ::CreateThread(NULL, | |
| 68 0, | |
| 69 &ProcessMonitor::MonitorThreadProc, | |
| 70 this, | |
| 71 0, | |
| 72 NULL)); | |
| 73 if (!valid(monitor_thread_)) { | |
| 74 return HRESULTFromLastError(); | |
| 75 } | |
| 76 | |
| 77 is_running_ = true; | |
| 78 return S_OK; | |
| 79 } | |
| 80 | |
| 81 HRESULT ProcessMonitor::Stop() { | |
| 82 SingleLock lock(&lock_); | |
| 83 | |
| 84 if (!is_running_) { | |
| 85 return E_UNEXPECTED; | |
| 86 } | |
| 87 | |
| 88 ::SetEvent(get(event_thread_exit_)); | |
| 89 ::WaitForSingleObject(get(monitor_thread_), INFINITE); | |
| 90 | |
| 91 is_running_ = false; | |
| 92 return S_OK; | |
| 93 } | |
| 94 | |
| 95 DWORD ProcessMonitor::MonitorThreadProc(void* param) { | |
| 96 ProcessMonitor* monitor = static_cast<ProcessMonitor*>(param); | |
| 97 if (monitor) { | |
| 98 return monitor->MonitorProc(); | |
| 99 } | |
| 100 return 1; | |
| 101 } | |
| 102 | |
| 103 DWORD ProcessMonitor::MonitorProc() { | |
| 104 // 200ms idle between polling for process creation. | |
| 105 const DWORD kWaitTimeoutMs = 200; | |
| 106 | |
| 107 MapHandleToDword map_handle_pid; | |
| 108 bool keep_running = true; | |
| 109 | |
| 110 do { | |
| 111 size_t map_count = map_handle_pid.size(); | |
| 112 size_t pids_to_monitor = (map_count < MAXIMUM_WAIT_OBJECTS) ? | |
| 113 map_count : MAXIMUM_WAIT_OBJECTS; | |
| 114 | |
| 115 std::vector<HANDLE> handles; | |
| 116 handles.push_back(get(event_thread_exit_)); | |
| 117 | |
| 118 MapHandleToDwordIterator iter = map_handle_pid.begin(); | |
| 119 for (; (iter != map_handle_pid.end()) && (handles.size() < pids_to_monitor); | |
| 120 ++iter) { | |
| 121 handles.push_back(iter->first); | |
| 122 } | |
| 123 | |
| 124 DWORD wait_result = ::WaitForMultipleObjects(handles.size(), | |
| 125 &handles.front(), | |
| 126 FALSE, | |
| 127 kWaitTimeoutMs); | |
| 128 if (wait_result < (WAIT_OBJECT_0 + handles.size())) { | |
| 129 HANDLE signalled = handles[wait_result - WAIT_OBJECT_0]; | |
| 130 | |
| 131 if (signalled == get(event_thread_exit_)) { | |
| 132 // We've been signalled to exit. | |
| 133 keep_running = false; | |
| 134 } else { | |
| 135 // One of the PIDs exited. | |
| 136 MapHandleToDwordIterator iter = map_handle_pid.begin(); | |
| 137 for (; iter != map_handle_pid.end(); ++iter) { | |
| 138 if (iter->first == signalled) { | |
| 139 OnProcessRemoved(iter->second); | |
| 140 ::CloseHandle(iter->first); | |
| 141 map_handle_pid.erase(iter); | |
| 142 break; | |
| 143 } | |
| 144 } | |
| 145 } | |
| 146 } else if (wait_result == WAIT_TIMEOUT) { | |
| 147 // Our polling time is up. Go look for running instances of the | |
| 148 // process we're monitoring and look for differences in the list of PIDs. | |
| 149 UpdateProcessList(&map_handle_pid); | |
| 150 } else { | |
| 151 // Some type of failure occurred. | |
| 152 keep_running = false; | |
| 153 } | |
| 154 } while (keep_running); | |
| 155 | |
| 156 return 0; | |
| 157 } | |
| 158 | |
| 159 void ProcessMonitor::CleanupHandleMap(MapHandleToDword* map_handle_pid) { | |
| 160 ASSERT1(map_handle_pid); | |
| 161 MapHandleToDwordIterator iter = map_handle_pid->begin(); | |
| 162 for (; iter != map_handle_pid->end(); ++iter) { | |
| 163 ::CloseHandle(iter->first); | |
| 164 } | |
| 165 map_handle_pid->clear(); | |
| 166 } | |
| 167 | |
| 168 bool ProcessMonitor::UpdateProcessList(MapHandleToDword* map_handle_pid) { | |
| 169 ASSERT1(map_handle_pid); | |
| 170 scoped_handle process_snap; | |
| 171 reset(process_snap, ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)); | |
| 172 if (!valid(process_snap)) { | |
| 173 return false; | |
| 174 } | |
| 175 | |
| 176 PROCESSENTRY32 process_entry32 = {0}; | |
| 177 process_entry32.dwSize = sizeof(PROCESSENTRY32); | |
| 178 | |
| 179 if (!::Process32First(get(process_snap), &process_entry32)) { | |
| 180 return false; | |
| 181 } | |
| 182 | |
| 183 do { | |
| 184 CString exe_file_name = process_entry32.szExeFile; | |
| 185 exe_file_name.MakeLower(); | |
| 186 | |
| 187 typedef std::vector<CString>::iterator VectorIterator; | |
| 188 VectorIterator pattern_iter = process_name_patterns_.begin(); | |
| 189 for (; pattern_iter != process_name_patterns_.end(); ++pattern_iter) { | |
| 190 CString process_pattern = *pattern_iter; | |
| 191 if (exe_file_name.Find(process_pattern) >= 0) { | |
| 192 // We've found a match. See if this ProcessID is already in our list | |
| 193 bool is_found = false; | |
| 194 MapHandleToDwordIterator iter = map_handle_pid->begin(); | |
| 195 for (; iter != map_handle_pid->end(); ++iter) { | |
| 196 if (iter->second == process_entry32.th32ProcessID) { | |
| 197 is_found = true; | |
| 198 break; | |
| 199 } | |
| 200 } | |
| 201 | |
| 202 if (!is_found) { | |
| 203 // Opening this handle and we'll give ownership of this HANDLE to | |
| 204 // map_handle_pid. | |
| 205 HANDLE process_handle = ::OpenProcess(PROCESS_ALL_ACCESS, | |
| 206 FALSE, | |
| 207 process_entry32.th32ProcessID); | |
| 208 if (process_handle) { | |
| 209 (*map_handle_pid)[process_handle] = process_entry32.th32ProcessID; | |
| 210 OnProcessAdded(process_entry32.th32ProcessID, process_pattern); | |
| 211 } | |
| 212 } | |
| 213 } | |
| 214 } | |
| 215 } while (::Process32Next(get(process_snap), &process_entry32)); | |
| 216 | |
| 217 return true; | |
| 218 } | |
| 219 | |
| 220 void ProcessMonitor::OnProcessAdded(DWORD process_id, | |
| 221 const CString& process_pattern) { | |
| 222 if (callback_) { | |
| 223 callback_->OnProcessAdded(process_id, process_pattern); | |
| 224 } | |
| 225 } | |
| 226 | |
| 227 void ProcessMonitor::OnProcessRemoved(DWORD process_id) { | |
| 228 if (callback_) { | |
| 229 callback_->OnProcessRemoved(process_id); | |
| 230 } | |
| 231 } | |
| 232 | |
| 233 } // namespace omaha | |
| 234 | |
| OLD | NEW |