ART: Clean up test exec code
Add a helper for fork+exec of another program and collection of
that process' output. Use the helper in other code.
Clean up some tests. Move away from global #ifdef ARCH and
disable tests with the usual-style macros so that it's easier
to see refactoring issues immediately.
Test: mmma
Test: m test-art-host
Change-Id: Ic450e8a3bb24fc6fe423c0e1e007eb0bb34e22b4
diff --git a/libartbase/base/common_art_test.cc b/libartbase/base/common_art_test.cc
index 67413eb..e24b073 100644
--- a/libartbase/base/common_art_test.cc
+++ b/libartbase/base/common_art_test.cc
@@ -24,6 +24,7 @@
#include "nativehelper/scoped_local_ref.h"
#include "android-base/stringprintf.h"
+#include "android-base/unique_fd.h"
#include <unicode/uvernum.h>
#include "art_field-inl.h"
@@ -423,4 +424,83 @@
return classpath;
}
+CommonArtTestImpl::ForkAndExecResult CommonArtTestImpl::ForkAndExec(
+ const std::vector<std::string>& argv,
+ const PostForkFn& post_fork,
+ const OutputHandlerFn& handler) {
+ ForkAndExecResult result;
+ result.status_code = 0;
+ result.stage = ForkAndExecResult::kLink;
+
+ std::vector<const char*> c_args;
+ for (const std::string& str : argv) {
+ c_args.push_back(str.c_str());
+ }
+ c_args.push_back(nullptr);
+
+ android::base::unique_fd link[2];
+ {
+ int link_fd[2];
+
+ if (pipe(link_fd) == -1) {
+ return result;
+ }
+ link[0].reset(link_fd[0]);
+ link[1].reset(link_fd[1]);
+ }
+
+ result.stage = ForkAndExecResult::kFork;
+
+ pid_t pid = fork();
+ if (pid == -1) {
+ return result;
+ }
+
+ if (pid == 0) {
+ if (!post_fork()) {
+ LOG(ERROR) << "Failed post-fork function";
+ exit(1);
+ UNREACHABLE();
+ }
+
+ // Redirect stdout and stderr.
+ dup2(link[1].get(), STDOUT_FILENO);
+ dup2(link[1].get(), STDERR_FILENO);
+
+ link[0].reset();
+ link[1].reset();
+
+ execv(c_args[0], const_cast<char* const*>(c_args.data()));
+ exit(1);
+ UNREACHABLE();
+ }
+
+ result.stage = ForkAndExecResult::kWaitpid;
+ link[1].reset();
+
+ char buffer[128] = { 0 };
+ ssize_t bytes_read = 0;
+ while (TEMP_FAILURE_RETRY(bytes_read = read(link[0].get(), buffer, 128)) > 0) {
+ handler(buffer, bytes_read);
+ }
+ handler(buffer, 0u); // End with a virtual write of zero length to simplify clients.
+
+ link[0].reset();
+
+ if (waitpid(pid, &result.status_code, 0) == -1) {
+ return result;
+ }
+
+ result.stage = ForkAndExecResult::kFinished;
+ return result;
+}
+
+CommonArtTestImpl::ForkAndExecResult CommonArtTestImpl::ForkAndExec(
+ const std::vector<std::string>& argv, const PostForkFn& post_fork, std::string* output) {
+ auto string_collect_fn = [output](char* buf, size_t len) {
+ *output += std::string(buf, len);
+ };
+ return ForkAndExec(argv, post_fork, string_collect_fn);
+}
+
} // namespace art