/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "UtilsHost.h" #include #include #include #include #include #include #include "FdUtils.h" #include "Utils.h" namespace android { using android::binder::unique_fd; CommandResult::~CommandResult() { if (!pid.has_value()) return; if (*pid == 0) { ALOGW("%s: PID is unexpectedly 0, won't kill it", __PRETTY_FUNCTION__); return; } ALOGE_IF(kill(*pid, SIGKILL) != 0, "kill(%d): %s", *pid, strerror(errno)); while (pid.has_value()) { int status; LOG_HOST("%s: Waiting for PID %d to exit.", __PRETTY_FUNCTION__, *pid); int waitres = waitpid(*pid, &status, 0); if (waitres == -1) { ALOGE("%s: waitpid(%d): %s", __PRETTY_FUNCTION__, *pid, strerror(errno)); break; } if (WIFEXITED(status)) { LOG_HOST("%s: PID %d exited.", __PRETTY_FUNCTION__, *pid); pid.reset(); } else if (WIFSIGNALED(status)) { LOG_HOST("%s: PID %d terminated by signal %d.", __PRETTY_FUNCTION__, *pid, WTERMSIG(status)); pid.reset(); } else if (WIFSTOPPED(status)) { ALOGW("%s: pid %d stopped", __PRETTY_FUNCTION__, *pid); } else if (WIFCONTINUED(status)) { ALOGW("%s: pid %d continued", __PRETTY_FUNCTION__, *pid); } } } std::ostream& operator<<(std::ostream& os, const CommandResult& res) { if (res.exitCode) os << "code=" << *res.exitCode; if (res.signal) os << "signal=" << *res.signal; if (res.pid) os << ", pid=" << *res.pid; return os << ", stdout=" << res.stdoutStr << ", stderr=" << res.stderrStr; } std::string CommandResult::toString() const { std::stringstream ss; ss << (*this); return ss.str(); } std::optional execute(std::vector argStringVec, const std::function& end) { // turn vector into null-terminated char* vector. std::vector argv; argv.reserve(argStringVec.size() + 1); for (auto& arg : argStringVec) argv.push_back(arg.data()); argv.push_back(nullptr); CommandResult ret; unique_fd outWrite; if (!binder::Pipe(&ret.outPipe, &outWrite)) { PLOGE("pipe() for outPipe"); return {}; } unique_fd errWrite; if (!binder::Pipe(&ret.errPipe, &errWrite)) { PLOGE("pipe() for errPipe"); return {}; } int pid = fork(); if (pid == -1) { PLOGE("fork()"); return {}; } if (pid == 0) { // child ret.outPipe.reset(); ret.errPipe.reset(); int res = TEMP_FAILURE_RETRY(dup2(outWrite.get(), STDOUT_FILENO)); LOG_ALWAYS_FATAL_IF(-1 == res, "dup2(outPipe): %s", strerror(errno)); outWrite.reset(); res = TEMP_FAILURE_RETRY(dup2(errWrite.get(), STDERR_FILENO)); LOG_ALWAYS_FATAL_IF(-1 == res, "dup2(errPipe): %s", strerror(errno)); errWrite.reset(); execvp(argv[0], argv.data()); LOG_ALWAYS_FATAL("execvp() returns"); } // parent outWrite.reset(); errWrite.reset(); ret.pid = pid; auto handlePoll = [](unique_fd* fd, const pollfd* pfd, std::string* s) { if (!fd->ok()) return true; if (pfd->revents & POLLIN) { char buf[1024]; ssize_t n = TEMP_FAILURE_RETRY(read(fd->get(), buf, sizeof(buf))); if (n < 0) return false; if (n > 0) *s += std::string_view(buf, n); } if (pfd->revents & POLLHUP) { fd->reset(); } return true; }; // Drain both stdout and stderr. Check end() regularly until both are closed. while (ret.outPipe.ok() || ret.errPipe.ok()) { pollfd fds[2]; pollfd *outPollFd = nullptr, *errPollFd = nullptr; memset(fds, 0, sizeof(fds)); nfds_t nfds = 0; if (ret.outPipe.ok()) { outPollFd = &fds[nfds++]; *outPollFd = {.fd = ret.outPipe.get(), .events = POLLIN}; } if (ret.errPipe.ok()) { errPollFd = &fds[nfds++]; *errPollFd = {.fd = ret.errPipe.get(), .events = POLLIN}; } int pollRet = poll(fds, nfds, 1000 /* ms timeout */); if (pollRet == -1) { PLOGE("poll()"); return {}; } if (!handlePoll(&ret.outPipe, outPollFd, &ret.stdoutStr)) { PLOGE("read(stdout)"); return {}; } if (!handlePoll(&ret.errPipe, errPollFd, &ret.stderrStr)) { PLOGE("read(stderr)"); return {}; } if (end && end(ret)) return ret; } // If both stdout and stderr are closed by the subprocess, it may or may not be terminated. while (ret.pid.has_value()) { int status; auto exitPid = waitpid(pid, &status, 0); if (exitPid == -1) { PLOGE("waitpid(%d)", pid); return {}; } if (exitPid == pid) { if (WIFEXITED(status)) { ret.pid = std::nullopt; ret.exitCode = WEXITSTATUS(status); } else if (WIFSIGNALED(status)) { ret.pid = std::nullopt; ret.signal = WTERMSIG(status); } else if (WIFSTOPPED(status)) { ALOGW("%s: pid %d stopped", __PRETTY_FUNCTION__, *ret.pid); } else if (WIFCONTINUED(status)) { ALOGW("%s: pid %d continued", __PRETTY_FUNCTION__, *ret.pid); } } // ret is not changed unless the process is terminated (where pid == nullopt). Hence there // is no need to check the predicate `end(ret)`. } return ret; } } // namespace android