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