1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/process/process.h"
6
7 #include <lib/zx/process.h>
8 #include <zircon/process.h>
9 #include <zircon/syscalls.h>
10
11 #include "base/clang_profiling_buildflags.h"
12 #include "base/debug/activity_tracker.h"
13 #include "base/fuchsia/default_job.h"
14 #include "base/fuchsia/fuchsia_logging.h"
15 #include "base/strings/stringprintf.h"
16
17 #if BUILDFLAG(CLANG_PROFILING)
18 #include "base/test/clang_profiling.h"
19 #endif
20
21 namespace base {
22
Process(ProcessHandle handle)23 Process::Process(ProcessHandle handle)
24 : process_(handle), is_current_process_(false) {
25 CHECK_NE(handle, zx_process_self());
26 }
27
~Process()28 Process::~Process() {
29 Close();
30 }
31
Process(Process && other)32 Process::Process(Process&& other)
33 : process_(std::move(other.process_)),
34 is_current_process_(other.is_current_process_) {
35 other.is_current_process_ = false;
36 }
37
operator =(Process && other)38 Process& Process::operator=(Process&& other) {
39 process_ = std::move(other.process_);
40 is_current_process_ = other.is_current_process_;
41 other.is_current_process_ = false;
42 return *this;
43 }
44
45 // static
Current()46 Process Process::Current() {
47 Process process;
48 process.is_current_process_ = true;
49 return process;
50 }
51
52 // static
Open(ProcessId pid)53 Process Process::Open(ProcessId pid) {
54 if (pid == GetCurrentProcId())
55 return Current();
56
57 // While a process with object id |pid| might exist, the job returned by
58 // zx::job::default_job() might not contain it, so this call can fail.
59 zx::process process;
60 zx_status_t status =
61 GetDefaultJob()->get_child(pid, ZX_RIGHT_SAME_RIGHTS, &process);
62 if (status != ZX_OK) {
63 ZX_DLOG(ERROR, status) << "zx_object_get_child";
64 return Process();
65 }
66 return Process(process.release());
67 }
68
69 // static
OpenWithExtraPrivileges(ProcessId pid)70 Process Process::OpenWithExtraPrivileges(ProcessId pid) {
71 // No privileges to set.
72 return Open(pid);
73 }
74
75 // static
DeprecatedGetProcessFromHandle(ProcessHandle handle)76 Process Process::DeprecatedGetProcessFromHandle(ProcessHandle handle) {
77 DCHECK_NE(handle, GetCurrentProcessHandle());
78 zx::process out;
79 zx_status_t result =
80 zx::unowned_process(handle)->duplicate(ZX_RIGHT_SAME_RIGHTS, &out);
81 if (result != ZX_OK) {
82 ZX_DLOG(ERROR, result) << "zx_handle_duplicate(from_handle)";
83 return Process();
84 }
85
86 return Process(out.release());
87 }
88
89 // static
CanBackgroundProcesses()90 bool Process::CanBackgroundProcesses() {
91 return false;
92 }
93
94 // static
TerminateCurrentProcessImmediately(int exit_code)95 void Process::TerminateCurrentProcessImmediately(int exit_code) {
96 #if BUILDFLAG(CLANG_PROFILING)
97 WriteClangProfilingProfile();
98 #endif
99 _exit(exit_code);
100 }
101
IsValid() const102 bool Process::IsValid() const {
103 return process_.is_valid() || is_current();
104 }
105
Handle() const106 ProcessHandle Process::Handle() const {
107 return is_current_process_ ? zx_process_self() : process_.get();
108 }
109
Duplicate() const110 Process Process::Duplicate() const {
111 if (is_current())
112 return Current();
113
114 if (!IsValid())
115 return Process();
116
117 zx::process out;
118 zx_status_t result = process_.duplicate(ZX_RIGHT_SAME_RIGHTS, &out);
119 if (result != ZX_OK) {
120 ZX_DLOG(ERROR, result) << "zx_handle_duplicate";
121 return Process();
122 }
123
124 return Process(out.release());
125 }
126
Pid() const127 ProcessId Process::Pid() const {
128 DCHECK(IsValid());
129 return GetProcId(Handle());
130 }
131
CreationTime() const132 Time Process::CreationTime() const {
133 // TODO(https://crbug.com/726484): There is no syscall providing this data.
134 NOTIMPLEMENTED();
135 return Time();
136 }
137
is_current() const138 bool Process::is_current() const {
139 return is_current_process_;
140 }
141
Close()142 void Process::Close() {
143 is_current_process_ = false;
144 process_.reset();
145 }
146
Terminate(int exit_code,bool wait) const147 bool Process::Terminate(int exit_code, bool wait) const {
148 // exit_code isn't supportable. https://crbug.com/753490.
149 zx_status_t status = zx_task_kill(Handle());
150 if (status == ZX_OK && wait) {
151 zx_signals_t signals;
152 status = zx_object_wait_one(Handle(), ZX_TASK_TERMINATED,
153 zx_deadline_after(ZX_SEC(60)), &signals);
154 if (status != ZX_OK) {
155 ZX_DLOG(ERROR, status) << "zx_object_wait_one(terminate)";
156 } else {
157 CHECK(signals & ZX_TASK_TERMINATED);
158 }
159 } else if (status != ZX_OK) {
160 ZX_DLOG(ERROR, status) << "zx_task_kill";
161 }
162
163 return status >= 0;
164 }
165
WaitForExit(int * exit_code) const166 bool Process::WaitForExit(int* exit_code) const {
167 return WaitForExitWithTimeout(TimeDelta::Max(), exit_code);
168 }
169
WaitForExitWithTimeout(TimeDelta timeout,int * exit_code) const170 bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) const {
171 if (is_current_process_)
172 return false;
173
174 // Record the event that this thread is blocking upon (for hang diagnosis).
175 base::debug::ScopedProcessWaitActivity process_activity(this);
176
177 zx_time_t deadline = timeout == TimeDelta::Max()
178 ? ZX_TIME_INFINITE
179 : (TimeTicks::Now() + timeout).ToZxTime();
180 zx_signals_t signals_observed = 0;
181 zx_status_t status = zx_object_wait_one(process_.get(), ZX_TASK_TERMINATED,
182 deadline, &signals_observed);
183 if (status != ZX_OK) {
184 ZX_DLOG(ERROR, status) << "zx_object_wait_one";
185 return false;
186 }
187
188 zx_info_process_t proc_info;
189 status = zx_object_get_info(process_.get(), ZX_INFO_PROCESS, &proc_info,
190 sizeof(proc_info), nullptr, nullptr);
191 if (status != ZX_OK) {
192 ZX_DLOG(ERROR, status) << "zx_object_get_info";
193 if (exit_code)
194 *exit_code = -1;
195 return false;
196 }
197
198 if (exit_code)
199 *exit_code = proc_info.return_code;
200
201 return true;
202 }
203
Exited(int exit_code) const204 void Process::Exited(int exit_code) const {}
205
IsProcessBackgrounded() const206 bool Process::IsProcessBackgrounded() const {
207 // See SetProcessBackgrounded().
208 DCHECK(IsValid());
209 return false;
210 }
211
SetProcessBackgrounded(bool value)212 bool Process::SetProcessBackgrounded(bool value) {
213 // No process priorities on Fuchsia. TODO(fuchsia): See MG-783, and update
214 // this later if priorities are implemented.
215 return false;
216 }
217
GetPriority() const218 int Process::GetPriority() const {
219 DCHECK(IsValid());
220 // No process priorities on Fuchsia.
221 return 0;
222 }
223
224 } // namespace base
225