blob: 45fbe1214593816d7bfca59724933c62d74c1830 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2011 The Chromium Authors
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
Takuto Ikutac8d6b16f2024-04-15 16:59:197#include <windows.h>
8
Sebastien Marchandbd02bc29e2020-03-11 15:53:369#include "base/clang_profiling_buildflags.h"
initial.commitd7cae122008-07-26 21:49:3810#include "base/logging.h"
rvargas85728972015-03-03 20:46:1911#include "base/numerics/safe_conversions.h"
rvargas126fd5822014-12-12 00:25:1412#include "base/process/kill.h"
Francois Doraya678fc12017-10-30 22:18:0613#include "base/threading/thread_restrictions.h"
Etienne Pierre-dorayfc7952f02025-06-06 00:04:3314#include "base/trace_event/trace_event.h"
Chris Davis3360a372025-02-06 23:21:3015#include "base/win/win_util.h"
Zheda Chen2808be72022-12-19 06:26:5516#include "base/win/windows_version.h"
initial.commitd7cae122008-07-26 21:49:3817
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 =
Peter Kasting134ef9af2024-12-28 02:30:0925 PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | SYNCHRONIZE;
rvargas747ff242015-01-17 02:46:4726
Peter Kasting134ef9af2024-12-28 02:30:0927} // namespace
rvargas747ff242015-01-17 02:46:4728
[email protected]176aa482008-11-14 03:25:1529namespace base {
30
François Dorayeb1e65ec2025-06-13 18:56:5531// Sets Eco QoS (Quality of Service) level for background process which would
32// select efficient CPU frequency and schedule the process to efficient cores
33// (available on hybrid CPUs).
34// QoS is a scheduling Win API which indicates the desired performance and power
35// efficiency of a process/thread. EcoQoS is introduced since Windows 11.
36BASE_FEATURE(kUseEcoQoSForBackgroundProcess,
37 "UseEcoQoSForBackgroundProcess",
38 FEATURE_ENABLED_BY_DEFAULT);
39
rvargas079d1842014-10-17 22:32:1640Process::Process(ProcessHandle handle)
scottmg297cc932017-05-24 03:45:5841 : process_(handle), is_current_process_(false) {
rvargas079d1842014-10-17 22:32:1642 CHECK_NE(handle, ::GetCurrentProcess());
43}
44
dchenge1b0277c2015-12-01 12:09:5245Process::Process(Process&& other)
Lei Zhang04c0bcb2022-02-04 04:13:4546 : process_(other.process_.release()),
scottmg297cc932017-05-24 03:45:5847 is_current_process_(other.is_current_process_) {
dchenge1b0277c2015-12-01 12:09:5248 other.Close();
rvargas079d1842014-10-17 22:32:1649}
50
Sorin Jianuf841ac62024-12-19 19:39:2251Process::~Process() = default;
thakis3096dac2015-04-20 16:44:4852
dchenge1b0277c2015-12-01 12:09:5253Process& Process::operator=(Process&& other) {
54 DCHECK_NE(this, &other);
Lei Zhang04c0bcb2022-02-04 04:13:4555 process_.Set(other.process_.release());
dchenge1b0277c2015-12-01 12:09:5256 is_current_process_ = other.is_current_process_;
57 other.Close();
rvargas079d1842014-10-17 22:32:1658 return *this;
59}
60
61// static
62Process Process::Current() {
63 Process process;
64 process.is_current_process_ = true;
dcheng70c49422016-03-02 23:20:3465 return process;
rvargas079d1842014-10-17 22:32:1666}
67
68// static
rvargas6b039c372015-02-04 21:11:2969Process Process::Open(ProcessId pid) {
70 return Process(::OpenProcess(kBasicProcessAccess, FALSE, pid));
71}
72
73// static
rvargas1c376a82015-03-16 23:03:5274Process Process::OpenWithExtraPrivileges(ProcessId pid) {
rvargas747ff242015-01-17 02:46:4775 DWORD access = kBasicProcessAccess | PROCESS_DUP_HANDLE | PROCESS_VM_READ;
rvargas6b039c372015-02-04 21:11:2976 return Process(::OpenProcess(access, FALSE, pid));
rvargas747ff242015-01-17 02:46:4777}
78
79// static
rvargas17a407d2015-01-23 20:36:4480Process Process::OpenWithAccess(ProcessId pid, DWORD desired_access) {
81 return Process(::OpenProcess(desired_access, FALSE, pid));
82}
83
84// static
Patrick Monette5d1ba7ca2023-08-02 22:05:2785bool Process::CanSetPriority() {
rvargas079d1842014-10-17 22:32:1686 return true;
87}
88
haraken940efb92017-02-08 05:58:1589// static
90void Process::TerminateCurrentProcessImmediately(int exit_code) {
Sebastien Marchandbd02bc29e2020-03-11 15:53:3691#if BUILDFLAG(CLANG_PROFILING)
92 WriteClangProfilingProfile();
Wezd2031d302018-08-16 23:34:2593#endif
Jesse McKenna8d3ec428a2025-02-11 21:01:4194 ::TerminateProcess(::GetCurrentProcess(), static_cast<UINT>(exit_code));
Bruce Dawson33ce2ff2017-11-28 20:47:5195 // There is some ambiguity over whether the call above can return. Rather than
96 // hitting confusing crashes later on we should crash right here.
Peter Boström25c6ec72022-11-02 23:25:1997 ImmediateCrash();
haraken940efb92017-02-08 05:58:1598}
99
rvargas079d1842014-10-17 22:32:16100bool Process::IsValid() const {
Lei Zhang04c0bcb2022-02-04 04:13:45101 return process_.is_valid() || is_current();
rvargas079d1842014-10-17 22:32:16102}
103
104ProcessHandle Process::Handle() const {
Jesse McKenna8d3ec428a2025-02-11 21:01:41105 return is_current_process_ ? ::GetCurrentProcess() : process_.get();
rvargas079d1842014-10-17 22:32:16106}
107
108Process Process::Duplicate() const {
Peter Kasting134ef9af2024-12-28 02:30:09109 if (is_current()) {
rvargas079d1842014-10-17 22:32:16110 return Current();
Peter Kasting134ef9af2024-12-28 02:30:09111 }
rvargas079d1842014-10-17 22:32:16112
113 ProcessHandle out_handle;
Peter Kasting134ef9af2024-12-28 02:30:09114 if (!IsValid() ||
Jesse McKenna8d3ec428a2025-02-11 21:01:41115 !::DuplicateHandle(::GetCurrentProcess(), Handle(), ::GetCurrentProcess(),
Peter Kasting134ef9af2024-12-28 02:30:09116 &out_handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
rvargas079d1842014-10-17 22:32:16117 return Process();
118 }
119 return Process(out_handle);
120}
121
Robert Sesek0e7f165a2020-11-20 21:31:45122ProcessHandle Process::Release() {
Peter Kasting134ef9af2024-12-28 02:30:09123 if (is_current()) {
Robert Sesek0e7f165a2020-11-20 21:31:45124 return ::GetCurrentProcess();
Peter Kasting134ef9af2024-12-28 02:30:09125 }
Lei Zhang04c0bcb2022-02-04 04:13:45126 return process_.release();
Robert Sesek0e7f165a2020-11-20 21:31:45127}
128
rvargas960db882015-01-24 00:27:25129ProcessId Process::Pid() const {
rvargas079d1842014-10-17 22:32:16130 DCHECK(IsValid());
131 return GetProcId(Handle());
132}
133
Francois Doray7d1315342018-10-21 03:54:47134Time Process::CreationTime() const {
135 FILETIME creation_time = {};
136 FILETIME ignore1 = {};
137 FILETIME ignore2 = {};
138 FILETIME ignore3 = {};
139 if (!::GetProcessTimes(Handle(), &creation_time, &ignore1, &ignore2,
140 &ignore3)) {
141 return Time();
142 }
143 return Time::FromFileTime(creation_time);
144}
145
rvargas079d1842014-10-17 22:32:16146bool Process::is_current() const {
147 return is_current_process_;
148}
149
[email protected]176aa482008-11-14 03:25:15150void Process::Close() {
rvargas079d1842014-10-17 22:32:16151 is_current_process_ = false;
Peter Kasting134ef9af2024-12-28 02:30:09152 if (!process_.is_valid()) {
[email protected]176aa482008-11-14 03:25:15153 return;
Peter Kasting134ef9af2024-12-28 02:30:09154 }
[email protected]b987e90e2011-08-15 19:22:44155
rvargas079d1842014-10-17 22:32:16156 process_.Close();
[email protected]176aa482008-11-14 03:25:15157}
158
rvargas02ad7832015-04-02 01:36:06159bool Process::Terminate(int exit_code, bool wait) const {
Brian White6c8f3b9c2017-12-01 18:55:31160 constexpr DWORD kWaitMs = 60 * 1000;
161
rvargaseedb7632015-03-09 23:53:45162 DCHECK(IsValid());
Peter Kasting4d3664b2022-06-16 19:27:54163 bool result =
164 ::TerminateProcess(Handle(), static_cast<UINT>(exit_code)) != FALSE;
Brian Whiteae2a8b9a2017-11-02 19:10:36165 if (result) {
rvargas02ad7832015-04-02 01:36:06166 // The process may not end immediately due to pending I/O
Peter Kasting134ef9af2024-12-28 02:30:09167 if (wait && ::WaitForSingleObject(Handle(), kWaitMs) != WAIT_OBJECT_0) {
rvargas02ad7832015-04-02 01:36:06168 DPLOG(ERROR) << "Error waiting for process exit";
Peter Kasting134ef9af2024-12-28 02:30:09169 }
Brian Whiteae2a8b9a2017-11-02 19:10:36170 Exited(exit_code);
Brian Whiteccb2c6e2017-11-14 19:09:44171 } else {
Bruce Dawsond9111de2019-06-18 23:29:38172 // The process can't be terminated, perhaps because it has already exited or
173 // is in the process of exiting. An error code of ERROR_ACCESS_DENIED is the
174 // undocumented-but-expected result if the process has already exited or
175 // started exiting when TerminateProcess is called, so don't print an error
176 // message in that case.
Jesse McKenna8d3ec428a2025-02-11 21:01:41177 if (::GetLastError() != ERROR_ACCESS_DENIED) {
Bruce Dawsond9111de2019-06-18 23:29:38178 DPLOG(ERROR) << "Unable to terminate process";
Peter Kasting134ef9af2024-12-28 02:30:09179 }
Bruce Dawsond9111de2019-06-18 23:29:38180 // A non-zero timeout is necessary here for the same reasons as above.
Brian White6c8f3b9c2017-12-01 18:55:31181 if (::WaitForSingleObject(Handle(), kWaitMs) == WAIT_OBJECT_0) {
Brian Whiteccb2c6e2017-11-14 19:09:44182 DWORD actual_exit;
Peter Kasting4d3664b2022-06-16 19:27:54183 Exited(::GetExitCodeProcess(Handle(), &actual_exit)
184 ? static_cast<int>(actual_exit)
185 : exit_code);
Brian Whiteccb2c6e2017-11-14 19:09:44186 result = true;
187 }
rvargas02ad7832015-04-02 01:36:06188 }
189 return result;
[email protected]176aa482008-11-14 03:25:15190}
191
Mike Rorkef36971b2020-03-06 17:56:29192Process::WaitExitStatus Process::WaitForExitOrEvent(
Jesse McKenna8d3ec428a2025-02-11 21:01:41193 const win::ScopedHandle& stop_event_handle,
Mike Rorkef36971b2020-03-06 17:56:29194 int* exit_code) const {
Lei Zhang04c0bcb2022-02-04 04:13:45195 HANDLE events[] = {Handle(), stop_event_handle.get()};
Mike Rorkef36971b2020-03-06 17:56:29196 DWORD wait_result =
Daniel Chengf45f47602022-02-28 22:38:32197 ::WaitForMultipleObjects(std::size(events), events, FALSE, INFINITE);
Mike Rorkef36971b2020-03-06 17:56:29198
199 if (wait_result == WAIT_OBJECT_0) {
200 DWORD temp_code; // Don't clobber out-parameters in case of failure.
Peter Kasting134ef9af2024-12-28 02:30:09201 if (!::GetExitCodeProcess(Handle(), &temp_code)) {
Mike Rorkef36971b2020-03-06 17:56:29202 return Process::WaitExitStatus::FAILED;
Peter Kasting134ef9af2024-12-28 02:30:09203 }
Mike Rorkef36971b2020-03-06 17:56:29204
Peter Kasting134ef9af2024-12-28 02:30:09205 if (exit_code) {
Peter Kasting4d3664b2022-06-16 19:27:54206 *exit_code = static_cast<int>(temp_code);
Peter Kasting134ef9af2024-12-28 02:30:09207 }
Mike Rorkef36971b2020-03-06 17:56:29208
Peter Kasting4d3664b2022-06-16 19:27:54209 Exited(static_cast<int>(temp_code));
Mike Rorkef36971b2020-03-06 17:56:29210 return Process::WaitExitStatus::PROCESS_EXITED;
211 }
212
213 if (wait_result == WAIT_OBJECT_0 + 1) {
214 return Process::WaitExitStatus::STOP_EVENT_SIGNALED;
215 }
216
217 return Process::WaitExitStatus::FAILED;
218}
219
jcivellif4462a352017-01-10 04:45:59220bool Process::WaitForExit(int* exit_code) const {
Bruce Dawsond3e5d6e2021-07-16 21:17:26221 return WaitForExitWithTimeout(TimeDelta::Max(), exit_code);
rvargas126fd5822014-12-12 00:25:14222}
223
jcivellif4462a352017-01-10 04:45:59224bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) const {
Gabriel Charette6836c0d52021-01-11 17:40:26225 TRACE_EVENT0("base", "Process::WaitForExitWithTimeout");
Francois Doraya678fc12017-10-30 22:18:06226
Gabriel Charette6836c0d52021-01-11 17:40:26227 if (!timeout.is_zero()) {
Gabriel Charette6836c0d52021-01-11 17:40:26228 // Assert that this thread is allowed to wait below. This intentionally
229 // doesn't use ScopedBlockingCallWithBaseSyncPrimitives because the process
230 // being waited upon tends to itself be using the CPU and considering this
231 // thread non-busy causes more issue than it fixes: http://crbug.com/905788
232 internal::AssertBaseSyncPrimitivesAllowed();
233 }
bcwhited9705962016-08-10 03:10:03234
rvargas85728972015-03-03 20:46:19235 // Limit timeout to INFINITE.
236 DWORD timeout_ms = saturated_cast<DWORD>(timeout.InMilliseconds());
Peter Kasting134ef9af2024-12-28 02:30:09237 if (::WaitForSingleObject(Handle(), timeout_ms) != WAIT_OBJECT_0) {
rvargas85728972015-03-03 20:46:19238 return false;
Peter Kasting134ef9af2024-12-28 02:30:09239 }
rvargas85728972015-03-03 20:46:19240
241 DWORD temp_code; // Don't clobber out-parameters in case of failure.
Peter Kasting134ef9af2024-12-28 02:30:09242 if (!::GetExitCodeProcess(Handle(), &temp_code)) {
rvargas85728972015-03-03 20:46:19243 return false;
Peter Kasting134ef9af2024-12-28 02:30:09244 }
rvargas85728972015-03-03 20:46:19245
Peter Kasting134ef9af2024-12-28 02:30:09246 if (exit_code) {
Peter Kasting4d3664b2022-06-16 19:27:54247 *exit_code = static_cast<int>(temp_code);
Peter Kasting134ef9af2024-12-28 02:30:09248 }
bcwhite815054b52017-03-16 18:41:12249
Peter Kasting4d3664b2022-06-16 19:27:54250 Exited(static_cast<int>(temp_code));
rvargas85728972015-03-03 20:46:19251 return true;
rvargas126fd5822014-12-12 00:25:14252}
253
Joe Masona0ba58b052023-02-22 20:46:29254void Process::Exited(int exit_code) const {}
Brian Whiteae2a8b9a2017-11-02 19:10:36255
Patrick Monette5d1ba7ca2023-08-02 22:05:27256Process::Priority Process::GetPriority() const {
rvargas079d1842014-10-17 22:32:16257 DCHECK(IsValid());
Jesse McKenna8d3ec428a2025-02-11 21:01:41258 const int priority = GetOSPriority();
Peter Kasting134ef9af2024-12-28 02:30:09259 if (priority == 0) {
Patrick Monette5d1ba7ca2023-08-02 22:05:27260 return Priority::kUserBlocking; // Failure case. Use default value.
Peter Kasting134ef9af2024-12-28 02:30:09261 }
Patrick Monette5d1ba7ca2023-08-02 22:05:27262 if ((priority == BELOW_NORMAL_PRIORITY_CLASS) ||
263 (priority == IDLE_PRIORITY_CLASS)) {
264 return Priority::kBestEffort;
265 }
Zheda Chene7421f32024-08-29 03:05:39266
Chris Davis3360a372025-02-06 23:21:30267 // Return Priority::kUserVisible if EcoQos is enabled.
268 if (win::GetProcessEcoQoSState(Handle()) ==
269 win::ProcessPowerState::kEnabled) {
Zheda Chene7421f32024-08-29 03:05:39270 return Priority::kUserVisible;
271 }
272
Patrick Monette5d1ba7ca2023-08-02 22:05:27273 return Priority::kUserBlocking;
initial.commitd7cae122008-07-26 21:49:38274}
275
Patrick Monette5d1ba7ca2023-08-02 22:05:27276bool Process::SetPriority(Priority priority) {
rvargas079d1842014-10-17 22:32:16277 DCHECK(IsValid());
Bruce Dawsonb7e516e2022-12-13 18:41:43278 // Having a process remove itself from background mode is a potential
279 // priority inversion, and having a process put itself in background mode is
280 // broken in Windows 11 22H2. So, it is no longer supported. See
281 // https://crbug.com/1396155 for details.
282 DCHECK(!is_current());
[email protected]568bfb02011-04-28 23:51:53283
Chris Davis3360a372025-02-06 23:21:30284 // Clear EcoQoS for kUserBlocking; otherwise enable it. Process power
285 // throttling is a Windows 11 feature, but before 22H2 there was no way to
286 // query the current state using GetProcessInformation. This is needed in
287 // GetPriority to determine the current priority. Calls made to
288 // SetProcessEcoQoSState before 22H2 are a no-op.
François Dorayeb1e65ec2025-06-13 18:56:55289 if (FeatureList::IsEnabled(kUseEcoQoSForBackgroundProcess)) {
290 win::SetProcessEcoQoSState(Handle(),
291 priority == Priority::kUserBlocking
292 ? win::ProcessPowerState::kUnset
293 : win::ProcessPowerState::kEnabled);
294 }
Zheda Chen2808be72022-12-19 06:26:55295
Chris Davis3360a372025-02-06 23:21:30296 return ::SetPriorityClass(Handle(), priority == Priority::kBestEffort
297 ? IDLE_PRIORITY_CLASS
298 : NORMAL_PRIORITY_CLASS) != 0;
[email protected]8a420802011-12-02 16:14:46299}
300
Patrick Monette740b81b2023-07-21 21:09:09301int Process::GetOSPriority() const {
rvargas079d1842014-10-17 22:32:16302 DCHECK(IsValid());
Peter Kasting4d3664b2022-06-16 19:27:54303 return static_cast<int>(::GetPriorityClass(Handle()));
[email protected]276aa6a2009-10-29 17:43:44304}
305
[email protected]176aa482008-11-14 03:25:15306} // namespace base