Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2011 The Chromium Authors |
license.bot | bf09a50 | 2008-08-24 00:55:55 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 4 | |
[email protected] | 76bea67 | 2013-07-19 16:48:56 | [diff] [blame] | 5 | #include "base/process/process.h" |
[email protected] | dd4b5126 | 2013-07-25 21:38:23 | [diff] [blame] | 6 | |
Takuto Ikuta | c8d6b16f | 2024-04-15 16:59:19 | [diff] [blame] | 7 | #include <windows.h> |
| 8 | |
Sebastien Marchand | bd02bc29e | 2020-03-11 15:53:36 | [diff] [blame] | 9 | #include "base/clang_profiling_buildflags.h" |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 10 | #include "base/logging.h" |
rvargas | 8572897 | 2015-03-03 20:46:19 | [diff] [blame] | 11 | #include "base/numerics/safe_conversions.h" |
rvargas | 126fd582 | 2014-12-12 00:25:14 | [diff] [blame] | 12 | #include "base/process/kill.h" |
Francois Doray | a678fc1 | 2017-10-30 22:18:06 | [diff] [blame] | 13 | #include "base/threading/thread_restrictions.h" |
Etienne Pierre-doray | fc7952f0 | 2025-06-06 00:04:33 | [diff] [blame] | 14 | #include "base/trace_event/trace_event.h" |
Chris Davis | 3360a37 | 2025-02-06 23:21:30 | [diff] [blame] | 15 | #include "base/win/win_util.h" |
Zheda Chen | 2808be7 | 2022-12-19 06:26:55 | [diff] [blame] | 16 | #include "base/win/windows_version.h" |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 17 | |
Sebastien Marchand | bd02bc29e | 2020-03-11 15:53:36 | [diff] [blame] | 18 | #if BUILDFLAG(CLANG_PROFILING) |
| 19 | #include "base/test/clang_profiling.h" |
Yannic Bonenberger | 6801e6c | 2019-06-07 10:42:53 | [diff] [blame] | 20 | #endif |
| 21 | |
rvargas | 747ff24 | 2015-01-17 02:46:47 | [diff] [blame] | 22 | namespace { |
| 23 | |
| 24 | DWORD kBasicProcessAccess = |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 25 | PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | SYNCHRONIZE; |
rvargas | 747ff24 | 2015-01-17 02:46:47 | [diff] [blame] | 26 | |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 27 | } // namespace |
rvargas | 747ff24 | 2015-01-17 02:46:47 | [diff] [blame] | 28 | |
[email protected] | 176aa48 | 2008-11-14 03:25:15 | [diff] [blame] | 29 | namespace base { |
| 30 | |
François Doray | eb1e65ec | 2025-06-13 18:56:55 | [diff] [blame] | 31 | // 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. |
| 36 | BASE_FEATURE(kUseEcoQoSForBackgroundProcess, |
| 37 | "UseEcoQoSForBackgroundProcess", |
| 38 | FEATURE_ENABLED_BY_DEFAULT); |
| 39 | |
rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 40 | Process::Process(ProcessHandle handle) |
scottmg | 297cc93 | 2017-05-24 03:45:58 | [diff] [blame] | 41 | : process_(handle), is_current_process_(false) { |
rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 42 | CHECK_NE(handle, ::GetCurrentProcess()); |
| 43 | } |
| 44 | |
dcheng | e1b0277c | 2015-12-01 12:09:52 | [diff] [blame] | 45 | Process::Process(Process&& other) |
Lei Zhang | 04c0bcb | 2022-02-04 04:13:45 | [diff] [blame] | 46 | : process_(other.process_.release()), |
scottmg | 297cc93 | 2017-05-24 03:45:58 | [diff] [blame] | 47 | is_current_process_(other.is_current_process_) { |
dcheng | e1b0277c | 2015-12-01 12:09:52 | [diff] [blame] | 48 | other.Close(); |
rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 49 | } |
| 50 | |
Sorin Jianu | f841ac6 | 2024-12-19 19:39:22 | [diff] [blame] | 51 | Process::~Process() = default; |
thakis | 3096dac | 2015-04-20 16:44:48 | [diff] [blame] | 52 | |
dcheng | e1b0277c | 2015-12-01 12:09:52 | [diff] [blame] | 53 | Process& Process::operator=(Process&& other) { |
| 54 | DCHECK_NE(this, &other); |
Lei Zhang | 04c0bcb | 2022-02-04 04:13:45 | [diff] [blame] | 55 | process_.Set(other.process_.release()); |
dcheng | e1b0277c | 2015-12-01 12:09:52 | [diff] [blame] | 56 | is_current_process_ = other.is_current_process_; |
| 57 | other.Close(); |
rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 58 | return *this; |
| 59 | } |
| 60 | |
| 61 | // static |
| 62 | Process Process::Current() { |
| 63 | Process process; |
| 64 | process.is_current_process_ = true; |
dcheng | 70c4942 | 2016-03-02 23:20:34 | [diff] [blame] | 65 | return process; |
rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 66 | } |
| 67 | |
| 68 | // static |
rvargas | 6b039c37 | 2015-02-04 21:11:29 | [diff] [blame] | 69 | Process Process::Open(ProcessId pid) { |
| 70 | return Process(::OpenProcess(kBasicProcessAccess, FALSE, pid)); |
| 71 | } |
| 72 | |
| 73 | // static |
rvargas | 1c376a8 | 2015-03-16 23:03:52 | [diff] [blame] | 74 | Process Process::OpenWithExtraPrivileges(ProcessId pid) { |
rvargas | 747ff24 | 2015-01-17 02:46:47 | [diff] [blame] | 75 | DWORD access = kBasicProcessAccess | PROCESS_DUP_HANDLE | PROCESS_VM_READ; |
rvargas | 6b039c37 | 2015-02-04 21:11:29 | [diff] [blame] | 76 | return Process(::OpenProcess(access, FALSE, pid)); |
rvargas | 747ff24 | 2015-01-17 02:46:47 | [diff] [blame] | 77 | } |
| 78 | |
| 79 | // static |
rvargas | 17a407d | 2015-01-23 20:36:44 | [diff] [blame] | 80 | Process Process::OpenWithAccess(ProcessId pid, DWORD desired_access) { |
| 81 | return Process(::OpenProcess(desired_access, FALSE, pid)); |
| 82 | } |
| 83 | |
| 84 | // static |
Patrick Monette | 5d1ba7ca | 2023-08-02 22:05:27 | [diff] [blame] | 85 | bool Process::CanSetPriority() { |
rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 86 | return true; |
| 87 | } |
| 88 | |
haraken | 940efb9 | 2017-02-08 05:58:15 | [diff] [blame] | 89 | // static |
| 90 | void Process::TerminateCurrentProcessImmediately(int exit_code) { |
Sebastien Marchand | bd02bc29e | 2020-03-11 15:53:36 | [diff] [blame] | 91 | #if BUILDFLAG(CLANG_PROFILING) |
| 92 | WriteClangProfilingProfile(); |
Wez | d2031d30 | 2018-08-16 23:34:25 | [diff] [blame] | 93 | #endif |
Jesse McKenna | 8d3ec428a | 2025-02-11 21:01:41 | [diff] [blame] | 94 | ::TerminateProcess(::GetCurrentProcess(), static_cast<UINT>(exit_code)); |
Bruce Dawson | 33ce2ff | 2017-11-28 20:47:51 | [diff] [blame] | 95 | // 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öm | 25c6ec7 | 2022-11-02 23:25:19 | [diff] [blame] | 97 | ImmediateCrash(); |
haraken | 940efb9 | 2017-02-08 05:58:15 | [diff] [blame] | 98 | } |
| 99 | |
rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 100 | bool Process::IsValid() const { |
Lei Zhang | 04c0bcb | 2022-02-04 04:13:45 | [diff] [blame] | 101 | return process_.is_valid() || is_current(); |
rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 102 | } |
| 103 | |
| 104 | ProcessHandle Process::Handle() const { |
Jesse McKenna | 8d3ec428a | 2025-02-11 21:01:41 | [diff] [blame] | 105 | return is_current_process_ ? ::GetCurrentProcess() : process_.get(); |
rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 106 | } |
| 107 | |
| 108 | Process Process::Duplicate() const { |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 109 | if (is_current()) { |
rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 110 | return Current(); |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 111 | } |
rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 112 | |
| 113 | ProcessHandle out_handle; |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 114 | if (!IsValid() || |
Jesse McKenna | 8d3ec428a | 2025-02-11 21:01:41 | [diff] [blame] | 115 | !::DuplicateHandle(::GetCurrentProcess(), Handle(), ::GetCurrentProcess(), |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 116 | &out_handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) { |
rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 117 | return Process(); |
| 118 | } |
| 119 | return Process(out_handle); |
| 120 | } |
| 121 | |
Robert Sesek | 0e7f165a | 2020-11-20 21:31:45 | [diff] [blame] | 122 | ProcessHandle Process::Release() { |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 123 | if (is_current()) { |
Robert Sesek | 0e7f165a | 2020-11-20 21:31:45 | [diff] [blame] | 124 | return ::GetCurrentProcess(); |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 125 | } |
Lei Zhang | 04c0bcb | 2022-02-04 04:13:45 | [diff] [blame] | 126 | return process_.release(); |
Robert Sesek | 0e7f165a | 2020-11-20 21:31:45 | [diff] [blame] | 127 | } |
| 128 | |
rvargas | 960db88 | 2015-01-24 00:27:25 | [diff] [blame] | 129 | ProcessId Process::Pid() const { |
rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 130 | DCHECK(IsValid()); |
| 131 | return GetProcId(Handle()); |
| 132 | } |
| 133 | |
Francois Doray | 7d131534 | 2018-10-21 03:54:47 | [diff] [blame] | 134 | Time 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 | |
rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 146 | bool Process::is_current() const { |
| 147 | return is_current_process_; |
| 148 | } |
| 149 | |
[email protected] | 176aa48 | 2008-11-14 03:25:15 | [diff] [blame] | 150 | void Process::Close() { |
rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 151 | is_current_process_ = false; |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 152 | if (!process_.is_valid()) { |
[email protected] | 176aa48 | 2008-11-14 03:25:15 | [diff] [blame] | 153 | return; |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 154 | } |
[email protected] | b987e90e | 2011-08-15 19:22:44 | [diff] [blame] | 155 | |
rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 156 | process_.Close(); |
[email protected] | 176aa48 | 2008-11-14 03:25:15 | [diff] [blame] | 157 | } |
| 158 | |
rvargas | 02ad783 | 2015-04-02 01:36:06 | [diff] [blame] | 159 | bool Process::Terminate(int exit_code, bool wait) const { |
Brian White | 6c8f3b9c | 2017-12-01 18:55:31 | [diff] [blame] | 160 | constexpr DWORD kWaitMs = 60 * 1000; |
| 161 | |
rvargas | eedb763 | 2015-03-09 23:53:45 | [diff] [blame] | 162 | DCHECK(IsValid()); |
Peter Kasting | 4d3664b | 2022-06-16 19:27:54 | [diff] [blame] | 163 | bool result = |
| 164 | ::TerminateProcess(Handle(), static_cast<UINT>(exit_code)) != FALSE; |
Brian White | ae2a8b9a | 2017-11-02 19:10:36 | [diff] [blame] | 165 | if (result) { |
rvargas | 02ad783 | 2015-04-02 01:36:06 | [diff] [blame] | 166 | // The process may not end immediately due to pending I/O |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 167 | if (wait && ::WaitForSingleObject(Handle(), kWaitMs) != WAIT_OBJECT_0) { |
rvargas | 02ad783 | 2015-04-02 01:36:06 | [diff] [blame] | 168 | DPLOG(ERROR) << "Error waiting for process exit"; |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 169 | } |
Brian White | ae2a8b9a | 2017-11-02 19:10:36 | [diff] [blame] | 170 | Exited(exit_code); |
Brian White | ccb2c6e | 2017-11-14 19:09:44 | [diff] [blame] | 171 | } else { |
Bruce Dawson | d9111de | 2019-06-18 23:29:38 | [diff] [blame] | 172 | // 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 McKenna | 8d3ec428a | 2025-02-11 21:01:41 | [diff] [blame] | 177 | if (::GetLastError() != ERROR_ACCESS_DENIED) { |
Bruce Dawson | d9111de | 2019-06-18 23:29:38 | [diff] [blame] | 178 | DPLOG(ERROR) << "Unable to terminate process"; |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 179 | } |
Bruce Dawson | d9111de | 2019-06-18 23:29:38 | [diff] [blame] | 180 | // A non-zero timeout is necessary here for the same reasons as above. |
Brian White | 6c8f3b9c | 2017-12-01 18:55:31 | [diff] [blame] | 181 | if (::WaitForSingleObject(Handle(), kWaitMs) == WAIT_OBJECT_0) { |
Brian White | ccb2c6e | 2017-11-14 19:09:44 | [diff] [blame] | 182 | DWORD actual_exit; |
Peter Kasting | 4d3664b | 2022-06-16 19:27:54 | [diff] [blame] | 183 | Exited(::GetExitCodeProcess(Handle(), &actual_exit) |
| 184 | ? static_cast<int>(actual_exit) |
| 185 | : exit_code); |
Brian White | ccb2c6e | 2017-11-14 19:09:44 | [diff] [blame] | 186 | result = true; |
| 187 | } |
rvargas | 02ad783 | 2015-04-02 01:36:06 | [diff] [blame] | 188 | } |
| 189 | return result; |
[email protected] | 176aa48 | 2008-11-14 03:25:15 | [diff] [blame] | 190 | } |
| 191 | |
Mike Rorke | f36971b | 2020-03-06 17:56:29 | [diff] [blame] | 192 | Process::WaitExitStatus Process::WaitForExitOrEvent( |
Jesse McKenna | 8d3ec428a | 2025-02-11 21:01:41 | [diff] [blame] | 193 | const win::ScopedHandle& stop_event_handle, |
Mike Rorke | f36971b | 2020-03-06 17:56:29 | [diff] [blame] | 194 | int* exit_code) const { |
Lei Zhang | 04c0bcb | 2022-02-04 04:13:45 | [diff] [blame] | 195 | HANDLE events[] = {Handle(), stop_event_handle.get()}; |
Mike Rorke | f36971b | 2020-03-06 17:56:29 | [diff] [blame] | 196 | DWORD wait_result = |
Daniel Cheng | f45f4760 | 2022-02-28 22:38:32 | [diff] [blame] | 197 | ::WaitForMultipleObjects(std::size(events), events, FALSE, INFINITE); |
Mike Rorke | f36971b | 2020-03-06 17:56:29 | [diff] [blame] | 198 | |
| 199 | if (wait_result == WAIT_OBJECT_0) { |
| 200 | DWORD temp_code; // Don't clobber out-parameters in case of failure. |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 201 | if (!::GetExitCodeProcess(Handle(), &temp_code)) { |
Mike Rorke | f36971b | 2020-03-06 17:56:29 | [diff] [blame] | 202 | return Process::WaitExitStatus::FAILED; |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 203 | } |
Mike Rorke | f36971b | 2020-03-06 17:56:29 | [diff] [blame] | 204 | |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 205 | if (exit_code) { |
Peter Kasting | 4d3664b | 2022-06-16 19:27:54 | [diff] [blame] | 206 | *exit_code = static_cast<int>(temp_code); |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 207 | } |
Mike Rorke | f36971b | 2020-03-06 17:56:29 | [diff] [blame] | 208 | |
Peter Kasting | 4d3664b | 2022-06-16 19:27:54 | [diff] [blame] | 209 | Exited(static_cast<int>(temp_code)); |
Mike Rorke | f36971b | 2020-03-06 17:56:29 | [diff] [blame] | 210 | 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 | |
jcivelli | f4462a35 | 2017-01-10 04:45:59 | [diff] [blame] | 220 | bool Process::WaitForExit(int* exit_code) const { |
Bruce Dawson | d3e5d6e | 2021-07-16 21:17:26 | [diff] [blame] | 221 | return WaitForExitWithTimeout(TimeDelta::Max(), exit_code); |
rvargas | 126fd582 | 2014-12-12 00:25:14 | [diff] [blame] | 222 | } |
| 223 | |
jcivelli | f4462a35 | 2017-01-10 04:45:59 | [diff] [blame] | 224 | bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) const { |
Gabriel Charette | 6836c0d5 | 2021-01-11 17:40:26 | [diff] [blame] | 225 | TRACE_EVENT0("base", "Process::WaitForExitWithTimeout"); |
Francois Doray | a678fc1 | 2017-10-30 22:18:06 | [diff] [blame] | 226 | |
Gabriel Charette | 6836c0d5 | 2021-01-11 17:40:26 | [diff] [blame] | 227 | if (!timeout.is_zero()) { |
Gabriel Charette | 6836c0d5 | 2021-01-11 17:40:26 | [diff] [blame] | 228 | // 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 | } |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 234 | |
rvargas | 8572897 | 2015-03-03 20:46:19 | [diff] [blame] | 235 | // Limit timeout to INFINITE. |
| 236 | DWORD timeout_ms = saturated_cast<DWORD>(timeout.InMilliseconds()); |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 237 | if (::WaitForSingleObject(Handle(), timeout_ms) != WAIT_OBJECT_0) { |
rvargas | 8572897 | 2015-03-03 20:46:19 | [diff] [blame] | 238 | return false; |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 239 | } |
rvargas | 8572897 | 2015-03-03 20:46:19 | [diff] [blame] | 240 | |
| 241 | DWORD temp_code; // Don't clobber out-parameters in case of failure. |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 242 | if (!::GetExitCodeProcess(Handle(), &temp_code)) { |
rvargas | 8572897 | 2015-03-03 20:46:19 | [diff] [blame] | 243 | return false; |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 244 | } |
rvargas | 8572897 | 2015-03-03 20:46:19 | [diff] [blame] | 245 | |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 246 | if (exit_code) { |
Peter Kasting | 4d3664b | 2022-06-16 19:27:54 | [diff] [blame] | 247 | *exit_code = static_cast<int>(temp_code); |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 248 | } |
bcwhite | 815054b5 | 2017-03-16 18:41:12 | [diff] [blame] | 249 | |
Peter Kasting | 4d3664b | 2022-06-16 19:27:54 | [diff] [blame] | 250 | Exited(static_cast<int>(temp_code)); |
rvargas | 8572897 | 2015-03-03 20:46:19 | [diff] [blame] | 251 | return true; |
rvargas | 126fd582 | 2014-12-12 00:25:14 | [diff] [blame] | 252 | } |
| 253 | |
Joe Mason | a0ba58b05 | 2023-02-22 20:46:29 | [diff] [blame] | 254 | void Process::Exited(int exit_code) const {} |
Brian White | ae2a8b9a | 2017-11-02 19:10:36 | [diff] [blame] | 255 | |
Patrick Monette | 5d1ba7ca | 2023-08-02 22:05:27 | [diff] [blame] | 256 | Process::Priority Process::GetPriority() const { |
rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 257 | DCHECK(IsValid()); |
Jesse McKenna | 8d3ec428a | 2025-02-11 21:01:41 | [diff] [blame] | 258 | const int priority = GetOSPriority(); |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 259 | if (priority == 0) { |
Patrick Monette | 5d1ba7ca | 2023-08-02 22:05:27 | [diff] [blame] | 260 | return Priority::kUserBlocking; // Failure case. Use default value. |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 261 | } |
Patrick Monette | 5d1ba7ca | 2023-08-02 22:05:27 | [diff] [blame] | 262 | if ((priority == BELOW_NORMAL_PRIORITY_CLASS) || |
| 263 | (priority == IDLE_PRIORITY_CLASS)) { |
| 264 | return Priority::kBestEffort; |
| 265 | } |
Zheda Chen | e7421f3 | 2024-08-29 03:05:39 | [diff] [blame] | 266 | |
Chris Davis | 3360a37 | 2025-02-06 23:21:30 | [diff] [blame] | 267 | // Return Priority::kUserVisible if EcoQos is enabled. |
| 268 | if (win::GetProcessEcoQoSState(Handle()) == |
| 269 | win::ProcessPowerState::kEnabled) { |
Zheda Chen | e7421f3 | 2024-08-29 03:05:39 | [diff] [blame] | 270 | return Priority::kUserVisible; |
| 271 | } |
| 272 | |
Patrick Monette | 5d1ba7ca | 2023-08-02 22:05:27 | [diff] [blame] | 273 | return Priority::kUserBlocking; |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 274 | } |
| 275 | |
Patrick Monette | 5d1ba7ca | 2023-08-02 22:05:27 | [diff] [blame] | 276 | bool Process::SetPriority(Priority priority) { |
rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 277 | DCHECK(IsValid()); |
Bruce Dawson | b7e516e | 2022-12-13 18:41:43 | [diff] [blame] | 278 | // 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] | 568bfb0 | 2011-04-28 23:51:53 | [diff] [blame] | 283 | |
Chris Davis | 3360a37 | 2025-02-06 23:21:30 | [diff] [blame] | 284 | // 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 Doray | eb1e65ec | 2025-06-13 18:56:55 | [diff] [blame] | 289 | if (FeatureList::IsEnabled(kUseEcoQoSForBackgroundProcess)) { |
| 290 | win::SetProcessEcoQoSState(Handle(), |
| 291 | priority == Priority::kUserBlocking |
| 292 | ? win::ProcessPowerState::kUnset |
| 293 | : win::ProcessPowerState::kEnabled); |
| 294 | } |
Zheda Chen | 2808be7 | 2022-12-19 06:26:55 | [diff] [blame] | 295 | |
Chris Davis | 3360a37 | 2025-02-06 23:21:30 | [diff] [blame] | 296 | return ::SetPriorityClass(Handle(), priority == Priority::kBestEffort |
| 297 | ? IDLE_PRIORITY_CLASS |
| 298 | : NORMAL_PRIORITY_CLASS) != 0; |
[email protected] | 8a42080 | 2011-12-02 16:14:46 | [diff] [blame] | 299 | } |
| 300 | |
Patrick Monette | 740b81b | 2023-07-21 21:09:09 | [diff] [blame] | 301 | int Process::GetOSPriority() const { |
rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 302 | DCHECK(IsValid()); |
Peter Kasting | 4d3664b | 2022-06-16 19:27:54 | [diff] [blame] | 303 | return static_cast<int>(::GetPriorityClass(Handle())); |
[email protected] | 276aa6a | 2009-10-29 17:43:44 | [diff] [blame] | 304 | } |
| 305 | |
[email protected] | 176aa48 | 2008-11-14 03:25:15 | [diff] [blame] | 306 | } // namespace base |