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