Home | History | Annotate | Download | only in base
      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 
     27 namespace base {
     28 
     29 namespace {
     30 
     31 // System pagesize. This value remains constant on x86/64 architectures.
     32 const int PAGESIZE_KB = 4;
     33 
     34 // Exit codes with special meanings on Windows.
     35 const DWORD kNormalTerminationExitCode = 0;
     36 const DWORD kDebuggerInactiveExitCode = 0xC0000354;
     37 const DWORD kKeyboardInterruptExitCode = 0xC000013A;
     38 const 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.
     46 const DWORD kProcessKilledExitCode = 1;
     47 
     48 // HeapSetInformation function pointer.
     49 typedef 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.
     53 LPTOP_LEVEL_EXCEPTION_FILTER g_previous_filter = NULL;
     54 
     55 // Prints the exception call stack.
     56 // This is the unit tests exception filter.
     57 long 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.
     65 void 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 
     99 ProcessId GetCurrentProcId() {
    100   return ::GetCurrentProcessId();
    101 }
    102 
    103 ProcessHandle GetCurrentProcessHandle() {
    104   return ::GetCurrentProcess();
    105 }
    106 
    107 bool 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 
    121 bool 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 
    136 bool 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 
    148 void CloseProcessHandle(ProcessHandle process) {
    149   CloseHandle(process);
    150 }
    151 
    152 ProcessId 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 
    169 bool 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 
    220 bool 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 
    249 bool 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 
    254 bool 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 
    260 bool 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 
    266 bool 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 
    304 bool 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.
    313 bool 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 
    327 bool 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 
    400 bool 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 
    412 TerminationStatus 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 
    466 bool WaitForExitCode(ProcessHandle handle, int* exit_code) {
    467   bool success = WaitForExitCodeWithTimeout(handle, exit_code, INFINITE);
    468   CloseProcessHandle(handle);
    469   return success;
    470 }
    471 
    472 bool 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 
    484 ProcessIterator::ProcessIterator(const ProcessFilter* filter)
    485     : started_iteration_(false),
    486       filter_(filter) {
    487   snapshot_ = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    488 }
    489 
    490 ProcessIterator::~ProcessIterator() {
    491   CloseHandle(snapshot_);
    492 }
    493 
    494 bool 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 
    505 void ProcessIterator::InitProcessEntry(ProcessEntry* entry) {
    506   memset(entry, 0, sizeof(*entry));
    507   entry->dwSize = sizeof(*entry);
    508 }
    509 
    510 bool NamedProcessIterator::IncludeEntry() {
    511   // Case insensitive.
    512   return _wcsicmp(executable_name_.c_str(), entry().exe_file()) == 0 &&
    513          ProcessIterator::IncludeEntry();
    514 }
    515 
    516 bool 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 
    538 bool WaitForSingleProcess(ProcessHandle handle, int64 wait_milliseconds) {
    539   bool retval = WaitForSingleObject(handle, wait_milliseconds) == WAIT_OBJECT_0;
    540   return retval;
    541 }
    542 
    543 bool 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 
    558 ProcessMetrics::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
    566 ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
    567   return new ProcessMetrics(process);
    568 }
    569 
    570 ProcessMetrics::~ProcessMetrics() { }
    571 
    572 size_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.
    581 size_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.
    590 size_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.
    599 size_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 
    607 bool 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 
    632 void 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 
    668 bool 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 
    737 static 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 
    744 double 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 
    787 bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
    788   return GetProcessIoCounters(process_, io_counters) != FALSE;
    789 }
    790 
    791 bool 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 
    817 bool 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 
    852 void EnableTerminationOnHeapCorruption() {
    853   // Ignore the result code. Supported on XP SP3 and Vista.
    854   HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
    855 }
    856 
    857 bool 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 
    865 void 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.
    871 const wchar_t kPsapiDllName[] = L"psapi.dll";
    872 typedef BOOL (WINAPI *GetPerformanceInfoFunction) (
    873     PPERFORMANCE_INFORMATION pPerformanceInformation,
    874     DWORD cb);
    875 
    876 // Beware of races if called concurrently from multiple threads.
    877 static 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 
    895 size_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