ipc/chromium/src/base/process_util_win.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
michael@0 2 // Use of this source code is governed by a BSD-style license that can be
michael@0 3 // found in the LICENSE file.
michael@0 4
michael@0 5 // We need extended process and thread attribute support
michael@0 6 #undef _WIN32_WINNT
michael@0 7 #define _WIN32_WINNT 0x0600
michael@0 8
michael@0 9 #include "base/process_util.h"
michael@0 10
michael@0 11 #include <windows.h>
michael@0 12 #include <winternl.h>
michael@0 13 #include <psapi.h>
michael@0 14
michael@0 15 #include "base/debug_util.h"
michael@0 16 #include "base/histogram.h"
michael@0 17 #include "base/logging.h"
michael@0 18 #include "base/scoped_handle_win.h"
michael@0 19 #include "base/scoped_ptr.h"
michael@0 20 #include "base/win_util.h"
michael@0 21
michael@0 22 #include <algorithm>
michael@0 23
michael@0 24 namespace {
michael@0 25
michael@0 26 // System pagesize. This value remains constant on x86/64 architectures.
michael@0 27 const int PAGESIZE_KB = 4;
michael@0 28
michael@0 29 // HeapSetInformation function pointer.
michael@0 30 typedef BOOL (WINAPI* HeapSetFn)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T);
michael@0 31
michael@0 32 typedef BOOL (WINAPI * InitializeProcThreadAttributeListFn)(
michael@0 33 LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,
michael@0 34 DWORD dwAttributeCount,
michael@0 35 DWORD dwFlags,
michael@0 36 PSIZE_T lpSize
michael@0 37 );
michael@0 38
michael@0 39 typedef BOOL (WINAPI * DeleteProcThreadAttributeListFn)(
michael@0 40 LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList
michael@0 41 );
michael@0 42
michael@0 43 typedef BOOL (WINAPI * UpdateProcThreadAttributeFn)(
michael@0 44 LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,
michael@0 45 DWORD dwFlags,
michael@0 46 DWORD_PTR Attribute,
michael@0 47 PVOID lpValue,
michael@0 48 SIZE_T cbSize,
michael@0 49 PVOID lpPreviousValue,
michael@0 50 PSIZE_T lpReturnSize
michael@0 51 );
michael@0 52
michael@0 53 static InitializeProcThreadAttributeListFn InitializeProcThreadAttributeListPtr;
michael@0 54 static DeleteProcThreadAttributeListFn DeleteProcThreadAttributeListPtr;
michael@0 55 static UpdateProcThreadAttributeFn UpdateProcThreadAttributePtr;
michael@0 56
michael@0 57 static mozilla::EnvironmentLog gProcessLog("MOZ_PROCESS_LOG");
michael@0 58
michael@0 59 } // namespace
michael@0 60
michael@0 61 namespace base {
michael@0 62
michael@0 63 ProcessId GetCurrentProcId() {
michael@0 64 return ::GetCurrentProcessId();
michael@0 65 }
michael@0 66
michael@0 67 ProcessHandle GetCurrentProcessHandle() {
michael@0 68 return ::GetCurrentProcess();
michael@0 69 }
michael@0 70
michael@0 71 bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) {
michael@0 72 // TODO(phajdan.jr): Take even more permissions out of this list.
michael@0 73 ProcessHandle result = OpenProcess(PROCESS_DUP_HANDLE |
michael@0 74 PROCESS_TERMINATE |
michael@0 75 PROCESS_QUERY_INFORMATION |
michael@0 76 SYNCHRONIZE,
michael@0 77 FALSE, pid);
michael@0 78
michael@0 79 if (result == INVALID_HANDLE_VALUE)
michael@0 80 return false;
michael@0 81
michael@0 82 *handle = result;
michael@0 83 return true;
michael@0 84 }
michael@0 85
michael@0 86 bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) {
michael@0 87 ProcessHandle result = OpenProcess(PROCESS_DUP_HANDLE |
michael@0 88 PROCESS_TERMINATE |
michael@0 89 PROCESS_QUERY_INFORMATION |
michael@0 90 PROCESS_VM_READ |
michael@0 91 SYNCHRONIZE,
michael@0 92 FALSE, pid);
michael@0 93
michael@0 94 if (result == INVALID_HANDLE_VALUE)
michael@0 95 return false;
michael@0 96
michael@0 97 *handle = result;
michael@0 98 return true;
michael@0 99 }
michael@0 100
michael@0 101 void CloseProcessHandle(ProcessHandle process) {
michael@0 102 // closing a handle twice on Windows can be catastrophic - after the first
michael@0 103 // close the handle value may be reused, so the second close will kill that
michael@0 104 // other new handle.
michael@0 105 BOOL ok = CloseHandle(process);
michael@0 106 DCHECK(ok);
michael@0 107 }
michael@0 108
michael@0 109 // Helper for GetProcId()
michael@0 110 bool GetProcIdViaGetProcessId(ProcessHandle process, DWORD* id) {
michael@0 111 // Dynamically get a pointer to GetProcessId().
michael@0 112 typedef DWORD (WINAPI *GetProcessIdFunction)(HANDLE);
michael@0 113 static GetProcessIdFunction GetProcessIdPtr = NULL;
michael@0 114 static bool initialize_get_process_id = true;
michael@0 115 if (initialize_get_process_id) {
michael@0 116 initialize_get_process_id = false;
michael@0 117 HMODULE kernel32_handle = GetModuleHandle(L"kernel32.dll");
michael@0 118 if (!kernel32_handle) {
michael@0 119 NOTREACHED();
michael@0 120 return false;
michael@0 121 }
michael@0 122 GetProcessIdPtr = reinterpret_cast<GetProcessIdFunction>(GetProcAddress(
michael@0 123 kernel32_handle, "GetProcessId"));
michael@0 124 }
michael@0 125 if (!GetProcessIdPtr)
michael@0 126 return false;
michael@0 127 // Ask for the process ID.
michael@0 128 *id = (*GetProcessIdPtr)(process);
michael@0 129 return true;
michael@0 130 }
michael@0 131
michael@0 132 // Helper for GetProcId()
michael@0 133 bool GetProcIdViaNtQueryInformationProcess(ProcessHandle process, DWORD* id) {
michael@0 134 // Dynamically get a pointer to NtQueryInformationProcess().
michael@0 135 typedef NTSTATUS (WINAPI *NtQueryInformationProcessFunction)(
michael@0 136 HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
michael@0 137 static NtQueryInformationProcessFunction NtQueryInformationProcessPtr = NULL;
michael@0 138 static bool initialize_query_information_process = true;
michael@0 139 if (initialize_query_information_process) {
michael@0 140 initialize_query_information_process = false;
michael@0 141 // According to nsylvain, ntdll.dll is guaranteed to be loaded, even though
michael@0 142 // the Windows docs seem to imply that you should LoadLibrary() it.
michael@0 143 HMODULE ntdll_handle = GetModuleHandle(L"ntdll.dll");
michael@0 144 if (!ntdll_handle) {
michael@0 145 NOTREACHED();
michael@0 146 return false;
michael@0 147 }
michael@0 148 NtQueryInformationProcessPtr =
michael@0 149 reinterpret_cast<NtQueryInformationProcessFunction>(GetProcAddress(
michael@0 150 ntdll_handle, "NtQueryInformationProcess"));
michael@0 151 }
michael@0 152 if (!NtQueryInformationProcessPtr)
michael@0 153 return false;
michael@0 154 // Ask for the process ID.
michael@0 155 PROCESS_BASIC_INFORMATION info;
michael@0 156 ULONG bytes_returned;
michael@0 157 NTSTATUS status = (*NtQueryInformationProcessPtr)(process,
michael@0 158 ProcessBasicInformation,
michael@0 159 &info, sizeof info,
michael@0 160 &bytes_returned);
michael@0 161 if (!SUCCEEDED(status) || (bytes_returned != (sizeof info)))
michael@0 162 return false;
michael@0 163
michael@0 164 *id = static_cast<DWORD>(info.UniqueProcessId);
michael@0 165 return true;
michael@0 166 }
michael@0 167
michael@0 168 ProcessId GetProcId(ProcessHandle process) {
michael@0 169 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
michael@0 170 HANDLE current_process = GetCurrentProcess();
michael@0 171 HANDLE process_with_query_rights;
michael@0 172 if (DuplicateHandle(current_process, process, current_process,
michael@0 173 &process_with_query_rights, PROCESS_QUERY_INFORMATION,
michael@0 174 false, 0)) {
michael@0 175 // Try to use GetProcessId(), if it exists. Fall back on
michael@0 176 // NtQueryInformationProcess() otherwise (< Win XP SP1).
michael@0 177 DWORD id;
michael@0 178 bool success =
michael@0 179 GetProcIdViaGetProcessId(process_with_query_rights, &id) ||
michael@0 180 GetProcIdViaNtQueryInformationProcess(process_with_query_rights, &id);
michael@0 181 CloseHandle(process_with_query_rights);
michael@0 182 if (success)
michael@0 183 return id;
michael@0 184 }
michael@0 185
michael@0 186 // We're screwed.
michael@0 187 NOTREACHED();
michael@0 188 return 0;
michael@0 189 }
michael@0 190
michael@0 191 // from sandbox_policy_base.cc in a later version of the chromium ipc code...
michael@0 192 bool IsInheritableHandle(HANDLE handle) {
michael@0 193 if (!handle)
michael@0 194 return false;
michael@0 195 if (handle == INVALID_HANDLE_VALUE)
michael@0 196 return false;
michael@0 197 // File handles (FILE_TYPE_DISK) and pipe handles are known to be
michael@0 198 // inheritable. Console handles (FILE_TYPE_CHAR) are not
michael@0 199 // inheritable via PROC_THREAD_ATTRIBUTE_HANDLE_LIST.
michael@0 200 DWORD handle_type = GetFileType(handle);
michael@0 201 return handle_type == FILE_TYPE_DISK || handle_type == FILE_TYPE_PIPE;
michael@0 202 }
michael@0 203
michael@0 204 void LoadThreadAttributeFunctions() {
michael@0 205 HMODULE kernel32 = GetModuleHandle(L"kernel32.dll");
michael@0 206 InitializeProcThreadAttributeListPtr =
michael@0 207 reinterpret_cast<InitializeProcThreadAttributeListFn>
michael@0 208 (GetProcAddress(kernel32, "InitializeProcThreadAttributeList"));
michael@0 209 DeleteProcThreadAttributeListPtr =
michael@0 210 reinterpret_cast<DeleteProcThreadAttributeListFn>
michael@0 211 (GetProcAddress(kernel32, "DeleteProcThreadAttributeList"));
michael@0 212 UpdateProcThreadAttributePtr =
michael@0 213 reinterpret_cast<UpdateProcThreadAttributeFn>
michael@0 214 (GetProcAddress(kernel32, "UpdateProcThreadAttribute"));
michael@0 215 }
michael@0 216
michael@0 217 // Creates and returns a "thread attribute list" to pass to the child process.
michael@0 218 // On return, is a pointer to a THREAD_ATTRIBUTE_LIST or NULL if either the
michael@0 219 // functions we need aren't available (eg, XP or earlier) or the functions we
michael@0 220 // need failed.
michael@0 221 // The result of this function must be passed to FreeThreadAttributeList.
michael@0 222 // Note that the pointer to the HANDLE array ends up embedded in the result of
michael@0 223 // this function and must stay alive until FreeThreadAttributeList is called,
michael@0 224 // hence it is passed in so the owner is the caller of this function.
michael@0 225 LPPROC_THREAD_ATTRIBUTE_LIST CreateThreadAttributeList(HANDLE *handlesToInherit,
michael@0 226 int handleCount) {
michael@0 227 if (!InitializeProcThreadAttributeListPtr ||
michael@0 228 !DeleteProcThreadAttributeListPtr ||
michael@0 229 !UpdateProcThreadAttributePtr)
michael@0 230 LoadThreadAttributeFunctions();
michael@0 231 // shouldn't happen as we are only called for Vista+, but better safe than sorry...
michael@0 232 if (!InitializeProcThreadAttributeListPtr ||
michael@0 233 !DeleteProcThreadAttributeListPtr ||
michael@0 234 !UpdateProcThreadAttributePtr)
michael@0 235 return NULL;
michael@0 236
michael@0 237 SIZE_T threadAttrSize;
michael@0 238 LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList;
michael@0 239
michael@0 240 if (!(*InitializeProcThreadAttributeListPtr)(NULL, 1, 0, &threadAttrSize) &&
michael@0 241 GetLastError() != ERROR_INSUFFICIENT_BUFFER)
michael@0 242 goto fail;
michael@0 243 lpAttributeList = reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>
michael@0 244 (malloc(threadAttrSize));
michael@0 245 if (!lpAttributeList ||
michael@0 246 !(*InitializeProcThreadAttributeListPtr)(lpAttributeList, 1, 0, &threadAttrSize))
michael@0 247 goto fail;
michael@0 248
michael@0 249 if (!(*UpdateProcThreadAttributePtr)(lpAttributeList,
michael@0 250 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
michael@0 251 handlesToInherit,
michael@0 252 sizeof(handlesToInherit[0]) * handleCount,
michael@0 253 NULL, NULL)) {
michael@0 254 (*DeleteProcThreadAttributeListPtr)(lpAttributeList);
michael@0 255 goto fail;
michael@0 256 }
michael@0 257 return lpAttributeList;
michael@0 258
michael@0 259 fail:
michael@0 260 if (lpAttributeList)
michael@0 261 free(lpAttributeList);
michael@0 262 return NULL;
michael@0 263 }
michael@0 264
michael@0 265 // Frees the data returned by CreateThreadAttributeList.
michael@0 266 void FreeThreadAttributeList(LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList) {
michael@0 267 // must be impossible to get a NULL DeleteProcThreadAttributeListPtr, as
michael@0 268 // we already checked it existed when creating the data we are now freeing.
michael@0 269 (*DeleteProcThreadAttributeListPtr)(lpAttributeList);
michael@0 270 free(lpAttributeList);
michael@0 271 }
michael@0 272
michael@0 273 bool LaunchApp(const std::wstring& cmdline,
michael@0 274 bool wait, bool start_hidden, ProcessHandle* process_handle) {
michael@0 275
michael@0 276 // We want to inherit the std handles so dump() statements and assertion
michael@0 277 // messages in the child process can be seen - but we *do not* want to
michael@0 278 // blindly have all handles inherited. Vista and later has a technique
michael@0 279 // where only specified handles are inherited - so we use this technique if
michael@0 280 // we can. If that technique isn't available (or it fails), we just don't
michael@0 281 // inherit anything. This means that dump() etc isn't going to be seen on
michael@0 282 // XP release builds, but that's OK (developers who really care can run a
michael@0 283 // debug build on XP, where the processes are marked as "console" apps, so
michael@0 284 // things work without these hoops)
michael@0 285 DWORD dwCreationFlags = 0;
michael@0 286 BOOL bInheritHandles = FALSE;
michael@0 287 // We use a STARTUPINFOEX, but if we can't do the thread attribute thing, we
michael@0 288 // just pass the size of a STARTUPINFO.
michael@0 289 STARTUPINFOEX startup_info_ex;
michael@0 290 ZeroMemory(&startup_info_ex, sizeof(startup_info_ex));
michael@0 291 STARTUPINFO &startup_info = startup_info_ex.StartupInfo;
michael@0 292 startup_info.cb = sizeof(startup_info);
michael@0 293 startup_info.dwFlags = STARTF_USESHOWWINDOW;
michael@0 294 startup_info.wShowWindow = start_hidden ? SW_HIDE : SW_SHOW;
michael@0 295
michael@0 296 LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList = NULL;
michael@0 297 // Don't even bother trying pre-Vista...
michael@0 298 if (win_util::GetWinVersion() >= win_util::WINVERSION_VISTA) {
michael@0 299 // setup our handle array first - if we end up with no handles that can
michael@0 300 // be inherited we can avoid trying to do the ThreadAttributeList dance...
michael@0 301 HANDLE handlesToInherit[2];
michael@0 302 int handleCount = 0;
michael@0 303 HANDLE stdOut = ::GetStdHandle(STD_OUTPUT_HANDLE);
michael@0 304 HANDLE stdErr = ::GetStdHandle(STD_ERROR_HANDLE);
michael@0 305
michael@0 306 if (IsInheritableHandle(stdOut))
michael@0 307 handlesToInherit[handleCount++] = stdOut;
michael@0 308 if (stdErr != stdOut && IsInheritableHandle(stdErr))
michael@0 309 handlesToInherit[handleCount++] = stdErr;
michael@0 310
michael@0 311 if (handleCount)
michael@0 312 lpAttributeList = CreateThreadAttributeList(handlesToInherit, handleCount);
michael@0 313 }
michael@0 314
michael@0 315 if (lpAttributeList) {
michael@0 316 // it's safe to inherit handles, so arrange for that...
michael@0 317 startup_info.cb = sizeof(startup_info_ex);
michael@0 318 startup_info.dwFlags |= STARTF_USESTDHANDLES;
michael@0 319 startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
michael@0 320 startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
michael@0 321 startup_info.hStdInput = INVALID_HANDLE_VALUE;
michael@0 322 startup_info_ex.lpAttributeList = lpAttributeList;
michael@0 323 dwCreationFlags |= EXTENDED_STARTUPINFO_PRESENT;
michael@0 324 bInheritHandles = TRUE;
michael@0 325 }
michael@0 326 PROCESS_INFORMATION process_info;
michael@0 327 BOOL createdOK = CreateProcess(NULL,
michael@0 328 const_cast<wchar_t*>(cmdline.c_str()), NULL, NULL,
michael@0 329 bInheritHandles, dwCreationFlags, NULL, NULL,
michael@0 330 &startup_info, &process_info);
michael@0 331 if (lpAttributeList)
michael@0 332 FreeThreadAttributeList(lpAttributeList);
michael@0 333 if (!createdOK)
michael@0 334 return false;
michael@0 335
michael@0 336 gProcessLog.print("==> process %d launched child process %d (%S)\n",
michael@0 337 GetCurrentProcId(),
michael@0 338 process_info.dwProcessId,
michael@0 339 cmdline.c_str());
michael@0 340
michael@0 341 // Handles must be closed or they will leak
michael@0 342 CloseHandle(process_info.hThread);
michael@0 343
michael@0 344 if (wait)
michael@0 345 WaitForSingleObject(process_info.hProcess, INFINITE);
michael@0 346
michael@0 347 // If the caller wants the process handle, we won't close it.
michael@0 348 if (process_handle) {
michael@0 349 *process_handle = process_info.hProcess;
michael@0 350 } else {
michael@0 351 CloseHandle(process_info.hProcess);
michael@0 352 }
michael@0 353 return true;
michael@0 354 }
michael@0 355
michael@0 356 bool LaunchApp(const CommandLine& cl,
michael@0 357 bool wait, bool start_hidden, ProcessHandle* process_handle) {
michael@0 358 return LaunchApp(cl.command_line_string(), wait,
michael@0 359 start_hidden, process_handle);
michael@0 360 }
michael@0 361
michael@0 362 bool KillProcess(ProcessHandle process, int exit_code, bool wait) {
michael@0 363 bool result = (TerminateProcess(process, exit_code) != FALSE);
michael@0 364 if (result && wait) {
michael@0 365 // The process may not end immediately due to pending I/O
michael@0 366 if (WAIT_OBJECT_0 != WaitForSingleObject(process, 60 * 1000))
michael@0 367 DLOG(ERROR) << "Error waiting for process exit: " << GetLastError();
michael@0 368 } else if (!result) {
michael@0 369 DLOG(ERROR) << "Unable to terminate process: " << GetLastError();
michael@0 370 }
michael@0 371 return result;
michael@0 372 }
michael@0 373
michael@0 374 bool DidProcessCrash(bool* child_exited, ProcessHandle handle) {
michael@0 375 DWORD exitcode = 0;
michael@0 376
michael@0 377 if (child_exited)
michael@0 378 *child_exited = true; // On Windows it an error to call this function if
michael@0 379 // the child hasn't already exited.
michael@0 380 if (!::GetExitCodeProcess(handle, &exitcode)) {
michael@0 381 NOTREACHED();
michael@0 382 return false;
michael@0 383 }
michael@0 384 if (exitcode == STILL_ACTIVE) {
michael@0 385 // The process is likely not dead or it used 0x103 as exit code.
michael@0 386 NOTREACHED();
michael@0 387 return false;
michael@0 388 }
michael@0 389
michael@0 390 // Warning, this is not generic code; it heavily depends on the way
michael@0 391 // the rest of the code kills a process.
michael@0 392
michael@0 393 if (exitcode == PROCESS_END_NORMAL_TERMINATON ||
michael@0 394 exitcode == PROCESS_END_KILLED_BY_USER ||
michael@0 395 exitcode == PROCESS_END_PROCESS_WAS_HUNG ||
michael@0 396 exitcode == 0xC0000354 || // STATUS_DEBUGGER_INACTIVE.
michael@0 397 exitcode == 0xC000013A || // Control-C/end session.
michael@0 398 exitcode == 0x40010004) { // Debugger terminated process/end session.
michael@0 399 return false;
michael@0 400 }
michael@0 401
michael@0 402 return true;
michael@0 403 }
michael@0 404
michael@0 405 void SetCurrentProcessPrivileges(ChildPrivileges privs) {
michael@0 406
michael@0 407 }
michael@0 408
michael@0 409 NamedProcessIterator::NamedProcessIterator(const std::wstring& executable_name,
michael@0 410 const ProcessFilter* filter)
michael@0 411 : started_iteration_(false),
michael@0 412 executable_name_(executable_name),
michael@0 413 filter_(filter) {
michael@0 414 snapshot_ = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
michael@0 415 }
michael@0 416
michael@0 417 NamedProcessIterator::~NamedProcessIterator() {
michael@0 418 CloseHandle(snapshot_);
michael@0 419 }
michael@0 420
michael@0 421
michael@0 422 const ProcessEntry* NamedProcessIterator::NextProcessEntry() {
michael@0 423 bool result = false;
michael@0 424 do {
michael@0 425 result = CheckForNextProcess();
michael@0 426 } while (result && !IncludeEntry());
michael@0 427
michael@0 428 if (result) {
michael@0 429 return &entry_;
michael@0 430 }
michael@0 431
michael@0 432 return NULL;
michael@0 433 }
michael@0 434
michael@0 435 bool NamedProcessIterator::CheckForNextProcess() {
michael@0 436 InitProcessEntry(&entry_);
michael@0 437
michael@0 438 if (!started_iteration_) {
michael@0 439 started_iteration_ = true;
michael@0 440 return !!Process32First(snapshot_, &entry_);
michael@0 441 }
michael@0 442
michael@0 443 return !!Process32Next(snapshot_, &entry_);
michael@0 444 }
michael@0 445
michael@0 446 bool NamedProcessIterator::IncludeEntry() {
michael@0 447 return _wcsicmp(executable_name_.c_str(), entry_.szExeFile) == 0 &&
michael@0 448 (!filter_ || filter_->Includes(entry_.th32ProcessID,
michael@0 449 entry_.th32ParentProcessID));
michael@0 450 }
michael@0 451
michael@0 452 void NamedProcessIterator::InitProcessEntry(ProcessEntry* entry) {
michael@0 453 memset(entry, 0, sizeof(*entry));
michael@0 454 entry->dwSize = sizeof(*entry);
michael@0 455 }
michael@0 456
michael@0 457 ///////////////////////////////////////////////////////////////////////////////
michael@0 458 // ProcesMetrics
michael@0 459
michael@0 460 ProcessMetrics::ProcessMetrics(ProcessHandle process) : process_(process),
michael@0 461 last_time_(0),
michael@0 462 last_system_time_(0) {
michael@0 463 SYSTEM_INFO system_info;
michael@0 464 GetSystemInfo(&system_info);
michael@0 465 processor_count_ = system_info.dwNumberOfProcessors;
michael@0 466 }
michael@0 467
michael@0 468 // static
michael@0 469 ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
michael@0 470 return new ProcessMetrics(process);
michael@0 471 }
michael@0 472
michael@0 473 ProcessMetrics::~ProcessMetrics() { }
michael@0 474
michael@0 475 static uint64_t FileTimeToUTC(const FILETIME& ftime) {
michael@0 476 LARGE_INTEGER li;
michael@0 477 li.LowPart = ftime.dwLowDateTime;
michael@0 478 li.HighPart = ftime.dwHighDateTime;
michael@0 479 return li.QuadPart;
michael@0 480 }
michael@0 481
michael@0 482 int ProcessMetrics::GetCPUUsage() {
michael@0 483 FILETIME now;
michael@0 484 FILETIME creation_time;
michael@0 485 FILETIME exit_time;
michael@0 486 FILETIME kernel_time;
michael@0 487 FILETIME user_time;
michael@0 488
michael@0 489 GetSystemTimeAsFileTime(&now);
michael@0 490
michael@0 491 if (!GetProcessTimes(process_, &creation_time, &exit_time,
michael@0 492 &kernel_time, &user_time)) {
michael@0 493 // We don't assert here because in some cases (such as in the Task Manager)
michael@0 494 // we may call this function on a process that has just exited but we have
michael@0 495 // not yet received the notification.
michael@0 496 return 0;
michael@0 497 }
michael@0 498 int64_t system_time = (FileTimeToUTC(kernel_time) + FileTimeToUTC(user_time)) /
michael@0 499 processor_count_;
michael@0 500 int64_t time = FileTimeToUTC(now);
michael@0 501
michael@0 502 if ((last_system_time_ == 0) || (last_time_ == 0)) {
michael@0 503 // First call, just set the last values.
michael@0 504 last_system_time_ = system_time;
michael@0 505 last_time_ = time;
michael@0 506 return 0;
michael@0 507 }
michael@0 508
michael@0 509 int64_t system_time_delta = system_time - last_system_time_;
michael@0 510 int64_t time_delta = time - last_time_;
michael@0 511 DCHECK(time_delta != 0);
michael@0 512 if (time_delta == 0)
michael@0 513 return 0;
michael@0 514
michael@0 515 // We add time_delta / 2 so the result is rounded.
michael@0 516 int cpu = static_cast<int>((system_time_delta * 100 + time_delta / 2) /
michael@0 517 time_delta);
michael@0 518
michael@0 519 last_system_time_ = system_time;
michael@0 520 last_time_ = time;
michael@0 521
michael@0 522 return cpu;
michael@0 523 }
michael@0 524
michael@0 525 } // namespace base

mercurial