blob: b62fdb4f8c38f55acb1696097813065dfe735a2c [file] [log] [blame]
[email protected]3b63f8f42011-03-28 01:54:151// Copyright (c) 2011 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commitd7cae122008-07-26 21:49:384
[email protected]76bea672013-07-19 16:48:565#include "base/process/process.h"
[email protected]dd4b51262013-07-25 21:38:236
initial.commitd7cae122008-07-26 21:49:387#include "base/logging.h"
[email protected]3b63f8f42011-03-28 01:54:158#include "base/memory/scoped_ptr.h"
gabd88d22a2015-02-20 04:26:539#include "base/metrics/field_trial.h"
rvargas85728972015-03-03 20:46:1910#include "base/numerics/safe_conversions.h"
rvargas126fd5822014-12-12 00:25:1411#include "base/process/kill.h"
[email protected]568bfb02011-04-28 23:51:5312#include "base/win/windows_version.h"
initial.commitd7cae122008-07-26 21:49:3813
rvargas747ff242015-01-17 02:46:4714namespace {
15
16DWORD kBasicProcessAccess =
17 PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | SYNCHRONIZE;
18
19} // namespace
20
[email protected]176aa482008-11-14 03:25:1521namespace base {
22
rvargas079d1842014-10-17 22:32:1623Process::Process(ProcessHandle handle)
24 : is_current_process_(false),
25 process_(handle) {
26 CHECK_NE(handle, ::GetCurrentProcess());
27}
28
29Process::Process(RValue other)
30 : is_current_process_(other.object->is_current_process_),
31 process_(other.object->process_.Take()) {
32 other.object->Close();
33}
34
35Process& Process::operator=(RValue other) {
36 if (this != other.object) {
37 process_.Set(other.object->process_.Take());
38 is_current_process_ = other.object->is_current_process_;
39 other.object->Close();
40 }
41 return *this;
42}
43
44// static
45Process Process::Current() {
46 Process process;
47 process.is_current_process_ = true;
48 return process.Pass();
49}
50
51// static
rvargas6b039c372015-02-04 21:11:2952Process Process::Open(ProcessId pid) {
53 return Process(::OpenProcess(kBasicProcessAccess, FALSE, pid));
54}
55
56// static
rvargas747ff242015-01-17 02:46:4757Process Process::OpenWithExtraPriviles(ProcessId pid) {
58 DWORD access = kBasicProcessAccess | PROCESS_DUP_HANDLE | PROCESS_VM_READ;
rvargas6b039c372015-02-04 21:11:2959 return Process(::OpenProcess(access, FALSE, pid));
rvargas747ff242015-01-17 02:46:4760}
61
62// static
rvargas17a407d2015-01-23 20:36:4463Process Process::OpenWithAccess(ProcessId pid, DWORD desired_access) {
64 return Process(::OpenProcess(desired_access, FALSE, pid));
65}
66
67// static
rvargas5779b382014-11-18 20:44:1168Process Process::DeprecatedGetProcessFromHandle(ProcessHandle handle) {
69 DCHECK_NE(handle, ::GetCurrentProcess());
70 ProcessHandle out_handle;
71 if (!::DuplicateHandle(GetCurrentProcess(), handle,
72 GetCurrentProcess(), &out_handle,
73 0, FALSE, DUPLICATE_SAME_ACCESS)) {
74 return Process();
75 }
76 return Process(out_handle);
77}
78
79// static
rvargas079d1842014-10-17 22:32:1680bool Process::CanBackgroundProcesses() {
81 return true;
82}
83
84bool Process::IsValid() const {
85 return process_.IsValid() || is_current();
86}
87
88ProcessHandle Process::Handle() const {
89 return is_current_process_ ? GetCurrentProcess() : process_.Get();
90}
91
92Process Process::Duplicate() const {
93 if (is_current())
94 return Current();
95
96 ProcessHandle out_handle;
97 if (!IsValid() || !::DuplicateHandle(GetCurrentProcess(),
98 Handle(),
99 GetCurrentProcess(),
100 &out_handle,
101 0,
102 FALSE,
103 DUPLICATE_SAME_ACCESS)) {
104 return Process();
105 }
106 return Process(out_handle);
107}
108
rvargas960db882015-01-24 00:27:25109ProcessId Process::Pid() const {
rvargas079d1842014-10-17 22:32:16110 DCHECK(IsValid());
111 return GetProcId(Handle());
112}
113
114bool Process::is_current() const {
115 return is_current_process_;
116}
117
[email protected]176aa482008-11-14 03:25:15118void Process::Close() {
rvargas079d1842014-10-17 22:32:16119 is_current_process_ = false;
120 if (!process_.IsValid())
[email protected]176aa482008-11-14 03:25:15121 return;
[email protected]b987e90e2011-08-15 19:22:44122
rvargas079d1842014-10-17 22:32:16123 process_.Close();
[email protected]176aa482008-11-14 03:25:15124}
125
126void Process::Terminate(int result_code) {
rvargas079d1842014-10-17 22:32:16127 DCHECK(IsValid());
[email protected]b987e90e2011-08-15 19:22:44128
[email protected]c4ed8022011-08-19 01:36:21129 // Call NtTerminateProcess directly, without going through the import table,
130 // which might have been hooked with a buggy replacement by third party
131 // software. http://crbug.com/81449.
[email protected]b987e90e2011-08-15 19:22:44132 HMODULE module = GetModuleHandle(L"ntdll.dll");
133 typedef UINT (WINAPI *TerminateProcessPtr)(HANDLE handle, UINT code);
134 TerminateProcessPtr terminate_process = reinterpret_cast<TerminateProcessPtr>(
135 GetProcAddress(module, "NtTerminateProcess"));
rvargas079d1842014-10-17 22:32:16136 terminate_process(Handle(), result_code);
[email protected]176aa482008-11-14 03:25:15137}
138
rvargas126fd5822014-12-12 00:25:14139bool Process::WaitForExit(int* exit_code) {
140 return WaitForExitWithTimeout(TimeDelta::FromMilliseconds(INFINITE),
141 exit_code);
142}
143
144bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) {
rvargas85728972015-03-03 20:46:19145 // Limit timeout to INFINITE.
146 DWORD timeout_ms = saturated_cast<DWORD>(timeout.InMilliseconds());
147 if (::WaitForSingleObject(Handle(), timeout_ms) != WAIT_OBJECT_0)
148 return false;
149
150 DWORD temp_code; // Don't clobber out-parameters in case of failure.
151 if (!::GetExitCodeProcess(Handle(), &temp_code))
152 return false;
153
154 *exit_code = temp_code;
155 return true;
rvargas126fd5822014-12-12 00:25:14156}
157
[email protected]2f15de42008-11-11 22:35:19158bool Process::IsProcessBackgrounded() const {
rvargas079d1842014-10-17 22:32:16159 DCHECK(IsValid());
[email protected]276aa6a2009-10-29 17:43:44160 DWORD priority = GetPriority();
initial.commitd7cae122008-07-26 21:49:38161 if (priority == 0)
162 return false; // Failure case.
[email protected]568bfb02011-04-28 23:51:53163 return ((priority == BELOW_NORMAL_PRIORITY_CLASS) ||
164 (priority == IDLE_PRIORITY_CLASS));
initial.commitd7cae122008-07-26 21:49:38165}
166
167bool Process::SetProcessBackgrounded(bool value) {
rvargas079d1842014-10-17 22:32:16168 DCHECK(IsValid());
[email protected]568bfb02011-04-28 23:51:53169 // Vista and above introduce a real background mode, which not only
170 // sets the priority class on the threads but also on the IO generated
171 // by it. Unfortunately it can only be set for the calling process.
172 DWORD priority;
rvargas079d1842014-10-17 22:32:16173 if ((base::win::GetVersion() >= base::win::VERSION_VISTA) && (is_current())) {
[email protected]568bfb02011-04-28 23:51:53174 priority = value ? PROCESS_MODE_BACKGROUND_BEGIN :
175 PROCESS_MODE_BACKGROUND_END;
176 } else {
gabd88d22a2015-02-20 04:26:53177 // Experiment (http://crbug.com/458594) with using IDLE_PRIORITY_CLASS as a
178 // background priority for background renderers (this code path is
179 // technically for more than just the renderers but they're the only use
180 // case in practice and experimenting here direclty is thus easier -- plus
181 // it doesn't really hurt as above we already state our intent of using
182 // PROCESS_MODE_BACKGROUND_BEGIN if available which is essentially
183 // IDLE_PRIORITY_CLASS plus lowered IO priority). Enabled by default in the
184 // asbence of field trials to get coverage on the perf waterfall.
185 DWORD background_priority = IDLE_PRIORITY_CLASS;
186 base::FieldTrial* trial =
187 base::FieldTrialList::Find("BackgroundRendererProcesses");
188 if (trial && trial->group_name() == "AllowBelowNormalFromBrowser")
189 background_priority = BELOW_NORMAL_PRIORITY_CLASS;
190
191 priority = value ? background_priority : NORMAL_PRIORITY_CLASS;
[email protected]568bfb02011-04-28 23:51:53192 }
193
rvargas079d1842014-10-17 22:32:16194 return (::SetPriorityClass(Handle(), priority) != 0);
[email protected]8a420802011-12-02 16:14:46195}
196
[email protected]276aa6a2009-10-29 17:43:44197int Process::GetPriority() const {
rvargas079d1842014-10-17 22:32:16198 DCHECK(IsValid());
199 return ::GetPriorityClass(Handle());
[email protected]276aa6a2009-10-29 17:43:44200}
201
[email protected]176aa482008-11-14 03:25:15202} // namespace base