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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/process.h ('k') | base/process_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/process.cc
diff --git a/base/process.cc b/base/process.cc
deleted file mode 100644
index 0ebfb07542f6aeaf5629e984f018d78150ed6f59..0000000000000000000000000000000000000000
--- a/base/process.cc
+++ /dev/null
@@ -1,1650 +0,0 @@
-// Copyright 2004-2009 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-// ========================================================================
-//
-// Defines class Process to incapsulate win32
-// functions for creation and some manipulations of
-// processes.
-
-#include "omaha/base/process.h"
-
-#include <ntsecapi.h>
-#include <psapi.h>
-#include <stierr.h>
-#include <tlhelp32.h>
-#include <vector>
-
-#ifndef NT_SUCCESS
-#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
-#endif
-
-#include "omaha/base/debug.h"
-#include "omaha/base/disk.h"
-#include "omaha/base/error.h"
-#include "omaha/base/logging.h"
-#include "omaha/base/scoped_any.h"
-#include "omaha/base/string.h"
-#include "omaha/base/system.h"
-#include "omaha/base/system_info.h"
-#include "omaha/base/utils.h"
-#include "omaha/base/user_info.h"
-#include "omaha/base/window_utils.h"
-
-namespace omaha {
-
-const int kNumRetriesToFindProcess = 4;
-const int kFindProcessRetryIntervalMs = 500;
-const int kMaxCmdLineLengthBytes = 4096;
-
-// Constructor
-Process::Process(const TCHAR* name,
- const TCHAR* window_class_name)
- : process_id_(0),
- exit_code_(0),
- number_of_restarts_(static_cast<uint32>(-1)),
- name_(name),
- shutdown_event_(NULL) {
- ASSERT1(name);
- command_line_ = name;
- window_class_name_ = window_class_name;
-}
-
-// Constructor
-Process::Process(uint32 process_id)
- : process_id_(process_id),
- exit_code_(0),
- number_of_restarts_(static_cast<uint32>(-1)),
- name_(itostr(static_cast<uint32>(process_id))),
- shutdown_event_(NULL) {
- reset(process_, ::OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
- false,
- process_id));
- if (!valid(process_)) {
- UTIL_LOG(LEVEL_ERROR,
- (_T("[Process::Process - failed to open process][%u][0x%x]"),
- process_id, HRESULTFromLastError()));
- }
-}
-
-// Destructor
-Process::~Process() {
-}
-
-// Start with command params
-HRESULT Process::Start(const TCHAR* command_line_parameters,
- HANDLE runas_token) {
- if (command_line_parameters && *command_line_parameters) {
- command_line_parameters_ = command_line_parameters;
- }
-
- number_of_restarts_ = static_cast<uint32>(-1);
- time_of_start_ = GetTickCount();
-
- return Restart(runas_token);
-}
-
-// Restart with the old command params
-HRESULT Process::Restart(HANDLE runas_token) {
- // Can't start the same process twice in the same containing object.
- if (Running()) {
- return E_FAIL;
- }
-
- PROCESS_INFORMATION process_info = {0};
- HRESULT hr = runas_token ?
- System::StartProcessAsUser(runas_token,
- command_line_,
- command_line_parameters_,
- _T("WinSta0\\Default"),
- &process_info) :
- System::StartProcessWithArgsAndInfo(command_line_,
- command_line_parameters_,
- &process_info);
-
- if (SUCCEEDED(hr)) {
- VERIFY1(::CloseHandle(process_info.hThread));
-
- reset(process_, process_info.hProcess);
- process_id_ = process_info.dwProcessId;
-
- ASSERT1(process_id_);
- number_of_restarts_++;
- } else {
- UTIL_LOG(LE, (_T("[Process Restart failed][%s][0x%x]"), command_line_, hr));
- }
-
- return hr;
-}
-
-// Check if the process is running.
-bool Process::Running() const {
- if (!get(process_)) {
- return false;
- }
-
- return (::WaitForSingleObject(get(process_), 0) == WAIT_TIMEOUT);
-}
-
-// Create a job and assign the process to it
-HANDLE Process::AssignToJob() {
- // Make sure that the process handle is valid
- if (!get(process_)) {
- return false;
- }
-
- // Create a job
- scoped_job job(::CreateJobObject(NULL, NULL));
- if (!valid(job)) {
- UTIL_LOG(LEVEL_ERROR,
- (_T("[Process::AssignToJob - CreateJobObject failed][0x%x]"),
- HRESULTFromLastError()));
- return false;
- }
-
- // Assign the process to the job
- if (!::AssignProcessToJobObject(get(job), get(process_))) {
- UTIL_LOG(LEVEL_ERROR,
- (_T("[Process::AssignToJob-AssignProcessToJobObject fail][0x%x]"),
- HRESULTFromLastError()));
- return false;
- }
-
- return release(job);
-}
-
-// Wait till the process finishes
-bool Process::WaitUntilDead(uint32 timeout_msec) {
- ASSERT1(timeout_msec);
-
- if (!get(process_)) {
- return false;
- }
-
- uint32 ret = 0;
- if (shutdown_event_) {
- HANDLE wait_handles[2] = {0};
- wait_handles[0] = get(process_);
- wait_handles[1] = shutdown_event_;
- ret = ::WaitForMultipleObjectsEx(2,
- wait_handles,
- false,
- timeout_msec,
- true);
- } else {
- ret = ::WaitForSingleObjectEx(get(process_), timeout_msec, true);
- }
- if (ret == WAIT_OBJECT_0) {
- UTIL_LOG(L2, (_T("[Process::WaitUntilDead - succeeded to wait process]")
- _T("[%s]"), GetName()));
- return true;
- } else if (ret == WAIT_IO_COMPLETION) {
- UTIL_LOG(LEVEL_ERROR, (_T("[Process::WaitUntilDead-recv APC][%s][%u][%u]"),
- GetName(), process_id_));
- return false;
- } else {
- UTIL_LOG(LEVEL_ERROR, (_T("[Process::WaitUntilDead - fail to wait process,")
- _T("possibly timeout][%s][%u][%u]"),
- GetName(), process_id_, ret));
- return false;
- }
-}
-
-// Wait some time till the process and all its descendent processes finish
-//
-// Background:
-// Some process might spawn another process and get itself terminated
-// without waiting the descendant process to finish.
-//
-// Args:
-// job: Job to which the process is assigned
-// AssignToJob() will be called when NULL value is passed
-// timeout_msec: Timeout value in msec
-// path_to_exclude: Path of descendant process to excluded from waiting
-// (this should be in long format)
-// exit_code: To hold the exit code being returned
-bool Process::WaitUntilAllDead(HANDLE job,
- uint32 timeout_msec,
- const TCHAR* path_to_exclude,
- uint32* exit_code) {
- ASSERT1(timeout_msec);
-
- UTIL_LOG(L2, (_T("[Process::WaitUntilAllDead][%u][%s]"),
- timeout_msec, path_to_exclude));
-
- if (exit_code) {
- *exit_code = 0;
- }
-
- scoped_job job_guard;
- if (!job) {
- reset(job_guard, AssignToJob());
- if (!valid(job_guard)) {
- return false;
- }
- job = get(job_guard);
- }
-
- return InternalWaitUntilAllDead(job,
- timeout_msec,
- path_to_exclude,
- exit_code);
-}
-
-// Helper function to wait till the process and all its descendent processes
-// finish.
-bool Process::InternalWaitUntilAllDead(HANDLE job,
- uint32 timeout_msec,
- const TCHAR* path_to_exclude,
- uint32* exit_code) {
- ASSERT1(job);
- ASSERT1(timeout_msec);
-
- // Wait until current process finishes
- if (!WaitUntilDead(timeout_msec)) {
- return false;
- }
-
- // Find descendant process
- uint32 desc_process_id = GetDescendantProcess(
- job,
- false, // child_only
- exit_code != NULL, // sole_descendent
- NULL, // search_name
- path_to_exclude);
-
- if (desc_process_id) {
- // Open descendent process
- Process desc_process(desc_process_id);
-
- // If descendant process dies too soon, do not need to wait for it
- if (desc_process.Running()) {
- // Release the parent process handle
- // This to handle the scenario that Firefox uninstall code will wait till
- // parent process handle becomes NULL
- reset(process_);
-
- UTIL_LOG(L2, (_T("[Process::InternalWaitUntilAllDead]")
- _T("[waiting descendant process][%u]"), desc_process_id));
-
- // Propagate the shutdown event to descendent process
- if (shutdown_event_) {
- desc_process.SetShutdownEvent(shutdown_event_);
- }
-
- // Wait till descendant process finishes
- bool wait_ret = desc_process.InternalWaitUntilAllDead(job,
- timeout_msec,
- path_to_exclude,
- exit_code);
-
- return wait_ret;
- }
- }
-
- // Use the exit code from parent process
- if (exit_code) {
- VERIFY1(GetExitCode(exit_code));
- }
-
- // Release the parent process handle
- reset(process_);
-
- return true;
-}
-
-// Wait until process is dead or a windows message arrives (for use in a message
-// loop while waiting)
-HRESULT Process::WaitUntilDeadOrInterrupt(uint32 msec) {
- if (!get(process_)) {
- return E_FAIL;
- }
-
- HANDLE events[1] = { get(process_) };
- uint32 dw = ::MsgWaitForMultipleObjects(1, events, FALSE, msec, QS_ALLEVENTS);
- switch (dw) {
- case WAIT_OBJECT_0:
- return CI_S_PROCESSWAIT_DEAD;
- case WAIT_OBJECT_0 + 1:
- return CI_S_PROCESSWAIT_MESSAGE;
- case WAIT_TIMEOUT:
- return CI_S_PROCESSWAIT_TIMEOUT;
- case WAIT_FAILED:
- default:
- return E_FAIL;
- }
-}
-
-#if !SHIPPING
-CString Process::GetDebugInfo() const {
- return debug_info_;
-}
-#endif
-
-// Return the process ID
-uint32 Process::GetId() const {
- return process_id_;
-}
-
-// Return the process name
-const TCHAR *Process::GetName() const {
- return name_;
-}
-
-// Return win32 handle to the process.
-HANDLE Process::GetHandle() const {
- return get(process_);
-}
-
-// Get process exit code.
-bool Process::GetExitCode(uint32* exit_code) const {
- ASSERT1(exit_code);
-
- if (!get(process_)) {
- return false;
- }
-
- if (!::GetExitCodeProcess(get(process_),
- reinterpret_cast<DWORD*>(&exit_code_))) {
- UTIL_LOG(LEVEL_ERROR,
- (_T("[Process::GetExitCode - failed to get exit code][%u][0x%x]"),
- process_id_, HRESULTFromLastError()));
- return false;
- }
- if (exit_code_ == STILL_ACTIVE) {
- return false;
- }
-
- *exit_code = exit_code_;
- return true;
-}
-
-// default implementation allows termination
-bool Process::IsTerminationAllowed() const {
- return true;
-}
-
-// Terminate the process. If wait_for_terminate_msec == 0 return value doesn't
-// mean that the process actualy terminated. It becomes assync. operation.
-// Check the status with Running accessor function in this case.
-bool Process::Terminate(uint32 wait_for_terminate_msec) {
- if (!Running()) {
- return true;
- }
-
- if (!IsTerminationAllowed()) {
- return false;
- }
-
- if (!::TerminateProcess(get(process_), 1)) {
- return false;
- }
-
- return wait_for_terminate_msec ? WaitUntilDead(wait_for_terminate_msec) :
- true;
-}
-
-// Default returns INFINITE means never restart.
-// Return any number of msec if overwriting
-uint32 Process::GetRestartInterval() const {
- return INFINITE;
-}
-
-// How many times the process can be restarted
-// in case it crashes. When overriding return any
-// number or INFINITE to restart forever.
-uint32 Process::GetMaxNumberOfRestarts() const {
- return 0;
-}
-
-// what is the time window for number of crashes returned by
-// GetMaxNumberOfRestarts(). If crashed more that this number of restarts
-// in a specified time window - do not restart it anymore.
-// Default implementation returns INFINITE which means that this is not time
-// based at all, if the process crashed more than the value returned by
-// GetMaxNumberOfRestarts it will not be restarted no matter how long it took.
-uint32 Process::GetTimeWindowForCrashes() const {
- return INFINITE;
-}
-
-uint32 Process::GetMaxMemory() const {
- return 0;
-}
-
-// Have we exceeded the number of maximum restarting?
-bool Process::AllowedToRestart() const {
- uint32 max_number_of_restarts = GetMaxNumberOfRestarts();
-
- if ((max_number_of_restarts == INFINITE) ||
- (number_of_restarts_ < max_number_of_restarts)) {
- return true;
- }
-
- // process crashed too many times. Let's look at the rate of crashes.
- // Maybe we can "forgive" the process if it took some time for it to crash.
- if ((::GetTickCount() - time_of_start_) < GetTimeWindowForCrashes()) {
- return false; // not forgiven
- }
-
- // Everything is forgiven. Give the process
- // new start in life.
- time_of_start_ = ::GetTickCount();
- number_of_restarts_ = static_cast<uint32>(-1);
-
- return true;
-}
-
-// Set shutdown event using in signaling the process watch
-void Process::SetShutdownEvent(HANDLE shutdown_event) {
- ASSERT1(shutdown_event);
-
- shutdown_event_ = shutdown_event;
-}
-
-// Set priority class to the process.
-bool Process::SetPriority(uint32 priority_class) const {
- if (!get(process_)) {
- return false;
- }
-
- VERIFY1(::SetPriorityClass(get(process_), priority_class));
- return true;
-}
-
-HRESULT Process::GetParentProcessId(uint32* parent_pid) {
- ASSERT1(parent_pid);
- *parent_pid = 0;
-
- scoped_hfile process_snap(::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
- if (!process_snap) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LE, (_T("[GetParentProcessId][Failed snapshot][0x%x]"), hr));
- return hr;
- }
-
- // Eumerate all processes in the snapshot
- PROCESSENTRY32 pe32;
- SetZero(pe32);
- pe32.dwSize = sizeof(PROCESSENTRY32);
- if (!::Process32First(get(process_snap), &pe32)) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LE, (_T("[Process32First failed][0x%x]"), hr));
- return hr;
- }
-
- do {
- if (pe32.th32ProcessID != process_id_) {
- continue;
- }
-
- if (pe32.th32ParentProcessID) {
- *parent_pid = pe32.th32ParentProcessID;
- return S_OK;
- }
- } while (::Process32Next(get(process_snap), &pe32));
-
- return E_FAIL;
-}
-
-// Try to get a descendant process. Return process id if found.
-uint32 Process::GetDescendantProcess(HANDLE job,
- bool child_only,
- bool sole_descedent,
- const TCHAR* search_name,
- const TCHAR* path_to_exclude) {
- ASSERT1(job);
-
- // Find all descendent processes
- std::vector<ProcessInfo> descendant_processes;
- if (FAILED(GetAllDescendantProcesses(job,
- child_only,
- search_name,
- path_to_exclude,
- &descendant_processes))) {
- return 0;
- }
-
- // If more than one decendent processes is found, filter out those that are
- // not direct children. This is because it might be the case that in a very
- // short period of time, process A spawns B and B spawns C, and we capture
- // both B and C.
- std::vector<ProcessInfo> child_processes;
- typedef std::vector<ProcessInfo>::const_iterator ProcessInfoConstIterator;
- if (descendant_processes.size() > 1) {
- for (ProcessInfoConstIterator it(descendant_processes.begin());
- it != descendant_processes.end(); ++it) {
- if (it->parent_id == process_id_) {
- child_processes.push_back(*it);
- }
- }
- if (!child_processes.empty()) {
- descendant_processes = child_processes;
- }
- }
-
- // Save the debugging information if needed
-#if !SHIPPING
- if (sole_descedent && descendant_processes.size() > 1) {
- debug_info_ = _T("More than one descendent process is found for process ");
- debug_info_ += itostr(process_id_);
- debug_info_ += _T("\n");
- for (ProcessInfoConstIterator it(descendant_processes.begin());
- it != descendant_processes.end(); ++it) {
- debug_info_.AppendFormat(_T("%u %u %s\n"),
- it->process_id,
- it->parent_id,
- it->exe_file);
- }
- }
-#else
- sole_descedent; // unreferenced formal parameter
-#endif
-
- return descendant_processes.empty() ? 0 : descendant_processes[0].process_id;
-}
-
-BOOL Process::IsProcessInJob(HANDLE process_handle,
- HANDLE job_handle,
- PBOOL result) {
- typedef BOOL (WINAPI *Fun)(HANDLE process_handle,
- HANDLE job_handle,
- PBOOL result);
-
- HINSTANCE kernel_instance = ::GetModuleHandle(_T("kernel32.dll"));
- ASSERT1(kernel_instance);
- Fun pfn = reinterpret_cast<Fun>(::GetProcAddress(kernel_instance,
- "IsProcessInJob"));
- ASSERT(pfn, (_T("IsProcessInJob export not found in kernel32.dll")));
- return pfn ? (*pfn)(process_handle, job_handle, result) : FALSE;
-}
-
-// Try to get all matching descendant processes
-HRESULT Process::GetAllDescendantProcesses(
- HANDLE job,
- bool child_only,
- const TCHAR* search_name,
- const TCHAR* path_to_exclude,
- std::vector<ProcessInfo>* descendant_processes) {
- ASSERT1(job);
- ASSERT1(descendant_processes);
-
- // Take a snapshot
- // Note that we do not have a seperate scoped_* type defined to wrap the
- // handle returned by CreateToolhelp32Snapshot. So scoped_hfile with similar
- // behavior is used.
- scoped_hfile process_snap(::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
- if (!process_snap) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LEVEL_ERROR,
- (_T("[Process::GetAllDescendantProcesses - fail to get snapshot]")
- _T("[0x%x]"), hr));
- return hr;
- }
-
- // Eumerate all processes in the snapshot
- PROCESSENTRY32 pe32;
- SetZero(pe32);
- pe32.dwSize = sizeof(PROCESSENTRY32);
- if (!::Process32First(get(process_snap), &pe32)) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LEVEL_ERROR, (_T("[Process::GetAllDescendantProcesses - failed to")
- _T("get first process][0x%x]"), hr));
- return hr;
- }
-
- do {
- // Skip process 0 and current process
- if (pe32.th32ProcessID == 0 || pe32.th32ProcessID == process_id_) {
- continue;
- }
-
- // If searching for child only, perform the check
- if (child_only && pe32.th32ParentProcessID != process_id_) {
- continue;
- }
-
- // Open the process
- scoped_process process(::OpenProcess(PROCESS_QUERY_INFORMATION |
- SYNCHRONIZE,
- false,
- pe32.th32ProcessID));
- if (!valid(process)) {
- continue;
- }
-
- // Determines whether the process is running in the specified job
- BOOL result = FALSE;
- if (!IsProcessInJob(get(process), job, &result) || !result) {
- continue;
- }
-
- // Check whether the process is still running
- if (::WaitForSingleObject(get(process), 0) != WAIT_TIMEOUT) {
- continue;
- }
-
- // Compare the name if needed
- if (search_name && *search_name) {
- if (_tcsicmp(pe32.szExeFile, search_name) != 0) {
- continue;
- }
- }
-
- // If we need to exclude certain path, check it now
- if (path_to_exclude && *path_to_exclude) {
- if (IsProcessRunningWithPath(pe32.th32ProcessID, path_to_exclude)) {
- continue;
- }
- }
-
- // Add to the list
- ProcessInfo proc_info;
- proc_info.process_id = pe32.th32ProcessID;
- proc_info.parent_id = pe32.th32ParentProcessID;
-#if !SHIPPING
- proc_info.exe_file = pe32.szExeFile;
-#endif
- descendant_processes->push_back(proc_info);
- } while (::Process32Next(get(process_snap), &pe32));
-
- return S_OK;
-}
-
-HRESULT Process::FindProcesses(uint32 exclude_mask,
- const TCHAR* search_name,
- bool search_main_executable_only,
- std::vector<uint32>* process_ids_found) {
- ASSERT1(process_ids_found);
- // Remove the only include processes owned by user mask from the exclude
- // mask. This is needed as this is the behavior expected by the method,
- // before the addition of the user_sid.
- exclude_mask &= (~INCLUDE_ONLY_PROCESS_OWNED_BY_USER);
- std::vector<CString> command_lines;
- return FindProcesses(exclude_mask, search_name, search_main_executable_only,
- _T(""), command_lines, process_ids_found);
-}
-
-bool Process::IsStringPresentInList(const CString& process_command_line,
- const std::vector<CString>& list) {
- std::vector<CString>::const_iterator iter = list.begin();
- for (; iter != list.end(); ++iter) {
- CString value_to_find = *iter;
-
- // If we are able to open the process command line, then we should
- // ensure that it does not contain the value that we are looking for.
- if (process_command_line.Find(value_to_find) != -1) {
- // Found a match.
- return true;
- }
- }
-
- return false;
-}
-
-// TODO(omaha): Change the implementation of this method to take in a
-// predicate that determines whether a process should be included in the
-// result set.
-HRESULT Process::FindProcesses(uint32 exclude_mask,
- const TCHAR* search_name,
- bool search_main_executable_only,
- const CString& user_sid,
- const std::vector<CString>& command_lines,
- std::vector<uint32>* process_ids_found) {
- ASSERT1(search_name && *search_name);
- ASSERT1(process_ids_found);
- ASSERT1(!((exclude_mask & EXCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING) &&
- (exclude_mask & INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING)));
-
- const TCHAR* const kLocalSystemSid = _T("S-1-5-18");
-
- // Clear the output queue
- process_ids_found->clear();
-
- // Get the list of process identifiers.
- uint32 process_ids[kMaxProcesses] = {0};
- uint32 bytes_returned = 0;
- if (!::EnumProcesses(reinterpret_cast<DWORD*>(process_ids),
- sizeof(process_ids),
- reinterpret_cast<DWORD*>(&bytes_returned))) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LEVEL_ERROR, (_T("[Process::FindProcesses-fail to EnumProcesses]")
- _T("[0x%x]"), hr));
- return hr;
- }
-
- // Enumerate all processes
- int num_processes = bytes_returned / sizeof(process_ids[0]);
- // We have found an elevated number of crashes in 1.2.584.15114 on what
- // we believe are Italian systems. The first step to solving this Italian job
- // is to assert on the condition while we are further testing this.
- ASSERT1(num_processes <= kMaxProcesses);
-
- // In Vista, SeDebugPrivilege is required to open the process not owned by
- // current user. Also required for XP admins to open Local System processes
- // with PROCESS_QUERY_INFORMATION access rights.
- System::AdjustPrivilege(SE_DEBUG_NAME, true);
-
- const uint32 cur_process_id = ::GetCurrentProcessId();
-
- uint32 parent_process_id = 0;
- if (exclude_mask & EXCLUDE_PARENT_PROCESS) {
- Process current_process(cur_process_id);
- uint32 ppid = 0;
- HRESULT hr = current_process.GetParentProcessId(&ppid);
- parent_process_id = SUCCEEDED(hr) ? ppid : 0;
- }
-
- // Get SID of current user
- CString cur_user_sid;
- HRESULT hr = omaha::user_info::GetProcessUser(NULL, NULL, &cur_user_sid);
- if (FAILED(hr)) {
- return hr;
- }
-
- UTIL_LOG(L4, (_T("[Process::FindProcesses][processes=%d]"), num_processes));
- for (int i = 0; i < num_processes; ++i) {
- // Skip the system idle process.
- if (process_ids[i] == 0) {
- continue;
- }
-
- // Skip the current process if needed.
- if ((exclude_mask & EXCLUDE_CURRENT_PROCESS) &&
- (process_ids[i] == cur_process_id)) {
- UTIL_LOG(L4, (_T("[Excluding current process %d"), process_ids[i]));
- continue;
- }
-
- // Skip the parent process if needed.
- if ((exclude_mask & EXCLUDE_PARENT_PROCESS) &&
- (process_ids[i] == parent_process_id)) {
- UTIL_LOG(L4, (_T("[Excluding parent process(%d) of %d"),
- process_ids[i], cur_process_id));
- continue;
- }
-
-
- // Get the owner sid.
- // Note that we may fail to get the owner which is not current user.
- // So if the owner_sid is empty, the process is sure not to be owned by the
- // current user.
- CString owner_sid;
- Process::GetProcessOwner(process_ids[i], &owner_sid);
-
- if ((exclude_mask & INCLUDE_ONLY_PROCESS_OWNED_BY_USER) &&
- owner_sid != user_sid) {
- UTIL_LOG(L4,
- (_T("[Excluding process as not owned by user][%d]"), process_ids[i]));
- continue;
- }
-
- if ((exclude_mask & EXCLUDE_PROCESS_OWNED_BY_CURRENT_USER) &&
- owner_sid == cur_user_sid) {
- UTIL_LOG(L4,
- (_T("[Excluding process as owned by current user][%d]"),
- process_ids[i]));
- continue;
- }
- if ((exclude_mask & EXCLUDE_PROCESS_OWNED_BY_SYSTEM) &&
- owner_sid == kLocalSystemSid) {
- UTIL_LOG(L4,
- (_T("[Excluding process as owned by system][%d]"), process_ids[i]));
- continue;
- }
- if (exclude_mask & EXCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING ||
- exclude_mask & INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING) {
- CString process_command_line;
- HRESULT hr = GetCommandLine(process_ids[i], &process_command_line);
- if (FAILED(hr)) {
- UTIL_LOG(L4,
- (_T("[Excluding process could not get command line][%d]"),
- process_ids[i]));
- continue;
- }
-
- // If we are able to open the process command line, then we should
- // ensure that it does not contain the value that we are looking for if
- // we are excluding the command line or that it contains the command line
- // that we are looking for in case the include switch is specified.
- bool present = IsStringPresentInList(process_command_line, command_lines);
- if ((present &&
- (exclude_mask & EXCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING)) ||
- (!present &&
- (exclude_mask & INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING))) {
- UTIL_LOG(L4, (_T("[Process command line matches criteria][%d]'[%s]'"),
- process_ids[i], process_command_line));
- continue;
- }
- }
-
- // If search_name is provided, make sure it matches
- if (Process::IsProcessUsingExeOrDll(process_ids[i],
- search_name,
- search_main_executable_only)) {
- UTIL_LOG(L4,
- (_T("[Including process][%d][%s]"), process_ids[i], search_name));
- process_ids_found->push_back(process_ids[i]);
- }
- }
-
- return S_OK;
-}
-
-HRESULT Process::FindProcessesInSession(
- DWORD session_id,
- uint32 exclude_mask,
- const TCHAR* search_name,
- bool search_main_executable_only,
- const CString& user_sid,
- const std::vector<CString>& cmd_lines,
- std::vector<uint32>* process_ids_found) {
- HRESULT hr = FindProcesses(exclude_mask,
- search_name,
- search_main_executable_only,
- user_sid,
- cmd_lines,
- process_ids_found);
- if (FAILED(hr)) {
- return hr;
- }
-
- // Filter to processes running under session_id.
- std::vector<uint32>::iterator iter = process_ids_found->begin();
- while (iter != process_ids_found->end()) {
- uint32 process_pid = *iter;
- DWORD process_session = 0;
- hr = S_OK;
- if (!::ProcessIdToSessionId(process_pid, &process_session)) {
- hr = HRESULTFromLastError();
- UTIL_LOG(LE, (_T("[::ProcessIdToSessionId failed][0x%x]"), hr));
- } else if (process_session != session_id) {
- UTIL_LOG(L4, (_T("[Excluding process, different session][%d][%d][%d]"),
- process_pid, process_session, session_id));
- }
-
- if (FAILED(hr) || process_session != session_id) {
- // Remove from list and continue.
- iter = process_ids_found->erase(iter);
- continue;
- }
-
- ++iter;
- }
-
- return S_OK;
-}
-
-bool Process::IsModuleMatchingExeOrDll(const TCHAR* module_name,
- const TCHAR* search_name,
- bool is_fully_qualified_name) {
- CString module_file_name;
- if (is_fully_qualified_name) {
- if (FAILED(GetLongPathName(module_name, &module_file_name))) {
- return false;
- }
- } else {
- module_file_name = ::PathFindFileName(module_name);
- ASSERT1(!module_file_name.IsEmpty());
- if (module_file_name.IsEmpty()) {
- return false;
- }
- }
-
- return (module_file_name.CompareNoCase(search_name) == 0);
-}
-
-DWORD Process::GetProcessImageFileName(HANDLE proc_handle,
- LPTSTR image_file,
- DWORD file_size) {
- typedef DWORD (WINAPI *Fun)(HANDLE proc_handle,
- LPWSTR image_file,
- DWORD file_size);
-
- HINSTANCE psapi_instance = ::GetModuleHandle(_T("Psapi.dll"));
- ASSERT1(psapi_instance);
- Fun pfn = reinterpret_cast<Fun>(::GetProcAddress(psapi_instance,
- "GetProcessImageFileNameW"));
- if (!pfn) {
- UTIL_LOG(L1, (_T("::GetProcessImageFileNameW() not found in Psapi.dll")));
- return 0;
- }
- return (*pfn)(proc_handle, image_file, file_size);
-}
-
-bool Process::IsProcImageMatch(HANDLE proc_handle,
- const TCHAR* search_name,
- bool is_fully_qualified_name) {
- TCHAR image_name[MAX_PATH] = _T("");
- if (!GetProcessImageFileName(proc_handle,
- image_name,
- arraysize(image_name))) {
- UTIL_LOG(L4, (_T("[GetProcessImageFileName fail[0x%x]"),
- HRESULTFromLastError()));
- return false;
- }
-
- UTIL_LOG(L4, (_T("[GetProcessImageFileName][%s]"), image_name));
- CString dos_name;
- HRESULT hr(DevicePathToDosPath(image_name, &dos_name));
- if (FAILED(hr)) {
- UTIL_LOG(L4, (_T("[DevicePathToDosPath fail[0x%x]"), hr));
- return false;
- }
-
- return IsModuleMatchingExeOrDll(dos_name,
- search_name,
- is_fully_qualified_name);
-}
-
-// Is the process using the specified exe/dll?
-bool Process::IsProcessUsingExeOrDll(uint32 process_id,
- const TCHAR* search_name,
- bool search_main_executable_only) {
- ASSERT1(search_name);
-
- // Open the process
- scoped_process process_handle(::OpenProcess(
- PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
- FALSE,
- process_id));
- if (!process_handle) {
- UTIL_LOG(L4, (_T("[::OpenProcess failed][0x%x]"), HRESULTFromLastError()));
- return false;
- }
-
- // Does the name represent a fully qualified name?
- // We only do a simple check here
- bool is_fully_qualified_name = String_FindChar(search_name, _T('\\')) != -1;
- CString long_search_name;
- if (is_fully_qualified_name) {
- HRESULT hr(GetLongPathName(search_name, &long_search_name));
- if (FAILED(hr)) {
- UTIL_LOG(L4, (_T("[GetLongPathName fail][hr=x%x]"), hr));
- return false;
- }
- search_name = long_search_name;
- }
-
- // Take a snapshot of all modules in the specified process
- int num_modules_to_fetch = search_main_executable_only ? 1 :
- kMaxProcessModules;
- HMODULE module_handles[kMaxProcessModules];
- SetZero(module_handles);
- uint32 bytes_needed = 0;
- if (!::EnumProcessModules(get(process_handle),
- module_handles,
- num_modules_to_fetch * sizeof(HMODULE),
- reinterpret_cast<DWORD*>(&bytes_needed))) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LEVEL_ERROR, (_T("[EnumProcessModules failed][0x%x]"), hr));
-
- if (IsWow64(::GetCurrentProcessId())) {
- // ::EnumProcessModules from a WoW64 process fails for x64 processes.
- // We try ::GetProcessImageFileName as a workaround here.
- return search_main_executable_only ?
- IsProcImageMatch(get(process_handle),
- search_name,
- is_fully_qualified_name) :
- false;
- } else {
- return false;
- }
- }
-
- int num_modules = bytes_needed / sizeof(HMODULE);
- if (num_modules > num_modules_to_fetch) {
- num_modules = num_modules_to_fetch;
- }
-
- for (int i = 0; i < num_modules; ++i) {
- TCHAR module_name[MAX_PATH];
- SetZero(module_name);
- if (!::GetModuleFileNameEx(get(process_handle),
- module_handles[i],
- module_name,
- arraysize(module_name))) {
- UTIL_LOG(LEVEL_ERROR, (_T("[GetModuleFileNameEx fail[x%x]"),
- HRESULTFromLastError()));
- continue;
- }
-
- if (IsModuleMatchingExeOrDll(module_name,
- search_name,
- is_fully_qualified_name)) {
- return true;
- }
- }
-
- return false;
-}
-
-// Helper function to get long path name
-HRESULT Process::GetLongPathName(const TCHAR* short_name, CString* long_name) {
- ASSERT1(short_name);
- ASSERT1(long_name);
-
- TCHAR temp_name[MAX_PATH];
- SetZero(temp_name);
-
- HRESULT hr = S_OK;
- if (!::GetLongPathName(short_name, temp_name, arraysize(temp_name))) {
- hr = HRESULTFromLastError();
- } else {
- long_name->SetString(temp_name);
- }
-
- return hr;
-}
-
-// Retrieve the FQPN for the executable file for a process. (Note: Using
-// GetModuleFileNameEx is slower than GetProcessImageFileName, but the former
-// is available on Win2K, while the latter is only only on XP and up.)
-HRESULT Process::GetExecutablePath(uint32 process_id, CString *exe_path) {
- ASSERT1(process_id);
- ASSERT1(exe_path);
-
- TCHAR temp_path[MAX_PATH];
- SetZero(temp_path);
-
- scoped_process process(::OpenProcess(PROCESS_QUERY_INFORMATION |
- PROCESS_VM_READ,
- FALSE,
- process_id));
- if (!valid(process)) {
- return HRESULTFromLastError();
- }
-
- if (0 == ::GetModuleFileNameEx(get(process), NULL, temp_path, MAX_PATH)) {
- return HRESULTFromLastError();
- }
-
- exe_path->SetString(temp_path);
- return S_OK;
-}
-
-// Type definitions needed for GetCommandLine() and GetProcessIdFromHandle()
-// From MSDN document on NtQueryInformationProcess() and other sources
-typedef struct _PROCESS_BASIC_INFORMATION {
- PVOID Reserved1;
- BYTE *PebBaseAddress;
- PVOID Reserved2[2];
- ULONG_PTR UniqueProcessId;
- PVOID Reserved3;
-} PROCESS_BASIC_INFORMATION;
-
-typedef enum _PROCESSINFOCLASS {
- ProcessBasicInformation = 0,
- ProcessWow64Information = 26
-} PROCESSINFOCLASS;
-
-typedef WINBASEAPI DWORD WINAPI
-GetProcessIdFn(
- HANDLE Process
-);
-
-typedef LONG WINAPI
-NtQueryInformationProcess(
- IN HANDLE ProcessHandle,
- IN PROCESSINFOCLASS ProcessInformationClass,
- OUT PVOID ProcessInformation,
- IN ULONG ProcessInformationLength,
- OUT PULONG ReturnLength OPTIONAL
-);
-
-typedef struct _RTL_DRIVE_LETTER_CURDIR {
- USHORT Flags;
- USHORT Length;
- ULONG TimeStamp;
- UNICODE_STRING DosPath;
-} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;
-
-typedef struct _RTL_USER_PROCESS_PARAMETERS {
- ULONG MaximumLength;
- ULONG Length;
- ULONG Flags;
- ULONG DebugFlags;
- PVOID ConsoleHandle;
- ULONG ConsoleFlags;
- HANDLE StdInputHandle;
- HANDLE StdOutputHandle;
- HANDLE StdErrorHandle;
- UNICODE_STRING CurrentDirectoryPath;
- HANDLE CurrentDirectoryHandle;
- UNICODE_STRING DllPath;
- UNICODE_STRING ImagePathName;
- UNICODE_STRING CommandLine;
- PVOID Environment;
- ULONG StartingPositionLeft;
- ULONG StartingPositionTop;
- ULONG Width;
- ULONG Height;
- ULONG CharWidth;
- ULONG CharHeight;
- ULONG ConsoleTextAttributes;
- ULONG WindowFlags;
- ULONG ShowWindowFlags;
- UNICODE_STRING WindowTitle;
- UNICODE_STRING DesktopName;
- UNICODE_STRING ShellInfo;
- UNICODE_STRING RuntimeData;
- RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20];
-} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
-
-// Get the function pointer to GetProcessId in KERNEL32.DLL
-static HRESULT EnsureGPIFunction(GetProcessIdFn** gpi_func_ptr) {
- static GetProcessIdFn* gpi_func = NULL;
- if (!gpi_func) {
- HMODULE kernel32_module = ::GetModuleHandle(_T("kernel32.dll"));
- if (!kernel32_module) {
- return HRESULTFromLastError();
- }
- gpi_func = reinterpret_cast<GetProcessIdFn*>(
- ::GetProcAddress(kernel32_module, "GetProcessId"));
- if (!gpi_func) {
- return HRESULTFromLastError();
- }
- }
-
- *gpi_func_ptr = gpi_func;
- return S_OK;
-}
-
-// Get the function pointer to NtQueryInformationProcess in NTDLL.DLL
-static HRESULT EnsureQIPFunction(NtQueryInformationProcess** qip_func_ptr) {
- static NtQueryInformationProcess* qip_func = NULL;
- if (!qip_func) {
- HMODULE ntdll_module = ::GetModuleHandle(_T("ntdll.dll"));
- if (!ntdll_module) {
- return HRESULTFromLastError();
- }
- qip_func = reinterpret_cast<NtQueryInformationProcess*>(
- ::GetProcAddress(ntdll_module, "NtQueryInformationProcess"));
- if (!qip_func) {
- return HRESULTFromLastError();
- }
- }
-
- *qip_func_ptr = qip_func;
- return S_OK;
-}
-
-// Obtain the process ID from a hProcess HANDLE
-ULONG Process::GetProcessIdFromHandle(HANDLE hProcess) {
- if (SystemInfo::IsRunningOnXPSP1OrLater()) {
- // Thunk to the documented ::GetProcessId() API
- GetProcessIdFn* gpi_func = NULL;
- HRESULT hr = EnsureGPIFunction(&gpi_func);
- if (FAILED(hr)) {
- ASSERT(FALSE,
- (_T("Process::GetProcessIdFromHandle - EnsureGPIFunction")
- _T(" failed[0x%x]"), hr));
- return 0;
- }
- ASSERT1(gpi_func);
- return gpi_func(hProcess);
- }
-
- // For lower versions of Windows, we use undocumented
- // function NtQueryInformationProcess to get at the PID
- NtQueryInformationProcess* qip_func = NULL;
- HRESULT hr = EnsureQIPFunction(&qip_func);
- if (FAILED(hr)) {
- ASSERT(FALSE,
- (_T("Process::GetProcessIdFromHandle - EnsureQIPFunction")
- _T(" failed[0x%x]"), hr));
- return 0;
- }
- ASSERT1(qip_func);
-
- PROCESS_BASIC_INFORMATION info;
- SetZero(info);
- if (!NT_SUCCESS(qip_func(hProcess,
- ProcessBasicInformation,
- &info,
- sizeof(info),
- NULL))) {
- ASSERT(FALSE, (_T("Process::GetProcessIdFromHandle - ")
- _T("NtQueryInformationProcess failed!")));
- return 0;
- }
-
- return info.UniqueProcessId;
-}
-
-// Get the command line of a process
-HRESULT Process::GetCommandLine(uint32 process_id, CString* cmd_line) {
- ASSERT1(process_id);
- ASSERT1(cmd_line);
-
- // Open the process
- scoped_process process_handle(::OpenProcess(
- PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
- false,
- process_id));
- if (!process_handle) {
- return HRESULTFromLastError();
- }
-
- // Obtain Process Environment Block
- // Note that NtQueryInformationProcess is not available in Windows 95/98/ME
- NtQueryInformationProcess* qip_func = NULL;
- HRESULT hr = EnsureQIPFunction(&qip_func);
-
- if (FAILED(hr)) {
- return hr;
- }
- ASSERT1(qip_func);
-
- PROCESS_BASIC_INFORMATION info;
- SetZero(info);
- if (!NT_SUCCESS(qip_func(get(process_handle),
- ProcessBasicInformation,
- &info,
- sizeof(info),
- NULL))) {
- return E_FAIL;
- }
- BYTE* peb = info.PebBaseAddress;
-
- // Read address of parameters (see some PEB reference)
- // TODO(omaha): use offsetof(PEB, ProcessParameters) to replace 0x10
- // http://msdn.microsoft.com/en-us/library/aa813706.aspx
- SIZE_T bytes_read = 0;
- uint32 dw = 0;
- if (!::ReadProcessMemory(get(process_handle),
- peb + 0x10,
- &dw,
- sizeof(dw),
- &bytes_read)) {
- return HRESULTFromLastError();
- }
-
- // Read all the parameters
- RTL_USER_PROCESS_PARAMETERS params;
- SetZero(params);
- if (!::ReadProcessMemory(get(process_handle),
- reinterpret_cast<PVOID>(dw),
- &params,
- sizeof(params),
- &bytes_read)) {
- return HRESULTFromLastError();
- }
-
- // Read the command line parameter
- const int max_cmd_line_len = std::min(
- static_cast<int>(params.CommandLine.MaximumLength),
- kMaxCmdLineLengthBytes);
- if (!::ReadProcessMemory(get(process_handle),
- params.CommandLine.Buffer,
- cmd_line->GetBufferSetLength(max_cmd_line_len),
- max_cmd_line_len,
- &bytes_read)) {
- return HRESULTFromLastError();
- }
-
- cmd_line->ReleaseBuffer();
-
- return S_OK;
-}
-
-// Check if the process is running with a specified path
-bool Process::IsProcessRunningWithPath(uint32 process_id, const TCHAR* path) {
- ASSERT1(process_id);
- ASSERT1(path && *path);
-
- const int kProcessWaitModuleFullyUpMs = 100;
- const int kProcessWaitModuleRetries = 10;
-
- // Open the process
- scoped_process process(::OpenProcess(
- PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
- false,
- process_id));
- if (!process) {
- UTIL_LOG(LEVEL_ERROR,
- (_T("[Process::IsProcessRunningWithPath - OpenProcess failed]")
- _T("[%u][0x%x]"),
- process_id, HRESULTFromLastError()));
- return false;
- }
-
- for (int i = 0; i < kProcessWaitModuleRetries; ++i) {
- // Get the command line path of the main module
- // Note that we are using psapi functions which is not supported in Windows
- // 95/98/ME
- //
- // Sometimes it might be the case that the process is created but the main
- // module is not fully loaded. If so, wait a while and then try again
- TCHAR process_path[MAX_PATH];
- if (::GetModuleFileNameEx(get(process),
- NULL,
- process_path,
- arraysize(process_path))) {
- // Do the check
- if (String_StartsWith(process_path, path, true)) {
- return true;
- }
-
- // Try again with short form
- TCHAR short_path[MAX_PATH];
- if (::GetShortPathName(path, short_path, arraysize(short_path)) &&
- String_StartsWith(process_path, short_path, true)) {
- return true;
- }
-
- return false;
- }
-
- UTIL_LOG(LEVEL_ERROR,
- (_T("[Process::IsProcessRunningWithPath - GetModuleFileNameEx ")
- _T("failed][%u][0x%x]"),
- process_id, HRESULTFromLastError()));
-
- ::Sleep(kProcessWaitModuleFullyUpMs);
- }
-
- UTIL_LOG(LEVEL_ERROR,
- (_T("[Process::IsProcessRunningWithPath - failed to get process ")
- _T("path][%u][0x%x]"),
- process_id, HRESULTFromLastError()));
-
- return false;
-}
-
-// Get the process owner
-// Note that we may fail to get the owner which is not current user.
-HRESULT Process::GetProcessOwner(uint32 pid, CString* owner_sid) {
- ASSERT1(pid);
- ASSERT1(owner_sid);
-
- scoped_process process(::OpenProcess(PROCESS_QUERY_INFORMATION, false, pid));
- if (!valid(process)) {
- return HRESULTFromLastError();
- }
-
- CAccessToken token;
- CSid sid;
- if (!token.GetProcessToken(READ_CONTROL | TOKEN_QUERY, get(process)) ||
- !token.GetUser(&sid)) {
- return HRESULTFromLastError();
- }
-
- *owner_sid = sid.Sid();
- return S_OK;
-}
-
-// Creates an impersonation token for the user running process_id.
-// The caller is responsible for closing the returned handle.
-HRESULT Process::GetImpersonationToken(DWORD process_id, HANDLE* user_token) {
- // Get a handle to the process.
- scoped_process process(::OpenProcess(
- PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION,
- TRUE,
- process_id));
- if (!valid(process)) {
- HRESULT hr(HRESULTFromLastError());
- UTIL_LOG(LEVEL_ERROR,
- (_T("[GetImpersonationToken - ::OpenProcess failed][0x%x]"),
- hr));
- return hr;
- }
-
- HRESULT result = S_OK;
- scoped_handle process_token;
- if (!::OpenProcessToken(get(process), TOKEN_DUPLICATE | TOKEN_QUERY,
- address(process_token))) {
- result = HRESULTFromLastError();
- } else {
- if (!::DuplicateTokenEx(get(process_token),
- TOKEN_IMPERSONATE | TOKEN_QUERY |
- TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE,
- NULL,
- SecurityImpersonation,
- TokenPrimary,
- user_token)) {
- result = HRESULTFromLastError();
- }
- }
-
- ASSERT(SUCCEEDED(result), (_T("[GetImpersonationToken Failed][hr=0x%x]"),
- result));
- return result;
-}
-
-HRESULT Process::GetUsersOfProcesses(const TCHAR* task_name,
- int maximum_users,
- scoped_handle user_tokens[],
- int* number_of_users) {
- ASSERT1(task_name && *task_name);
- ASSERT1(maximum_users);
- ASSERT1(user_tokens);
- ASSERT1(number_of_users);
-
- scoped_hfile th32cs_snapshot(::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,
- 0));
- if (!valid(th32cs_snapshot)) {
- HRESULT hr(HRESULTFromLastError());
- UTIL_LOG(LEVEL_ERROR, (_T("[::CreateToolhelp32Snapshot fail][0x%x]"), hr));
- return hr;
- }
-
- HRESULT result = S_OK;
- *number_of_users = 0;
- // Walk the list of processes.
- PROCESSENTRY32 process = {0};
- process.dwSize = sizeof(PROCESSENTRY32);
- for (BOOL found = ::Process32First(get(th32cs_snapshot), &process); found;
- found = ::Process32Next(get(th32cs_snapshot), &process)) {
- // Check if it is one of the processes we are looking for.
- if (_tcsicmp(task_name, process.szExeFile) == 0) {
- // We match. Get the user's token.
- scoped_handle user_token;
- if (FAILED(GetImpersonationToken(process.th32ProcessID,
- address(user_token))))
- continue;
-
- // Search through the existing list to see if it's a duplicate.
- // It's O(n^2) but we should have very few logged on users.
- int i = 0;
- for (; i < *number_of_users; i++) {
- if (get(user_tokens[i]) == get(user_token)) {
- // It's a duplicate.
- break;
- }
- }
- if (i >= *number_of_users) {
- // It's a new one. Add it if there's room.
- ASSERT1(i < maximum_users);
- if (i < maximum_users) {
- // Release the user_token, we don't want it to be closed
- // by the user_token destructor
- reset(user_tokens[(*number_of_users)++], release(user_token));
- }
- }
- }
- }
- return result;
-}
-
-HRESULT Process::GetImagePath(const CString& process_name,
- const CString& user_sid,
- CString* path) {
- ASSERT1(path);
-
- // Search for running processes with process_name.
- uint32 mask = INCLUDE_ONLY_PROCESS_OWNED_BY_USER;
- std::vector<CString> command_line;
- std::vector<uint32> process_ids;
- HRESULT hr = FindProcesses(mask,
- process_name,
- true,
- user_sid,
- command_line,
- &process_ids);
- if (FAILED(hr)) {
- UTIL_LOG(LEVEL_WARNING, (_T("[FindProcesses failed][0x%08x]"), hr));
- return hr;
- }
-
- if (process_ids.empty()) {
- return E_FAIL;
- }
-
- uint32 process_id = process_ids[0];
- UTIL_LOG(L4, (_T("[GetImagePath][pid=%d]"), process_id));
- scoped_process process_handle(::OpenProcess(PROCESS_QUERY_INFORMATION |
- PROCESS_VM_READ,
- FALSE,
- process_id));
- if (!process_handle) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(L4, (_T("[OpenProcess failed][0x%08x]"), hr));
- return hr;
- }
-
- HMODULE module_handle = NULL;
- DWORD bytes_needed = 0;
- if (!::EnumProcessModules(get(process_handle),
- &module_handle,
- sizeof(HMODULE),
- &bytes_needed)) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LEVEL_WARNING, (_T("[EnumProcessModules failed][0x%08x]"), hr));
- // ::EnumProcessModules from a WoW64 process fails for x64 processes. We try
- // ::GetProcessImageFileName as a workaround here.
- TCHAR image_name[MAX_PATH] = {0};
- if (!GetProcessImageFileName(get(process_handle),
- image_name,
- arraysize(image_name))) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LE, (_T("[GetProcessImageFileName failed][0x%08x]"), hr));
- return hr;
- } else {
- *path = image_name;
- return S_OK;
- }
- }
-
- TCHAR module_name[MAX_PATH] = {0};
- if (!::GetModuleFileNameEx(get(process_handle),
- module_handle,
- module_name,
- arraysize(module_name))) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LEVEL_ERROR, (_T("[GetModuleFileNameEx failed][0x%08x]"), hr));
- return hr;
- }
-
- *path = module_name;
- return S_OK;
-}
-
-bool Process::IsWow64(uint32 pid) {
- typedef BOOL (WINAPI *IsWow64Process)(HANDLE, BOOL*);
- scoped_process handle(::OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
- false,
- pid));
- if (!handle) {
- return false;
- }
-
- HINSTANCE kernel_instance = ::GetModuleHandle(_T("kernel32.dll"));
- if (kernel_instance == NULL) {
- ASSERT1(false);
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LW, (_T("[::GetModuleHandle kernel32.dll failed][0x%08x]"), hr));
- return false;
- }
-
- IsWow64Process pfn = reinterpret_cast<IsWow64Process>(::GetProcAddress(
- kernel_instance,
- "IsWow64Process"));
- if (!pfn) {
- UTIL_LOG(LW, (_T("[::IsWow64Process() not found in kernel32.dll]")));
- return false;
- }
-
- BOOL wow64 = FALSE;
- if (!(*pfn)(get(handle), &wow64)) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LW, (_T("[::IsWow64Process() failed][0x%08x]"), hr));
- return false;
- }
-
- return (wow64 != 0);
-}
-
-HRESULT Process::MakeProcessWindowForeground(const CString& executable) {
- UTIL_LOG(L3, (_T("[MakeProcessWindowForeground]")));
-
- CString sid;
- HRESULT hr = omaha::user_info::GetProcessUser(NULL, NULL, &sid);
- if (FAILED(hr)) {
- return hr;
- }
-
- // This code does not handle two cases:
- // 1. If a new process instance is starting up but there are other process
- // instances running, then we will not wait for the new process instance.
- // One way to fix this is to pass the number of expected processes to this
- // method.
- // 2. If we find multiple processes, and we are able to find the windows only
- // for some of the processes (maybe because the rest are still starting up)
- // then we will only set the windows of the one that we found to the
- // foreground and ignore the rest.
- bool found = false;
- for (int retries = 0; retries < kNumRetriesToFindProcess && !found;
- ++retries) {
- std::vector<CString> command_lines;
- std::vector<uint32> processes;
- DWORD flags = EXCLUDE_CURRENT_PROCESS | INCLUDE_ONLY_PROCESS_OWNED_BY_USER;
- hr = Process::FindProcesses(flags,
- executable,
- true,
- sid,
- command_lines,
- &processes);
- if (FAILED(hr)) {
- UTIL_LOG(LW, (_T("[FindProcesses failed][0x%08x]"), hr));
- return hr;
- }
-
- UTIL_LOG(L3, (_T("[Found %d processes]"), processes.size()));
- for (size_t i = 0; i < processes.size(); ++i) {
- CSimpleArray<HWND> windows;
- if (!WindowUtils::FindProcessWindows(processes[i], 0, &windows)) {
- UTIL_LOG(L3, (_T("[FindProcessWindows failed][0x%08x]"), hr));
- continue;
- }
-
- for (int j = 0; j < windows.GetSize(); ++j) {
- if (WindowUtils::IsMainWindow(windows[j])) {
- UTIL_LOG(L4, (_T("[Found main window of process %d]"), processes[i]));
- WindowUtils::MakeWindowForeground(windows[j]);
- ::FlashWindow(windows[j], true);
- found = true;
- break;
- }
- }
- }
-
- if (!found) {
- ::Sleep(kFindProcessRetryIntervalMs);
- }
- }
-
- return S_OK;
-}
-
-} // namespace omaha
-
« 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