diff options
| author | 2018-07-16 15:54:50 +0000 | |
|---|---|---|
| committer | 2018-07-16 15:54:50 +0000 | |
| commit | eb577ebe86a7d13a6ab18f7975a55a8b592f0e4c (patch) | |
| tree | 5fe593b0006e3ab2db9292f10bfa08af2cc6689b | |
| parent | 06a45b7588830c04dec723beee365a2e4c1c52f2 (diff) | |
| parent | 38aa0b53545a647581411b7e84cd229c5023a3c1 (diff) | |
Merge "ART: Clean up test exec code"
| -rw-r--r-- | dex2oat/dex2oat_image_test.cc | 47 | ||||
| -rw-r--r-- | dex2oat/dex2oat_test.cc | 48 | ||||
| -rw-r--r-- | libartbase/base/common_art_test.cc | 80 | ||||
| -rw-r--r-- | libartbase/base/common_art_test.h | 26 | ||||
| -rw-r--r-- | oatdump/oatdump_app_test.cc | 24 | ||||
| -rw-r--r-- | oatdump/oatdump_image_test.cc | 21 | ||||
| -rw-r--r-- | oatdump/oatdump_test.cc | 53 | ||||
| -rw-r--r-- | oatdump/oatdump_test.h | 226 | ||||
| -rw-r--r-- | runtime/common_runtime_test.h | 18 |
9 files changed, 311 insertions, 232 deletions
diff --git a/dex2oat/dex2oat_image_test.cc b/dex2oat/dex2oat_image_test.cc index ae8e1b7597..4247e176aa 100644 --- a/dex2oat/dex2oat_image_test.cc +++ b/dex2oat/dex2oat_image_test.cc @@ -186,48 +186,15 @@ class Dex2oatImageTest : public CommonRuntimeTest { return RunDex2Oat(argv, error_msg); } - int RunDex2Oat(const std::vector<std::string>& args, std::string* error_msg) { - int link[2]; - - if (pipe(link) == -1) { - return false; - } - - pid_t pid = fork(); - if (pid == -1) { - return false; - } - - if (pid == 0) { - // We need dex2oat to actually log things. - setenv("ANDROID_LOG_TAGS", "*:f", 1); - dup2(link[1], STDERR_FILENO); - close(link[0]); - close(link[1]); - std::vector<const char*> c_args; - for (const std::string& str : args) { - c_args.push_back(str.c_str()); - } - c_args.push_back(nullptr); - execv(c_args[0], const_cast<char* const*>(c_args.data())); - exit(1); - UNREACHABLE(); - } else { - close(link[1]); - char buffer[128]; - memset(buffer, 0, 128); - ssize_t bytes_read = 0; - - while (TEMP_FAILURE_RETRY(bytes_read = read(link[0], buffer, 128)) > 0) { - *error_msg += std::string(buffer, bytes_read); - } - close(link[0]); - int status = -1; - if (waitpid(pid, &status, 0) != -1) { - return (status == 0); - } + bool RunDex2Oat(const std::vector<std::string>& args, std::string* error_msg) { + // We only want fatal logging for the error message. + auto post_fork_fn = []() { return setenv("ANDROID_LOG_TAGS", "*:f", 1) == 0; }; + ForkAndExecResult res = ForkAndExec(args, post_fork_fn, error_msg); + if (res.stage != ForkAndExecResult::kFinished) { + *error_msg = strerror(errno); return false; } + return res.StandardSuccess(); } }; diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc index ad44624f76..1196d113d4 100644 --- a/dex2oat/dex2oat_test.cc +++ b/dex2oat/dex2oat_test.cc @@ -230,47 +230,15 @@ class Dex2oatTest : public Dex2oatEnvironmentTest { LOG(ERROR) << all_args; } - int link[2]; - - if (pipe(link) == -1) { - return false; - } - - pid_t pid = fork(); - if (pid == -1) { - return false; - } - - if (pid == 0) { - // We need dex2oat to actually log things. - setenv("ANDROID_LOG_TAGS", "*:d", 1); - dup2(link[1], STDERR_FILENO); - close(link[0]); - close(link[1]); - std::vector<const char*> c_args; - for (const std::string& str : argv) { - c_args.push_back(str.c_str()); - } - c_args.push_back(nullptr); - execv(c_args[0], const_cast<char* const*>(c_args.data())); - exit(1); - UNREACHABLE(); - } else { - close(link[1]); - char buffer[128]; - memset(buffer, 0, 128); - ssize_t bytes_read = 0; - - while (TEMP_FAILURE_RETRY(bytes_read = read(link[0], buffer, 128)) > 0) { - output_ += std::string(buffer, bytes_read); - } - close(link[0]); - int status = -1; - if (waitpid(pid, &status, 0) != -1) { - success_ = (status == 0); - } - return status; + // We need dex2oat to actually log things. + auto post_fork_fn = []() { return setenv("ANDROID_LOG_TAGS", "*:d", 1) == 0; }; + ForkAndExecResult res = ForkAndExec(argv, post_fork_fn, &output_); + if (res.stage != ForkAndExecResult::kFinished) { + *error_msg = strerror(errno); + return -1; } + success_ = res.StandardSuccess(); + return res.status_code; } std::string output_ = ""; diff --git a/libartbase/base/common_art_test.cc b/libartbase/base/common_art_test.cc index 67413eb85c..e24b073142 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 @@ std::string CommonArtTestImpl::CreateClassPathWithChecksums( 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 diff --git a/libartbase/base/common_art_test.h b/libartbase/base/common_art_test.h index 0ace09de1a..62834c7d35 100644 --- a/libartbase/base/common_art_test.h +++ b/libartbase/base/common_art_test.h @@ -19,8 +19,11 @@ #include <gtest/gtest.h> +#include <functional> #include <string> +#include <sys/wait.h> + #include <android-base/logging.h> #include "base/globals.h" @@ -125,6 +128,29 @@ class CommonArtTestImpl { return true; } + struct ForkAndExecResult { + enum Stage { + kLink, + kFork, + kWaitpid, + kFinished, + }; + Stage stage; + int status_code; + + bool StandardSuccess() { + return stage == kFinished && WIFEXITED(status_code) && WEXITSTATUS(status_code) == 0; + } + }; + using OutputHandlerFn = std::function<void(char*, size_t)>; + using PostForkFn = std::function<bool()>; + static ForkAndExecResult ForkAndExec(const std::vector<std::string>& argv, + const PostForkFn& post_fork, + const OutputHandlerFn& handler); + static ForkAndExecResult ForkAndExec(const std::vector<std::string>& argv, + const PostForkFn& post_fork, + std::string* output); + protected: static bool IsHost() { return !kIsTargetBuild; diff --git a/oatdump/oatdump_app_test.cc b/oatdump/oatdump_app_test.cc index 34b07d2ddf..a344286259 100644 --- a/oatdump/oatdump_app_test.cc +++ b/oatdump/oatdump_app_test.cc @@ -19,31 +19,23 @@ namespace art { TEST_F(OatDumpTest, TestAppWithBootImage) { - std::string error_msg; - ASSERT_TRUE(GenerateAppOdexFile(kDynamic, {"--runtime-arg", "-Xmx64M"}, &error_msg)) << error_msg; - ASSERT_TRUE(Exec(kDynamic, kModeOatWithBootImage, {}, kListAndCode, &error_msg)) << error_msg; + ASSERT_TRUE(GenerateAppOdexFile(kDynamic, {"--runtime-arg", "-Xmx64M"})); + ASSERT_TRUE(Exec(kDynamic, kModeOatWithBootImage, {}, kListAndCode)); } TEST_F(OatDumpTest, TestAppWithBootImageStatic) { TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS(); - std::string error_msg; - ASSERT_TRUE(GenerateAppOdexFile(kStatic, {"--runtime-arg", "-Xmx64M"}, &error_msg)) << error_msg; - ASSERT_TRUE(Exec(kStatic, kModeOatWithBootImage, {}, kListAndCode, &error_msg)) << error_msg; + ASSERT_TRUE(GenerateAppOdexFile(kStatic, {"--runtime-arg", "-Xmx64M"})); + ASSERT_TRUE(Exec(kStatic, kModeOatWithBootImage, {}, kListAndCode)); } TEST_F(OatDumpTest, TestPicAppWithBootImage) { - std::string error_msg; - ASSERT_TRUE( - GenerateAppOdexFile(kDynamic, {"--runtime-arg", "-Xmx64M", "--compile-pic"}, &error_msg)) - << error_msg; - ASSERT_TRUE(Exec(kDynamic, kModeOatWithBootImage, {}, kListAndCode, &error_msg)) << error_msg; + ASSERT_TRUE(GenerateAppOdexFile(kDynamic, {"--runtime-arg", "-Xmx64M", "--compile-pic"})); + ASSERT_TRUE(Exec(kDynamic, kModeOatWithBootImage, {}, kListAndCode)); } TEST_F(OatDumpTest, TestPicAppWithBootImageStatic) { TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS(); - std::string error_msg; - ASSERT_TRUE( - GenerateAppOdexFile(kStatic, {"--runtime-arg", "-Xmx64M", "--compile-pic"}, &error_msg)) - << error_msg; - ASSERT_TRUE(Exec(kStatic, kModeOatWithBootImage, {}, kListAndCode, &error_msg)) << error_msg; + ASSERT_TRUE(GenerateAppOdexFile(kStatic, {"--runtime-arg", "-Xmx64M", "--compile-pic"})); + ASSERT_TRUE(Exec(kStatic, kModeOatWithBootImage, {}, kListAndCode)); } } // namespace art diff --git a/oatdump/oatdump_image_test.cc b/oatdump/oatdump_image_test.cc index d054ecefbb..de48b04214 100644 --- a/oatdump/oatdump_image_test.cc +++ b/oatdump/oatdump_image_test.cc @@ -19,25 +19,34 @@ namespace art { // Disable tests on arm and mips as they are taking too long to run. b/27824283. -#if !defined(__arm__) && !defined(__mips__) +#define TEST_DISABLED_FOR_ARM_AND_MIPS() \ + TEST_DISABLED_FOR_ARM(); \ + TEST_DISABLED_FOR_ARM64(); \ + TEST_DISABLED_FOR_MIPS(); \ + TEST_DISABLED_FOR_MIPS64(); \ + TEST_F(OatDumpTest, TestImage) { + TEST_DISABLED_FOR_ARM_AND_MIPS(); std::string error_msg; - ASSERT_TRUE(Exec(kDynamic, kModeArt, {}, kListAndCode, &error_msg)) << error_msg; + ASSERT_TRUE(Exec(kDynamic, kModeArt, {}, kListAndCode)); } TEST_F(OatDumpTest, TestImageStatic) { + TEST_DISABLED_FOR_ARM_AND_MIPS(); TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS(); std::string error_msg; - ASSERT_TRUE(Exec(kStatic, kModeArt, {}, kListAndCode, &error_msg)) << error_msg; + ASSERT_TRUE(Exec(kStatic, kModeArt, {}, kListAndCode)); } TEST_F(OatDumpTest, TestOatImage) { + TEST_DISABLED_FOR_ARM_AND_MIPS(); std::string error_msg; - ASSERT_TRUE(Exec(kDynamic, kModeOat, {}, kListAndCode, &error_msg)) << error_msg; + ASSERT_TRUE(Exec(kDynamic, kModeOat, {}, kListAndCode)); } TEST_F(OatDumpTest, TestOatImageStatic) { + TEST_DISABLED_FOR_ARM_AND_MIPS(); TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS(); std::string error_msg; - ASSERT_TRUE(Exec(kStatic, kModeOat, {}, kListAndCode, &error_msg)) << error_msg; + ASSERT_TRUE(Exec(kStatic, kModeOat, {}, kListAndCode)); } -#endif + } // namespace art diff --git a/oatdump/oatdump_test.cc b/oatdump/oatdump_test.cc index b4eddb91f9..bcba18208b 100644 --- a/oatdump/oatdump_test.cc +++ b/oatdump/oatdump_test.cc @@ -19,75 +19,92 @@ namespace art { // Disable tests on arm and mips as they are taking too long to run. b/27824283. -#if !defined(__arm__) && !defined(__mips__) +#define TEST_DISABLED_FOR_ARM_AND_MIPS() \ + TEST_DISABLED_FOR_ARM(); \ + TEST_DISABLED_FOR_ARM64(); \ + TEST_DISABLED_FOR_MIPS(); \ + TEST_DISABLED_FOR_MIPS64(); \ + TEST_F(OatDumpTest, TestNoDumpVmap) { + TEST_DISABLED_FOR_ARM_AND_MIPS(); std::string error_msg; - ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--no-dump:vmap"}, kListAndCode, &error_msg)) << error_msg; + ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--no-dump:vmap"}, kListAndCode)); } TEST_F(OatDumpTest, TestNoDumpVmapStatic) { + TEST_DISABLED_FOR_ARM_AND_MIPS(); TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS(); std::string error_msg; - ASSERT_TRUE(Exec(kStatic, kModeArt, {"--no-dump:vmap"}, kListAndCode, &error_msg)) << error_msg; + ASSERT_TRUE(Exec(kStatic, kModeArt, {"--no-dump:vmap"}, kListAndCode)); } TEST_F(OatDumpTest, TestNoDisassemble) { + TEST_DISABLED_FOR_ARM_AND_MIPS(); std::string error_msg; - ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--no-disassemble"}, kListAndCode, &error_msg)) - << error_msg; + ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--no-disassemble"}, kListAndCode)); } TEST_F(OatDumpTest, TestNoDisassembleStatic) { + TEST_DISABLED_FOR_ARM_AND_MIPS(); TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS(); std::string error_msg; - ASSERT_TRUE(Exec(kStatic, kModeArt, {"--no-disassemble"}, kListAndCode, &error_msg)) << error_msg; + ASSERT_TRUE(Exec(kStatic, kModeArt, {"--no-disassemble"}, kListAndCode)); } TEST_F(OatDumpTest, TestListClasses) { + TEST_DISABLED_FOR_ARM_AND_MIPS(); std::string error_msg; - ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--list-classes"}, kListOnly, &error_msg)) << error_msg; + ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--list-classes"}, kListOnly)); } TEST_F(OatDumpTest, TestListClassesStatic) { + TEST_DISABLED_FOR_ARM_AND_MIPS(); TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS(); std::string error_msg; - ASSERT_TRUE(Exec(kStatic, kModeArt, {"--list-classes"}, kListOnly, &error_msg)) << error_msg; + ASSERT_TRUE(Exec(kStatic, kModeArt, {"--list-classes"}, kListOnly)); } TEST_F(OatDumpTest, TestListMethods) { + TEST_DISABLED_FOR_ARM_AND_MIPS(); std::string error_msg; - ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--list-methods"}, kListOnly, &error_msg)) << error_msg; + ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--list-methods"}, kListOnly)); } TEST_F(OatDumpTest, TestListMethodsStatic) { + TEST_DISABLED_FOR_ARM_AND_MIPS(); TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS(); std::string error_msg; - ASSERT_TRUE(Exec(kStatic, kModeArt, {"--list-methods"}, kListOnly, &error_msg)) << error_msg; + ASSERT_TRUE(Exec(kStatic, kModeArt, {"--list-methods"}, kListOnly)); } TEST_F(OatDumpTest, TestSymbolize) { + TEST_DISABLED_FOR_ARM_AND_MIPS(); std::string error_msg; - ASSERT_TRUE(Exec(kDynamic, kModeSymbolize, {}, kListOnly, &error_msg)) << error_msg; + ASSERT_TRUE(Exec(kDynamic, kModeSymbolize, {}, kListOnly)); } TEST_F(OatDumpTest, TestSymbolizeStatic) { + TEST_DISABLED_FOR_ARM_AND_MIPS(); TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS(); std::string error_msg; - ASSERT_TRUE(Exec(kStatic, kModeSymbolize, {}, kListOnly, &error_msg)) << error_msg; + ASSERT_TRUE(Exec(kStatic, kModeSymbolize, {}, kListOnly)); } TEST_F(OatDumpTest, TestExportDex) { + TEST_DISABLED_FOR_ARM_AND_MIPS(); // Test is failing on target, b/77469384. TEST_DISABLED_FOR_TARGET(); std::string error_msg; - ASSERT_TRUE(Exec(kDynamic, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly, &error_msg)) - << error_msg; + ASSERT_TRUE(Exec(kDynamic, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly)); const std::string dex_location = tmp_dir_+ "/core-oj-hostdex.jar_export.dex"; const std::string dexdump2 = GetExecutableFilePath("dexdump2", /*is_debug*/false, /*is_static*/false); - ASSERT_TRUE(ForkAndExecAndWait({dexdump2, "-d", dex_location}, &error_msg)) << error_msg; + std::string output; + auto post_fork_fn = []() { return true; }; + ForkAndExecResult res = ForkAndExec({dexdump2, "-d", dex_location}, post_fork_fn, &output); + ASSERT_TRUE(res.StandardSuccess()); } TEST_F(OatDumpTest, TestExportDexStatic) { + TEST_DISABLED_FOR_ARM_AND_MIPS(); TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS(); std::string error_msg; - ASSERT_TRUE(Exec(kStatic, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly, &error_msg)) - << error_msg; + ASSERT_TRUE(Exec(kStatic, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly)); } -#endif + } // namespace art diff --git a/oatdump/oatdump_test.h b/oatdump/oatdump_test.h index 231163b674..7f997b364f 100644 --- a/oatdump/oatdump_test.h +++ b/oatdump/oatdump_test.h @@ -111,9 +111,8 @@ class OatDumpTest : public CommonRuntimeTest { return tmp_dir_ + "/" + GetAppBaseName() + ".odex"; } - bool GenerateAppOdexFile(Flavor flavor, - const std::vector<std::string>& args, - /*out*/ std::string* error_msg) { + ::testing::AssertionResult GenerateAppOdexFile(Flavor flavor, + const std::vector<std::string>& args) { std::string dex2oat_path = GetExecutableFilePath(flavor, "dex2oat"); std::vector<std::string> exec_argv = { dex2oat_path, @@ -131,18 +130,32 @@ class OatDumpTest : public CommonRuntimeTest { }; exec_argv.insert(exec_argv.end(), args.begin(), args.end()); - return ForkAndExecAndWait(exec_argv, error_msg); + auto post_fork_fn = []() { + setpgid(0, 0); // Change process groups, so we don't get reaped by ProcessManager. + // Ignore setpgid errors. + return setenv("ANDROID_LOG_TAGS", "*:e", 1) == 0; // We're only interested in errors and + // fatal logs. + }; + + std::string error_msg; + ForkAndExecResult res = ForkAndExec(exec_argv, post_fork_fn, &error_msg); + if (res.stage != ForkAndExecResult::kFinished) { + return ::testing::AssertionFailure() << strerror(errno); + } + return res.StandardSuccess() ? ::testing::AssertionSuccess() + : (::testing::AssertionFailure() << error_msg); } // Run the test with custom arguments. - bool Exec(Flavor flavor, - Mode mode, - const std::vector<std::string>& args, - Display display, - /*out*/ std::string* error_msg) { + ::testing::AssertionResult Exec(Flavor flavor, + Mode mode, + const std::vector<std::string>& args, + Display display) { std::string file_path = GetExecutableFilePath(flavor, "oatdump"); - EXPECT_TRUE(OS::FileExists(file_path.c_str())) << file_path << " should be a valid file path"; + if (!OS::FileExists(file_path.c_str())) { + return ::testing::AssertionFailure() << file_path << " should be a valid file path"; + } // ScratchFile scratch; std::vector<std::string> exec_argv = { file_path }; @@ -179,129 +192,118 @@ class OatDumpTest : public CommonRuntimeTest { } exec_argv.insert(exec_argv.end(), args.begin(), args.end()); - pid_t pid; - int pipe_fd; - bool result = ForkAndExec(exec_argv, &pid, &pipe_fd, error_msg); - if (result) { - static const size_t kLineMax = 256; - char line[kLineMax] = {}; - size_t line_len = 0; - size_t total = 0; - std::vector<bool> found(expected_prefixes.size(), false); - while (true) { - while (true) { + std::vector<bool> found(expected_prefixes.size(), false); + auto line_handle_fn = [&found, &expected_prefixes](const char* line, size_t line_len) { + if (line_len == 0) { + return; + } + // Check contents. + for (size_t i = 0; i < expected_prefixes.size(); ++i) { + const std::string& expected = expected_prefixes[i]; + if (!found[i] && + line_len >= expected.length() && + memcmp(line, expected.c_str(), expected.length()) == 0) { + found[i] = true; + } + } + }; + + static constexpr size_t kLineMax = 256; + char line[kLineMax] = {}; + size_t line_len = 0; + size_t total = 0; + bool ignore_next_line = false; + auto line_buf_fn = [&](char* buf, size_t len) { + total += len; + + if (len == 0 && line_len > 0 && !ignore_next_line) { + // Everything done, handle leftovers. + line_handle_fn(line, line_len); + } + + while (len > 0) { + // Copy buf into the free tail of the line buffer, and move input buffer along. + size_t copy = std::min(kLineMax - line_len, len); + memcpy(&line[line_len], buf, copy); + buf += copy; + len -= copy; + + // Skip spaces. Declare a lambda for reuse (incurs a potential extra memmove). + auto trim_space = [&]() { size_t spaces = 0; - // Trim spaces at the start of the line. for (; spaces < line_len && isspace(line[spaces]); ++spaces) {} if (spaces > 0) { line_len -= spaces; memmove(&line[0], &line[spaces], line_len); } - ssize_t bytes_read = - TEMP_FAILURE_RETRY(read(pipe_fd, &line[line_len], kLineMax - line_len)); - if (bytes_read <= 0) { - break; - } - line_len += bytes_read; - total += bytes_read; - } - if (line_len == 0) { - break; - } - // Check contents. - for (size_t i = 0; i < expected_prefixes.size(); ++i) { - const std::string& expected = expected_prefixes[i]; - if (!found[i] && - line_len >= expected.length() && - memcmp(line, expected.c_str(), expected.length()) == 0) { - found[i] = true; + }; + trim_space(); // This is really only necessary if there wasn't any content in line before. + + // Scan for newline characters. + size_t index = line_len; + line_len += copy; + while (index < line_len) { + if (line[index] == '\n') { + // Handle line. + if (!ignore_next_line) { + line_handle_fn(line, index); + } + // Move the rest to the front, but trim leading spaces. + line_len -= index + 1; + memmove(&line[0], &line[index + 1], line_len); + trim_space(); + index = 0; + ignore_next_line = false; + } else { + index++; } } - // Skip to next line. - size_t next_line = 0; - for (; next_line + 1 < line_len && line[next_line] != '\n'; ++next_line) {} - line_len -= next_line + 1; - memmove(&line[0], &line[next_line + 1], line_len); - } - if (mode == kModeSymbolize) { - EXPECT_EQ(total, 0u); - } else { - EXPECT_GT(total, 0u); - } - LOG(INFO) << "Processed bytes " << total; - close(pipe_fd); - int status = 0; - if (waitpid(pid, &status, 0) != -1) { - result = (status == 0); - } - for (size_t i = 0; i < expected_prefixes.size(); ++i) { - if (!found[i]) { - LOG(ERROR) << "Did not find prefix " << expected_prefixes[i]; - result = false; + // Handle a full line without newline characters. Ignore the "next" line, as it is the + // tail end of this. + if (line_len == kLineMax) { + if (!ignore_next_line) { + line_handle_fn(line, kLineMax); + } + line_len = 0; + ignore_next_line = true; } } - } + }; - return result; - } + auto post_fork_fn = []() { + setpgid(0, 0); // Change process groups, so we don't get reaped by ProcessManager. + return true; // Ignore setpgid failures. + }; - bool ForkAndExec(const std::vector<std::string>& exec_argv, - /*out*/ pid_t* pid, - /*out*/ int* pipe_fd, - /*out*/ std::string* error_msg) { - int link[2]; - if (pipe(link) == -1) { - *error_msg = strerror(errno); - return false; + ForkAndExecResult res = ForkAndExec(exec_argv, post_fork_fn, line_buf_fn); + if (res.stage != ForkAndExecResult::kFinished) { + return ::testing::AssertionFailure() << strerror(errno); } - - *pid = fork(); - if (*pid == -1) { - *error_msg = strerror(errno); - close(link[0]); - close(link[1]); - return false; + if (!res.StandardSuccess()) { + return ::testing::AssertionFailure() << "Did not terminate successfully: " << res.status_code; } - if (*pid == 0) { - dup2(link[1], STDOUT_FILENO); - close(link[0]); - close(link[1]); - // change process groups, so we don't get reaped by ProcessManager - setpgid(0, 0); - // Use execv here rather than art::Exec to avoid blocking on waitpid here. - std::vector<char*> argv; - for (size_t i = 0; i < exec_argv.size(); ++i) { - argv.push_back(const_cast<char*>(exec_argv[i].c_str())); - } - argv.push_back(nullptr); - UNUSED(execv(argv[0], &argv[0])); - const std::string command_line(android::base::Join(exec_argv, ' ')); - PLOG(ERROR) << "Failed to execv(" << command_line << ")"; - // _exit to avoid atexit handlers in child. - _exit(1); - UNREACHABLE(); + if (mode == kModeSymbolize) { + EXPECT_EQ(total, 0u); } else { - close(link[1]); - *pipe_fd = link[0]; - return true; + EXPECT_GT(total, 0u); } - } - bool ForkAndExecAndWait(const std::vector<std::string>& exec_argv, - /*out*/ std::string* error_msg) { - pid_t pid; - int pipe_fd; - bool result = ForkAndExec(exec_argv, &pid, &pipe_fd, error_msg); - if (result) { - close(pipe_fd); - int status = 0; - if (waitpid(pid, &status, 0) != -1) { - result = (status == 0); + bool result = true; + std::ostringstream oss; + for (size_t i = 0; i < expected_prefixes.size(); ++i) { + if (!found[i]) { + oss << "Did not find prefix " << expected_prefixes[i] << std::endl; + result = false; } } - return result; + if (!result) { + oss << "Processed bytes " << total; + } + + return result ? ::testing::AssertionSuccess() + : (::testing::AssertionFailure() << oss.str()); } std::string tmp_dir_; diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h index d21973ec7e..234b66a862 100644 --- a/runtime/common_runtime_test.h +++ b/runtime/common_runtime_test.h @@ -191,12 +191,30 @@ class CheckJniAbortCatcher { DISALLOW_COPY_AND_ASSIGN(CheckJniAbortCatcher); }; +#define TEST_DISABLED_FOR_ARM() \ + if (kRuntimeISA == InstructionSet::kArm || kRuntimeISA == InstructionSet::kThumb2) { \ + printf("WARNING: TEST DISABLED FOR ARM\n"); \ + return; \ + } + +#define TEST_DISABLED_FOR_ARM64() \ + if (kRuntimeISA == InstructionSet::kArm64) { \ + printf("WARNING: TEST DISABLED FOR ARM64\n"); \ + return; \ + } + #define TEST_DISABLED_FOR_MIPS() \ if (kRuntimeISA == InstructionSet::kMips) { \ printf("WARNING: TEST DISABLED FOR MIPS\n"); \ return; \ } +#define TEST_DISABLED_FOR_MIPS64() \ + if (kRuntimeISA == InstructionSet::kMips64) { \ + printf("WARNING: TEST DISABLED FOR MIPS64\n"); \ + return; \ + } + #define TEST_DISABLED_FOR_X86() \ if (kRuntimeISA == InstructionSet::kX86) { \ printf("WARNING: TEST DISABLED FOR X86\n"); \ |