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.
5 #include "base/process_util.h"
15 #include "base/bind.h"
16 #include "base/bind_helpers.h"
17 #include "base/command_line.h"
18 #include "base/debug/stack_trace.h"
19 #include "base/logging.h"
20 #include "base/memory/scoped_ptr.h"
21 #include "base/message_loop.h"
22 #include "base/metrics/histogram.h"
23 #include "base/sys_info.h"
24 #include "base/win/object_watcher.h"
25 #include "base/win/scoped_handle.h"
26 #include "base/win/windows_version.h"
28 // userenv.dll is required for CreateEnvironmentBlock().
29 #pragma comment(lib, "userenv.lib")
35 // System pagesize. This value remains constant on x86/64 architectures.
36 const int PAGESIZE_KB
= 4;
38 // Exit codes with special meanings on Windows.
39 const DWORD kNormalTerminationExitCode
= 0;
40 const DWORD kDebuggerInactiveExitCode
= 0xC0000354;
41 const DWORD kKeyboardInterruptExitCode
= 0xC000013A;
42 const DWORD kDebuggerTerminatedExitCode
= 0x40010004;
44 // Maximum amount of time (in milliseconds) to wait for the process to exit.
45 static const int kWaitInterval
= 2000;
47 // This exit code is used by the Windows task manager when it kills a
48 // process. It's value is obviously not that unique, and it's
49 // surprising to me that the task manager uses this value, but it
50 // seems to be common practice on Windows to test for it as an
51 // indication that the task manager has killed something if the
53 const DWORD kProcessKilledExitCode
= 1;
55 // HeapSetInformation function pointer.
56 typedef BOOL (WINAPI
* HeapSetFn
)(HANDLE
, HEAP_INFORMATION_CLASS
, PVOID
, SIZE_T
);
58 // Previous unhandled filter. Will be called if not NULL when we intercept an
59 // exception. Only used in unit tests.
60 LPTOP_LEVEL_EXCEPTION_FILTER g_previous_filter
= NULL
;
62 // Prints the exception call stack.
63 // This is the unit tests exception filter.
64 long WINAPI
StackDumpExceptionFilter(EXCEPTION_POINTERS
* info
) {
65 debug::StackTrace(info
).PrintBacktrace();
66 if (g_previous_filter
)
67 return g_previous_filter(info
);
68 return EXCEPTION_CONTINUE_SEARCH
;
71 // Connects back to a console if available.
72 void AttachToConsole() {
73 if (!AttachConsole(ATTACH_PARENT_PROCESS
)) {
74 unsigned int result
= GetLastError();
75 // Was probably already attached.
76 if (result
== ERROR_ACCESS_DENIED
)
79 if (result
== ERROR_INVALID_HANDLE
|| result
== ERROR_INVALID_HANDLE
) {
80 // TODO(maruel): Walk up the process chain if deemed necessary.
82 // Continue even if the function call fails.
85 // http://support.microsoft.com/kb/105305
86 int raw_out
= _open_osfhandle(
87 reinterpret_cast<intptr_t>(GetStdHandle(STD_OUTPUT_HANDLE
)), _O_TEXT
);
88 *stdout
= *_fdopen(raw_out
, "w");
89 setvbuf(stdout
, NULL
, _IONBF
, 0);
91 int raw_err
= _open_osfhandle(
92 reinterpret_cast<intptr_t>(GetStdHandle(STD_ERROR_HANDLE
)), _O_TEXT
);
93 *stderr
= *_fdopen(raw_err
, "w");
94 setvbuf(stderr
, NULL
, _IONBF
, 0);
96 int raw_in
= _open_osfhandle(
97 reinterpret_cast<intptr_t>(GetStdHandle(STD_INPUT_HANDLE
)), _O_TEXT
);
98 *stdin
= *_fdopen(raw_in
, "r");
99 setvbuf(stdin
, NULL
, _IONBF
, 0);
100 // Fix all cout, wcout, cin, wcin, cerr, wcerr, clog and wclog.
101 std::ios::sync_with_stdio();
105 // Kill the process. This is important for security, since WebKit doesn't
106 // NULL-check many memory allocations. If a malloc fails, returns NULL, and
107 // the buffer is then used, it provides a handy mapping of memory starting at
108 // address 0 for an attacker to utilize.
113 class TimerExpiredTask
: public win::ObjectWatcher::Delegate
{
115 explicit TimerExpiredTask(ProcessHandle process
);
120 // MessageLoop::Watcher -----------------------------------------------------
121 virtual void OnObjectSignaled(HANDLE object
);
126 // The process that we are watching.
127 ProcessHandle process_
;
129 win::ObjectWatcher watcher_
;
131 DISALLOW_COPY_AND_ASSIGN(TimerExpiredTask
);
134 TimerExpiredTask::TimerExpiredTask(ProcessHandle process
) : process_(process
) {
135 watcher_
.StartWatching(process_
, this);
138 TimerExpiredTask::~TimerExpiredTask() {
140 DCHECK(!process_
) << "Make sure to close the handle.";
143 void TimerExpiredTask::TimedOut() {
148 void TimerExpiredTask::OnObjectSignaled(HANDLE object
) {
149 CloseHandle(process_
);
153 void TimerExpiredTask::KillProcess() {
154 // Stop watching the process handle since we're killing it.
155 watcher_
.StopWatching();
157 // OK, time to get frisky. We don't actually care when the process
158 // terminates. We just care that it eventually terminates, and that's what
159 // TerminateProcess should do for us. Don't check for the result code since
160 // it fails quite often. This should be investigated eventually.
161 base::KillProcess(process_
, kProcessKilledExitCode
, false);
163 // Now, just cleanup as if the process exited normally.
164 OnObjectSignaled(process_
);
169 ProcessId
GetCurrentProcId() {
170 return ::GetCurrentProcessId();
173 ProcessHandle
GetCurrentProcessHandle() {
174 return ::GetCurrentProcess();
177 bool OpenProcessHandle(ProcessId pid
, ProcessHandle
* handle
) {
178 // We try to limit privileges granted to the handle. If you need this
179 // for test code, consider using OpenPrivilegedProcessHandle instead of
180 // adding more privileges here.
181 ProcessHandle result
= OpenProcess(PROCESS_DUP_HANDLE
| PROCESS_TERMINATE
,
184 if (result
== INVALID_HANDLE_VALUE
)
191 bool OpenPrivilegedProcessHandle(ProcessId pid
, ProcessHandle
* handle
) {
192 ProcessHandle result
= OpenProcess(PROCESS_DUP_HANDLE
|
194 PROCESS_QUERY_INFORMATION
|
199 if (result
== INVALID_HANDLE_VALUE
)
206 bool OpenProcessHandleWithAccess(ProcessId pid
,
208 ProcessHandle
* handle
) {
209 ProcessHandle result
= OpenProcess(access_flags
, FALSE
, pid
);
211 if (result
== INVALID_HANDLE_VALUE
)
218 void CloseProcessHandle(ProcessHandle process
) {
219 CloseHandle(process
);
222 ProcessId
GetProcId(ProcessHandle process
) {
223 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
224 HANDLE current_process
= GetCurrentProcess();
225 HANDLE process_with_query_rights
;
226 if (DuplicateHandle(current_process
, process
, current_process
,
227 &process_with_query_rights
, PROCESS_QUERY_INFORMATION
,
229 DWORD id
= GetProcessId(process_with_query_rights
);
230 CloseHandle(process_with_query_rights
);
239 bool GetProcessIntegrityLevel(ProcessHandle process
, IntegrityLevel
*level
) {
243 if (win::GetVersion() < base::win::VERSION_VISTA
)
246 HANDLE process_token
;
247 if (!OpenProcessToken(process
, TOKEN_QUERY
| TOKEN_QUERY_SOURCE
,
251 win::ScopedHandle
scoped_process_token(process_token
);
253 DWORD token_info_length
= 0;
254 if (GetTokenInformation(process_token
, TokenIntegrityLevel
, NULL
, 0,
255 &token_info_length
) ||
256 GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
259 scoped_array
<char> token_label_bytes(new char[token_info_length
]);
260 if (!token_label_bytes
.get())
263 TOKEN_MANDATORY_LABEL
* token_label
=
264 reinterpret_cast<TOKEN_MANDATORY_LABEL
*>(token_label_bytes
.get());
268 if (!GetTokenInformation(process_token
, TokenIntegrityLevel
, token_label
,
269 token_info_length
, &token_info_length
))
272 DWORD integrity_level
= *GetSidSubAuthority(token_label
->Label
.Sid
,
273 (DWORD
)(UCHAR
)(*GetSidSubAuthorityCount(token_label
->Label
.Sid
)-1));
275 if (integrity_level
< SECURITY_MANDATORY_MEDIUM_RID
) {
276 *level
= LOW_INTEGRITY
;
277 } else if (integrity_level
>= SECURITY_MANDATORY_MEDIUM_RID
&&
278 integrity_level
< SECURITY_MANDATORY_HIGH_RID
) {
279 *level
= MEDIUM_INTEGRITY
;
280 } else if (integrity_level
>= SECURITY_MANDATORY_HIGH_RID
) {
281 *level
= HIGH_INTEGRITY
;
290 bool LaunchProcess(const string16
& cmdline
,
291 const LaunchOptions
& options
,
292 ProcessHandle
* process_handle
) {
293 STARTUPINFO startup_info
= {};
294 startup_info
.cb
= sizeof(startup_info
);
295 if (options
.empty_desktop_name
)
296 startup_info
.lpDesktop
= L
"";
297 startup_info
.dwFlags
= STARTF_USESHOWWINDOW
;
298 startup_info
.wShowWindow
= options
.start_hidden
? SW_HIDE
: SW_SHOW
;
299 PROCESS_INFORMATION process_info
;
303 if (options
.job_handle
) {
304 flags
|= CREATE_SUSPENDED
;
306 // If this code is run under a debugger, the launched process is
307 // automatically associated with a job object created by the debugger.
308 // The CREATE_BREAKAWAY_FROM_JOB flag is used to prevent this.
309 flags
|= CREATE_BREAKAWAY_FROM_JOB
;
312 if (options
.as_user
) {
313 flags
|= CREATE_UNICODE_ENVIRONMENT
;
314 void* enviroment_block
= NULL
;
316 if (!CreateEnvironmentBlock(&enviroment_block
, options
.as_user
, FALSE
))
320 CreateProcessAsUser(options
.as_user
, NULL
,
321 const_cast<wchar_t*>(cmdline
.c_str()),
322 NULL
, NULL
, options
.inherit_handles
, flags
,
323 enviroment_block
, NULL
, &startup_info
,
325 DestroyEnvironmentBlock(enviroment_block
);
329 if (!CreateProcess(NULL
,
330 const_cast<wchar_t*>(cmdline
.c_str()), NULL
, NULL
,
331 options
.inherit_handles
, flags
, NULL
, NULL
,
332 &startup_info
, &process_info
)) {
337 if (options
.job_handle
) {
338 if (0 == AssignProcessToJobObject(options
.job_handle
,
339 process_info
.hProcess
)) {
340 DLOG(ERROR
) << "Could not AssignProcessToObject.";
341 KillProcess(process_info
.hProcess
, kProcessKilledExitCode
, true);
345 ResumeThread(process_info
.hThread
);
348 // Handles must be closed or they will leak.
349 CloseHandle(process_info
.hThread
);
352 WaitForSingleObject(process_info
.hProcess
, INFINITE
);
354 // If the caller wants the process handle, we won't close it.
355 if (process_handle
) {
356 *process_handle
= process_info
.hProcess
;
358 CloseHandle(process_info
.hProcess
);
363 bool LaunchProcess(const CommandLine
& cmdline
,
364 const LaunchOptions
& options
,
365 ProcessHandle
* process_handle
) {
366 return LaunchProcess(cmdline
.GetCommandLineString(), options
, process_handle
);
369 bool SetJobObjectAsKillOnJobClose(HANDLE job_object
) {
370 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info
= {0};
371 limit_info
.BasicLimitInformation
.LimitFlags
=
372 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
;
373 return 0 != SetInformationJobObject(
375 JobObjectExtendedLimitInformation
,
380 // Attempts to kill the process identified by the given process
381 // entry structure, giving it the specified exit code.
382 // Returns true if this is successful, false otherwise.
383 bool KillProcessById(ProcessId process_id
, int exit_code
, bool wait
) {
384 HANDLE process
= OpenProcess(PROCESS_TERMINATE
| SYNCHRONIZE
,
385 FALSE
, // Don't inherit handle
388 DLOG(ERROR
) << "Unable to open process " << process_id
<< " : "
392 bool ret
= KillProcess(process
, exit_code
, wait
);
393 CloseHandle(process
);
397 bool GetAppOutput(const CommandLine
& cl
, std::string
* output
) {
398 HANDLE out_read
= NULL
;
399 HANDLE out_write
= NULL
;
401 SECURITY_ATTRIBUTES sa_attr
;
402 // Set the bInheritHandle flag so pipe handles are inherited.
403 sa_attr
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
404 sa_attr
.bInheritHandle
= TRUE
;
405 sa_attr
.lpSecurityDescriptor
= NULL
;
407 // Create the pipe for the child process's STDOUT.
408 if (!CreatePipe(&out_read
, &out_write
, &sa_attr
, 0)) {
409 NOTREACHED() << "Failed to create pipe";
413 // Ensure we don't leak the handles.
414 win::ScopedHandle
scoped_out_read(out_read
);
415 win::ScopedHandle
scoped_out_write(out_write
);
417 // Ensure the read handle to the pipe for STDOUT is not inherited.
418 if (!SetHandleInformation(out_read
, HANDLE_FLAG_INHERIT
, 0)) {
419 NOTREACHED() << "Failed to disabled pipe inheritance";
423 std::wstring
writable_command_line_string(cl
.GetCommandLineString());
425 PROCESS_INFORMATION proc_info
= { 0 };
426 STARTUPINFO start_info
= { 0 };
428 start_info
.cb
= sizeof(STARTUPINFO
);
429 start_info
.hStdOutput
= out_write
;
430 // Keep the normal stdin and stderr.
431 start_info
.hStdInput
= GetStdHandle(STD_INPUT_HANDLE
);
432 start_info
.hStdError
= GetStdHandle(STD_ERROR_HANDLE
);
433 start_info
.dwFlags
|= STARTF_USESTDHANDLES
;
435 // Create the child process.
436 if (!CreateProcess(NULL
,
437 &writable_command_line_string
[0],
439 TRUE
, // Handles are inherited.
440 0, NULL
, NULL
, &start_info
, &proc_info
)) {
441 NOTREACHED() << "Failed to start process";
445 // We don't need the thread handle, close it now.
446 CloseHandle(proc_info
.hThread
);
448 // Close our writing end of pipe now. Otherwise later read would not be able
449 // to detect end of child's output.
450 scoped_out_write
.Close();
452 // Read output from the child process's pipe for STDOUT
453 const int kBufferSize
= 1024;
454 char buffer
[kBufferSize
];
457 DWORD bytes_read
= 0;
458 BOOL success
= ReadFile(out_read
, buffer
, kBufferSize
, &bytes_read
, NULL
);
459 if (!success
|| bytes_read
== 0)
461 output
->append(buffer
, bytes_read
);
464 // Let's wait for the process to finish.
465 WaitForSingleObject(proc_info
.hProcess
, INFINITE
);
466 CloseHandle(proc_info
.hProcess
);
471 bool KillProcess(ProcessHandle process
, int exit_code
, bool wait
) {
472 bool result
= (TerminateProcess(process
, exit_code
) != FALSE
);
473 if (result
&& wait
) {
474 // The process may not end immediately due to pending I/O
475 if (WAIT_OBJECT_0
!= WaitForSingleObject(process
, 60 * 1000))
476 DLOG(ERROR
) << "Error waiting for process exit: " << GetLastError();
477 } else if (!result
) {
478 DLOG(ERROR
) << "Unable to terminate process: " << GetLastError();
483 TerminationStatus
GetTerminationStatus(ProcessHandle handle
, int* exit_code
) {
484 DWORD tmp_exit_code
= 0;
486 if (!::GetExitCodeProcess(handle
, &tmp_exit_code
)) {
489 // This really is a random number. We haven't received any
490 // information about the exit code, presumably because this
491 // process doesn't have permission to get the exit code, or
492 // because of some other cause for GetExitCodeProcess to fail
493 // (MSDN docs don't give the possible failure error codes for
494 // this function, so it could be anything). But we don't want
495 // to leave exit_code uninitialized, since that could cause
496 // random interpretations of the exit code. So we assume it
497 // terminated "normally" in this case.
498 *exit_code
= kNormalTerminationExitCode
;
500 // Assume the child has exited normally if we can't get the exit
502 return TERMINATION_STATUS_NORMAL_TERMINATION
;
504 if (tmp_exit_code
== STILL_ACTIVE
) {
505 DWORD wait_result
= WaitForSingleObject(handle
, 0);
506 if (wait_result
== WAIT_TIMEOUT
) {
508 *exit_code
= wait_result
;
509 return TERMINATION_STATUS_STILL_RUNNING
;
512 DCHECK_EQ(WAIT_OBJECT_0
, wait_result
);
514 // Strange, the process used 0x103 (STILL_ACTIVE) as exit code.
517 return TERMINATION_STATUS_ABNORMAL_TERMINATION
;
521 *exit_code
= tmp_exit_code
;
523 switch (tmp_exit_code
) {
524 case kNormalTerminationExitCode
:
525 return TERMINATION_STATUS_NORMAL_TERMINATION
;
526 case kDebuggerInactiveExitCode
: // STATUS_DEBUGGER_INACTIVE.
527 case kKeyboardInterruptExitCode
: // Control-C/end session.
528 case kDebuggerTerminatedExitCode
: // Debugger terminated process.
529 case kProcessKilledExitCode
: // Task manager kill.
530 return TERMINATION_STATUS_PROCESS_WAS_KILLED
;
532 // All other exit codes indicate crashes.
533 return TERMINATION_STATUS_PROCESS_CRASHED
;
537 bool WaitForExitCode(ProcessHandle handle
, int* exit_code
) {
538 bool success
= WaitForExitCodeWithTimeout(handle
, exit_code
, INFINITE
);
539 CloseProcessHandle(handle
);
543 bool WaitForExitCodeWithTimeout(ProcessHandle handle
, int* exit_code
,
544 int64 timeout_milliseconds
) {
545 if (::WaitForSingleObject(handle
, timeout_milliseconds
) != WAIT_OBJECT_0
)
547 DWORD temp_code
; // Don't clobber out-parameters in case of failure.
548 if (!::GetExitCodeProcess(handle
, &temp_code
))
551 *exit_code
= temp_code
;
555 ProcessIterator::ProcessIterator(const ProcessFilter
* filter
)
556 : started_iteration_(false),
558 snapshot_
= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS
, 0);
561 ProcessIterator::~ProcessIterator() {
562 CloseHandle(snapshot_
);
565 bool ProcessIterator::CheckForNextProcess() {
566 InitProcessEntry(&entry_
);
568 if (!started_iteration_
) {
569 started_iteration_
= true;
570 return !!Process32First(snapshot_
, &entry_
);
573 return !!Process32Next(snapshot_
, &entry_
);
576 void ProcessIterator::InitProcessEntry(ProcessEntry
* entry
) {
577 memset(entry
, 0, sizeof(*entry
));
578 entry
->dwSize
= sizeof(*entry
);
581 bool NamedProcessIterator::IncludeEntry() {
583 return _wcsicmp(executable_name_
.c_str(), entry().exe_file()) == 0 &&
584 ProcessIterator::IncludeEntry();
587 bool WaitForProcessesToExit(const std::wstring
& executable_name
,
588 int64 wait_milliseconds
,
589 const ProcessFilter
* filter
) {
590 const ProcessEntry
* entry
;
592 DWORD start_time
= GetTickCount();
594 NamedProcessIterator
iter(executable_name
, filter
);
595 while (entry
= iter
.NextProcessEntry()) {
596 DWORD remaining_wait
=
597 std::max
<int64
>(0, wait_milliseconds
- (GetTickCount() - start_time
));
598 HANDLE process
= OpenProcess(SYNCHRONIZE
,
600 entry
->th32ProcessID
);
601 DWORD wait_result
= WaitForSingleObject(process
, remaining_wait
);
602 CloseHandle(process
);
603 result
= result
&& (wait_result
== WAIT_OBJECT_0
);
609 bool WaitForSingleProcess(ProcessHandle handle
, int64 wait_milliseconds
) {
610 bool retval
= WaitForSingleObject(handle
, wait_milliseconds
) == WAIT_OBJECT_0
;
614 bool CleanupProcesses(const std::wstring
& executable_name
,
615 int64 wait_milliseconds
,
617 const ProcessFilter
* filter
) {
618 bool exited_cleanly
= WaitForProcessesToExit(executable_name
,
622 KillProcesses(executable_name
, exit_code
, filter
);
623 return exited_cleanly
;
626 void EnsureProcessTerminated(ProcessHandle process
) {
627 DCHECK(process
!= GetCurrentProcess());
629 // If already signaled, then we are done!
630 if (WaitForSingleObject(process
, 0) == WAIT_OBJECT_0
) {
631 CloseHandle(process
);
635 MessageLoop::current()->PostDelayedTask(
637 base::Bind(&TimerExpiredTask::TimedOut
,
638 base::Owned(new TimerExpiredTask(process
))),
642 ///////////////////////////////////////////////////////////////////////////////
645 ProcessMetrics::ProcessMetrics(ProcessHandle process
)
647 processor_count_(base::SysInfo::NumberOfProcessors()),
649 last_system_time_(0) {
653 ProcessMetrics
* ProcessMetrics::CreateProcessMetrics(ProcessHandle process
) {
654 return new ProcessMetrics(process
);
657 ProcessMetrics::~ProcessMetrics() { }
659 size_t ProcessMetrics::GetPagefileUsage() const {
660 PROCESS_MEMORY_COUNTERS pmc
;
661 if (GetProcessMemoryInfo(process_
, &pmc
, sizeof(pmc
))) {
662 return pmc
.PagefileUsage
;
667 // Returns the peak space allocated for the pagefile, in bytes.
668 size_t ProcessMetrics::GetPeakPagefileUsage() const {
669 PROCESS_MEMORY_COUNTERS pmc
;
670 if (GetProcessMemoryInfo(process_
, &pmc
, sizeof(pmc
))) {
671 return pmc
.PeakPagefileUsage
;
676 // Returns the current working set size, in bytes.
677 size_t ProcessMetrics::GetWorkingSetSize() const {
678 PROCESS_MEMORY_COUNTERS pmc
;
679 if (GetProcessMemoryInfo(process_
, &pmc
, sizeof(pmc
))) {
680 return pmc
.WorkingSetSize
;
685 // Returns the peak working set size, in bytes.
686 size_t ProcessMetrics::GetPeakWorkingSetSize() const {
687 PROCESS_MEMORY_COUNTERS pmc
;
688 if (GetProcessMemoryInfo(process_
, &pmc
, sizeof(pmc
))) {
689 return pmc
.PeakWorkingSetSize
;
694 bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes
,
695 size_t* shared_bytes
) {
696 // PROCESS_MEMORY_COUNTERS_EX is not supported until XP SP2.
697 // GetProcessMemoryInfo() will simply fail on prior OS. So the requested
698 // information is simply not available. Hence, we will return 0 on unsupported
699 // OSes. Unlike most Win32 API, we don't need to initialize the "cb" member.
700 PROCESS_MEMORY_COUNTERS_EX pmcx
;
702 GetProcessMemoryInfo(process_
,
703 reinterpret_cast<PROCESS_MEMORY_COUNTERS
*>(&pmcx
),
705 *private_bytes
= pmcx
.PrivateUsage
;
709 WorkingSetKBytes ws_usage
;
710 if (!GetWorkingSetKBytes(&ws_usage
))
713 *shared_bytes
= ws_usage
.shared
* 1024;
719 void ProcessMetrics::GetCommittedKBytes(CommittedKBytes
* usage
) const {
720 MEMORY_BASIC_INFORMATION mbi
= {0};
721 size_t committed_private
= 0;
722 size_t committed_mapped
= 0;
723 size_t committed_image
= 0;
724 void* base_address
= NULL
;
725 while (VirtualQueryEx(process_
, base_address
, &mbi
, sizeof(mbi
)) ==
727 if (mbi
.State
== MEM_COMMIT
) {
728 if (mbi
.Type
== MEM_PRIVATE
) {
729 committed_private
+= mbi
.RegionSize
;
730 } else if (mbi
.Type
== MEM_MAPPED
) {
731 committed_mapped
+= mbi
.RegionSize
;
732 } else if (mbi
.Type
== MEM_IMAGE
) {
733 committed_image
+= mbi
.RegionSize
;
738 void* new_base
= (static_cast<BYTE
*>(mbi
.BaseAddress
)) + mbi
.RegionSize
;
739 // Avoid infinite loop by weird MEMORY_BASIC_INFORMATION.
740 // If we query 64bit processes in a 32bit process, VirtualQueryEx()
741 // returns such data.
742 if (new_base
<= base_address
) {
748 base_address
= new_base
;
750 usage
->image
= committed_image
/ 1024;
751 usage
->mapped
= committed_mapped
/ 1024;
752 usage
->priv
= committed_private
/ 1024;
755 bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes
* ws_usage
) const {
756 size_t ws_private
= 0;
757 size_t ws_shareable
= 0;
758 size_t ws_shared
= 0;
761 memset(ws_usage
, 0, sizeof(*ws_usage
));
763 DWORD number_of_entries
= 4096; // Just a guess.
764 PSAPI_WORKING_SET_INFORMATION
* buffer
= NULL
;
767 DWORD buffer_size
= sizeof(PSAPI_WORKING_SET_INFORMATION
) +
768 (number_of_entries
* sizeof(PSAPI_WORKING_SET_BLOCK
));
770 // if we can't expand the buffer, don't leak the previous
771 // contents or pass a NULL pointer to QueryWorkingSet
772 PSAPI_WORKING_SET_INFORMATION
* new_buffer
=
773 reinterpret_cast<PSAPI_WORKING_SET_INFORMATION
*>(
774 realloc(buffer
, buffer_size
));
781 // Call the function once to get number of items
782 if (QueryWorkingSet(process_
, buffer
, buffer_size
))
785 if (GetLastError() != ERROR_BAD_LENGTH
) {
790 number_of_entries
= static_cast<DWORD
>(buffer
->NumberOfEntries
);
792 // Maybe some entries are being added right now. Increase the buffer to
793 // take that into account.
794 number_of_entries
= static_cast<DWORD
>(number_of_entries
* 1.25);
796 if (--retries
== 0) {
797 free(buffer
); // If we're looping, eventually fail.
802 // On windows 2000 the function returns 1 even when the buffer is too small.
803 // The number of entries that we are going to parse is the minimum between the
804 // size we allocated and the real number of entries.
806 std::min(number_of_entries
, static_cast<DWORD
>(buffer
->NumberOfEntries
));
807 for (unsigned int i
= 0; i
< number_of_entries
; i
++) {
808 if (buffer
->WorkingSetInfo
[i
].Shared
) {
810 if (buffer
->WorkingSetInfo
[i
].ShareCount
> 1)
817 ws_usage
->priv
= ws_private
* PAGESIZE_KB
;
818 ws_usage
->shareable
= ws_shareable
* PAGESIZE_KB
;
819 ws_usage
->shared
= ws_shared
* PAGESIZE_KB
;
824 static uint64
FileTimeToUTC(const FILETIME
& ftime
) {
826 li
.LowPart
= ftime
.dwLowDateTime
;
827 li
.HighPart
= ftime
.dwHighDateTime
;
831 double ProcessMetrics::GetCPUUsage() {
833 FILETIME creation_time
;
835 FILETIME kernel_time
;
838 GetSystemTimeAsFileTime(&now
);
840 if (!GetProcessTimes(process_
, &creation_time
, &exit_time
,
841 &kernel_time
, &user_time
)) {
842 // We don't assert here because in some cases (such as in the Task Manager)
843 // we may call this function on a process that has just exited but we have
844 // not yet received the notification.
847 int64 system_time
= (FileTimeToUTC(kernel_time
) + FileTimeToUTC(user_time
)) /
849 int64 time
= FileTimeToUTC(now
);
851 if ((last_system_time_
== 0) || (last_time_
== 0)) {
852 // First call, just set the last values.
853 last_system_time_
= system_time
;
858 int64 system_time_delta
= system_time
- last_system_time_
;
859 int64 time_delta
= time
- last_time_
;
860 DCHECK_NE(0U, time_delta
);
864 // We add time_delta / 2 so the result is rounded.
865 int cpu
= static_cast<int>((system_time_delta
* 100 + time_delta
/ 2) /
868 last_system_time_
= system_time
;
874 bool ProcessMetrics::GetIOCounters(IoCounters
* io_counters
) const {
875 return GetProcessIoCounters(process_
, io_counters
) != FALSE
;
878 bool ProcessMetrics::CalculateFreeMemory(FreeMBytes
* free
) const {
879 const SIZE_T kTopAddress
= 0x7F000000;
880 const SIZE_T kMegabyte
= 1024 * 1024;
881 SIZE_T accumulated
= 0;
883 MEMORY_BASIC_INFORMATION largest
= {0};
885 while (scan
< kTopAddress
) {
886 MEMORY_BASIC_INFORMATION info
;
887 if (!::VirtualQueryEx(process_
, reinterpret_cast<void*>(scan
),
888 &info
, sizeof(info
)))
890 if (info
.State
== MEM_FREE
) {
891 accumulated
+= info
.RegionSize
;
892 UINT_PTR end
= scan
+ info
.RegionSize
;
893 if (info
.RegionSize
> largest
.RegionSize
)
896 scan
+= info
.RegionSize
;
898 free
->largest
= largest
.RegionSize
/ kMegabyte
;
899 free
->largest_ptr
= largest
.BaseAddress
;
900 free
->total
= accumulated
/ kMegabyte
;
904 bool EnableLowFragmentationHeap() {
905 HMODULE kernel32
= GetModuleHandle(L
"kernel32.dll");
906 HeapSetFn heap_set
= reinterpret_cast<HeapSetFn
>(GetProcAddress(
908 "HeapSetInformation"));
910 // On Windows 2000, the function is not exported. This is not a reason to
915 unsigned number_heaps
= GetProcessHeaps(0, NULL
);
919 // Gives us some extra space in the array in case a thread is creating heaps
920 // at the same time we're querying them.
921 static const int MARGIN
= 8;
922 scoped_array
<HANDLE
> heaps(new HANDLE
[number_heaps
+ MARGIN
]);
923 number_heaps
= GetProcessHeaps(number_heaps
+ MARGIN
, heaps
.get());
927 for (unsigned i
= 0; i
< number_heaps
; ++i
) {
929 // Don't bother with the result code. It may fails on heaps that have the
930 // HEAP_NO_SERIALIZE flag. This is expected and not a problem at all.
932 HeapCompatibilityInformation
,
939 void EnableTerminationOnHeapCorruption() {
940 // Ignore the result code. Supported on XP SP3 and Vista.
941 HeapSetInformation(NULL
, HeapEnableTerminationOnCorruption
, NULL
, 0);
944 void EnableTerminationOnOutOfMemory() {
945 std::set_new_handler(&OnNoMemory
);
948 bool EnableInProcessStackDumping() {
949 // Add stack dumping support on exception on windows. Similar to OS_POSIX
950 // signal() handling in process_util_posix.cc.
951 g_previous_filter
= SetUnhandledExceptionFilter(&StackDumpExceptionFilter
);
956 void RaiseProcessToHighPriority() {
957 SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS
);
960 // GetPerformanceInfo is not available on WIN2K. So we'll
961 // load it on-the-fly.
962 const wchar_t kPsapiDllName
[] = L
"psapi.dll";
963 typedef BOOL (WINAPI
*GetPerformanceInfoFunction
) (
964 PPERFORMANCE_INFORMATION pPerformanceInformation
,
967 // Beware of races if called concurrently from multiple threads.
968 static BOOL
InternalGetPerformanceInfo(
969 PPERFORMANCE_INFORMATION pPerformanceInformation
, DWORD cb
) {
970 static GetPerformanceInfoFunction GetPerformanceInfo_func
= NULL
;
971 if (!GetPerformanceInfo_func
) {
972 HMODULE psapi_dll
= ::GetModuleHandle(kPsapiDllName
);
974 GetPerformanceInfo_func
= reinterpret_cast<GetPerformanceInfoFunction
>(
975 GetProcAddress(psapi_dll
, "GetPerformanceInfo"));
977 if (!GetPerformanceInfo_func
) {
978 // The function could be loaded!
979 memset(pPerformanceInformation
, 0, cb
);
983 return GetPerformanceInfo_func(pPerformanceInformation
, cb
);
986 size_t GetSystemCommitCharge() {
987 // Get the System Page Size.
988 SYSTEM_INFO system_info
;
989 GetSystemInfo(&system_info
);
991 PERFORMANCE_INFORMATION info
;
992 if (!InternalGetPerformanceInfo(&info
, sizeof(info
))) {
993 DLOG(ERROR
) << "Failed to fetch internal performance info.";
996 return (info
.CommitTotal
* system_info
.dwPageSize
) / 1024;