process_util_win.cc revision ddb351dbec246cf1fab5ec20d2d5520909041de1
1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/process_util.h"
6
7#include <fcntl.h>
8#include <io.h>
9#include <windows.h>
10#include <userenv.h>
11#include <psapi.h>
12
13#include <ios>
14
15#include "base/command_line.h"
16#include "base/debug/stack_trace.h"
17#include "base/logging.h"
18#include "base/memory/scoped_ptr.h"
19#include "base/metrics/histogram.h"
20#include "base/sys_info.h"
21#include "base/win/scoped_handle.h"
22#include "base/win/windows_version.h"
23
24// userenv.dll is required for CreateEnvironmentBlock().
25#pragma comment(lib, "userenv.lib")
26
27namespace base {
28
29namespace {
30
31// System pagesize. This value remains constant on x86/64 architectures.
32const int PAGESIZE_KB = 4;
33
34// Exit codes with special meanings on Windows.
35const DWORD kNormalTerminationExitCode = 0;
36const DWORD kDebuggerInactiveExitCode = 0xC0000354;
37const DWORD kKeyboardInterruptExitCode = 0xC000013A;
38const DWORD kDebuggerTerminatedExitCode = 0x40010004;
39
40// This exit code is used by the Windows task manager when it kills a
41// process.  It's value is obviously not that unique, and it's
42// surprising to me that the task manager uses this value, but it
43// seems to be common practice on Windows to test for it as an
44// indication that the task manager has killed something if the
45// process goes away.
46const DWORD kProcessKilledExitCode = 1;
47
48// HeapSetInformation function pointer.
49typedef BOOL (WINAPI* HeapSetFn)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T);
50
51// Previous unhandled filter. Will be called if not NULL when we intercept an
52// exception. Only used in unit tests.
53LPTOP_LEVEL_EXCEPTION_FILTER g_previous_filter = NULL;
54
55// Prints the exception call stack.
56// This is the unit tests exception filter.
57long WINAPI StackDumpExceptionFilter(EXCEPTION_POINTERS* info) {
58  debug::StackTrace(info).PrintBacktrace();
59  if (g_previous_filter)
60    return g_previous_filter(info);
61  return EXCEPTION_CONTINUE_SEARCH;
62}
63
64// Connects back to a console if available.
65void AttachToConsole() {
66  if (!AttachConsole(ATTACH_PARENT_PROCESS)) {
67    unsigned int result = GetLastError();
68    // Was probably already attached.
69    if (result == ERROR_ACCESS_DENIED)
70      return;
71
72    if (result == ERROR_INVALID_HANDLE || result == ERROR_INVALID_HANDLE) {
73      // TODO(maruel): Walk up the process chain if deemed necessary.
74    }
75    // Continue even if the function call fails.
76    AllocConsole();
77  }
78  // http://support.microsoft.com/kb/105305
79  int raw_out = _open_osfhandle(
80      reinterpret_cast<intptr_t>(GetStdHandle(STD_OUTPUT_HANDLE)), _O_TEXT);
81  *stdout = *_fdopen(raw_out, "w");
82  setvbuf(stdout, NULL, _IONBF, 0);
83
84  int raw_err = _open_osfhandle(
85      reinterpret_cast<intptr_t>(GetStdHandle(STD_ERROR_HANDLE)), _O_TEXT);
86  *stderr = *_fdopen(raw_err, "w");
87  setvbuf(stderr, NULL, _IONBF, 0);
88
89  int raw_in = _open_osfhandle(
90      reinterpret_cast<intptr_t>(GetStdHandle(STD_INPUT_HANDLE)), _O_TEXT);
91  *stdin = *_fdopen(raw_in, "r");
92  setvbuf(stdin, NULL, _IONBF, 0);
93  // Fix all cout, wcout, cin, wcin, cerr, wcerr, clog and wclog.
94  std::ios::sync_with_stdio();
95}
96
97}  // namespace
98
99ProcessId GetCurrentProcId() {
100  return ::GetCurrentProcessId();
101}
102
103ProcessHandle GetCurrentProcessHandle() {
104  return ::GetCurrentProcess();
105}
106
107bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) {
108  // We try to limit privileges granted to the handle. If you need this
109  // for test code, consider using OpenPrivilegedProcessHandle instead of
110  // adding more privileges here.
111  ProcessHandle result = OpenProcess(PROCESS_DUP_HANDLE | PROCESS_TERMINATE,
112                                     FALSE, pid);
113
114  if (result == INVALID_HANDLE_VALUE)
115    return false;
116
117  *handle = result;
118  return true;
119}
120
121bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) {
122  ProcessHandle result = OpenProcess(PROCESS_DUP_HANDLE |
123                                     PROCESS_TERMINATE |
124                                     PROCESS_QUERY_INFORMATION |
125                                     PROCESS_VM_READ |
126                                     SYNCHRONIZE,
127                                     FALSE, pid);
128
129  if (result == INVALID_HANDLE_VALUE)
130    return false;
131
132  *handle = result;
133  return true;
134}
135
136bool OpenProcessHandleWithAccess(ProcessId pid,
137                                 uint32 access_flags,
138                                 ProcessHandle* handle) {
139  ProcessHandle result = OpenProcess(access_flags, FALSE, pid);
140
141  if (result == INVALID_HANDLE_VALUE)
142    return false;
143
144  *handle = result;
145  return true;
146}
147
148void CloseProcessHandle(ProcessHandle process) {
149  CloseHandle(process);
150}
151
152ProcessId GetProcId(ProcessHandle process) {
153  // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
154  HANDLE current_process = GetCurrentProcess();
155  HANDLE process_with_query_rights;
156  if (DuplicateHandle(current_process, process, current_process,
157                      &process_with_query_rights, PROCESS_QUERY_INFORMATION,
158                      false, 0)) {
159    DWORD id = GetProcessId(process_with_query_rights);
160    CloseHandle(process_with_query_rights);
161    return id;
162  }
163
164  // We're screwed.
165  NOTREACHED();
166  return 0;
167}
168
169bool GetProcessIntegrityLevel(ProcessHandle process, IntegrityLevel *level) {
170  if (!level)
171    return false;
172
173  if (win::GetVersion() < base::win::VERSION_VISTA)
174    return false;
175
176  HANDLE process_token;
177  if (!OpenProcessToken(process, TOKEN_QUERY | TOKEN_QUERY_SOURCE,
178      &process_token))
179    return false;
180
181  win::ScopedHandle scoped_process_token(process_token);
182
183  DWORD token_info_length = 0;
184  if (GetTokenInformation(process_token, TokenIntegrityLevel, NULL, 0,
185                          &token_info_length) ||
186      GetLastError() != ERROR_INSUFFICIENT_BUFFER)
187    return false;
188
189  scoped_array<char> token_label_bytes(new char[token_info_length]);
190  if (!token_label_bytes.get())
191    return false;
192
193  TOKEN_MANDATORY_LABEL* token_label =
194      reinterpret_cast<TOKEN_MANDATORY_LABEL*>(token_label_bytes.get());
195  if (!token_label)
196    return false;
197
198  if (!GetTokenInformation(process_token, TokenIntegrityLevel, token_label,
199                           token_info_length, &token_info_length))
200    return false;
201
202  DWORD integrity_level = *GetSidSubAuthority(token_label->Label.Sid,
203      (DWORD)(UCHAR)(*GetSidSubAuthorityCount(token_label->Label.Sid)-1));
204
205  if (integrity_level < SECURITY_MANDATORY_MEDIUM_RID) {
206    *level = LOW_INTEGRITY;
207  } else if (integrity_level >= SECURITY_MANDATORY_MEDIUM_RID &&
208      integrity_level < SECURITY_MANDATORY_HIGH_RID) {
209    *level = MEDIUM_INTEGRITY;
210  } else if (integrity_level >= SECURITY_MANDATORY_HIGH_RID) {
211    *level = HIGH_INTEGRITY;
212  } else {
213    NOTREACHED();
214    return false;
215  }
216
217  return true;
218}
219
220bool LaunchAppImpl(const std::wstring& cmdline,
221                   bool wait, bool start_hidden, bool inherit_handles,
222                   ProcessHandle* process_handle) {
223  STARTUPINFO startup_info = {0};
224  startup_info.cb = sizeof(startup_info);
225  startup_info.dwFlags = STARTF_USESHOWWINDOW;
226  startup_info.wShowWindow = start_hidden ? SW_HIDE : SW_SHOW;
227  PROCESS_INFORMATION process_info;
228  if (!CreateProcess(NULL,
229                     const_cast<wchar_t*>(cmdline.c_str()), NULL, NULL,
230                     inherit_handles, 0, NULL, NULL,
231                     &startup_info, &process_info))
232    return false;
233
234  // Handles must be closed or they will leak
235  CloseHandle(process_info.hThread);
236
237  if (wait)
238    WaitForSingleObject(process_info.hProcess, INFINITE);
239
240  // If the caller wants the process handle, we won't close it.
241  if (process_handle) {
242    *process_handle = process_info.hProcess;
243  } else {
244    CloseHandle(process_info.hProcess);
245  }
246  return true;
247}
248
249bool LaunchApp(const std::wstring& cmdline,
250               bool wait, bool start_hidden, ProcessHandle* process_handle) {
251  return LaunchAppImpl(cmdline, wait, start_hidden, false, process_handle);
252}
253
254bool LaunchAppWithHandleInheritance(
255    const std::wstring& cmdline, bool wait, bool start_hidden,
256    ProcessHandle* process_handle) {
257  return LaunchAppImpl(cmdline, wait, start_hidden, true, process_handle);
258}
259
260bool LaunchAppAsUser(UserTokenHandle token, const std::wstring& cmdline,
261                     bool start_hidden, ProcessHandle* process_handle) {
262  return LaunchAppAsUser(token, cmdline, start_hidden, process_handle,
263                         false, false);
264}
265
266bool LaunchAppAsUser(UserTokenHandle token, const std::wstring& cmdline,
267                     bool start_hidden, ProcessHandle* process_handle,
268                     bool empty_desktop_name, bool inherit_handles) {
269  STARTUPINFO startup_info = {0};
270  startup_info.cb = sizeof(startup_info);
271  if (empty_desktop_name)
272    startup_info.lpDesktop = L"";
273  PROCESS_INFORMATION process_info;
274  if (start_hidden) {
275    startup_info.dwFlags = STARTF_USESHOWWINDOW;
276    startup_info.wShowWindow = SW_HIDE;
277  }
278  DWORD flags = CREATE_UNICODE_ENVIRONMENT;
279  void* enviroment_block = NULL;
280
281  if (!CreateEnvironmentBlock(&enviroment_block, token, FALSE))
282    return false;
283
284  BOOL launched =
285      CreateProcessAsUser(token, NULL, const_cast<wchar_t*>(cmdline.c_str()),
286                          NULL, NULL, inherit_handles, flags, enviroment_block,
287                          NULL, &startup_info, &process_info);
288
289  DestroyEnvironmentBlock(enviroment_block);
290
291  if (!launched)
292    return false;
293
294  CloseHandle(process_info.hThread);
295
296  if (process_handle) {
297    *process_handle = process_info.hProcess;
298  } else {
299    CloseHandle(process_info.hProcess);
300  }
301  return true;
302}
303
304bool LaunchApp(const CommandLine& cl,
305               bool wait, bool start_hidden, ProcessHandle* process_handle) {
306  return LaunchAppImpl(cl.command_line_string(), wait,
307                       start_hidden, false, process_handle);
308}
309
310// Attempts to kill the process identified by the given process
311// entry structure, giving it the specified exit code.
312// Returns true if this is successful, false otherwise.
313bool KillProcessById(ProcessId process_id, int exit_code, bool wait) {
314  HANDLE process = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE,
315                               FALSE,  // Don't inherit handle
316                               process_id);
317  if (!process) {
318    DLOG(ERROR) << "Unable to open process " << process_id << " : "
319                << GetLastError();
320    return false;
321  }
322  bool ret = KillProcess(process, exit_code, wait);
323  CloseHandle(process);
324  return ret;
325}
326
327bool GetAppOutput(const CommandLine& cl, std::string* output) {
328  HANDLE out_read = NULL;
329  HANDLE out_write = NULL;
330
331  SECURITY_ATTRIBUTES sa_attr;
332  // Set the bInheritHandle flag so pipe handles are inherited.
333  sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
334  sa_attr.bInheritHandle = TRUE;
335  sa_attr.lpSecurityDescriptor = NULL;
336
337  // Create the pipe for the child process's STDOUT.
338  if (!CreatePipe(&out_read, &out_write, &sa_attr, 0)) {
339    NOTREACHED() << "Failed to create pipe";
340    return false;
341  }
342
343  // Ensure we don't leak the handles.
344  win::ScopedHandle scoped_out_read(out_read);
345  win::ScopedHandle scoped_out_write(out_write);
346
347  // Ensure the read handle to the pipe for STDOUT is not inherited.
348  if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) {
349    NOTREACHED() << "Failed to disabled pipe inheritance";
350    return false;
351  }
352
353  // Now create the child process
354  PROCESS_INFORMATION proc_info = { 0 };
355  STARTUPINFO start_info = { 0 };
356
357  start_info.cb = sizeof(STARTUPINFO);
358  start_info.hStdOutput = out_write;
359  // Keep the normal stdin and stderr.
360  start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
361  start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
362  start_info.dwFlags |= STARTF_USESTDHANDLES;
363
364  // Create the child process.
365  if (!CreateProcess(NULL,
366                     const_cast<wchar_t*>(cl.command_line_string().c_str()),
367                     NULL, NULL,
368                     TRUE,  // Handles are inherited.
369                     0, NULL, NULL, &start_info, &proc_info)) {
370    NOTREACHED() << "Failed to start process";
371    return false;
372  }
373
374  // We don't need the thread handle, close it now.
375  CloseHandle(proc_info.hThread);
376
377  // Close our writing end of pipe now. Otherwise later read would not be able
378  // to detect end of child's output.
379  scoped_out_write.Close();
380
381  // Read output from the child process's pipe for STDOUT
382  const int kBufferSize = 1024;
383  char buffer[kBufferSize];
384
385  for (;;) {
386    DWORD bytes_read = 0;
387    BOOL success = ReadFile(out_read, buffer, kBufferSize, &bytes_read, NULL);
388    if (!success || bytes_read == 0)
389      break;
390    output->append(buffer, bytes_read);
391  }
392
393  // Let's wait for the process to finish.
394  WaitForSingleObject(proc_info.hProcess, INFINITE);
395  CloseHandle(proc_info.hProcess);
396
397  return true;
398}
399
400bool KillProcess(ProcessHandle process, int exit_code, bool wait) {
401  bool result = (TerminateProcess(process, exit_code) != FALSE);
402  if (result && wait) {
403    // The process may not end immediately due to pending I/O
404    if (WAIT_OBJECT_0 != WaitForSingleObject(process, 60 * 1000))
405      DLOG(ERROR) << "Error waiting for process exit: " << GetLastError();
406  } else if (!result) {
407    DLOG(ERROR) << "Unable to terminate process: " << GetLastError();
408  }
409  return result;
410}
411
412TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) {
413  DWORD tmp_exit_code = 0;
414
415  if (!::GetExitCodeProcess(handle, &tmp_exit_code)) {
416    NOTREACHED();
417    if (exit_code) {
418      // This really is a random number.  We haven't received any
419      // information about the exit code, presumably because this
420      // process doesn't have permission to get the exit code, or
421      // because of some other cause for GetExitCodeProcess to fail
422      // (MSDN docs don't give the possible failure error codes for
423      // this function, so it could be anything).  But we don't want
424      // to leave exit_code uninitialized, since that could cause
425      // random interpretations of the exit code.  So we assume it
426      // terminated "normally" in this case.
427      *exit_code = kNormalTerminationExitCode;
428    }
429    // Assume the child has exited normally if we can't get the exit
430    // code.
431    return TERMINATION_STATUS_NORMAL_TERMINATION;
432  }
433  if (tmp_exit_code == STILL_ACTIVE) {
434    DWORD wait_result = WaitForSingleObject(handle, 0);
435    if (wait_result == WAIT_TIMEOUT) {
436      if (exit_code)
437        *exit_code = wait_result;
438      return TERMINATION_STATUS_STILL_RUNNING;
439    }
440
441    DCHECK_EQ(WAIT_OBJECT_0, wait_result);
442
443    // Strange, the process used 0x103 (STILL_ACTIVE) as exit code.
444    NOTREACHED();
445
446    return TERMINATION_STATUS_ABNORMAL_TERMINATION;
447  }
448
449  if (exit_code)
450    *exit_code = tmp_exit_code;
451
452  switch (tmp_exit_code) {
453    case kNormalTerminationExitCode:
454      return TERMINATION_STATUS_NORMAL_TERMINATION;
455    case kDebuggerInactiveExitCode:  // STATUS_DEBUGGER_INACTIVE.
456    case kKeyboardInterruptExitCode:  // Control-C/end session.
457    case kDebuggerTerminatedExitCode:  // Debugger terminated process.
458    case kProcessKilledExitCode:  // Task manager kill.
459      return TERMINATION_STATUS_PROCESS_WAS_KILLED;
460    default:
461      // All other exit codes indicate crashes.
462      return TERMINATION_STATUS_PROCESS_CRASHED;
463  }
464}
465
466bool WaitForExitCode(ProcessHandle handle, int* exit_code) {
467  bool success = WaitForExitCodeWithTimeout(handle, exit_code, INFINITE);
468  CloseProcessHandle(handle);
469  return success;
470}
471
472bool WaitForExitCodeWithTimeout(ProcessHandle handle, int* exit_code,
473                                int64 timeout_milliseconds) {
474  if (::WaitForSingleObject(handle, timeout_milliseconds) != WAIT_OBJECT_0)
475    return false;
476  DWORD temp_code;  // Don't clobber out-parameters in case of failure.
477  if (!::GetExitCodeProcess(handle, &temp_code))
478    return false;
479
480  *exit_code = temp_code;
481  return true;
482}
483
484ProcessIterator::ProcessIterator(const ProcessFilter* filter)
485    : started_iteration_(false),
486      filter_(filter) {
487  snapshot_ = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
488}
489
490ProcessIterator::~ProcessIterator() {
491  CloseHandle(snapshot_);
492}
493
494bool ProcessIterator::CheckForNextProcess() {
495  InitProcessEntry(&entry_);
496
497  if (!started_iteration_) {
498    started_iteration_ = true;
499    return !!Process32First(snapshot_, &entry_);
500  }
501
502  return !!Process32Next(snapshot_, &entry_);
503}
504
505void ProcessIterator::InitProcessEntry(ProcessEntry* entry) {
506  memset(entry, 0, sizeof(*entry));
507  entry->dwSize = sizeof(*entry);
508}
509
510bool NamedProcessIterator::IncludeEntry() {
511  // Case insensitive.
512  return _wcsicmp(executable_name_.c_str(), entry().exe_file()) == 0 &&
513         ProcessIterator::IncludeEntry();
514}
515
516bool WaitForProcessesToExit(const std::wstring& executable_name,
517                            int64 wait_milliseconds,
518                            const ProcessFilter* filter) {
519  const ProcessEntry* entry;
520  bool result = true;
521  DWORD start_time = GetTickCount();
522
523  NamedProcessIterator iter(executable_name, filter);
524  while (entry = iter.NextProcessEntry()) {
525    DWORD remaining_wait =
526        std::max<int64>(0, wait_milliseconds - (GetTickCount() - start_time));
527    HANDLE process = OpenProcess(SYNCHRONIZE,
528                                 FALSE,
529                                 entry->th32ProcessID);
530    DWORD wait_result = WaitForSingleObject(process, remaining_wait);
531    CloseHandle(process);
532    result = result && (wait_result == WAIT_OBJECT_0);
533  }
534
535  return result;
536}
537
538bool WaitForSingleProcess(ProcessHandle handle, int64 wait_milliseconds) {
539  bool retval = WaitForSingleObject(handle, wait_milliseconds) == WAIT_OBJECT_0;
540  return retval;
541}
542
543bool CleanupProcesses(const std::wstring& executable_name,
544                      int64 wait_milliseconds,
545                      int exit_code,
546                      const ProcessFilter* filter) {
547  bool exited_cleanly = WaitForProcessesToExit(executable_name,
548                                               wait_milliseconds,
549                                               filter);
550  if (!exited_cleanly)
551    KillProcesses(executable_name, exit_code, filter);
552  return exited_cleanly;
553}
554
555///////////////////////////////////////////////////////////////////////////////
556// ProcesMetrics
557
558ProcessMetrics::ProcessMetrics(ProcessHandle process)
559    : process_(process),
560      processor_count_(base::SysInfo::NumberOfProcessors()),
561      last_time_(0),
562      last_system_time_(0) {
563}
564
565// static
566ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
567  return new ProcessMetrics(process);
568}
569
570ProcessMetrics::~ProcessMetrics() { }
571
572size_t ProcessMetrics::GetPagefileUsage() const {
573  PROCESS_MEMORY_COUNTERS pmc;
574  if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) {
575    return pmc.PagefileUsage;
576  }
577  return 0;
578}
579
580// Returns the peak space allocated for the pagefile, in bytes.
581size_t ProcessMetrics::GetPeakPagefileUsage() const {
582  PROCESS_MEMORY_COUNTERS pmc;
583  if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) {
584    return pmc.PeakPagefileUsage;
585  }
586  return 0;
587}
588
589// Returns the current working set size, in bytes.
590size_t ProcessMetrics::GetWorkingSetSize() const {
591  PROCESS_MEMORY_COUNTERS pmc;
592  if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) {
593    return pmc.WorkingSetSize;
594  }
595  return 0;
596}
597
598// Returns the peak working set size, in bytes.
599size_t ProcessMetrics::GetPeakWorkingSetSize() const {
600  PROCESS_MEMORY_COUNTERS pmc;
601  if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) {
602    return pmc.PeakWorkingSetSize;
603  }
604  return 0;
605}
606
607bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
608                                    size_t* shared_bytes) {
609  // PROCESS_MEMORY_COUNTERS_EX is not supported until XP SP2.
610  // GetProcessMemoryInfo() will simply fail on prior OS. So the requested
611  // information is simply not available. Hence, we will return 0 on unsupported
612  // OSes. Unlike most Win32 API, we don't need to initialize the "cb" member.
613  PROCESS_MEMORY_COUNTERS_EX pmcx;
614  if (private_bytes &&
615      GetProcessMemoryInfo(process_,
616                           reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmcx),
617                           sizeof(pmcx))) {
618    *private_bytes = pmcx.PrivateUsage;
619  }
620
621  if (shared_bytes) {
622    WorkingSetKBytes ws_usage;
623    if (!GetWorkingSetKBytes(&ws_usage))
624      return false;
625
626    *shared_bytes = ws_usage.shared * 1024;
627  }
628
629  return true;
630}
631
632void ProcessMetrics::GetCommittedKBytes(CommittedKBytes* usage) const {
633  MEMORY_BASIC_INFORMATION mbi = {0};
634  size_t committed_private = 0;
635  size_t committed_mapped = 0;
636  size_t committed_image = 0;
637  void* base_address = NULL;
638  while (VirtualQueryEx(process_, base_address, &mbi, sizeof(mbi)) ==
639      sizeof(mbi)) {
640    if (mbi.State == MEM_COMMIT) {
641      if (mbi.Type == MEM_PRIVATE) {
642        committed_private += mbi.RegionSize;
643      } else if (mbi.Type == MEM_MAPPED) {
644        committed_mapped += mbi.RegionSize;
645      } else if (mbi.Type == MEM_IMAGE) {
646        committed_image += mbi.RegionSize;
647      } else {
648        NOTREACHED();
649      }
650    }
651    void* new_base = (static_cast<BYTE*>(mbi.BaseAddress)) + mbi.RegionSize;
652    // Avoid infinite loop by weird MEMORY_BASIC_INFORMATION.
653    // If we query 64bit processes in a 32bit process, VirtualQueryEx()
654    // returns such data.
655    if (new_base <= base_address) {
656      usage->image = 0;
657      usage->mapped = 0;
658      usage->priv = 0;
659      return;
660    }
661    base_address = new_base;
662  }
663  usage->image = committed_image / 1024;
664  usage->mapped = committed_mapped / 1024;
665  usage->priv = committed_private / 1024;
666}
667
668bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
669  size_t ws_private = 0;
670  size_t ws_shareable = 0;
671  size_t ws_shared = 0;
672
673  DCHECK(ws_usage);
674  memset(ws_usage, 0, sizeof(*ws_usage));
675
676  DWORD number_of_entries = 4096;  // Just a guess.
677  PSAPI_WORKING_SET_INFORMATION* buffer = NULL;
678  int retries = 5;
679  for (;;) {
680    DWORD buffer_size = sizeof(PSAPI_WORKING_SET_INFORMATION) +
681                        (number_of_entries * sizeof(PSAPI_WORKING_SET_BLOCK));
682
683    // if we can't expand the buffer, don't leak the previous
684    // contents or pass a NULL pointer to QueryWorkingSet
685    PSAPI_WORKING_SET_INFORMATION* new_buffer =
686        reinterpret_cast<PSAPI_WORKING_SET_INFORMATION*>(
687            realloc(buffer, buffer_size));
688    if (!new_buffer) {
689      free(buffer);
690      return false;
691    }
692    buffer = new_buffer;
693
694    // Call the function once to get number of items
695    if (QueryWorkingSet(process_, buffer, buffer_size))
696      break;  // Success
697
698    if (GetLastError() != ERROR_BAD_LENGTH) {
699      free(buffer);
700      return false;
701    }
702
703    number_of_entries = static_cast<DWORD>(buffer->NumberOfEntries);
704
705    // Maybe some entries are being added right now. Increase the buffer to
706    // take that into account.
707    number_of_entries = static_cast<DWORD>(number_of_entries * 1.25);
708
709    if (--retries == 0) {
710      free(buffer);  // If we're looping, eventually fail.
711      return false;
712    }
713  }
714
715  // On windows 2000 the function returns 1 even when the buffer is too small.
716  // The number of entries that we are going to parse is the minimum between the
717  // size we allocated and the real number of entries.
718  number_of_entries =
719      std::min(number_of_entries, static_cast<DWORD>(buffer->NumberOfEntries));
720  for (unsigned int i = 0; i < number_of_entries; i++) {
721    if (buffer->WorkingSetInfo[i].Shared) {
722      ws_shareable++;
723      if (buffer->WorkingSetInfo[i].ShareCount > 1)
724        ws_shared++;
725    } else {
726      ws_private++;
727    }
728  }
729
730  ws_usage->priv = ws_private * PAGESIZE_KB;
731  ws_usage->shareable = ws_shareable * PAGESIZE_KB;
732  ws_usage->shared = ws_shared * PAGESIZE_KB;
733  free(buffer);
734  return true;
735}
736
737static uint64 FileTimeToUTC(const FILETIME& ftime) {
738  LARGE_INTEGER li;
739  li.LowPart = ftime.dwLowDateTime;
740  li.HighPart = ftime.dwHighDateTime;
741  return li.QuadPart;
742}
743
744double ProcessMetrics::GetCPUUsage() {
745  FILETIME now;
746  FILETIME creation_time;
747  FILETIME exit_time;
748  FILETIME kernel_time;
749  FILETIME user_time;
750
751  GetSystemTimeAsFileTime(&now);
752
753  if (!GetProcessTimes(process_, &creation_time, &exit_time,
754                       &kernel_time, &user_time)) {
755    // We don't assert here because in some cases (such as in the Task Manager)
756    // we may call this function on a process that has just exited but we have
757    // not yet received the notification.
758    return 0;
759  }
760  int64 system_time = (FileTimeToUTC(kernel_time) + FileTimeToUTC(user_time)) /
761                        processor_count_;
762  int64 time = FileTimeToUTC(now);
763
764  if ((last_system_time_ == 0) || (last_time_ == 0)) {
765    // First call, just set the last values.
766    last_system_time_ = system_time;
767    last_time_ = time;
768    return 0;
769  }
770
771  int64 system_time_delta = system_time - last_system_time_;
772  int64 time_delta = time - last_time_;
773  DCHECK(time_delta != 0);
774  if (time_delta == 0)
775    return 0;
776
777  // We add time_delta / 2 so the result is rounded.
778  int cpu = static_cast<int>((system_time_delta * 100 + time_delta / 2) /
779                             time_delta);
780
781  last_system_time_ = system_time;
782  last_time_ = time;
783
784  return cpu;
785}
786
787bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
788  return GetProcessIoCounters(process_, io_counters) != FALSE;
789}
790
791bool ProcessMetrics::CalculateFreeMemory(FreeMBytes* free) const {
792  const SIZE_T kTopAddress = 0x7F000000;
793  const SIZE_T kMegabyte = 1024 * 1024;
794  SIZE_T accumulated = 0;
795
796  MEMORY_BASIC_INFORMATION largest = {0};
797  UINT_PTR scan = 0;
798  while (scan < kTopAddress) {
799    MEMORY_BASIC_INFORMATION info;
800    if (!::VirtualQueryEx(process_, reinterpret_cast<void*>(scan),
801                          &info, sizeof(info)))
802      return false;
803    if (info.State == MEM_FREE) {
804      accumulated += info.RegionSize;
805      UINT_PTR end = scan + info.RegionSize;
806      if (info.RegionSize > largest.RegionSize)
807        largest = info;
808    }
809    scan += info.RegionSize;
810  }
811  free->largest = largest.RegionSize / kMegabyte;
812  free->largest_ptr = largest.BaseAddress;
813  free->total = accumulated / kMegabyte;
814  return true;
815}
816
817bool EnableLowFragmentationHeap() {
818  HMODULE kernel32 = GetModuleHandle(L"kernel32.dll");
819  HeapSetFn heap_set = reinterpret_cast<HeapSetFn>(GetProcAddress(
820      kernel32,
821      "HeapSetInformation"));
822
823  // On Windows 2000, the function is not exported. This is not a reason to
824  // fail.
825  if (!heap_set)
826    return true;
827
828  unsigned number_heaps = GetProcessHeaps(0, NULL);
829  if (!number_heaps)
830    return false;
831
832  // Gives us some extra space in the array in case a thread is creating heaps
833  // at the same time we're querying them.
834  static const int MARGIN = 8;
835  scoped_array<HANDLE> heaps(new HANDLE[number_heaps + MARGIN]);
836  number_heaps = GetProcessHeaps(number_heaps + MARGIN, heaps.get());
837  if (!number_heaps)
838    return false;
839
840  for (unsigned i = 0; i < number_heaps; ++i) {
841    ULONG lfh_flag = 2;
842    // Don't bother with the result code. It may fails on heaps that have the
843    // HEAP_NO_SERIALIZE flag. This is expected and not a problem at all.
844    heap_set(heaps[i],
845             HeapCompatibilityInformation,
846             &lfh_flag,
847             sizeof(lfh_flag));
848  }
849  return true;
850}
851
852void EnableTerminationOnHeapCorruption() {
853  // Ignore the result code. Supported on XP SP3 and Vista.
854  HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
855}
856
857bool EnableInProcessStackDumping() {
858  // Add stack dumping support on exception on windows. Similar to OS_POSIX
859  // signal() handling in process_util_posix.cc.
860  g_previous_filter = SetUnhandledExceptionFilter(&StackDumpExceptionFilter);
861  AttachToConsole();
862  return true;
863}
864
865void RaiseProcessToHighPriority() {
866  SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
867}
868
869// GetPerformanceInfo is not available on WIN2K.  So we'll
870// load it on-the-fly.
871const wchar_t kPsapiDllName[] = L"psapi.dll";
872typedef BOOL (WINAPI *GetPerformanceInfoFunction) (
873    PPERFORMANCE_INFORMATION pPerformanceInformation,
874    DWORD cb);
875
876// Beware of races if called concurrently from multiple threads.
877static BOOL InternalGetPerformanceInfo(
878    PPERFORMANCE_INFORMATION pPerformanceInformation, DWORD cb) {
879  static GetPerformanceInfoFunction GetPerformanceInfo_func = NULL;
880  if (!GetPerformanceInfo_func) {
881    HMODULE psapi_dll = ::GetModuleHandle(kPsapiDllName);
882    if (psapi_dll)
883      GetPerformanceInfo_func = reinterpret_cast<GetPerformanceInfoFunction>(
884          GetProcAddress(psapi_dll, "GetPerformanceInfo"));
885
886    if (!GetPerformanceInfo_func) {
887      // The function could be loaded!
888      memset(pPerformanceInformation, 0, cb);
889      return FALSE;
890    }
891  }
892  return GetPerformanceInfo_func(pPerformanceInformation, cb);
893}
894
895size_t GetSystemCommitCharge() {
896  // Get the System Page Size.
897  SYSTEM_INFO system_info;
898  GetSystemInfo(&system_info);
899
900  PERFORMANCE_INFORMATION info;
901  if (!InternalGetPerformanceInfo(&info, sizeof(info))) {
902    LOG(ERROR) << "Failed to fetch internal performance info.";
903    return 0;
904  }
905  return (info.CommitTotal * system_info.dwPageSize) / 1024;
906}
907
908}  // namespace base
909