Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(17)

Side by Side Diff: base/process.cc

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/process.h ('k') | base/process_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2004-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 // Defines class Process to incapsulate win32
17 // functions for creation and some manipulations of
18 // processes.
19
20 #include "omaha/base/process.h"
21
22 #include <ntsecapi.h>
23 #include <psapi.h>
24 #include <stierr.h>
25 #include <tlhelp32.h>
26 #include <vector>
27
28 #ifndef NT_SUCCESS
29 #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
30 #endif
31
32 #include "omaha/base/debug.h"
33 #include "omaha/base/disk.h"
34 #include "omaha/base/error.h"
35 #include "omaha/base/logging.h"
36 #include "omaha/base/scoped_any.h"
37 #include "omaha/base/string.h"
38 #include "omaha/base/system.h"
39 #include "omaha/base/system_info.h"
40 #include "omaha/base/utils.h"
41 #include "omaha/base/user_info.h"
42 #include "omaha/base/window_utils.h"
43
44 namespace omaha {
45
46 const int kNumRetriesToFindProcess = 4;
47 const int kFindProcessRetryIntervalMs = 500;
48 const int kMaxCmdLineLengthBytes = 4096;
49
50 // Constructor
51 Process::Process(const TCHAR* name,
52 const TCHAR* window_class_name)
53 : process_id_(0),
54 exit_code_(0),
55 number_of_restarts_(static_cast<uint32>(-1)),
56 name_(name),
57 shutdown_event_(NULL) {
58 ASSERT1(name);
59 command_line_ = name;
60 window_class_name_ = window_class_name;
61 }
62
63 // Constructor
64 Process::Process(uint32 process_id)
65 : process_id_(process_id),
66 exit_code_(0),
67 number_of_restarts_(static_cast<uint32>(-1)),
68 name_(itostr(static_cast<uint32>(process_id))),
69 shutdown_event_(NULL) {
70 reset(process_, ::OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
71 false,
72 process_id));
73 if (!valid(process_)) {
74 UTIL_LOG(LEVEL_ERROR,
75 (_T("[Process::Process - failed to open process][%u][0x%x]"),
76 process_id, HRESULTFromLastError()));
77 }
78 }
79
80 // Destructor
81 Process::~Process() {
82 }
83
84 // Start with command params
85 HRESULT Process::Start(const TCHAR* command_line_parameters,
86 HANDLE runas_token) {
87 if (command_line_parameters && *command_line_parameters) {
88 command_line_parameters_ = command_line_parameters;
89 }
90
91 number_of_restarts_ = static_cast<uint32>(-1);
92 time_of_start_ = GetTickCount();
93
94 return Restart(runas_token);
95 }
96
97 // Restart with the old command params
98 HRESULT Process::Restart(HANDLE runas_token) {
99 // Can't start the same process twice in the same containing object.
100 if (Running()) {
101 return E_FAIL;
102 }
103
104 PROCESS_INFORMATION process_info = {0};
105 HRESULT hr = runas_token ?
106 System::StartProcessAsUser(runas_token,
107 command_line_,
108 command_line_parameters_,
109 _T("WinSta0\\Default"),
110 &process_info) :
111 System::StartProcessWithArgsAndInfo(command_line_,
112 command_line_parameters_,
113 &process_info);
114
115 if (SUCCEEDED(hr)) {
116 VERIFY1(::CloseHandle(process_info.hThread));
117
118 reset(process_, process_info.hProcess);
119 process_id_ = process_info.dwProcessId;
120
121 ASSERT1(process_id_);
122 number_of_restarts_++;
123 } else {
124 UTIL_LOG(LE, (_T("[Process Restart failed][%s][0x%x]"), command_line_, hr));
125 }
126
127 return hr;
128 }
129
130 // Check if the process is running.
131 bool Process::Running() const {
132 if (!get(process_)) {
133 return false;
134 }
135
136 return (::WaitForSingleObject(get(process_), 0) == WAIT_TIMEOUT);
137 }
138
139 // Create a job and assign the process to it
140 HANDLE Process::AssignToJob() {
141 // Make sure that the process handle is valid
142 if (!get(process_)) {
143 return false;
144 }
145
146 // Create a job
147 scoped_job job(::CreateJobObject(NULL, NULL));
148 if (!valid(job)) {
149 UTIL_LOG(LEVEL_ERROR,
150 (_T("[Process::AssignToJob - CreateJobObject failed][0x%x]"),
151 HRESULTFromLastError()));
152 return false;
153 }
154
155 // Assign the process to the job
156 if (!::AssignProcessToJobObject(get(job), get(process_))) {
157 UTIL_LOG(LEVEL_ERROR,
158 (_T("[Process::AssignToJob-AssignProcessToJobObject fail][0x%x]"),
159 HRESULTFromLastError()));
160 return false;
161 }
162
163 return release(job);
164 }
165
166 // Wait till the process finishes
167 bool Process::WaitUntilDead(uint32 timeout_msec) {
168 ASSERT1(timeout_msec);
169
170 if (!get(process_)) {
171 return false;
172 }
173
174 uint32 ret = 0;
175 if (shutdown_event_) {
176 HANDLE wait_handles[2] = {0};
177 wait_handles[0] = get(process_);
178 wait_handles[1] = shutdown_event_;
179 ret = ::WaitForMultipleObjectsEx(2,
180 wait_handles,
181 false,
182 timeout_msec,
183 true);
184 } else {
185 ret = ::WaitForSingleObjectEx(get(process_), timeout_msec, true);
186 }
187 if (ret == WAIT_OBJECT_0) {
188 UTIL_LOG(L2, (_T("[Process::WaitUntilDead - succeeded to wait process]")
189 _T("[%s]"), GetName()));
190 return true;
191 } else if (ret == WAIT_IO_COMPLETION) {
192 UTIL_LOG(LEVEL_ERROR, (_T("[Process::WaitUntilDead-recv APC][%s][%u][%u]"),
193 GetName(), process_id_));
194 return false;
195 } else {
196 UTIL_LOG(LEVEL_ERROR, (_T("[Process::WaitUntilDead - fail to wait process,")
197 _T("possibly timeout][%s][%u][%u]"),
198 GetName(), process_id_, ret));
199 return false;
200 }
201 }
202
203 // Wait some time till the process and all its descendent processes finish
204 //
205 // Background:
206 // Some process might spawn another process and get itself terminated
207 // without waiting the descendant process to finish.
208 //
209 // Args:
210 // job: Job to which the process is assigned
211 // AssignToJob() will be called when NULL value is passed
212 // timeout_msec: Timeout value in msec
213 // path_to_exclude: Path of descendant process to excluded from waiting
214 // (this should be in long format)
215 // exit_code: To hold the exit code being returned
216 bool Process::WaitUntilAllDead(HANDLE job,
217 uint32 timeout_msec,
218 const TCHAR* path_to_exclude,
219 uint32* exit_code) {
220 ASSERT1(timeout_msec);
221
222 UTIL_LOG(L2, (_T("[Process::WaitUntilAllDead][%u][%s]"),
223 timeout_msec, path_to_exclude));
224
225 if (exit_code) {
226 *exit_code = 0;
227 }
228
229 scoped_job job_guard;
230 if (!job) {
231 reset(job_guard, AssignToJob());
232 if (!valid(job_guard)) {
233 return false;
234 }
235 job = get(job_guard);
236 }
237
238 return InternalWaitUntilAllDead(job,
239 timeout_msec,
240 path_to_exclude,
241 exit_code);
242 }
243
244 // Helper function to wait till the process and all its descendent processes
245 // finish.
246 bool Process::InternalWaitUntilAllDead(HANDLE job,
247 uint32 timeout_msec,
248 const TCHAR* path_to_exclude,
249 uint32* exit_code) {
250 ASSERT1(job);
251 ASSERT1(timeout_msec);
252
253 // Wait until current process finishes
254 if (!WaitUntilDead(timeout_msec)) {
255 return false;
256 }
257
258 // Find descendant process
259 uint32 desc_process_id = GetDescendantProcess(
260 job,
261 false, // child_only
262 exit_code != NULL, // sole_descendent
263 NULL, // search_name
264 path_to_exclude);
265
266 if (desc_process_id) {
267 // Open descendent process
268 Process desc_process(desc_process_id);
269
270 // If descendant process dies too soon, do not need to wait for it
271 if (desc_process.Running()) {
272 // Release the parent process handle
273 // This to handle the scenario that Firefox uninstall code will wait till
274 // parent process handle becomes NULL
275 reset(process_);
276
277 UTIL_LOG(L2, (_T("[Process::InternalWaitUntilAllDead]")
278 _T("[waiting descendant process][%u]"), desc_process_id));
279
280 // Propagate the shutdown event to descendent process
281 if (shutdown_event_) {
282 desc_process.SetShutdownEvent(shutdown_event_);
283 }
284
285 // Wait till descendant process finishes
286 bool wait_ret = desc_process.InternalWaitUntilAllDead(job,
287 timeout_msec,
288 path_to_exclude,
289 exit_code);
290
291 return wait_ret;
292 }
293 }
294
295 // Use the exit code from parent process
296 if (exit_code) {
297 VERIFY1(GetExitCode(exit_code));
298 }
299
300 // Release the parent process handle
301 reset(process_);
302
303 return true;
304 }
305
306 // Wait until process is dead or a windows message arrives (for use in a message
307 // loop while waiting)
308 HRESULT Process::WaitUntilDeadOrInterrupt(uint32 msec) {
309 if (!get(process_)) {
310 return E_FAIL;
311 }
312
313 HANDLE events[1] = { get(process_) };
314 uint32 dw = ::MsgWaitForMultipleObjects(1, events, FALSE, msec, QS_ALLEVENTS);
315 switch (dw) {
316 case WAIT_OBJECT_0:
317 return CI_S_PROCESSWAIT_DEAD;
318 case WAIT_OBJECT_0 + 1:
319 return CI_S_PROCESSWAIT_MESSAGE;
320 case WAIT_TIMEOUT:
321 return CI_S_PROCESSWAIT_TIMEOUT;
322 case WAIT_FAILED:
323 default:
324 return E_FAIL;
325 }
326 }
327
328 #if !SHIPPING
329 CString Process::GetDebugInfo() const {
330 return debug_info_;
331 }
332 #endif
333
334 // Return the process ID
335 uint32 Process::GetId() const {
336 return process_id_;
337 }
338
339 // Return the process name
340 const TCHAR *Process::GetName() const {
341 return name_;
342 }
343
344 // Return win32 handle to the process.
345 HANDLE Process::GetHandle() const {
346 return get(process_);
347 }
348
349 // Get process exit code.
350 bool Process::GetExitCode(uint32* exit_code) const {
351 ASSERT1(exit_code);
352
353 if (!get(process_)) {
354 return false;
355 }
356
357 if (!::GetExitCodeProcess(get(process_),
358 reinterpret_cast<DWORD*>(&exit_code_))) {
359 UTIL_LOG(LEVEL_ERROR,
360 (_T("[Process::GetExitCode - failed to get exit code][%u][0x%x]"),
361 process_id_, HRESULTFromLastError()));
362 return false;
363 }
364 if (exit_code_ == STILL_ACTIVE) {
365 return false;
366 }
367
368 *exit_code = exit_code_;
369 return true;
370 }
371
372 // default implementation allows termination
373 bool Process::IsTerminationAllowed() const {
374 return true;
375 }
376
377 // Terminate the process. If wait_for_terminate_msec == 0 return value doesn't
378 // mean that the process actualy terminated. It becomes assync. operation.
379 // Check the status with Running accessor function in this case.
380 bool Process::Terminate(uint32 wait_for_terminate_msec) {
381 if (!Running()) {
382 return true;
383 }
384
385 if (!IsTerminationAllowed()) {
386 return false;
387 }
388
389 if (!::TerminateProcess(get(process_), 1)) {
390 return false;
391 }
392
393 return wait_for_terminate_msec ? WaitUntilDead(wait_for_terminate_msec) :
394 true;
395 }
396
397 // Default returns INFINITE means never restart.
398 // Return any number of msec if overwriting
399 uint32 Process::GetRestartInterval() const {
400 return INFINITE;
401 }
402
403 // How many times the process can be restarted
404 // in case it crashes. When overriding return any
405 // number or INFINITE to restart forever.
406 uint32 Process::GetMaxNumberOfRestarts() const {
407 return 0;
408 }
409
410 // what is the time window for number of crashes returned by
411 // GetMaxNumberOfRestarts(). If crashed more that this number of restarts
412 // in a specified time window - do not restart it anymore.
413 // Default implementation returns INFINITE which means that this is not time
414 // based at all, if the process crashed more than the value returned by
415 // GetMaxNumberOfRestarts it will not be restarted no matter how long it took.
416 uint32 Process::GetTimeWindowForCrashes() const {
417 return INFINITE;
418 }
419
420 uint32 Process::GetMaxMemory() const {
421 return 0;
422 }
423
424 // Have we exceeded the number of maximum restarting?
425 bool Process::AllowedToRestart() const {
426 uint32 max_number_of_restarts = GetMaxNumberOfRestarts();
427
428 if ((max_number_of_restarts == INFINITE) ||
429 (number_of_restarts_ < max_number_of_restarts)) {
430 return true;
431 }
432
433 // process crashed too many times. Let's look at the rate of crashes.
434 // Maybe we can "forgive" the process if it took some time for it to crash.
435 if ((::GetTickCount() - time_of_start_) < GetTimeWindowForCrashes()) {
436 return false; // not forgiven
437 }
438
439 // Everything is forgiven. Give the process
440 // new start in life.
441 time_of_start_ = ::GetTickCount();
442 number_of_restarts_ = static_cast<uint32>(-1);
443
444 return true;
445 }
446
447 // Set shutdown event using in signaling the process watch
448 void Process::SetShutdownEvent(HANDLE shutdown_event) {
449 ASSERT1(shutdown_event);
450
451 shutdown_event_ = shutdown_event;
452 }
453
454 // Set priority class to the process.
455 bool Process::SetPriority(uint32 priority_class) const {
456 if (!get(process_)) {
457 return false;
458 }
459
460 VERIFY1(::SetPriorityClass(get(process_), priority_class));
461 return true;
462 }
463
464 HRESULT Process::GetParentProcessId(uint32* parent_pid) {
465 ASSERT1(parent_pid);
466 *parent_pid = 0;
467
468 scoped_hfile process_snap(::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
469 if (!process_snap) {
470 HRESULT hr = HRESULTFromLastError();
471 UTIL_LOG(LE, (_T("[GetParentProcessId][Failed snapshot][0x%x]"), hr));
472 return hr;
473 }
474
475 // Eumerate all processes in the snapshot
476 PROCESSENTRY32 pe32;
477 SetZero(pe32);
478 pe32.dwSize = sizeof(PROCESSENTRY32);
479 if (!::Process32First(get(process_snap), &pe32)) {
480 HRESULT hr = HRESULTFromLastError();
481 UTIL_LOG(LE, (_T("[Process32First failed][0x%x]"), hr));
482 return hr;
483 }
484
485 do {
486 if (pe32.th32ProcessID != process_id_) {
487 continue;
488 }
489
490 if (pe32.th32ParentProcessID) {
491 *parent_pid = pe32.th32ParentProcessID;
492 return S_OK;
493 }
494 } while (::Process32Next(get(process_snap), &pe32));
495
496 return E_FAIL;
497 }
498
499 // Try to get a descendant process. Return process id if found.
500 uint32 Process::GetDescendantProcess(HANDLE job,
501 bool child_only,
502 bool sole_descedent,
503 const TCHAR* search_name,
504 const TCHAR* path_to_exclude) {
505 ASSERT1(job);
506
507 // Find all descendent processes
508 std::vector<ProcessInfo> descendant_processes;
509 if (FAILED(GetAllDescendantProcesses(job,
510 child_only,
511 search_name,
512 path_to_exclude,
513 &descendant_processes))) {
514 return 0;
515 }
516
517 // If more than one decendent processes is found, filter out those that are
518 // not direct children. This is because it might be the case that in a very
519 // short period of time, process A spawns B and B spawns C, and we capture
520 // both B and C.
521 std::vector<ProcessInfo> child_processes;
522 typedef std::vector<ProcessInfo>::const_iterator ProcessInfoConstIterator;
523 if (descendant_processes.size() > 1) {
524 for (ProcessInfoConstIterator it(descendant_processes.begin());
525 it != descendant_processes.end(); ++it) {
526 if (it->parent_id == process_id_) {
527 child_processes.push_back(*it);
528 }
529 }
530 if (!child_processes.empty()) {
531 descendant_processes = child_processes;
532 }
533 }
534
535 // Save the debugging information if needed
536 #if !SHIPPING
537 if (sole_descedent && descendant_processes.size() > 1) {
538 debug_info_ = _T("More than one descendent process is found for process ");
539 debug_info_ += itostr(process_id_);
540 debug_info_ += _T("\n");
541 for (ProcessInfoConstIterator it(descendant_processes.begin());
542 it != descendant_processes.end(); ++it) {
543 debug_info_.AppendFormat(_T("%u %u %s\n"),
544 it->process_id,
545 it->parent_id,
546 it->exe_file);
547 }
548 }
549 #else
550 sole_descedent; // unreferenced formal parameter
551 #endif
552
553 return descendant_processes.empty() ? 0 : descendant_processes[0].process_id;
554 }
555
556 BOOL Process::IsProcessInJob(HANDLE process_handle,
557 HANDLE job_handle,
558 PBOOL result) {
559 typedef BOOL (WINAPI *Fun)(HANDLE process_handle,
560 HANDLE job_handle,
561 PBOOL result);
562
563 HINSTANCE kernel_instance = ::GetModuleHandle(_T("kernel32.dll"));
564 ASSERT1(kernel_instance);
565 Fun pfn = reinterpret_cast<Fun>(::GetProcAddress(kernel_instance,
566 "IsProcessInJob"));
567 ASSERT(pfn, (_T("IsProcessInJob export not found in kernel32.dll")));
568 return pfn ? (*pfn)(process_handle, job_handle, result) : FALSE;
569 }
570
571 // Try to get all matching descendant processes
572 HRESULT Process::GetAllDescendantProcesses(
573 HANDLE job,
574 bool child_only,
575 const TCHAR* search_name,
576 const TCHAR* path_to_exclude,
577 std::vector<ProcessInfo>* descendant_processes) {
578 ASSERT1(job);
579 ASSERT1(descendant_processes);
580
581 // Take a snapshot
582 // Note that we do not have a seperate scoped_* type defined to wrap the
583 // handle returned by CreateToolhelp32Snapshot. So scoped_hfile with similar
584 // behavior is used.
585 scoped_hfile process_snap(::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
586 if (!process_snap) {
587 HRESULT hr = HRESULTFromLastError();
588 UTIL_LOG(LEVEL_ERROR,
589 (_T("[Process::GetAllDescendantProcesses - fail to get snapshot]")
590 _T("[0x%x]"), hr));
591 return hr;
592 }
593
594 // Eumerate all processes in the snapshot
595 PROCESSENTRY32 pe32;
596 SetZero(pe32);
597 pe32.dwSize = sizeof(PROCESSENTRY32);
598 if (!::Process32First(get(process_snap), &pe32)) {
599 HRESULT hr = HRESULTFromLastError();
600 UTIL_LOG(LEVEL_ERROR, (_T("[Process::GetAllDescendantProcesses - failed to")
601 _T("get first process][0x%x]"), hr));
602 return hr;
603 }
604
605 do {
606 // Skip process 0 and current process
607 if (pe32.th32ProcessID == 0 || pe32.th32ProcessID == process_id_) {
608 continue;
609 }
610
611 // If searching for child only, perform the check
612 if (child_only && pe32.th32ParentProcessID != process_id_) {
613 continue;
614 }
615
616 // Open the process
617 scoped_process process(::OpenProcess(PROCESS_QUERY_INFORMATION |
618 SYNCHRONIZE,
619 false,
620 pe32.th32ProcessID));
621 if (!valid(process)) {
622 continue;
623 }
624
625 // Determines whether the process is running in the specified job
626 BOOL result = FALSE;
627 if (!IsProcessInJob(get(process), job, &result) || !result) {
628 continue;
629 }
630
631 // Check whether the process is still running
632 if (::WaitForSingleObject(get(process), 0) != WAIT_TIMEOUT) {
633 continue;
634 }
635
636 // Compare the name if needed
637 if (search_name && *search_name) {
638 if (_tcsicmp(pe32.szExeFile, search_name) != 0) {
639 continue;
640 }
641 }
642
643 // If we need to exclude certain path, check it now
644 if (path_to_exclude && *path_to_exclude) {
645 if (IsProcessRunningWithPath(pe32.th32ProcessID, path_to_exclude)) {
646 continue;
647 }
648 }
649
650 // Add to the list
651 ProcessInfo proc_info;
652 proc_info.process_id = pe32.th32ProcessID;
653 proc_info.parent_id = pe32.th32ParentProcessID;
654 #if !SHIPPING
655 proc_info.exe_file = pe32.szExeFile;
656 #endif
657 descendant_processes->push_back(proc_info);
658 } while (::Process32Next(get(process_snap), &pe32));
659
660 return S_OK;
661 }
662
663 HRESULT Process::FindProcesses(uint32 exclude_mask,
664 const TCHAR* search_name,
665 bool search_main_executable_only,
666 std::vector<uint32>* process_ids_found) {
667 ASSERT1(process_ids_found);
668 // Remove the only include processes owned by user mask from the exclude
669 // mask. This is needed as this is the behavior expected by the method,
670 // before the addition of the user_sid.
671 exclude_mask &= (~INCLUDE_ONLY_PROCESS_OWNED_BY_USER);
672 std::vector<CString> command_lines;
673 return FindProcesses(exclude_mask, search_name, search_main_executable_only,
674 _T(""), command_lines, process_ids_found);
675 }
676
677 bool Process::IsStringPresentInList(const CString& process_command_line,
678 const std::vector<CString>& list) {
679 std::vector<CString>::const_iterator iter = list.begin();
680 for (; iter != list.end(); ++iter) {
681 CString value_to_find = *iter;
682
683 // If we are able to open the process command line, then we should
684 // ensure that it does not contain the value that we are looking for.
685 if (process_command_line.Find(value_to_find) != -1) {
686 // Found a match.
687 return true;
688 }
689 }
690
691 return false;
692 }
693
694 // TODO(omaha): Change the implementation of this method to take in a
695 // predicate that determines whether a process should be included in the
696 // result set.
697 HRESULT Process::FindProcesses(uint32 exclude_mask,
698 const TCHAR* search_name,
699 bool search_main_executable_only,
700 const CString& user_sid,
701 const std::vector<CString>& command_lines,
702 std::vector<uint32>* process_ids_found) {
703 ASSERT1(search_name && *search_name);
704 ASSERT1(process_ids_found);
705 ASSERT1(!((exclude_mask & EXCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING) &&
706 (exclude_mask & INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING)));
707
708 const TCHAR* const kLocalSystemSid = _T("S-1-5-18");
709
710 // Clear the output queue
711 process_ids_found->clear();
712
713 // Get the list of process identifiers.
714 uint32 process_ids[kMaxProcesses] = {0};
715 uint32 bytes_returned = 0;
716 if (!::EnumProcesses(reinterpret_cast<DWORD*>(process_ids),
717 sizeof(process_ids),
718 reinterpret_cast<DWORD*>(&bytes_returned))) {
719 HRESULT hr = HRESULTFromLastError();
720 UTIL_LOG(LEVEL_ERROR, (_T("[Process::FindProcesses-fail to EnumProcesses]")
721 _T("[0x%x]"), hr));
722 return hr;
723 }
724
725 // Enumerate all processes
726 int num_processes = bytes_returned / sizeof(process_ids[0]);
727 // We have found an elevated number of crashes in 1.2.584.15114 on what
728 // we believe are Italian systems. The first step to solving this Italian job
729 // is to assert on the condition while we are further testing this.
730 ASSERT1(num_processes <= kMaxProcesses);
731
732 // In Vista, SeDebugPrivilege is required to open the process not owned by
733 // current user. Also required for XP admins to open Local System processes
734 // with PROCESS_QUERY_INFORMATION access rights.
735 System::AdjustPrivilege(SE_DEBUG_NAME, true);
736
737 const uint32 cur_process_id = ::GetCurrentProcessId();
738
739 uint32 parent_process_id = 0;
740 if (exclude_mask & EXCLUDE_PARENT_PROCESS) {
741 Process current_process(cur_process_id);
742 uint32 ppid = 0;
743 HRESULT hr = current_process.GetParentProcessId(&ppid);
744 parent_process_id = SUCCEEDED(hr) ? ppid : 0;
745 }
746
747 // Get SID of current user
748 CString cur_user_sid;
749 HRESULT hr = omaha::user_info::GetProcessUser(NULL, NULL, &cur_user_sid);
750 if (FAILED(hr)) {
751 return hr;
752 }
753
754 UTIL_LOG(L4, (_T("[Process::FindProcesses][processes=%d]"), num_processes));
755 for (int i = 0; i < num_processes; ++i) {
756 // Skip the system idle process.
757 if (process_ids[i] == 0) {
758 continue;
759 }
760
761 // Skip the current process if needed.
762 if ((exclude_mask & EXCLUDE_CURRENT_PROCESS) &&
763 (process_ids[i] == cur_process_id)) {
764 UTIL_LOG(L4, (_T("[Excluding current process %d"), process_ids[i]));
765 continue;
766 }
767
768 // Skip the parent process if needed.
769 if ((exclude_mask & EXCLUDE_PARENT_PROCESS) &&
770 (process_ids[i] == parent_process_id)) {
771 UTIL_LOG(L4, (_T("[Excluding parent process(%d) of %d"),
772 process_ids[i], cur_process_id));
773 continue;
774 }
775
776
777 // Get the owner sid.
778 // Note that we may fail to get the owner which is not current user.
779 // So if the owner_sid is empty, the process is sure not to be owned by the
780 // current user.
781 CString owner_sid;
782 Process::GetProcessOwner(process_ids[i], &owner_sid);
783
784 if ((exclude_mask & INCLUDE_ONLY_PROCESS_OWNED_BY_USER) &&
785 owner_sid != user_sid) {
786 UTIL_LOG(L4,
787 (_T("[Excluding process as not owned by user][%d]"), process_ids[i]));
788 continue;
789 }
790
791 if ((exclude_mask & EXCLUDE_PROCESS_OWNED_BY_CURRENT_USER) &&
792 owner_sid == cur_user_sid) {
793 UTIL_LOG(L4,
794 (_T("[Excluding process as owned by current user][%d]"),
795 process_ids[i]));
796 continue;
797 }
798 if ((exclude_mask & EXCLUDE_PROCESS_OWNED_BY_SYSTEM) &&
799 owner_sid == kLocalSystemSid) {
800 UTIL_LOG(L4,
801 (_T("[Excluding process as owned by system][%d]"), process_ids[i]));
802 continue;
803 }
804 if (exclude_mask & EXCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING ||
805 exclude_mask & INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING) {
806 CString process_command_line;
807 HRESULT hr = GetCommandLine(process_ids[i], &process_command_line);
808 if (FAILED(hr)) {
809 UTIL_LOG(L4,
810 (_T("[Excluding process could not get command line][%d]"),
811 process_ids[i]));
812 continue;
813 }
814
815 // If we are able to open the process command line, then we should
816 // ensure that it does not contain the value that we are looking for if
817 // we are excluding the command line or that it contains the command line
818 // that we are looking for in case the include switch is specified.
819 bool present = IsStringPresentInList(process_command_line, command_lines);
820 if ((present &&
821 (exclude_mask & EXCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING)) ||
822 (!present &&
823 (exclude_mask & INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING))) {
824 UTIL_LOG(L4, (_T("[Process command line matches criteria][%d]'[%s]'"),
825 process_ids[i], process_command_line));
826 continue;
827 }
828 }
829
830 // If search_name is provided, make sure it matches
831 if (Process::IsProcessUsingExeOrDll(process_ids[i],
832 search_name,
833 search_main_executable_only)) {
834 UTIL_LOG(L4,
835 (_T("[Including process][%d][%s]"), process_ids[i], search_name));
836 process_ids_found->push_back(process_ids[i]);
837 }
838 }
839
840 return S_OK;
841 }
842
843 HRESULT Process::FindProcessesInSession(
844 DWORD session_id,
845 uint32 exclude_mask,
846 const TCHAR* search_name,
847 bool search_main_executable_only,
848 const CString& user_sid,
849 const std::vector<CString>& cmd_lines,
850 std::vector<uint32>* process_ids_found) {
851 HRESULT hr = FindProcesses(exclude_mask,
852 search_name,
853 search_main_executable_only,
854 user_sid,
855 cmd_lines,
856 process_ids_found);
857 if (FAILED(hr)) {
858 return hr;
859 }
860
861 // Filter to processes running under session_id.
862 std::vector<uint32>::iterator iter = process_ids_found->begin();
863 while (iter != process_ids_found->end()) {
864 uint32 process_pid = *iter;
865 DWORD process_session = 0;
866 hr = S_OK;
867 if (!::ProcessIdToSessionId(process_pid, &process_session)) {
868 hr = HRESULTFromLastError();
869 UTIL_LOG(LE, (_T("[::ProcessIdToSessionId failed][0x%x]"), hr));
870 } else if (process_session != session_id) {
871 UTIL_LOG(L4, (_T("[Excluding process, different session][%d][%d][%d]"),
872 process_pid, process_session, session_id));
873 }
874
875 if (FAILED(hr) || process_session != session_id) {
876 // Remove from list and continue.
877 iter = process_ids_found->erase(iter);
878 continue;
879 }
880
881 ++iter;
882 }
883
884 return S_OK;
885 }
886
887 bool Process::IsModuleMatchingExeOrDll(const TCHAR* module_name,
888 const TCHAR* search_name,
889 bool is_fully_qualified_name) {
890 CString module_file_name;
891 if (is_fully_qualified_name) {
892 if (FAILED(GetLongPathName(module_name, &module_file_name))) {
893 return false;
894 }
895 } else {
896 module_file_name = ::PathFindFileName(module_name);
897 ASSERT1(!module_file_name.IsEmpty());
898 if (module_file_name.IsEmpty()) {
899 return false;
900 }
901 }
902
903 return (module_file_name.CompareNoCase(search_name) == 0);
904 }
905
906 DWORD Process::GetProcessImageFileName(HANDLE proc_handle,
907 LPTSTR image_file,
908 DWORD file_size) {
909 typedef DWORD (WINAPI *Fun)(HANDLE proc_handle,
910 LPWSTR image_file,
911 DWORD file_size);
912
913 HINSTANCE psapi_instance = ::GetModuleHandle(_T("Psapi.dll"));
914 ASSERT1(psapi_instance);
915 Fun pfn = reinterpret_cast<Fun>(::GetProcAddress(psapi_instance,
916 "GetProcessImageFileNameW"));
917 if (!pfn) {
918 UTIL_LOG(L1, (_T("::GetProcessImageFileNameW() not found in Psapi.dll")));
919 return 0;
920 }
921 return (*pfn)(proc_handle, image_file, file_size);
922 }
923
924 bool Process::IsProcImageMatch(HANDLE proc_handle,
925 const TCHAR* search_name,
926 bool is_fully_qualified_name) {
927 TCHAR image_name[MAX_PATH] = _T("");
928 if (!GetProcessImageFileName(proc_handle,
929 image_name,
930 arraysize(image_name))) {
931 UTIL_LOG(L4, (_T("[GetProcessImageFileName fail[0x%x]"),
932 HRESULTFromLastError()));
933 return false;
934 }
935
936 UTIL_LOG(L4, (_T("[GetProcessImageFileName][%s]"), image_name));
937 CString dos_name;
938 HRESULT hr(DevicePathToDosPath(image_name, &dos_name));
939 if (FAILED(hr)) {
940 UTIL_LOG(L4, (_T("[DevicePathToDosPath fail[0x%x]"), hr));
941 return false;
942 }
943
944 return IsModuleMatchingExeOrDll(dos_name,
945 search_name,
946 is_fully_qualified_name);
947 }
948
949 // Is the process using the specified exe/dll?
950 bool Process::IsProcessUsingExeOrDll(uint32 process_id,
951 const TCHAR* search_name,
952 bool search_main_executable_only) {
953 ASSERT1(search_name);
954
955 // Open the process
956 scoped_process process_handle(::OpenProcess(
957 PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
958 FALSE,
959 process_id));
960 if (!process_handle) {
961 UTIL_LOG(L4, (_T("[::OpenProcess failed][0x%x]"), HRESULTFromLastError()));
962 return false;
963 }
964
965 // Does the name represent a fully qualified name?
966 // We only do a simple check here
967 bool is_fully_qualified_name = String_FindChar(search_name, _T('\\')) != -1;
968 CString long_search_name;
969 if (is_fully_qualified_name) {
970 HRESULT hr(GetLongPathName(search_name, &long_search_name));
971 if (FAILED(hr)) {
972 UTIL_LOG(L4, (_T("[GetLongPathName fail][hr=x%x]"), hr));
973 return false;
974 }
975 search_name = long_search_name;
976 }
977
978 // Take a snapshot of all modules in the specified process
979 int num_modules_to_fetch = search_main_executable_only ? 1 :
980 kMaxProcessModules;
981 HMODULE module_handles[kMaxProcessModules];
982 SetZero(module_handles);
983 uint32 bytes_needed = 0;
984 if (!::EnumProcessModules(get(process_handle),
985 module_handles,
986 num_modules_to_fetch * sizeof(HMODULE),
987 reinterpret_cast<DWORD*>(&bytes_needed))) {
988 HRESULT hr = HRESULTFromLastError();
989 UTIL_LOG(LEVEL_ERROR, (_T("[EnumProcessModules failed][0x%x]"), hr));
990
991 if (IsWow64(::GetCurrentProcessId())) {
992 // ::EnumProcessModules from a WoW64 process fails for x64 processes.
993 // We try ::GetProcessImageFileName as a workaround here.
994 return search_main_executable_only ?
995 IsProcImageMatch(get(process_handle),
996 search_name,
997 is_fully_qualified_name) :
998 false;
999 } else {
1000 return false;
1001 }
1002 }
1003
1004 int num_modules = bytes_needed / sizeof(HMODULE);
1005 if (num_modules > num_modules_to_fetch) {
1006 num_modules = num_modules_to_fetch;
1007 }
1008
1009 for (int i = 0; i < num_modules; ++i) {
1010 TCHAR module_name[MAX_PATH];
1011 SetZero(module_name);
1012 if (!::GetModuleFileNameEx(get(process_handle),
1013 module_handles[i],
1014 module_name,
1015 arraysize(module_name))) {
1016 UTIL_LOG(LEVEL_ERROR, (_T("[GetModuleFileNameEx fail[x%x]"),
1017 HRESULTFromLastError()));
1018 continue;
1019 }
1020
1021 if (IsModuleMatchingExeOrDll(module_name,
1022 search_name,
1023 is_fully_qualified_name)) {
1024 return true;
1025 }
1026 }
1027
1028 return false;
1029 }
1030
1031 // Helper function to get long path name
1032 HRESULT Process::GetLongPathName(const TCHAR* short_name, CString* long_name) {
1033 ASSERT1(short_name);
1034 ASSERT1(long_name);
1035
1036 TCHAR temp_name[MAX_PATH];
1037 SetZero(temp_name);
1038
1039 HRESULT hr = S_OK;
1040 if (!::GetLongPathName(short_name, temp_name, arraysize(temp_name))) {
1041 hr = HRESULTFromLastError();
1042 } else {
1043 long_name->SetString(temp_name);
1044 }
1045
1046 return hr;
1047 }
1048
1049 // Retrieve the FQPN for the executable file for a process. (Note: Using
1050 // GetModuleFileNameEx is slower than GetProcessImageFileName, but the former
1051 // is available on Win2K, while the latter is only only on XP and up.)
1052 HRESULT Process::GetExecutablePath(uint32 process_id, CString *exe_path) {
1053 ASSERT1(process_id);
1054 ASSERT1(exe_path);
1055
1056 TCHAR temp_path[MAX_PATH];
1057 SetZero(temp_path);
1058
1059 scoped_process process(::OpenProcess(PROCESS_QUERY_INFORMATION |
1060 PROCESS_VM_READ,
1061 FALSE,
1062 process_id));
1063 if (!valid(process)) {
1064 return HRESULTFromLastError();
1065 }
1066
1067 if (0 == ::GetModuleFileNameEx(get(process), NULL, temp_path, MAX_PATH)) {
1068 return HRESULTFromLastError();
1069 }
1070
1071 exe_path->SetString(temp_path);
1072 return S_OK;
1073 }
1074
1075 // Type definitions needed for GetCommandLine() and GetProcessIdFromHandle()
1076 // From MSDN document on NtQueryInformationProcess() and other sources
1077 typedef struct _PROCESS_BASIC_INFORMATION {
1078 PVOID Reserved1;
1079 BYTE *PebBaseAddress;
1080 PVOID Reserved2[2];
1081 ULONG_PTR UniqueProcessId;
1082 PVOID Reserved3;
1083 } PROCESS_BASIC_INFORMATION;
1084
1085 typedef enum _PROCESSINFOCLASS {
1086 ProcessBasicInformation = 0,
1087 ProcessWow64Information = 26
1088 } PROCESSINFOCLASS;
1089
1090 typedef WINBASEAPI DWORD WINAPI
1091 GetProcessIdFn(
1092 HANDLE Process
1093 );
1094
1095 typedef LONG WINAPI
1096 NtQueryInformationProcess(
1097 IN HANDLE ProcessHandle,
1098 IN PROCESSINFOCLASS ProcessInformationClass,
1099 OUT PVOID ProcessInformation,
1100 IN ULONG ProcessInformationLength,
1101 OUT PULONG ReturnLength OPTIONAL
1102 );
1103
1104 typedef struct _RTL_DRIVE_LETTER_CURDIR {
1105 USHORT Flags;
1106 USHORT Length;
1107 ULONG TimeStamp;
1108 UNICODE_STRING DosPath;
1109 } RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;
1110
1111 typedef struct _RTL_USER_PROCESS_PARAMETERS {
1112 ULONG MaximumLength;
1113 ULONG Length;
1114 ULONG Flags;
1115 ULONG DebugFlags;
1116 PVOID ConsoleHandle;
1117 ULONG ConsoleFlags;
1118 HANDLE StdInputHandle;
1119 HANDLE StdOutputHandle;
1120 HANDLE StdErrorHandle;
1121 UNICODE_STRING CurrentDirectoryPath;
1122 HANDLE CurrentDirectoryHandle;
1123 UNICODE_STRING DllPath;
1124 UNICODE_STRING ImagePathName;
1125 UNICODE_STRING CommandLine;
1126 PVOID Environment;
1127 ULONG StartingPositionLeft;
1128 ULONG StartingPositionTop;
1129 ULONG Width;
1130 ULONG Height;
1131 ULONG CharWidth;
1132 ULONG CharHeight;
1133 ULONG ConsoleTextAttributes;
1134 ULONG WindowFlags;
1135 ULONG ShowWindowFlags;
1136 UNICODE_STRING WindowTitle;
1137 UNICODE_STRING DesktopName;
1138 UNICODE_STRING ShellInfo;
1139 UNICODE_STRING RuntimeData;
1140 RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20];
1141 } RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
1142
1143 // Get the function pointer to GetProcessId in KERNEL32.DLL
1144 static HRESULT EnsureGPIFunction(GetProcessIdFn** gpi_func_ptr) {
1145 static GetProcessIdFn* gpi_func = NULL;
1146 if (!gpi_func) {
1147 HMODULE kernel32_module = ::GetModuleHandle(_T("kernel32.dll"));
1148 if (!kernel32_module) {
1149 return HRESULTFromLastError();
1150 }
1151 gpi_func = reinterpret_cast<GetProcessIdFn*>(
1152 ::GetProcAddress(kernel32_module, "GetProcessId"));
1153 if (!gpi_func) {
1154 return HRESULTFromLastError();
1155 }
1156 }
1157
1158 *gpi_func_ptr = gpi_func;
1159 return S_OK;
1160 }
1161
1162 // Get the function pointer to NtQueryInformationProcess in NTDLL.DLL
1163 static HRESULT EnsureQIPFunction(NtQueryInformationProcess** qip_func_ptr) {
1164 static NtQueryInformationProcess* qip_func = NULL;
1165 if (!qip_func) {
1166 HMODULE ntdll_module = ::GetModuleHandle(_T("ntdll.dll"));
1167 if (!ntdll_module) {
1168 return HRESULTFromLastError();
1169 }
1170 qip_func = reinterpret_cast<NtQueryInformationProcess*>(
1171 ::GetProcAddress(ntdll_module, "NtQueryInformationProcess"));
1172 if (!qip_func) {
1173 return HRESULTFromLastError();
1174 }
1175 }
1176
1177 *qip_func_ptr = qip_func;
1178 return S_OK;
1179 }
1180
1181 // Obtain the process ID from a hProcess HANDLE
1182 ULONG Process::GetProcessIdFromHandle(HANDLE hProcess) {
1183 if (SystemInfo::IsRunningOnXPSP1OrLater()) {
1184 // Thunk to the documented ::GetProcessId() API
1185 GetProcessIdFn* gpi_func = NULL;
1186 HRESULT hr = EnsureGPIFunction(&gpi_func);
1187 if (FAILED(hr)) {
1188 ASSERT(FALSE,
1189 (_T("Process::GetProcessIdFromHandle - EnsureGPIFunction")
1190 _T(" failed[0x%x]"), hr));
1191 return 0;
1192 }
1193 ASSERT1(gpi_func);
1194 return gpi_func(hProcess);
1195 }
1196
1197 // For lower versions of Windows, we use undocumented
1198 // function NtQueryInformationProcess to get at the PID
1199 NtQueryInformationProcess* qip_func = NULL;
1200 HRESULT hr = EnsureQIPFunction(&qip_func);
1201 if (FAILED(hr)) {
1202 ASSERT(FALSE,
1203 (_T("Process::GetProcessIdFromHandle - EnsureQIPFunction")
1204 _T(" failed[0x%x]"), hr));
1205 return 0;
1206 }
1207 ASSERT1(qip_func);
1208
1209 PROCESS_BASIC_INFORMATION info;
1210 SetZero(info);
1211 if (!NT_SUCCESS(qip_func(hProcess,
1212 ProcessBasicInformation,
1213 &info,
1214 sizeof(info),
1215 NULL))) {
1216 ASSERT(FALSE, (_T("Process::GetProcessIdFromHandle - ")
1217 _T("NtQueryInformationProcess failed!")));
1218 return 0;
1219 }
1220
1221 return info.UniqueProcessId;
1222 }
1223
1224 // Get the command line of a process
1225 HRESULT Process::GetCommandLine(uint32 process_id, CString* cmd_line) {
1226 ASSERT1(process_id);
1227 ASSERT1(cmd_line);
1228
1229 // Open the process
1230 scoped_process process_handle(::OpenProcess(
1231 PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
1232 false,
1233 process_id));
1234 if (!process_handle) {
1235 return HRESULTFromLastError();
1236 }
1237
1238 // Obtain Process Environment Block
1239 // Note that NtQueryInformationProcess is not available in Windows 95/98/ME
1240 NtQueryInformationProcess* qip_func = NULL;
1241 HRESULT hr = EnsureQIPFunction(&qip_func);
1242
1243 if (FAILED(hr)) {
1244 return hr;
1245 }
1246 ASSERT1(qip_func);
1247
1248 PROCESS_BASIC_INFORMATION info;
1249 SetZero(info);
1250 if (!NT_SUCCESS(qip_func(get(process_handle),
1251 ProcessBasicInformation,
1252 &info,
1253 sizeof(info),
1254 NULL))) {
1255 return E_FAIL;
1256 }
1257 BYTE* peb = info.PebBaseAddress;
1258
1259 // Read address of parameters (see some PEB reference)
1260 // TODO(omaha): use offsetof(PEB, ProcessParameters) to replace 0x10
1261 // http://msdn.microsoft.com/en-us/library/aa813706.aspx
1262 SIZE_T bytes_read = 0;
1263 uint32 dw = 0;
1264 if (!::ReadProcessMemory(get(process_handle),
1265 peb + 0x10,
1266 &dw,
1267 sizeof(dw),
1268 &bytes_read)) {
1269 return HRESULTFromLastError();
1270 }
1271
1272 // Read all the parameters
1273 RTL_USER_PROCESS_PARAMETERS params;
1274 SetZero(params);
1275 if (!::ReadProcessMemory(get(process_handle),
1276 reinterpret_cast<PVOID>(dw),
1277 &params,
1278 sizeof(params),
1279 &bytes_read)) {
1280 return HRESULTFromLastError();
1281 }
1282
1283 // Read the command line parameter
1284 const int max_cmd_line_len = std::min(
1285 static_cast<int>(params.CommandLine.MaximumLength),
1286 kMaxCmdLineLengthBytes);
1287 if (!::ReadProcessMemory(get(process_handle),
1288 params.CommandLine.Buffer,
1289 cmd_line->GetBufferSetLength(max_cmd_line_len),
1290 max_cmd_line_len,
1291 &bytes_read)) {
1292 return HRESULTFromLastError();
1293 }
1294
1295 cmd_line->ReleaseBuffer();
1296
1297 return S_OK;
1298 }
1299
1300 // Check if the process is running with a specified path
1301 bool Process::IsProcessRunningWithPath(uint32 process_id, const TCHAR* path) {
1302 ASSERT1(process_id);
1303 ASSERT1(path && *path);
1304
1305 const int kProcessWaitModuleFullyUpMs = 100;
1306 const int kProcessWaitModuleRetries = 10;
1307
1308 // Open the process
1309 scoped_process process(::OpenProcess(
1310 PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
1311 false,
1312 process_id));
1313 if (!process) {
1314 UTIL_LOG(LEVEL_ERROR,
1315 (_T("[Process::IsProcessRunningWithPath - OpenProcess failed]")
1316 _T("[%u][0x%x]"),
1317 process_id, HRESULTFromLastError()));
1318 return false;
1319 }
1320
1321 for (int i = 0; i < kProcessWaitModuleRetries; ++i) {
1322 // Get the command line path of the main module
1323 // Note that we are using psapi functions which is not supported in Windows
1324 // 95/98/ME
1325 //
1326 // Sometimes it might be the case that the process is created but the main
1327 // module is not fully loaded. If so, wait a while and then try again
1328 TCHAR process_path[MAX_PATH];
1329 if (::GetModuleFileNameEx(get(process),
1330 NULL,
1331 process_path,
1332 arraysize(process_path))) {
1333 // Do the check
1334 if (String_StartsWith(process_path, path, true)) {
1335 return true;
1336 }
1337
1338 // Try again with short form
1339 TCHAR short_path[MAX_PATH];
1340 if (::GetShortPathName(path, short_path, arraysize(short_path)) &&
1341 String_StartsWith(process_path, short_path, true)) {
1342 return true;
1343 }
1344
1345 return false;
1346 }
1347
1348 UTIL_LOG(LEVEL_ERROR,
1349 (_T("[Process::IsProcessRunningWithPath - GetModuleFileNameEx ")
1350 _T("failed][%u][0x%x]"),
1351 process_id, HRESULTFromLastError()));
1352
1353 ::Sleep(kProcessWaitModuleFullyUpMs);
1354 }
1355
1356 UTIL_LOG(LEVEL_ERROR,
1357 (_T("[Process::IsProcessRunningWithPath - failed to get process ")
1358 _T("path][%u][0x%x]"),
1359 process_id, HRESULTFromLastError()));
1360
1361 return false;
1362 }
1363
1364 // Get the process owner
1365 // Note that we may fail to get the owner which is not current user.
1366 HRESULT Process::GetProcessOwner(uint32 pid, CString* owner_sid) {
1367 ASSERT1(pid);
1368 ASSERT1(owner_sid);
1369
1370 scoped_process process(::OpenProcess(PROCESS_QUERY_INFORMATION, false, pid));
1371 if (!valid(process)) {
1372 return HRESULTFromLastError();
1373 }
1374
1375 CAccessToken token;
1376 CSid sid;
1377 if (!token.GetProcessToken(READ_CONTROL | TOKEN_QUERY, get(process)) ||
1378 !token.GetUser(&sid)) {
1379 return HRESULTFromLastError();
1380 }
1381
1382 *owner_sid = sid.Sid();
1383 return S_OK;
1384 }
1385
1386 // Creates an impersonation token for the user running process_id.
1387 // The caller is responsible for closing the returned handle.
1388 HRESULT Process::GetImpersonationToken(DWORD process_id, HANDLE* user_token) {
1389 // Get a handle to the process.
1390 scoped_process process(::OpenProcess(
1391 PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION,
1392 TRUE,
1393 process_id));
1394 if (!valid(process)) {
1395 HRESULT hr(HRESULTFromLastError());
1396 UTIL_LOG(LEVEL_ERROR,
1397 (_T("[GetImpersonationToken - ::OpenProcess failed][0x%x]"),
1398 hr));
1399 return hr;
1400 }
1401
1402 HRESULT result = S_OK;
1403 scoped_handle process_token;
1404 if (!::OpenProcessToken(get(process), TOKEN_DUPLICATE | TOKEN_QUERY,
1405 address(process_token))) {
1406 result = HRESULTFromLastError();
1407 } else {
1408 if (!::DuplicateTokenEx(get(process_token),
1409 TOKEN_IMPERSONATE | TOKEN_QUERY |
1410 TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE,
1411 NULL,
1412 SecurityImpersonation,
1413 TokenPrimary,
1414 user_token)) {
1415 result = HRESULTFromLastError();
1416 }
1417 }
1418
1419 ASSERT(SUCCEEDED(result), (_T("[GetImpersonationToken Failed][hr=0x%x]"),
1420 result));
1421 return result;
1422 }
1423
1424 HRESULT Process::GetUsersOfProcesses(const TCHAR* task_name,
1425 int maximum_users,
1426 scoped_handle user_tokens[],
1427 int* number_of_users) {
1428 ASSERT1(task_name && *task_name);
1429 ASSERT1(maximum_users);
1430 ASSERT1(user_tokens);
1431 ASSERT1(number_of_users);
1432
1433 scoped_hfile th32cs_snapshot(::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,
1434 0));
1435 if (!valid(th32cs_snapshot)) {
1436 HRESULT hr(HRESULTFromLastError());
1437 UTIL_LOG(LEVEL_ERROR, (_T("[::CreateToolhelp32Snapshot fail][0x%x]"), hr));
1438 return hr;
1439 }
1440
1441 HRESULT result = S_OK;
1442 *number_of_users = 0;
1443 // Walk the list of processes.
1444 PROCESSENTRY32 process = {0};
1445 process.dwSize = sizeof(PROCESSENTRY32);
1446 for (BOOL found = ::Process32First(get(th32cs_snapshot), &process); found;
1447 found = ::Process32Next(get(th32cs_snapshot), &process)) {
1448 // Check if it is one of the processes we are looking for.
1449 if (_tcsicmp(task_name, process.szExeFile) == 0) {
1450 // We match. Get the user's token.
1451 scoped_handle user_token;
1452 if (FAILED(GetImpersonationToken(process.th32ProcessID,
1453 address(user_token))))
1454 continue;
1455
1456 // Search through the existing list to see if it's a duplicate.
1457 // It's O(n^2) but we should have very few logged on users.
1458 int i = 0;
1459 for (; i < *number_of_users; i++) {
1460 if (get(user_tokens[i]) == get(user_token)) {
1461 // It's a duplicate.
1462 break;
1463 }
1464 }
1465 if (i >= *number_of_users) {
1466 // It's a new one. Add it if there's room.
1467 ASSERT1(i < maximum_users);
1468 if (i < maximum_users) {
1469 // Release the user_token, we don't want it to be closed
1470 // by the user_token destructor
1471 reset(user_tokens[(*number_of_users)++], release(user_token));
1472 }
1473 }
1474 }
1475 }
1476 return result;
1477 }
1478
1479 HRESULT Process::GetImagePath(const CString& process_name,
1480 const CString& user_sid,
1481 CString* path) {
1482 ASSERT1(path);
1483
1484 // Search for running processes with process_name.
1485 uint32 mask = INCLUDE_ONLY_PROCESS_OWNED_BY_USER;
1486 std::vector<CString> command_line;
1487 std::vector<uint32> process_ids;
1488 HRESULT hr = FindProcesses(mask,
1489 process_name,
1490 true,
1491 user_sid,
1492 command_line,
1493 &process_ids);
1494 if (FAILED(hr)) {
1495 UTIL_LOG(LEVEL_WARNING, (_T("[FindProcesses failed][0x%08x]"), hr));
1496 return hr;
1497 }
1498
1499 if (process_ids.empty()) {
1500 return E_FAIL;
1501 }
1502
1503 uint32 process_id = process_ids[0];
1504 UTIL_LOG(L4, (_T("[GetImagePath][pid=%d]"), process_id));
1505 scoped_process process_handle(::OpenProcess(PROCESS_QUERY_INFORMATION |
1506 PROCESS_VM_READ,
1507 FALSE,
1508 process_id));
1509 if (!process_handle) {
1510 HRESULT hr = HRESULTFromLastError();
1511 UTIL_LOG(L4, (_T("[OpenProcess failed][0x%08x]"), hr));
1512 return hr;
1513 }
1514
1515 HMODULE module_handle = NULL;
1516 DWORD bytes_needed = 0;
1517 if (!::EnumProcessModules(get(process_handle),
1518 &module_handle,
1519 sizeof(HMODULE),
1520 &bytes_needed)) {
1521 HRESULT hr = HRESULTFromLastError();
1522 UTIL_LOG(LEVEL_WARNING, (_T("[EnumProcessModules failed][0x%08x]"), hr));
1523 // ::EnumProcessModules from a WoW64 process fails for x64 processes. We try
1524 // ::GetProcessImageFileName as a workaround here.
1525 TCHAR image_name[MAX_PATH] = {0};
1526 if (!GetProcessImageFileName(get(process_handle),
1527 image_name,
1528 arraysize(image_name))) {
1529 HRESULT hr = HRESULTFromLastError();
1530 UTIL_LOG(LE, (_T("[GetProcessImageFileName failed][0x%08x]"), hr));
1531 return hr;
1532 } else {
1533 *path = image_name;
1534 return S_OK;
1535 }
1536 }
1537
1538 TCHAR module_name[MAX_PATH] = {0};
1539 if (!::GetModuleFileNameEx(get(process_handle),
1540 module_handle,
1541 module_name,
1542 arraysize(module_name))) {
1543 HRESULT hr = HRESULTFromLastError();
1544 UTIL_LOG(LEVEL_ERROR, (_T("[GetModuleFileNameEx failed][0x%08x]"), hr));
1545 return hr;
1546 }
1547
1548 *path = module_name;
1549 return S_OK;
1550 }
1551
1552 bool Process::IsWow64(uint32 pid) {
1553 typedef BOOL (WINAPI *IsWow64Process)(HANDLE, BOOL*);
1554 scoped_process handle(::OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
1555 false,
1556 pid));
1557 if (!handle) {
1558 return false;
1559 }
1560
1561 HINSTANCE kernel_instance = ::GetModuleHandle(_T("kernel32.dll"));
1562 if (kernel_instance == NULL) {
1563 ASSERT1(false);
1564 HRESULT hr = HRESULTFromLastError();
1565 UTIL_LOG(LW, (_T("[::GetModuleHandle kernel32.dll failed][0x%08x]"), hr));
1566 return false;
1567 }
1568
1569 IsWow64Process pfn = reinterpret_cast<IsWow64Process>(::GetProcAddress(
1570 kernel_instance,
1571 "IsWow64Process"));
1572 if (!pfn) {
1573 UTIL_LOG(LW, (_T("[::IsWow64Process() not found in kernel32.dll]")));
1574 return false;
1575 }
1576
1577 BOOL wow64 = FALSE;
1578 if (!(*pfn)(get(handle), &wow64)) {
1579 HRESULT hr = HRESULTFromLastError();
1580 UTIL_LOG(LW, (_T("[::IsWow64Process() failed][0x%08x]"), hr));
1581 return false;
1582 }
1583
1584 return (wow64 != 0);
1585 }
1586
1587 HRESULT Process::MakeProcessWindowForeground(const CString& executable) {
1588 UTIL_LOG(L3, (_T("[MakeProcessWindowForeground]")));
1589
1590 CString sid;
1591 HRESULT hr = omaha::user_info::GetProcessUser(NULL, NULL, &sid);
1592 if (FAILED(hr)) {
1593 return hr;
1594 }
1595
1596 // This code does not handle two cases:
1597 // 1. If a new process instance is starting up but there are other process
1598 // instances running, then we will not wait for the new process instance.
1599 // One way to fix this is to pass the number of expected processes to this
1600 // method.
1601 // 2. If we find multiple processes, and we are able to find the windows only
1602 // for some of the processes (maybe because the rest are still starting up)
1603 // then we will only set the windows of the one that we found to the
1604 // foreground and ignore the rest.
1605 bool found = false;
1606 for (int retries = 0; retries < kNumRetriesToFindProcess && !found;
1607 ++retries) {
1608 std::vector<CString> command_lines;
1609 std::vector<uint32> processes;
1610 DWORD flags = EXCLUDE_CURRENT_PROCESS | INCLUDE_ONLY_PROCESS_OWNED_BY_USER;
1611 hr = Process::FindProcesses(flags,
1612 executable,
1613 true,
1614 sid,
1615 command_lines,
1616 &processes);
1617 if (FAILED(hr)) {
1618 UTIL_LOG(LW, (_T("[FindProcesses failed][0x%08x]"), hr));
1619 return hr;
1620 }
1621
1622 UTIL_LOG(L3, (_T("[Found %d processes]"), processes.size()));
1623 for (size_t i = 0; i < processes.size(); ++i) {
1624 CSimpleArray<HWND> windows;
1625 if (!WindowUtils::FindProcessWindows(processes[i], 0, &windows)) {
1626 UTIL_LOG(L3, (_T("[FindProcessWindows failed][0x%08x]"), hr));
1627 continue;
1628 }
1629
1630 for (int j = 0; j < windows.GetSize(); ++j) {
1631 if (WindowUtils::IsMainWindow(windows[j])) {
1632 UTIL_LOG(L4, (_T("[Found main window of process %d]"), processes[i]));
1633 WindowUtils::MakeWindowForeground(windows[j]);
1634 ::FlashWindow(windows[j], true);
1635 found = true;
1636 break;
1637 }
1638 }
1639 }
1640
1641 if (!found) {
1642 ::Sleep(kFindProcessRetryIntervalMs);
1643 }
1644 }
1645
1646 return S_OK;
1647 }
1648
1649 } // namespace omaha
1650
OLDNEW
« no previous file with comments | « base/process.h ('k') | base/process_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698