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/metrics/field_trial.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();
34 Process
& Process::operator=(RValue other
) {
35 if (this != other
.object
) {
36 process_
.Set(other
.object
->process_
.Take());
37 is_current_process_
= other
.object
->is_current_process_
;
38 other
.object
->Close();
44 Process
Process::Current() {
46 process
.is_current_process_
= true;
47 return process
.Pass();
51 Process
Process::Open(ProcessId pid
) {
52 return Process(::OpenProcess(kBasicProcessAccess
, FALSE
, pid
));
56 Process
Process::OpenWithExtraPriviles(ProcessId pid
) {
57 DWORD access
= kBasicProcessAccess
| PROCESS_DUP_HANDLE
| PROCESS_VM_READ
;
58 return Process(::OpenProcess(access
, FALSE
, pid
));
62 Process
Process::OpenWithAccess(ProcessId pid
, DWORD desired_access
) {
63 return Process(::OpenProcess(desired_access
, FALSE
, pid
));
67 Process
Process::DeprecatedGetProcessFromHandle(ProcessHandle handle
) {
68 DCHECK_NE(handle
, ::GetCurrentProcess());
69 ProcessHandle out_handle
;
70 if (!::DuplicateHandle(GetCurrentProcess(), handle
,
71 GetCurrentProcess(), &out_handle
,
72 0, FALSE
, DUPLICATE_SAME_ACCESS
)) {
75 return Process(out_handle
);
79 bool Process::CanBackgroundProcesses() {
83 bool Process::IsValid() const {
84 return process_
.IsValid() || is_current();
87 ProcessHandle
Process::Handle() const {
88 return is_current_process_
? GetCurrentProcess() : process_
.Get();
91 Process
Process::Duplicate() const {
95 ProcessHandle out_handle
;
96 if (!IsValid() || !::DuplicateHandle(GetCurrentProcess(),
102 DUPLICATE_SAME_ACCESS
)) {
105 return Process(out_handle
);
108 ProcessId
Process::Pid() const {
110 return GetProcId(Handle());
113 bool Process::is_current() const {
114 return is_current_process_
;
117 void Process::Close() {
118 is_current_process_
= false;
119 if (!process_
.IsValid())
125 void Process::Terminate(int result_code
) {
128 // Call NtTerminateProcess directly, without going through the import table,
129 // which might have been hooked with a buggy replacement by third party
130 // software. http://crbug.com/81449.
131 HMODULE module
= GetModuleHandle(L
"ntdll.dll");
132 typedef UINT (WINAPI
*TerminateProcessPtr
)(HANDLE handle
, UINT code
);
133 TerminateProcessPtr terminate_process
= reinterpret_cast<TerminateProcessPtr
>(
134 GetProcAddress(module
, "NtTerminateProcess"));
135 terminate_process(Handle(), result_code
);
138 bool Process::WaitForExit(int* exit_code
) {
139 return WaitForExitWithTimeout(TimeDelta::FromMilliseconds(INFINITE
),
143 bool Process::WaitForExitWithTimeout(TimeDelta timeout
, int* exit_code
) {
144 // TODO(rvargas) crbug.com/417532: Move the implementation here.
145 if (timeout
> TimeDelta::FromMilliseconds(INFINITE
))
146 timeout
= TimeDelta::FromMilliseconds(INFINITE
);
147 return base::WaitForExitCodeWithTimeout(Handle(), exit_code
, timeout
);
150 bool Process::IsProcessBackgrounded() const {
152 DWORD priority
= GetPriority();
154 return false; // Failure case.
155 return ((priority
== BELOW_NORMAL_PRIORITY_CLASS
) ||
156 (priority
== IDLE_PRIORITY_CLASS
));
159 bool Process::SetProcessBackgrounded(bool value
) {
161 // Vista and above introduce a real background mode, which not only
162 // sets the priority class on the threads but also on the IO generated
163 // by it. Unfortunately it can only be set for the calling process.
165 if ((base::win::GetVersion() >= base::win::VERSION_VISTA
) && (is_current())) {
166 priority
= value
? PROCESS_MODE_BACKGROUND_BEGIN
:
167 PROCESS_MODE_BACKGROUND_END
;
169 // Experiment (http://crbug.com/458594) with using IDLE_PRIORITY_CLASS as a
170 // background priority for background renderers (this code path is
171 // technically for more than just the renderers but they're the only use
172 // case in practice and experimenting here direclty is thus easier -- plus
173 // it doesn't really hurt as above we already state our intent of using
174 // PROCESS_MODE_BACKGROUND_BEGIN if available which is essentially
175 // IDLE_PRIORITY_CLASS plus lowered IO priority). Enabled by default in the
176 // asbence of field trials to get coverage on the perf waterfall.
177 DWORD background_priority
= IDLE_PRIORITY_CLASS
;
178 base::FieldTrial
* trial
=
179 base::FieldTrialList::Find("BackgroundRendererProcesses");
180 if (trial
&& trial
->group_name() == "AllowBelowNormalFromBrowser")
181 background_priority
= BELOW_NORMAL_PRIORITY_CLASS
;
183 priority
= value
? background_priority
: NORMAL_PRIORITY_CLASS
;
186 return (::SetPriorityClass(Handle(), priority
) != 0);
189 int Process::GetPriority() const {
191 return ::GetPriorityClass(Handle());