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