xref: /aosp_15_r20/art/runtime/exec_utils.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2011 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "exec_utils.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include <poll.h>
20*795d594fSAndroid Build Coastguard Worker #include <sys/types.h>
21*795d594fSAndroid Build Coastguard Worker #include <sys/wait.h>
22*795d594fSAndroid Build Coastguard Worker #include <unistd.h>
23*795d594fSAndroid Build Coastguard Worker 
24*795d594fSAndroid Build Coastguard Worker #include <chrono>
25*795d594fSAndroid Build Coastguard Worker #include <climits>
26*795d594fSAndroid Build Coastguard Worker #include <condition_variable>
27*795d594fSAndroid Build Coastguard Worker #include <cstdint>
28*795d594fSAndroid Build Coastguard Worker #include <cstring>
29*795d594fSAndroid Build Coastguard Worker #include <ctime>
30*795d594fSAndroid Build Coastguard Worker #include <mutex>
31*795d594fSAndroid Build Coastguard Worker #include <optional>
32*795d594fSAndroid Build Coastguard Worker #include <string>
33*795d594fSAndroid Build Coastguard Worker #include <string_view>
34*795d594fSAndroid Build Coastguard Worker #include <thread>
35*795d594fSAndroid Build Coastguard Worker #include <vector>
36*795d594fSAndroid Build Coastguard Worker 
37*795d594fSAndroid Build Coastguard Worker #include "android-base/file.h"
38*795d594fSAndroid Build Coastguard Worker #include "android-base/parseint.h"
39*795d594fSAndroid Build Coastguard Worker #include "android-base/scopeguard.h"
40*795d594fSAndroid Build Coastguard Worker #include "android-base/stringprintf.h"
41*795d594fSAndroid Build Coastguard Worker #include "android-base/strings.h"
42*795d594fSAndroid Build Coastguard Worker #include "android-base/unique_fd.h"
43*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
44*795d594fSAndroid Build Coastguard Worker #include "base/pidfd.h"
45*795d594fSAndroid Build Coastguard Worker #include "base/utils.h"
46*795d594fSAndroid Build Coastguard Worker #include "runtime.h"
47*795d594fSAndroid Build Coastguard Worker 
48*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
49*795d594fSAndroid Build Coastguard Worker 
50*795d594fSAndroid Build Coastguard Worker namespace {
51*795d594fSAndroid Build Coastguard Worker 
52*795d594fSAndroid Build Coastguard Worker using ::android::base::ParseInt;
53*795d594fSAndroid Build Coastguard Worker using ::android::base::ReadFileToString;
54*795d594fSAndroid Build Coastguard Worker using ::android::base::StringPrintf;
55*795d594fSAndroid Build Coastguard Worker using ::android::base::unique_fd;
56*795d594fSAndroid Build Coastguard Worker 
ToCommandLine(const std::vector<std::string> & args)57*795d594fSAndroid Build Coastguard Worker std::string ToCommandLine(const std::vector<std::string>& args) {
58*795d594fSAndroid Build Coastguard Worker   return android::base::Join(args, ' ');
59*795d594fSAndroid Build Coastguard Worker }
60*795d594fSAndroid Build Coastguard Worker 
61*795d594fSAndroid Build Coastguard Worker // Fork and execute a command specified in a subprocess.
62*795d594fSAndroid Build Coastguard Worker // If there is a runtime (Runtime::Current != nullptr) then the subprocess is created with the
63*795d594fSAndroid Build Coastguard Worker // same environment that existed when the runtime was started.
64*795d594fSAndroid Build Coastguard Worker // Returns the process id of the child process on success, -1 otherwise.
ExecWithoutWait(const std::vector<std::string> & arg_vector,bool new_process_group,std::string * error_msg)65*795d594fSAndroid Build Coastguard Worker pid_t ExecWithoutWait(const std::vector<std::string>& arg_vector,
66*795d594fSAndroid Build Coastguard Worker                       bool new_process_group,
67*795d594fSAndroid Build Coastguard Worker                       std::string* error_msg) {
68*795d594fSAndroid Build Coastguard Worker   // Convert the args to char pointers.
69*795d594fSAndroid Build Coastguard Worker   const char* program = arg_vector[0].c_str();
70*795d594fSAndroid Build Coastguard Worker   std::vector<char*> args;
71*795d594fSAndroid Build Coastguard Worker   args.reserve(arg_vector.size() + 1);
72*795d594fSAndroid Build Coastguard Worker   for (const auto& arg : arg_vector) {
73*795d594fSAndroid Build Coastguard Worker     args.push_back(const_cast<char*>(arg.c_str()));
74*795d594fSAndroid Build Coastguard Worker   }
75*795d594fSAndroid Build Coastguard Worker   args.push_back(nullptr);
76*795d594fSAndroid Build Coastguard Worker 
77*795d594fSAndroid Build Coastguard Worker   // fork and exec
78*795d594fSAndroid Build Coastguard Worker   pid_t pid = fork();
79*795d594fSAndroid Build Coastguard Worker   if (pid == 0) {
80*795d594fSAndroid Build Coastguard Worker     // no allocation allowed between fork and exec
81*795d594fSAndroid Build Coastguard Worker 
82*795d594fSAndroid Build Coastguard Worker     if (new_process_group) {
83*795d594fSAndroid Build Coastguard Worker       setpgid(0, 0);
84*795d594fSAndroid Build Coastguard Worker     }
85*795d594fSAndroid Build Coastguard Worker 
86*795d594fSAndroid Build Coastguard Worker     // (b/30160149): protect subprocesses from modifications to LD_LIBRARY_PATH, etc.
87*795d594fSAndroid Build Coastguard Worker     // Use the snapshot of the environment from the time the runtime was created.
88*795d594fSAndroid Build Coastguard Worker     char** envp = (Runtime::Current() == nullptr) ? nullptr : Runtime::Current()->GetEnvSnapshot();
89*795d594fSAndroid Build Coastguard Worker     if (envp == nullptr) {
90*795d594fSAndroid Build Coastguard Worker       execv(program, &args[0]);
91*795d594fSAndroid Build Coastguard Worker     } else {
92*795d594fSAndroid Build Coastguard Worker       execve(program, &args[0], envp);
93*795d594fSAndroid Build Coastguard Worker     }
94*795d594fSAndroid Build Coastguard Worker     // This should be regarded as a crash rather than a normal return.
95*795d594fSAndroid Build Coastguard Worker     PLOG(FATAL) << "Failed to execute (" << ToCommandLine(arg_vector) << ")";
96*795d594fSAndroid Build Coastguard Worker     UNREACHABLE();
97*795d594fSAndroid Build Coastguard Worker   } else if (pid == -1) {
98*795d594fSAndroid Build Coastguard Worker     *error_msg = StringPrintf("Failed to execute (%s) because fork failed: %s",
99*795d594fSAndroid Build Coastguard Worker                               ToCommandLine(arg_vector).c_str(),
100*795d594fSAndroid Build Coastguard Worker                               strerror(errno));
101*795d594fSAndroid Build Coastguard Worker     return -1;
102*795d594fSAndroid Build Coastguard Worker   } else {
103*795d594fSAndroid Build Coastguard Worker     return pid;
104*795d594fSAndroid Build Coastguard Worker   }
105*795d594fSAndroid Build Coastguard Worker }
106*795d594fSAndroid Build Coastguard Worker 
WaitChild(pid_t pid,const std::vector<std::string> & arg_vector,bool no_wait,std::string * error_msg)107*795d594fSAndroid Build Coastguard Worker ExecResult WaitChild(pid_t pid,
108*795d594fSAndroid Build Coastguard Worker                      const std::vector<std::string>& arg_vector,
109*795d594fSAndroid Build Coastguard Worker                      bool no_wait,
110*795d594fSAndroid Build Coastguard Worker                      std::string* error_msg) {
111*795d594fSAndroid Build Coastguard Worker   siginfo_t info;
112*795d594fSAndroid Build Coastguard Worker   // WNOWAIT leaves the child in a waitable state. The call is still blocking.
113*795d594fSAndroid Build Coastguard Worker   int options = WEXITED | (no_wait ? WNOWAIT : 0);
114*795d594fSAndroid Build Coastguard Worker   if (TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, options)) != 0) {
115*795d594fSAndroid Build Coastguard Worker     *error_msg = StringPrintf("waitid failed for (%s) pid %d: %s",
116*795d594fSAndroid Build Coastguard Worker                               ToCommandLine(arg_vector).c_str(),
117*795d594fSAndroid Build Coastguard Worker                               pid,
118*795d594fSAndroid Build Coastguard Worker                               strerror(errno));
119*795d594fSAndroid Build Coastguard Worker     return {.status = ExecResult::kUnknown};
120*795d594fSAndroid Build Coastguard Worker   }
121*795d594fSAndroid Build Coastguard Worker   if (info.si_pid != pid) {
122*795d594fSAndroid Build Coastguard Worker     *error_msg = StringPrintf("waitid failed for (%s): wanted pid %d, got %d: %s",
123*795d594fSAndroid Build Coastguard Worker                               ToCommandLine(arg_vector).c_str(),
124*795d594fSAndroid Build Coastguard Worker                               pid,
125*795d594fSAndroid Build Coastguard Worker                               info.si_pid,
126*795d594fSAndroid Build Coastguard Worker                               strerror(errno));
127*795d594fSAndroid Build Coastguard Worker     return {.status = ExecResult::kUnknown};
128*795d594fSAndroid Build Coastguard Worker   }
129*795d594fSAndroid Build Coastguard Worker   if (info.si_code != CLD_EXITED) {
130*795d594fSAndroid Build Coastguard Worker     *error_msg =
131*795d594fSAndroid Build Coastguard Worker         StringPrintf("Failed to execute (%s) because the child process is terminated by signal %d",
132*795d594fSAndroid Build Coastguard Worker                      ToCommandLine(arg_vector).c_str(),
133*795d594fSAndroid Build Coastguard Worker                      info.si_status);
134*795d594fSAndroid Build Coastguard Worker     return {.status = ExecResult::kSignaled, .signal = info.si_status};
135*795d594fSAndroid Build Coastguard Worker   }
136*795d594fSAndroid Build Coastguard Worker   return {.status = ExecResult::kExited, .exit_code = info.si_status};
137*795d594fSAndroid Build Coastguard Worker }
138*795d594fSAndroid Build Coastguard Worker 
139*795d594fSAndroid Build Coastguard Worker // A fallback implementation of `WaitChildWithTimeout` that creates a thread to wait instead of
140*795d594fSAndroid Build Coastguard Worker // relying on `pidfd_open`.
WaitChildWithTimeoutFallback(pid_t pid,const std::vector<std::string> & arg_vector,int timeout_ms,std::string * error_msg)141*795d594fSAndroid Build Coastguard Worker ExecResult WaitChildWithTimeoutFallback(pid_t pid,
142*795d594fSAndroid Build Coastguard Worker                                         const std::vector<std::string>& arg_vector,
143*795d594fSAndroid Build Coastguard Worker                                         int timeout_ms,
144*795d594fSAndroid Build Coastguard Worker                                         std::string* error_msg) {
145*795d594fSAndroid Build Coastguard Worker   bool child_exited = false;
146*795d594fSAndroid Build Coastguard Worker   bool timed_out = false;
147*795d594fSAndroid Build Coastguard Worker   std::condition_variable cv;
148*795d594fSAndroid Build Coastguard Worker   std::mutex m;
149*795d594fSAndroid Build Coastguard Worker 
150*795d594fSAndroid Build Coastguard Worker   std::thread wait_thread([&]() {
151*795d594fSAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lock(m);
152*795d594fSAndroid Build Coastguard Worker     if (!cv.wait_for(lock, std::chrono::milliseconds(timeout_ms), [&] { return child_exited; })) {
153*795d594fSAndroid Build Coastguard Worker       timed_out = true;
154*795d594fSAndroid Build Coastguard Worker       kill(pid, SIGKILL);
155*795d594fSAndroid Build Coastguard Worker     }
156*795d594fSAndroid Build Coastguard Worker   });
157*795d594fSAndroid Build Coastguard Worker 
158*795d594fSAndroid Build Coastguard Worker   ExecResult result = WaitChild(pid, arg_vector, /*no_wait=*/true, error_msg);
159*795d594fSAndroid Build Coastguard Worker 
160*795d594fSAndroid Build Coastguard Worker   {
161*795d594fSAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lock(m);
162*795d594fSAndroid Build Coastguard Worker     child_exited = true;
163*795d594fSAndroid Build Coastguard Worker   }
164*795d594fSAndroid Build Coastguard Worker   cv.notify_all();
165*795d594fSAndroid Build Coastguard Worker   wait_thread.join();
166*795d594fSAndroid Build Coastguard Worker 
167*795d594fSAndroid Build Coastguard Worker   // The timeout error should have a higher priority than any other error.
168*795d594fSAndroid Build Coastguard Worker   if (timed_out) {
169*795d594fSAndroid Build Coastguard Worker     *error_msg =
170*795d594fSAndroid Build Coastguard Worker         StringPrintf("Failed to execute (%s) because the child process timed out after %dms",
171*795d594fSAndroid Build Coastguard Worker                      ToCommandLine(arg_vector).c_str(),
172*795d594fSAndroid Build Coastguard Worker                      timeout_ms);
173*795d594fSAndroid Build Coastguard Worker     return ExecResult{.status = ExecResult::kTimedOut};
174*795d594fSAndroid Build Coastguard Worker   }
175*795d594fSAndroid Build Coastguard Worker 
176*795d594fSAndroid Build Coastguard Worker   return result;
177*795d594fSAndroid Build Coastguard Worker }
178*795d594fSAndroid Build Coastguard Worker 
179*795d594fSAndroid Build Coastguard Worker // Waits for the child process to finish and leaves the child in a waitable state.
WaitChildWithTimeout(pid_t pid,unique_fd pidfd,const std::vector<std::string> & arg_vector,int timeout_ms,std::string * error_msg)180*795d594fSAndroid Build Coastguard Worker ExecResult WaitChildWithTimeout(pid_t pid,
181*795d594fSAndroid Build Coastguard Worker                                 unique_fd pidfd,
182*795d594fSAndroid Build Coastguard Worker                                 const std::vector<std::string>& arg_vector,
183*795d594fSAndroid Build Coastguard Worker                                 int timeout_ms,
184*795d594fSAndroid Build Coastguard Worker                                 std::string* error_msg) {
185*795d594fSAndroid Build Coastguard Worker   auto cleanup = android::base::make_scope_guard([&]() {
186*795d594fSAndroid Build Coastguard Worker     kill(pid, SIGKILL);
187*795d594fSAndroid Build Coastguard Worker     std::string ignored_error_msg;
188*795d594fSAndroid Build Coastguard Worker     WaitChild(pid, arg_vector, /*no_wait=*/true, &ignored_error_msg);
189*795d594fSAndroid Build Coastguard Worker   });
190*795d594fSAndroid Build Coastguard Worker 
191*795d594fSAndroid Build Coastguard Worker   struct pollfd pfd;
192*795d594fSAndroid Build Coastguard Worker   pfd.fd = pidfd.get();
193*795d594fSAndroid Build Coastguard Worker   pfd.events = POLLIN;
194*795d594fSAndroid Build Coastguard Worker   int poll_ret = TEMP_FAILURE_RETRY(poll(&pfd, /*nfds=*/1, timeout_ms));
195*795d594fSAndroid Build Coastguard Worker 
196*795d594fSAndroid Build Coastguard Worker   pidfd.reset();
197*795d594fSAndroid Build Coastguard Worker 
198*795d594fSAndroid Build Coastguard Worker   if (poll_ret < 0) {
199*795d594fSAndroid Build Coastguard Worker     *error_msg = StringPrintf("poll failed for pid %d: %s", pid, strerror(errno));
200*795d594fSAndroid Build Coastguard Worker     return {.status = ExecResult::kUnknown};
201*795d594fSAndroid Build Coastguard Worker   }
202*795d594fSAndroid Build Coastguard Worker   if (poll_ret == 0) {
203*795d594fSAndroid Build Coastguard Worker     *error_msg =
204*795d594fSAndroid Build Coastguard Worker         StringPrintf("Failed to execute (%s) because the child process timed out after %dms",
205*795d594fSAndroid Build Coastguard Worker                      ToCommandLine(arg_vector).c_str(),
206*795d594fSAndroid Build Coastguard Worker                      timeout_ms);
207*795d594fSAndroid Build Coastguard Worker     return {.status = ExecResult::kTimedOut};
208*795d594fSAndroid Build Coastguard Worker   }
209*795d594fSAndroid Build Coastguard Worker 
210*795d594fSAndroid Build Coastguard Worker   cleanup.Disable();
211*795d594fSAndroid Build Coastguard Worker   return WaitChild(pid, arg_vector, /*no_wait=*/true, error_msg);
212*795d594fSAndroid Build Coastguard Worker }
213*795d594fSAndroid Build Coastguard Worker 
ParseProcStat(const std::string & stat_content,int64_t ticks_per_sec,int64_t * cpu_time_ms)214*795d594fSAndroid Build Coastguard Worker bool ParseProcStat(const std::string& stat_content,
215*795d594fSAndroid Build Coastguard Worker                    int64_t ticks_per_sec,
216*795d594fSAndroid Build Coastguard Worker                    /*out*/ int64_t* cpu_time_ms) {
217*795d594fSAndroid Build Coastguard Worker   size_t pos = stat_content.rfind(") ");
218*795d594fSAndroid Build Coastguard Worker   if (pos == std::string::npos) {
219*795d594fSAndroid Build Coastguard Worker     return false;
220*795d594fSAndroid Build Coastguard Worker   }
221*795d594fSAndroid Build Coastguard Worker   std::vector<std::string> stat_fields;
222*795d594fSAndroid Build Coastguard Worker   // Skip the first two fields. The second field is the parenthesized process filename, which can
223*795d594fSAndroid Build Coastguard Worker   // contain anything, including spaces.
224*795d594fSAndroid Build Coastguard Worker   Split(std::string_view(stat_content).substr(pos + 2), ' ', &stat_fields);
225*795d594fSAndroid Build Coastguard Worker   constexpr int kSkippedFields = 2;
226*795d594fSAndroid Build Coastguard Worker   int64_t utime, stime, cutime, cstime;
227*795d594fSAndroid Build Coastguard Worker   if (stat_fields.size() < 22 - kSkippedFields ||
228*795d594fSAndroid Build Coastguard Worker       !ParseInt(stat_fields[13 - kSkippedFields], &utime) ||
229*795d594fSAndroid Build Coastguard Worker       !ParseInt(stat_fields[14 - kSkippedFields], &stime) ||
230*795d594fSAndroid Build Coastguard Worker       !ParseInt(stat_fields[15 - kSkippedFields], &cutime) ||
231*795d594fSAndroid Build Coastguard Worker       !ParseInt(stat_fields[16 - kSkippedFields], &cstime)) {
232*795d594fSAndroid Build Coastguard Worker     return false;
233*795d594fSAndroid Build Coastguard Worker   }
234*795d594fSAndroid Build Coastguard Worker   *cpu_time_ms = (utime + stime + cutime + cstime) * 1000 / ticks_per_sec;
235*795d594fSAndroid Build Coastguard Worker   return true;
236*795d594fSAndroid Build Coastguard Worker }
237*795d594fSAndroid Build Coastguard Worker 
238*795d594fSAndroid Build Coastguard Worker }  // namespace
239*795d594fSAndroid Build Coastguard Worker 
ExecAndReturnCode(const std::vector<std::string> & arg_vector,std::string * error_msg) const240*795d594fSAndroid Build Coastguard Worker int ExecUtils::ExecAndReturnCode(const std::vector<std::string>& arg_vector,
241*795d594fSAndroid Build Coastguard Worker                                  std::string* error_msg) const {
242*795d594fSAndroid Build Coastguard Worker   return ExecAndReturnResult(arg_vector, /*timeout_sec=*/-1, error_msg).exit_code;
243*795d594fSAndroid Build Coastguard Worker }
244*795d594fSAndroid Build Coastguard Worker 
ExecAndReturnResult(const std::vector<std::string> & arg_vector,int timeout_sec,std::string * error_msg) const245*795d594fSAndroid Build Coastguard Worker ExecResult ExecUtils::ExecAndReturnResult(const std::vector<std::string>& arg_vector,
246*795d594fSAndroid Build Coastguard Worker                                           int timeout_sec,
247*795d594fSAndroid Build Coastguard Worker                                           std::string* error_msg) const {
248*795d594fSAndroid Build Coastguard Worker   return ExecAndReturnResult(arg_vector,
249*795d594fSAndroid Build Coastguard Worker                              timeout_sec,
250*795d594fSAndroid Build Coastguard Worker                              ExecCallbacks(),
251*795d594fSAndroid Build Coastguard Worker                              /*new_process_group=*/false,
252*795d594fSAndroid Build Coastguard Worker                              /*stat=*/nullptr,
253*795d594fSAndroid Build Coastguard Worker                              error_msg);
254*795d594fSAndroid Build Coastguard Worker }
255*795d594fSAndroid Build Coastguard Worker 
ExecAndReturnResult(const std::vector<std::string> & arg_vector,int timeout_sec,const ExecCallbacks & callbacks,bool new_process_group,ProcessStat * stat,std::string * error_msg) const256*795d594fSAndroid Build Coastguard Worker ExecResult ExecUtils::ExecAndReturnResult(const std::vector<std::string>& arg_vector,
257*795d594fSAndroid Build Coastguard Worker                                           int timeout_sec,
258*795d594fSAndroid Build Coastguard Worker                                           const ExecCallbacks& callbacks,
259*795d594fSAndroid Build Coastguard Worker                                           bool new_process_group,
260*795d594fSAndroid Build Coastguard Worker                                           /*out*/ ProcessStat* stat,
261*795d594fSAndroid Build Coastguard Worker                                           /*out*/ std::string* error_msg) const {
262*795d594fSAndroid Build Coastguard Worker   if (timeout_sec > INT_MAX / 1000) {
263*795d594fSAndroid Build Coastguard Worker     *error_msg = "Timeout too large";
264*795d594fSAndroid Build Coastguard Worker     return {.status = ExecResult::kStartFailed};
265*795d594fSAndroid Build Coastguard Worker   }
266*795d594fSAndroid Build Coastguard Worker 
267*795d594fSAndroid Build Coastguard Worker   // Start subprocess.
268*795d594fSAndroid Build Coastguard Worker   pid_t pid = ExecWithoutWait(arg_vector, new_process_group, error_msg);
269*795d594fSAndroid Build Coastguard Worker   if (pid == -1) {
270*795d594fSAndroid Build Coastguard Worker     return {.status = ExecResult::kStartFailed};
271*795d594fSAndroid Build Coastguard Worker   }
272*795d594fSAndroid Build Coastguard Worker 
273*795d594fSAndroid Build Coastguard Worker   std::string stat_error_msg;
274*795d594fSAndroid Build Coastguard Worker   std::optional<int64_t> start_time = GetUptimeMs(&stat_error_msg);
275*795d594fSAndroid Build Coastguard Worker   callbacks.on_start(pid);
276*795d594fSAndroid Build Coastguard Worker 
277*795d594fSAndroid Build Coastguard Worker   // Wait for subprocess to finish.
278*795d594fSAndroid Build Coastguard Worker   ExecResult result;
279*795d594fSAndroid Build Coastguard Worker   if (timeout_sec >= 0) {
280*795d594fSAndroid Build Coastguard Worker     unique_fd pidfd = PidfdOpen(pid);
281*795d594fSAndroid Build Coastguard Worker     if (pidfd.get() >= 0) {
282*795d594fSAndroid Build Coastguard Worker       result =
283*795d594fSAndroid Build Coastguard Worker           WaitChildWithTimeout(pid, std::move(pidfd), arg_vector, timeout_sec * 1000, error_msg);
284*795d594fSAndroid Build Coastguard Worker     } else {
285*795d594fSAndroid Build Coastguard Worker       LOG(DEBUG) << StringPrintf(
286*795d594fSAndroid Build Coastguard Worker           "pidfd_open failed for pid %d: %s, falling back", pid, strerror(errno));
287*795d594fSAndroid Build Coastguard Worker       result = WaitChildWithTimeoutFallback(pid, arg_vector, timeout_sec * 1000, error_msg);
288*795d594fSAndroid Build Coastguard Worker     }
289*795d594fSAndroid Build Coastguard Worker   } else {
290*795d594fSAndroid Build Coastguard Worker     result = WaitChild(pid, arg_vector, /*no_wait=*/true, error_msg);
291*795d594fSAndroid Build Coastguard Worker   }
292*795d594fSAndroid Build Coastguard Worker 
293*795d594fSAndroid Build Coastguard Worker   if (stat != nullptr) {
294*795d594fSAndroid Build Coastguard Worker     if (!start_time.has_value() || !GetStat(pid, start_time.value(), stat, &stat_error_msg)) {
295*795d594fSAndroid Build Coastguard Worker       LOG(ERROR) << "Failed to get process stat: " << stat_error_msg;
296*795d594fSAndroid Build Coastguard Worker     }
297*795d594fSAndroid Build Coastguard Worker   }
298*795d594fSAndroid Build Coastguard Worker 
299*795d594fSAndroid Build Coastguard Worker   callbacks.on_end(pid);
300*795d594fSAndroid Build Coastguard Worker 
301*795d594fSAndroid Build Coastguard Worker   std::string local_error_msg;
302*795d594fSAndroid Build Coastguard Worker   // TODO(jiakaiz): Use better logic to detect waitid failure.
303*795d594fSAndroid Build Coastguard Worker   if (WaitChild(pid, arg_vector, /*no_wait=*/false, &local_error_msg).status ==
304*795d594fSAndroid Build Coastguard Worker       ExecResult::kUnknown) {
305*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to clean up child process '" << arg_vector[0] << "': " << local_error_msg;
306*795d594fSAndroid Build Coastguard Worker   }
307*795d594fSAndroid Build Coastguard Worker 
308*795d594fSAndroid Build Coastguard Worker   return result;
309*795d594fSAndroid Build Coastguard Worker }
310*795d594fSAndroid Build Coastguard Worker 
Exec(const std::vector<std::string> & arg_vector,std::string * error_msg) const311*795d594fSAndroid Build Coastguard Worker bool ExecUtils::Exec(const std::vector<std::string>& arg_vector, std::string* error_msg) const {
312*795d594fSAndroid Build Coastguard Worker   int status = ExecAndReturnCode(arg_vector, error_msg);
313*795d594fSAndroid Build Coastguard Worker   if (status < 0) {
314*795d594fSAndroid Build Coastguard Worker     // Internal error. The error message is already set.
315*795d594fSAndroid Build Coastguard Worker     return false;
316*795d594fSAndroid Build Coastguard Worker   }
317*795d594fSAndroid Build Coastguard Worker   if (status > 0) {
318*795d594fSAndroid Build Coastguard Worker     *error_msg =
319*795d594fSAndroid Build Coastguard Worker         StringPrintf("Failed to execute (%s) because the child process returns non-zero exit code",
320*795d594fSAndroid Build Coastguard Worker                      ToCommandLine(arg_vector).c_str());
321*795d594fSAndroid Build Coastguard Worker     return false;
322*795d594fSAndroid Build Coastguard Worker   }
323*795d594fSAndroid Build Coastguard Worker   return true;
324*795d594fSAndroid Build Coastguard Worker }
325*795d594fSAndroid Build Coastguard Worker 
PidfdOpen(pid_t pid) const326*795d594fSAndroid Build Coastguard Worker unique_fd ExecUtils::PidfdOpen(pid_t pid) const { return art::PidfdOpen(pid, /*flags=*/0); }
327*795d594fSAndroid Build Coastguard Worker 
GetProcStat(pid_t pid) const328*795d594fSAndroid Build Coastguard Worker std::string ExecUtils::GetProcStat(pid_t pid) const {
329*795d594fSAndroid Build Coastguard Worker   std::string stat_content;
330*795d594fSAndroid Build Coastguard Worker   if (!ReadFileToString(StringPrintf("/proc/%d/stat", pid), &stat_content)) {
331*795d594fSAndroid Build Coastguard Worker     stat_content = "";
332*795d594fSAndroid Build Coastguard Worker   }
333*795d594fSAndroid Build Coastguard Worker   return stat_content;
334*795d594fSAndroid Build Coastguard Worker }
335*795d594fSAndroid Build Coastguard Worker 
GetUptimeMs(std::string * error_msg) const336*795d594fSAndroid Build Coastguard Worker std::optional<int64_t> ExecUtils::GetUptimeMs(std::string* error_msg) const {
337*795d594fSAndroid Build Coastguard Worker   timespec t;
338*795d594fSAndroid Build Coastguard Worker   if (clock_gettime(CLOCK_MONOTONIC, &t) != 0) {
339*795d594fSAndroid Build Coastguard Worker     *error_msg = ART_FORMAT("Failed to get uptime: {}", strerror(errno));
340*795d594fSAndroid Build Coastguard Worker     return std::nullopt;
341*795d594fSAndroid Build Coastguard Worker   }
342*795d594fSAndroid Build Coastguard Worker   return t.tv_sec * 1000 + t.tv_nsec / 1000000;
343*795d594fSAndroid Build Coastguard Worker }
344*795d594fSAndroid Build Coastguard Worker 
GetTicksPerSec() const345*795d594fSAndroid Build Coastguard Worker int64_t ExecUtils::GetTicksPerSec() const { return sysconf(_SC_CLK_TCK); }
346*795d594fSAndroid Build Coastguard Worker 
GetStat(pid_t pid,int64_t start_time,ProcessStat * stat,std::string * error_msg) const347*795d594fSAndroid Build Coastguard Worker bool ExecUtils::GetStat(pid_t pid,
348*795d594fSAndroid Build Coastguard Worker                         int64_t start_time,
349*795d594fSAndroid Build Coastguard Worker                         /*out*/ ProcessStat* stat,
350*795d594fSAndroid Build Coastguard Worker                         /*out*/ std::string* error_msg) const {
351*795d594fSAndroid Build Coastguard Worker   std::optional<int64_t> uptime_ms = GetUptimeMs(error_msg);
352*795d594fSAndroid Build Coastguard Worker   if (!uptime_ms.has_value()) {
353*795d594fSAndroid Build Coastguard Worker     return false;
354*795d594fSAndroid Build Coastguard Worker   }
355*795d594fSAndroid Build Coastguard Worker   std::string stat_content = GetProcStat(pid);
356*795d594fSAndroid Build Coastguard Worker   if (stat_content.empty()) {
357*795d594fSAndroid Build Coastguard Worker     *error_msg = StringPrintf("Failed to read /proc/%d/stat: %s", pid, strerror(errno));
358*795d594fSAndroid Build Coastguard Worker     return false;
359*795d594fSAndroid Build Coastguard Worker   }
360*795d594fSAndroid Build Coastguard Worker   int64_t ticks_per_sec = GetTicksPerSec();
361*795d594fSAndroid Build Coastguard Worker   if (!ParseProcStat(stat_content, ticks_per_sec, &stat->cpu_time_ms)) {
362*795d594fSAndroid Build Coastguard Worker     *error_msg = StringPrintf("Failed to parse /proc/%d/stat '%s'", pid, stat_content.c_str());
363*795d594fSAndroid Build Coastguard Worker     return false;
364*795d594fSAndroid Build Coastguard Worker   }
365*795d594fSAndroid Build Coastguard Worker   stat->wall_time_ms = uptime_ms.value() - start_time;
366*795d594fSAndroid Build Coastguard Worker   return true;
367*795d594fSAndroid Build Coastguard Worker }
368*795d594fSAndroid Build Coastguard Worker 
369*795d594fSAndroid Build Coastguard Worker }  // namespace art
370