blob: cc94f53baa97a73906cedc6d24a1551971fd8146 [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
Sebastien Marchandbd02bc29e2020-03-11 15:53:367#include "base/clang_profiling_buildflags.h"
bcwhited9705962016-08-10 03:10:038#include "base/debug/activity_tracker.h"
initial.commitd7cae122008-07-26 21:49:389#include "base/logging.h"
rvargas85728972015-03-03 20:46:1910#include "base/numerics/safe_conversions.h"
rvargas126fd5822014-12-12 00:25:1411#include "base/process/kill.h"
Francois Doraya678fc12017-10-30 22:18:0612#include "base/threading/thread_restrictions.h"
Gabriel Charette6836c0d52021-01-11 17:40:2613#include "base/trace_event/base_tracing.h"
Anton Bikineev7dd58ad2021-05-18 01:01:3914#include "third_party/abseil-cpp/absl/types/optional.h"
initial.commitd7cae122008-07-26 21:49:3815
Bruce Dawsonbfdc3fd2018-01-03 20:32:3616#include <windows.h>
17
Sebastien Marchandbd02bc29e2020-03-11 15:53:3618#if BUILDFLAG(CLANG_PROFILING)
19#include "base/test/clang_profiling.h"
Yannic Bonenberger6801e6c2019-06-07 10:42:5320#endif
21
rvargas747ff242015-01-17 02:46:4722namespace {
23
24DWORD kBasicProcessAccess =
25 PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | SYNCHRONIZE;
26
27} // namespace
28
[email protected]176aa482008-11-14 03:25:1529namespace base {
30
rvargas079d1842014-10-17 22:32:1631Process::Process(ProcessHandle handle)
scottmg297cc932017-05-24 03:45:5832 : process_(handle), is_current_process_(false) {
rvargas079d1842014-10-17 22:32:1633 CHECK_NE(handle, ::GetCurrentProcess());
34}
35
dchenge1b0277c2015-12-01 12:09:5236Process::Process(Process&& other)
scottmg297cc932017-05-24 03:45:5837 : process_(other.process_.Take()),
38 is_current_process_(other.is_current_process_) {
dchenge1b0277c2015-12-01 12:09:5239 other.Close();
rvargas079d1842014-10-17 22:32:1640}
41
thakis3096dac2015-04-20 16:44:4842Process::~Process() {
43}
44
dchenge1b0277c2015-12-01 12:09:5245Process& Process::operator=(Process&& other) {
46 DCHECK_NE(this, &other);
47 process_.Set(other.process_.Take());
48 is_current_process_ = other.is_current_process_;
49 other.Close();
rvargas079d1842014-10-17 22:32:1650 return *this;
51}
52
53// static
54Process Process::Current() {
55 Process process;
56 process.is_current_process_ = true;
dcheng70c49422016-03-02 23:20:3457 return process;
rvargas079d1842014-10-17 22:32:1658}
59
60// static
rvargas6b039c372015-02-04 21:11:2961Process Process::Open(ProcessId pid) {
62 return Process(::OpenProcess(kBasicProcessAccess, FALSE, pid));
63}
64
65// static
rvargas1c376a82015-03-16 23:03:5266Process Process::OpenWithExtraPrivileges(ProcessId pid) {
rvargas747ff242015-01-17 02:46:4767 DWORD access = kBasicProcessAccess | PROCESS_DUP_HANDLE | PROCESS_VM_READ;
rvargas6b039c372015-02-04 21:11:2968 return Process(::OpenProcess(access, FALSE, pid));
rvargas747ff242015-01-17 02:46:4769}
70
71// static
rvargas17a407d2015-01-23 20:36:4472Process Process::OpenWithAccess(ProcessId pid, DWORD desired_access) {
73 return Process(::OpenProcess(desired_access, FALSE, pid));
74}
75
76// static
rvargas079d1842014-10-17 22:32:1677bool Process::CanBackgroundProcesses() {
78 return true;
79}
80
haraken940efb92017-02-08 05:58:1581// static
82void Process::TerminateCurrentProcessImmediately(int exit_code) {
Sebastien Marchandbd02bc29e2020-03-11 15:53:3683#if BUILDFLAG(CLANG_PROFILING)
84 WriteClangProfilingProfile();
Wezd2031d302018-08-16 23:34:2585#endif
haraken940efb92017-02-08 05:58:1586 ::TerminateProcess(GetCurrentProcess(), exit_code);
Bruce Dawson33ce2ff2017-11-28 20:47:5187 // There is some ambiguity over whether the call above can return. Rather than
88 // hitting confusing crashes later on we should crash right here.
Wez5f117412018-02-07 04:17:4789 IMMEDIATE_CRASH();
haraken940efb92017-02-08 05:58:1590}
91
rvargas079d1842014-10-17 22:32:1692bool Process::IsValid() const {
93 return process_.IsValid() || is_current();
94}
95
96ProcessHandle Process::Handle() const {
97 return is_current_process_ ? GetCurrentProcess() : process_.Get();
98}
99
100Process Process::Duplicate() const {
101 if (is_current())
102 return Current();
103
104 ProcessHandle out_handle;
105 if (!IsValid() || !::DuplicateHandle(GetCurrentProcess(),
106 Handle(),
107 GetCurrentProcess(),
108 &out_handle,
109 0,
110 FALSE,
111 DUPLICATE_SAME_ACCESS)) {
112 return Process();
113 }
114 return Process(out_handle);
115}
116
Robert Sesek0e7f165a2020-11-20 21:31:45117ProcessHandle Process::Release() {
118 if (is_current())
119 return ::GetCurrentProcess();
120 return process_.Take();
121}
122
rvargas960db882015-01-24 00:27:25123ProcessId Process::Pid() const {
rvargas079d1842014-10-17 22:32:16124 DCHECK(IsValid());
125 return GetProcId(Handle());
126}
127
Francois Doray7d1315342018-10-21 03:54:47128Time Process::CreationTime() const {
129 FILETIME creation_time = {};
130 FILETIME ignore1 = {};
131 FILETIME ignore2 = {};
132 FILETIME ignore3 = {};
133 if (!::GetProcessTimes(Handle(), &creation_time, &ignore1, &ignore2,
134 &ignore3)) {
135 return Time();
136 }
137 return Time::FromFileTime(creation_time);
138}
139
rvargas079d1842014-10-17 22:32:16140bool Process::is_current() const {
141 return is_current_process_;
142}
143
[email protected]176aa482008-11-14 03:25:15144void Process::Close() {
rvargas079d1842014-10-17 22:32:16145 is_current_process_ = false;
146 if (!process_.IsValid())
[email protected]176aa482008-11-14 03:25:15147 return;
[email protected]b987e90e2011-08-15 19:22:44148
rvargas079d1842014-10-17 22:32:16149 process_.Close();
[email protected]176aa482008-11-14 03:25:15150}
151
rvargas02ad7832015-04-02 01:36:06152bool Process::Terminate(int exit_code, bool wait) const {
Brian White6c8f3b9c2017-12-01 18:55:31153 constexpr DWORD kWaitMs = 60 * 1000;
154
rvargaseedb763e2015-03-09 23:53:45155 DCHECK(IsValid());
rvargas02ad7832015-04-02 01:36:06156 bool result = (::TerminateProcess(Handle(), exit_code) != FALSE);
Brian Whiteae2a8b9a2017-11-02 19:10:36157 if (result) {
rvargas02ad7832015-04-02 01:36:06158 // The process may not end immediately due to pending I/O
Brian White6c8f3b9c2017-12-01 18:55:31159 if (wait && ::WaitForSingleObject(Handle(), kWaitMs) != WAIT_OBJECT_0)
rvargas02ad7832015-04-02 01:36:06160 DPLOG(ERROR) << "Error waiting for process exit";
Brian Whiteae2a8b9a2017-11-02 19:10:36161 Exited(exit_code);
Brian Whiteccb2c6e2017-11-14 19:09:44162 } else {
Bruce Dawsond9111de2019-06-18 23:29:38163 // The process can't be terminated, perhaps because it has already exited or
164 // is in the process of exiting. An error code of ERROR_ACCESS_DENIED is the
165 // undocumented-but-expected result if the process has already exited or
166 // started exiting when TerminateProcess is called, so don't print an error
167 // message in that case.
168 if (GetLastError() != ERROR_ACCESS_DENIED)
169 DPLOG(ERROR) << "Unable to terminate process";
170 // A non-zero timeout is necessary here for the same reasons as above.
Brian White6c8f3b9c2017-12-01 18:55:31171 if (::WaitForSingleObject(Handle(), kWaitMs) == WAIT_OBJECT_0) {
Brian Whiteccb2c6e2017-11-14 19:09:44172 DWORD actual_exit;
173 Exited(::GetExitCodeProcess(Handle(), &actual_exit) ? actual_exit
174 : exit_code);
175 result = true;
176 }
rvargas02ad7832015-04-02 01:36:06177 }
178 return result;
[email protected]176aa482008-11-14 03:25:15179}
180
Mike Rorkef36971b2020-03-06 17:56:29181Process::WaitExitStatus Process::WaitForExitOrEvent(
182 const base::win::ScopedHandle& stop_event_handle,
183 int* exit_code) const {
184 // Record the event that this thread is blocking upon (for hang diagnosis).
185 base::debug::ScopedProcessWaitActivity process_activity(this);
186
187 HANDLE events[] = {Handle(), stop_event_handle.Get()};
188 DWORD wait_result =
189 ::WaitForMultipleObjects(base::size(events), events, FALSE, INFINITE);
190
191 if (wait_result == WAIT_OBJECT_0) {
192 DWORD temp_code; // Don't clobber out-parameters in case of failure.
193 if (!::GetExitCodeProcess(Handle(), &temp_code))
194 return Process::WaitExitStatus::FAILED;
195
196 if (exit_code)
197 *exit_code = temp_code;
198
199 Exited(temp_code);
200 return Process::WaitExitStatus::PROCESS_EXITED;
201 }
202
203 if (wait_result == WAIT_OBJECT_0 + 1) {
204 return Process::WaitExitStatus::STOP_EVENT_SIGNALED;
205 }
206
207 return Process::WaitExitStatus::FAILED;
208}
209
jcivellif4462a352017-01-10 04:45:59210bool Process::WaitForExit(int* exit_code) const {
Bruce Dawsond3e5d6e2021-07-16 21:17:26211 return WaitForExitWithTimeout(TimeDelta::Max(), exit_code);
rvargas126fd5822014-12-12 00:25:14212}
213
jcivellif4462a352017-01-10 04:45:59214bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) const {
Gabriel Charette6836c0d52021-01-11 17:40:26215 TRACE_EVENT0("base", "Process::WaitForExitWithTimeout");
Francois Doraya678fc12017-10-30 22:18:06216
bcwhited9705962016-08-10 03:10:03217 // Record the event that this thread is blocking upon (for hang diagnosis).
Anton Bikineev7dd58ad2021-05-18 01:01:39218 absl::optional<debug::ScopedProcessWaitActivity> process_activity;
Gabriel Charette6836c0d52021-01-11 17:40:26219 if (!timeout.is_zero()) {
220 process_activity.emplace(this);
221 // Assert that this thread is allowed to wait below. This intentionally
222 // doesn't use ScopedBlockingCallWithBaseSyncPrimitives because the process
223 // being waited upon tends to itself be using the CPU and considering this
224 // thread non-busy causes more issue than it fixes: http://crbug.com/905788
225 internal::AssertBaseSyncPrimitivesAllowed();
226 }
bcwhited9705962016-08-10 03:10:03227
rvargas85728972015-03-03 20:46:19228 // Limit timeout to INFINITE.
229 DWORD timeout_ms = saturated_cast<DWORD>(timeout.InMilliseconds());
230 if (::WaitForSingleObject(Handle(), timeout_ms) != WAIT_OBJECT_0)
231 return false;
232
233 DWORD temp_code; // Don't clobber out-parameters in case of failure.
234 if (!::GetExitCodeProcess(Handle(), &temp_code))
235 return false;
236
g.mehndirattfd19e232015-05-29 08:17:14237 if (exit_code)
238 *exit_code = temp_code;
bcwhite815054b52017-03-16 18:41:12239
Brian Whiteae2a8b9a2017-11-02 19:10:36240 Exited(temp_code);
rvargas85728972015-03-03 20:46:19241 return true;
rvargas126fd5822014-12-12 00:25:14242}
243
Brian Whiteae2a8b9a2017-11-02 19:10:36244void Process::Exited(int exit_code) const {
245 base::debug::GlobalActivityTracker::RecordProcessExitIfEnabled(Pid(),
246 exit_code);
247}
248
[email protected]2f15de42008-11-11 22:35:19249bool Process::IsProcessBackgrounded() const {
rvargas079d1842014-10-17 22:32:16250 DCHECK(IsValid());
[email protected]276aa6a2009-10-29 17:43:44251 DWORD priority = GetPriority();
initial.commitd7cae122008-07-26 21:49:38252 if (priority == 0)
253 return false; // Failure case.
[email protected]568bfb02011-04-28 23:51:53254 return ((priority == BELOW_NORMAL_PRIORITY_CLASS) ||
255 (priority == IDLE_PRIORITY_CLASS));
initial.commitd7cae122008-07-26 21:49:38256}
257
258bool Process::SetProcessBackgrounded(bool value) {
rvargas079d1842014-10-17 22:32:16259 DCHECK(IsValid());
[email protected]568bfb02011-04-28 23:51:53260 // Vista and above introduce a real background mode, which not only
261 // sets the priority class on the threads but also on the IO generated
262 // by it. Unfortunately it can only be set for the calling process.
263 DWORD priority;
Patrick Monetteab240ec2017-07-13 22:49:14264 if (is_current()) {
[email protected]568bfb02011-04-28 23:51:53265 priority = value ? PROCESS_MODE_BACKGROUND_BEGIN :
266 PROCESS_MODE_BACKGROUND_END;
267 } else {
gab3d473432015-07-21 17:20:20268 priority = value ? IDLE_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS;
[email protected]568bfb02011-04-28 23:51:53269 }
270
rvargas079d1842014-10-17 22:32:16271 return (::SetPriorityClass(Handle(), priority) != 0);
[email protected]8a420802011-12-02 16:14:46272}
273
[email protected]276aa6a2009-10-29 17:43:44274int Process::GetPriority() const {
rvargas079d1842014-10-17 22:32:16275 DCHECK(IsValid());
276 return ::GetPriorityClass(Handle());
[email protected]276aa6a2009-10-29 17:43:44277}
278
[email protected]176aa482008-11-14 03:25:15279} // namespace base