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 |