diff options
author | 2022-07-05 08:15:37 +0000 | |
---|---|---|
committer | 2022-07-05 10:35:07 +0000 | |
commit | ff95ad517297384d4a2ea589490019f90d637e17 (patch) | |
tree | 8632d5ae79887bdc0ab671f091142f2c38a49728 /runtime/exec_utils.cc | |
parent | c7df8d12ea3228af445fb821c3cac13ca85a9e5f (diff) |
Revert "Update ExecUtils to support artd use cases."
This reverts commit f0061f62fbd5e4766220c154d914e7b9d07a86eb.
Reason for revert: Broke LUCI.
Change-Id: Iec793a667545a8469f2a712135353e816c623262
Diffstat (limited to 'runtime/exec_utils.cc')
-rw-r--r-- | runtime/exec_utils.cc | 184 |
1 files changed, 80 insertions, 104 deletions
diff --git a/runtime/exec_utils.cc b/runtime/exec_utils.cc index 6e2a5b40f0..463d4580cf 100644 --- a/runtime/exec_utils.cc +++ b/runtime/exec_utils.cc @@ -16,31 +16,21 @@ #include "exec_utils.h" -#include <poll.h> #include <sys/types.h> #include <sys/wait.h> -#include <unistd.h> - -#include "base/macros.h" - -#ifdef __BIONIC__ -#include <sys/pidfd.h> -#endif - -#include <cstdint> #include <string> #include <vector> -#include "android-base/scopeguard.h" #include "android-base/stringprintf.h" #include "android-base/strings.h" + #include "runtime.h" namespace art { -namespace { +using android::base::StringPrintf; -using ::android::base::StringPrintf; +namespace { std::string ToCommandLine(const std::vector<std::string>& args) { return android::base::Join(args, ' '); @@ -50,7 +40,7 @@ std::string ToCommandLine(const std::vector<std::string>& args) { // If there is a runtime (Runtime::Current != nullptr) then the subprocess is created with the // same environment that existed when the runtime was started. // Returns the process id of the child process on success, -1 otherwise. -pid_t ExecWithoutWait(const std::vector<std::string>& arg_vector, std::string* error_msg) { +pid_t ExecWithoutWait(std::vector<std::string>& arg_vector) { // Convert the args to char pointers. const char* program = arg_vector[0].c_str(); std::vector<char*> args; @@ -75,124 +65,110 @@ pid_t ExecWithoutWait(const std::vector<std::string>& arg_vector, std::string* e } else { execve(program, &args[0], envp); } - // This should be regarded as a crash rather than a normal return. - PLOG(FATAL) << "Failed to execute (" << ToCommandLine(arg_vector) << ")"; - UNREACHABLE(); - } else if (pid == -1) { - *error_msg = StringPrintf("Failed to execute (%s) because fork failed: %s", - ToCommandLine(arg_vector).c_str(), - strerror(errno)); - return -1; + PLOG(ERROR) << "Failed to execve(" << ToCommandLine(arg_vector) << ")"; + // _exit to avoid atexit handlers in child. + _exit(1); } else { return pid; } } -int WaitChild(pid_t pid, const std::vector<std::string>& arg_vector, std::string* error_msg) { - int status = -1; - pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)); - if (got_pid != pid) { - *error_msg = - StringPrintf("Failed to execute (%s) because waitpid failed: wanted %d, got %d: %s", - ToCommandLine(arg_vector).c_str(), - pid, - got_pid, - strerror(errno)); - return -1; - } - if (!WIFEXITED(status)) { - *error_msg = - StringPrintf("Failed to execute (%s) because the child process is terminated by signal %d", - ToCommandLine(arg_vector).c_str(), - WTERMSIG(status)); - return -1; - } - return WEXITSTATUS(status); -} +} // namespace -int WaitChildWithTimeout(pid_t pid, - const std::vector<std::string>& arg_vector, - int timeout_sec, - bool* timed_out, - std::string* error_msg) { - auto cleanup = android::base::make_scope_guard([&]() { - kill(pid, SIGKILL); - std::string ignored_error_msg; - WaitChild(pid, arg_vector, &ignored_error_msg); - }); - -#ifdef __BIONIC__ - int pidfd = pidfd_open(pid, /*flags=*/0); -#else - // There is no glibc wrapper for pidfd_open. - constexpr int SYS_pidfd_open = 434; - int pidfd = syscall(SYS_pidfd_open, pid, /*flags=*/0); -#endif - if (pidfd < 0) { - *error_msg = StringPrintf("pidfd_open failed for pid %d: %s", pid, strerror(errno)); +int ExecAndReturnCode(std::vector<std::string>& arg_vector, std::string* error_msg) { + pid_t pid = ExecWithoutWait(arg_vector); + if (pid == -1) { + *error_msg = StringPrintf("Failed to execv(%s) because fork failed: %s", + ToCommandLine(arg_vector).c_str(), strerror(errno)); return -1; } - struct pollfd pfd; - pfd.fd = pidfd; - pfd.events = POLLIN; - int poll_ret = TEMP_FAILURE_RETRY(poll(&pfd, /*nfds=*/1, timeout_sec * 1000)); - - close(pidfd); - - if (poll_ret < 0) { - *error_msg = StringPrintf("poll failed for pid %d: %s", pid, strerror(errno)); + // wait for subprocess to finish + int status = -1; + pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)); + if (got_pid != pid) { + *error_msg = StringPrintf("Failed after fork for execv(%s) because waitpid failed: " + "wanted %d, got %d: %s", + ToCommandLine(arg_vector).c_str(), pid, got_pid, strerror(errno)); return -1; } - if (poll_ret == 0) { - *timed_out = true; - *error_msg = StringPrintf("Child process %d timed out after %ds. Killing it", pid, timeout_sec); - return -1; + if (WIFEXITED(status)) { + return WEXITSTATUS(status); } - - cleanup.Disable(); - return WaitChild(pid, arg_vector, error_msg); + return -1; } -} // namespace +int ExecAndReturnCode(std::vector<std::string>& arg_vector, + time_t timeout_secs, + bool* timed_out, + std::string* error_msg) { + *timed_out = false; -int ExecAndReturnCode(const std::vector<std::string>& arg_vector, std::string* error_msg) { // Start subprocess. - pid_t pid = ExecWithoutWait(arg_vector, error_msg); + pid_t pid = ExecWithoutWait(arg_vector); if (pid == -1) { + *error_msg = StringPrintf("Failed to execv(%s) because fork failed: %s", + ToCommandLine(arg_vector).c_str(), strerror(errno)); return -1; } - // Wait for subprocess to finish. - return WaitChild(pid, arg_vector, error_msg); -} + // Add SIGCHLD to the signal set. + sigset_t child_mask, original_mask; + sigemptyset(&child_mask); + sigaddset(&child_mask, SIGCHLD); + if (sigprocmask(SIG_BLOCK, &child_mask, &original_mask) == -1) { + *error_msg = StringPrintf("Failed to set sigprocmask(): %s", strerror(errno)); + return -1; + } -int ExecAndReturnCode(const std::vector<std::string>& arg_vector, - int timeout_sec, - bool* timed_out, - std::string* error_msg) { - *timed_out = false; + // Wait for a SIGCHLD notification. + errno = 0; + timespec ts = {timeout_secs, 0}; + int wait_result = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, nullptr, &ts)); + int wait_errno = errno; + + // Restore the original signal set. + if (sigprocmask(SIG_SETMASK, &original_mask, nullptr) == -1) { + *error_msg = StringPrintf("Fail to restore sigprocmask(): %s", strerror(errno)); + if (wait_result == 0) { + return -1; + } + } - // Start subprocess. - pid_t pid = ExecWithoutWait(arg_vector, error_msg); - if (pid == -1) { - return -1; + // Having restored the signal set, see if we need to terminate the subprocess. + if (wait_result == -1) { + if (wait_errno == EAGAIN) { + *error_msg = "Timed out."; + *timed_out = true; + } else { + *error_msg = StringPrintf("Failed to sigtimedwait(): %s", strerror(errno)); + } + if (kill(pid, SIGKILL) != 0) { + PLOG(ERROR) << "Failed to kill() subprocess: "; + } } // Wait for subprocess to finish. - return WaitChildWithTimeout(pid, arg_vector, timeout_sec, timed_out, error_msg); + int status = -1; + pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)); + if (got_pid != pid) { + *error_msg = StringPrintf("Failed after fork for execv(%s) because waitpid failed: " + "wanted %d, got %d: %s", + ToCommandLine(arg_vector).c_str(), pid, got_pid, strerror(errno)); + return -1; + } + if (WIFEXITED(status)) { + return WEXITSTATUS(status); + } + return -1; } -bool Exec(const std::vector<std::string>& arg_vector, std::string* error_msg) { + +bool Exec(std::vector<std::string>& arg_vector, std::string* error_msg) { int status = ExecAndReturnCode(arg_vector, error_msg); - if (status < 0) { - // Internal error. The error message is already set. - return false; - } - if (status > 0) { - *error_msg = - StringPrintf("Failed to execute (%s) because the child process returns non-zero exit code", - ToCommandLine(arg_vector).c_str()); + if (status != 0) { + *error_msg = StringPrintf("Failed execv(%s) because non-0 exit status", + ToCommandLine(arg_vector).c_str()); return false; } return true; |