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/process.h"
7 #include "base/logging.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/numerics/safe_conversions.h"
10 #include "base/process/kill.h"
11 #include "base/win/windows_version.h"
15 DWORD kBasicProcessAccess
=
16 PROCESS_TERMINATE
| PROCESS_QUERY_INFORMATION
| SYNCHRONIZE
;
22 Process::Process(ProcessHandle handle
)
23 : is_current_process_(false),
25 CHECK_NE(handle
, ::GetCurrentProcess());
28 Process::Process(RValue other
)
29 : is_current_process_(other
.object
->is_current_process_
),
30 process_(other
.object
->process_
.Take()) {
31 other
.object
->Close();
37 Process
& Process::operator=(RValue other
) {
38 if (this != other
.object
) {
39 process_
.Set(other
.object
->process_
.Take());
40 is_current_process_
= other
.object
->is_current_process_
;
41 other
.object
->Close();
47 Process
Process::Current() {
49 process
.is_current_process_
= true;
50 return process
.Pass();
54 Process
Process::Open(ProcessId pid
) {
55 return Process(::OpenProcess(kBasicProcessAccess
, FALSE
, pid
));
59 Process
Process::OpenWithExtraPrivileges(ProcessId pid
) {
60 DWORD access
= kBasicProcessAccess
| PROCESS_DUP_HANDLE
| PROCESS_VM_READ
;
61 return Process(::OpenProcess(access
, FALSE
, pid
));
65 Process
Process::OpenWithAccess(ProcessId pid
, DWORD desired_access
) {
66 return Process(::OpenProcess(desired_access
, FALSE
, pid
));
70 Process
Process::DeprecatedGetProcessFromHandle(ProcessHandle handle
) {
71 DCHECK_NE(handle
, ::GetCurrentProcess());
72 ProcessHandle out_handle
;
73 if (!::DuplicateHandle(GetCurrentProcess(), handle
,
74 GetCurrentProcess(), &out_handle
,
75 0, FALSE
, DUPLICATE_SAME_ACCESS
)) {
78 return Process(out_handle
);
82 bool Process::CanBackgroundProcesses() {
86 bool Process::IsValid() const {
87 return process_
.IsValid() || is_current();
90 ProcessHandle
Process::Handle() const {
91 return is_current_process_
? GetCurrentProcess() : process_
.Get();
94 Process
Process::Duplicate() const {
98 ProcessHandle out_handle
;
99 if (!IsValid() || !::DuplicateHandle(GetCurrentProcess(),
105 DUPLICATE_SAME_ACCESS
)) {
108 return Process(out_handle
);
111 ProcessId
Process::Pid() const {
113 return GetProcId(Handle());
116 bool Process::is_current() const {
117 return is_current_process_
;
120 void Process::Close() {
121 is_current_process_
= false;
122 if (!process_
.IsValid())
128 bool Process::Terminate(int exit_code
, bool wait
) const {
130 bool result
= (::TerminateProcess(Handle(), exit_code
) != FALSE
);
131 if (result
&& wait
) {
132 // The process may not end immediately due to pending I/O
133 if (::WaitForSingleObject(Handle(), 60 * 1000) != WAIT_OBJECT_0
)
134 DPLOG(ERROR
) << "Error waiting for process exit";
135 } else if (!result
) {
136 DPLOG(ERROR
) << "Unable to terminate process";
141 bool Process::WaitForExit(int* exit_code
) {
142 return WaitForExitWithTimeout(TimeDelta::FromMilliseconds(INFINITE
),
146 bool Process::WaitForExitWithTimeout(TimeDelta timeout
, int* exit_code
) {
147 // Limit timeout to INFINITE.
148 DWORD timeout_ms
= saturated_cast
<DWORD
>(timeout
.InMilliseconds());
149 if (::WaitForSingleObject(Handle(), timeout_ms
) != WAIT_OBJECT_0
)
152 DWORD temp_code
; // Don't clobber out-parameters in case of failure.
153 if (!::GetExitCodeProcess(Handle(), &temp_code
))
157 *exit_code
= temp_code
;
161 bool Process::IsProcessBackgrounded() const {
163 DWORD priority
= GetPriority();
165 return false; // Failure case.
166 return ((priority
== BELOW_NORMAL_PRIORITY_CLASS
) ||
167 (priority
== IDLE_PRIORITY_CLASS
));
170 bool Process::SetProcessBackgrounded(bool value
) {
172 // Vista and above introduce a real background mode, which not only
173 // sets the priority class on the threads but also on the IO generated
174 // by it. Unfortunately it can only be set for the calling process.
176 if ((base::win::GetVersion() >= base::win::VERSION_VISTA
) && (is_current())) {
177 priority
= value
? PROCESS_MODE_BACKGROUND_BEGIN
:
178 PROCESS_MODE_BACKGROUND_END
;
180 priority
= value
? IDLE_PRIORITY_CLASS
: NORMAL_PRIORITY_CLASS
;
183 return (::SetPriorityClass(Handle(), priority
) != 0);
186 int Process::GetPriority() const {
188 return ::GetPriorityClass(Handle());