blob: afc6a786ba439dd96b7fd1a621902b7e26a10e28 [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
bcwhited9705962016-08-10 03:10:037#include "base/debug/activity_tracker.h"
initial.commitd7cae122008-07-26 21:49:388#include "base/logging.h"
rvargas85728972015-03-03 20:46:199#include "base/numerics/safe_conversions.h"
rvargas126fd5822014-12-12 00:25:1410#include "base/process/kill.h"
[email protected]568bfb02011-04-28 23:51:5311#include "base/win/windows_version.h"
initial.commitd7cae122008-07-26 21:49:3812
rvargas747ff242015-01-17 02:46:4713namespace {
14
15DWORD kBasicProcessAccess =
16 PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | SYNCHRONIZE;
17
18} // namespace
19
[email protected]176aa482008-11-14 03:25:1520namespace base {
21
rvargas079d1842014-10-17 22:32:1622Process::Process(ProcessHandle handle)
23 : is_current_process_(false),
24 process_(handle) {
25 CHECK_NE(handle, ::GetCurrentProcess());
26}
27
dchenge1b0277c2015-12-01 12:09:5228Process::Process(Process&& other)
29 : is_current_process_(other.is_current_process_),
30 process_(other.process_.Take()) {
31 other.Close();
rvargas079d1842014-10-17 22:32:1632}
33
thakis3096dac2015-04-20 16:44:4834Process::~Process() {
35}
36
dchenge1b0277c2015-12-01 12:09:5237Process& Process::operator=(Process&& other) {
38 DCHECK_NE(this, &other);
39 process_.Set(other.process_.Take());
40 is_current_process_ = other.is_current_process_;
41 other.Close();
rvargas079d1842014-10-17 22:32:1642 return *this;
43}
44
45// static
46Process Process::Current() {
47 Process process;
48 process.is_current_process_ = true;
dcheng70c49422016-03-02 23:20:3449 return process;
rvargas079d1842014-10-17 22:32:1650}
51
52// static
rvargas6b039c372015-02-04 21:11:2953Process Process::Open(ProcessId pid) {
54 return Process(::OpenProcess(kBasicProcessAccess, FALSE, pid));
55}
56
57// static
rvargas1c376a82015-03-16 23:03:5258Process Process::OpenWithExtraPrivileges(ProcessId pid) {
rvargas747ff242015-01-17 02:46:4759 DWORD access = kBasicProcessAccess | PROCESS_DUP_HANDLE | PROCESS_VM_READ;
rvargas6b039c372015-02-04 21:11:2960 return Process(::OpenProcess(access, FALSE, pid));
rvargas747ff242015-01-17 02:46:4761}
62
63// static
rvargas17a407d2015-01-23 20:36:4464Process Process::OpenWithAccess(ProcessId pid, DWORD desired_access) {
65 return Process(::OpenProcess(desired_access, FALSE, pid));
66}
67
68// static
rvargas5779b382014-11-18 20:44:1169Process Process::DeprecatedGetProcessFromHandle(ProcessHandle handle) {
70 DCHECK_NE(handle, ::GetCurrentProcess());
71 ProcessHandle out_handle;
72 if (!::DuplicateHandle(GetCurrentProcess(), handle,
73 GetCurrentProcess(), &out_handle,
74 0, FALSE, DUPLICATE_SAME_ACCESS)) {
75 return Process();
76 }
77 return Process(out_handle);
78}
79
80// static
rvargas079d1842014-10-17 22:32:1681bool Process::CanBackgroundProcesses() {
82 return true;
83}
84
85bool Process::IsValid() const {
86 return process_.IsValid() || is_current();
87}
88
89ProcessHandle Process::Handle() const {
90 return is_current_process_ ? GetCurrentProcess() : process_.Get();
91}
92
93Process Process::Duplicate() const {
94 if (is_current())
95 return Current();
96
97 ProcessHandle out_handle;
98 if (!IsValid() || !::DuplicateHandle(GetCurrentProcess(),
99 Handle(),
100 GetCurrentProcess(),
101 &out_handle,
102 0,
103 FALSE,
104 DUPLICATE_SAME_ACCESS)) {
105 return Process();
106 }
107 return Process(out_handle);
108}
109
rvargas960db882015-01-24 00:27:25110ProcessId Process::Pid() const {
rvargas079d1842014-10-17 22:32:16111 DCHECK(IsValid());
112 return GetProcId(Handle());
113}
114
115bool Process::is_current() const {
116 return is_current_process_;
117}
118
[email protected]176aa482008-11-14 03:25:15119void Process::Close() {
rvargas079d1842014-10-17 22:32:16120 is_current_process_ = false;
121 if (!process_.IsValid())
[email protected]176aa482008-11-14 03:25:15122 return;
[email protected]b987e90e2011-08-15 19:22:44123
rvargas079d1842014-10-17 22:32:16124 process_.Close();
[email protected]176aa482008-11-14 03:25:15125}
126
rvargas02ad7832015-04-02 01:36:06127bool Process::Terminate(int exit_code, bool wait) const {
rvargaseedb763e2015-03-09 23:53:45128 DCHECK(IsValid());
rvargas02ad7832015-04-02 01:36:06129 bool result = (::TerminateProcess(Handle(), exit_code) != FALSE);
130 if (result && wait) {
131 // The process may not end immediately due to pending I/O
132 if (::WaitForSingleObject(Handle(), 60 * 1000) != WAIT_OBJECT_0)
133 DPLOG(ERROR) << "Error waiting for process exit";
134 } else if (!result) {
135 DPLOG(ERROR) << "Unable to terminate process";
136 }
137 return result;
[email protected]176aa482008-11-14 03:25:15138}
139
jcivellif4462a352017-01-10 04:45:59140bool Process::WaitForExit(int* exit_code) const {
rvargas126fd5822014-12-12 00:25:14141 return WaitForExitWithTimeout(TimeDelta::FromMilliseconds(INFINITE),
142 exit_code);
143}
144
jcivellif4462a352017-01-10 04:45:59145bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) const {
bcwhited9705962016-08-10 03:10:03146 // Record the event that this thread is blocking upon (for hang diagnosis).
147 base::debug::ScopedProcessWaitActivity process_activity(this);
148
rvargas85728972015-03-03 20:46:19149 // Limit timeout to INFINITE.
150 DWORD timeout_ms = saturated_cast<DWORD>(timeout.InMilliseconds());
151 if (::WaitForSingleObject(Handle(), timeout_ms) != WAIT_OBJECT_0)
152 return false;
153
154 DWORD temp_code; // Don't clobber out-parameters in case of failure.
155 if (!::GetExitCodeProcess(Handle(), &temp_code))
156 return false;
157
g.mehndirattfd19e232015-05-29 08:17:14158 if (exit_code)
159 *exit_code = temp_code;
rvargas85728972015-03-03 20:46:19160 return true;
rvargas126fd5822014-12-12 00:25:14161}
162
[email protected]2f15de42008-11-11 22:35:19163bool Process::IsProcessBackgrounded() const {
rvargas079d1842014-10-17 22:32:16164 DCHECK(IsValid());
[email protected]276aa6a2009-10-29 17:43:44165 DWORD priority = GetPriority();
initial.commitd7cae122008-07-26 21:49:38166 if (priority == 0)
167 return false; // Failure case.
[email protected]568bfb02011-04-28 23:51:53168 return ((priority == BELOW_NORMAL_PRIORITY_CLASS) ||
169 (priority == IDLE_PRIORITY_CLASS));
initial.commitd7cae122008-07-26 21:49:38170}
171
172bool Process::SetProcessBackgrounded(bool value) {
rvargas079d1842014-10-17 22:32:16173 DCHECK(IsValid());
[email protected]568bfb02011-04-28 23:51:53174 // Vista and above introduce a real background mode, which not only
175 // sets the priority class on the threads but also on the IO generated
176 // by it. Unfortunately it can only be set for the calling process.
177 DWORD priority;
rvargas079d1842014-10-17 22:32:16178 if ((base::win::GetVersion() >= base::win::VERSION_VISTA) && (is_current())) {
[email protected]568bfb02011-04-28 23:51:53179 priority = value ? PROCESS_MODE_BACKGROUND_BEGIN :
180 PROCESS_MODE_BACKGROUND_END;
181 } else {
gab3d473432015-07-21 17:20:20182 priority = value ? IDLE_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS;
[email protected]568bfb02011-04-28 23:51:53183 }
184
rvargas079d1842014-10-17 22:32:16185 return (::SetPriorityClass(Handle(), priority) != 0);
[email protected]8a420802011-12-02 16:14:46186}
187
[email protected]276aa6a2009-10-29 17:43:44188int Process::GetPriority() const {
rvargas079d1842014-10-17 22:32:16189 DCHECK(IsValid());
190 return ::GetPriorityClass(Handle());
[email protected]276aa6a2009-10-29 17:43:44191}
192
[email protected]176aa482008-11-14 03:25:15193} // namespace base