diff options
-rw-r--r-- | build/Android.gtest.mk | 6 | ||||
-rw-r--r-- | oatdump/Android.bp | 1 | ||||
-rw-r--r-- | oatdump/oatdump.cc | 18 | ||||
-rw-r--r-- | oatdump/oatdump_app_test.cc | 45 | ||||
-rw-r--r-- | oatdump/oatdump_image_test.cc | 2 | ||||
-rw-r--r-- | oatdump/oatdump_test.h | 148 |
6 files changed, 170 insertions, 50 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index 4a35ccfa13..524dc0572f 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -184,6 +184,7 @@ ART_GTEST_unstarted_runtime_test_DEX_DEPS := Nested ART_GTEST_heap_verification_test_DEX_DEPS := ProtoCompare ProtoCompare2 StaticsFromCode XandY ART_GTEST_verifier_deps_test_DEX_DEPS := VerifierDeps VerifierDepsMulti MultiDex ART_GTEST_dex_to_dex_decompiler_test_DEX_DEPS := VerifierDeps DexToDexDecompiler +ART_GTEST_oatdump_app_test_DEX_DEPS := ProfileTestMultiDex # The elf writer test has dependencies on core.oat. ART_GTEST_elf_writer_test_HOST_DEPS := $(HOST_CORE_IMAGE_DEFAULT_64) $(HOST_CORE_IMAGE_DEFAULT_32) @@ -303,6 +304,11 @@ ART_GTEST_oatdump_test_TARGET_DEPS := \ oatdumpd-target ART_GTEST_oatdump_image_test_HOST_DEPS := $(ART_GTEST_oatdump_test_HOST_DEPS) ART_GTEST_oatdump_image_test_TARGET_DEPS := $(ART_GTEST_oatdump_test_TARGET_DEPS) +ART_GTEST_oatdump_app_test_HOST_DEPS := $(ART_GTEST_oatdump_test_HOST_DEPS) \ + dex2oatd-host \ + dex2oatds-host +ART_GTEST_oatdump_app_test_TARGET_DEPS := $(ART_GTEST_oatdump_test_TARGET_DEPS) \ + dex2oatd-target ART_GTEST_patchoat_test_HOST_DEPS := \ $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS) diff --git a/oatdump/Android.bp b/oatdump/Android.bp index 012100d470..71e276db10 100644 --- a/oatdump/Android.bp +++ b/oatdump/Android.bp @@ -121,6 +121,7 @@ art_cc_test { "art_gtest_defaults", ], srcs: [ + "oatdump_app_test.cc", "oatdump_test.cc", "oatdump_image_test.cc", ], diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 82bb88a5d5..c8e20e4c6c 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -1675,10 +1675,10 @@ class OatDumper { if ((method_access_flags & kAccNative) == 0) { ScopedObjectAccess soa(Thread::Current()); Runtime* const runtime = Runtime::Current(); - Handle<mirror::DexCache> dex_cache( - hs->NewHandle(runtime->GetClassLinker()->RegisterDexFile(*dex_file, nullptr))); - CHECK(dex_cache != nullptr); DCHECK(options_.class_loader_ != nullptr); + Handle<mirror::DexCache> dex_cache = hs->NewHandle( + runtime->GetClassLinker()->RegisterDexFile(*dex_file, options_.class_loader_->Get())); + CHECK(dex_cache != nullptr); return verifier::MethodVerifier::VerifyMethodAndDump( soa.Self(), vios, dex_method_idx, dex_file, dex_cache, *options_.class_loader_, class_def, code_item, nullptr, method_access_flags); @@ -2997,7 +2997,7 @@ static jobject InstallOatFile(Runtime* runtime, // Need well-known-classes. WellKnownClasses::Init(self->GetJniEnv()); - // Need to register dex files to get a working dex cache. + // Open dex files. OatFile* oat_file_ptr = oat_file.get(); ClassLinker* class_linker = runtime->GetClassLinker(); runtime->GetOatFileManager().RegisterOatFile(std::move(oat_file)); @@ -3005,9 +3005,6 @@ static jobject InstallOatFile(Runtime* runtime, std::string error_msg; const DexFile* const dex_file = OpenDexFile(odf, &error_msg); CHECK(dex_file != nullptr) << error_msg; - ObjPtr<mirror::DexCache> dex_cache = - class_linker->RegisterDexFile(*dex_file, nullptr); - CHECK(dex_cache != nullptr); class_path->push_back(dex_file); } @@ -3018,6 +3015,13 @@ static jobject InstallOatFile(Runtime* runtime, jobject class_loader = class_linker->CreatePathClassLoader(self, *class_path); + // Need to register dex files to get a working dex cache. + for (const DexFile* dex_file : *class_path) { + ObjPtr<mirror::DexCache> dex_cache = class_linker->RegisterDexFile( + *dex_file, self->DecodeJObject(class_loader)->AsClassLoader()); + CHECK(dex_cache != nullptr); + } + return class_loader; } diff --git a/oatdump/oatdump_app_test.cc b/oatdump/oatdump_app_test.cc new file mode 100644 index 0000000000..f12522277b --- /dev/null +++ b/oatdump/oatdump_app_test.cc @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 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 "oatdump_test.h" + +namespace art { + +TEST_F(OatDumpTest, TestAppWithBootImage) { + std::string error_msg; + ASSERT_TRUE(GenerateAppOdexFile(kDynamic, {}, &error_msg)) << error_msg; + ASSERT_TRUE(Exec(kDynamic, kModeOatWithBootImage, {}, kListAndCode, &error_msg)) << error_msg; +} +TEST_F(OatDumpTest, TestAppWithBootImageStatic) { + TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS(); + std::string error_msg; + ASSERT_TRUE(GenerateAppOdexFile(kStatic, {}, &error_msg)) << error_msg; + ASSERT_TRUE(Exec(kStatic, kModeOatWithBootImage, {}, kListAndCode, &error_msg)) << error_msg; +} + +TEST_F(OatDumpTest, TestPicAppWithBootImage) { + std::string error_msg; + ASSERT_TRUE(GenerateAppOdexFile(kDynamic, {"--compile-pic"}, &error_msg)) << error_msg; + ASSERT_TRUE(Exec(kDynamic, kModeOatWithBootImage, {}, kListAndCode, &error_msg)) << error_msg; +} +TEST_F(OatDumpTest, TestPicAppWithBootImageStatic) { + TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS(); + std::string error_msg; + ASSERT_TRUE(GenerateAppOdexFile(kStatic, {"--compile-pic"}, &error_msg)) << error_msg; + ASSERT_TRUE(Exec(kStatic, kModeOatWithBootImage, {}, kListAndCode, &error_msg)) << error_msg; +} + +} // namespace art diff --git a/oatdump/oatdump_image_test.cc b/oatdump/oatdump_image_test.cc index e9cc922d9b..d054ecefbb 100644 --- a/oatdump/oatdump_image_test.cc +++ b/oatdump/oatdump_image_test.cc @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 The Android Open Source Project + * Copyright (C) 2017 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. diff --git a/oatdump/oatdump_test.h b/oatdump/oatdump_test.h index d0f05d9e66..d4bed6b3da 100644 --- a/oatdump/oatdump_test.h +++ b/oatdump/oatdump_test.h @@ -66,14 +66,15 @@ class OatDumpTest : public CommonRuntimeTest { // Linking flavor. enum Flavor { - kDynamic, // oatdump(d) - kStatic, // oatdump(d)s + kDynamic, // oatdump(d), dex2oat(d) + kStatic, // oatdump(d)s, dex2oat(d)s }; - // Returns path to the oatdump binary. - std::string GetOatDumpFilePath(Flavor flavor) { + // Returns path to the oatdump/dex2oat binary. + std::string GetExecutableFilePath(Flavor flavor, const char* name) { std::string root = GetTestAndroidRoot(); - root += "/bin/oatdump"; + root += "/bin/"; + root += name; if (kIsDebugBuild) { root += "d"; } @@ -85,6 +86,7 @@ class OatDumpTest : public CommonRuntimeTest { enum Mode { kModeOat, + kModeOatWithBootImage, kModeArt, kModeSymbolize, }; @@ -95,13 +97,56 @@ class OatDumpTest : public CommonRuntimeTest { kListAndCode }; + std::string GetAppBaseName() { + // Use ProfileTestMultiDex as it contains references to boot image strings + // that shall use different code for PIC and non-PIC. + return "ProfileTestMultiDex"; + } + + std::string GetAppOdexName() { + return tmp_dir_ + "/" + GetAppBaseName() + ".odex"; + } + + bool GenerateAppOdexFile(Flavor flavor, + const std::vector<std::string>& args, + /*out*/ std::string* error_msg) { + std::string dex2oat_path = GetExecutableFilePath(flavor, "dex2oat"); + std::vector<std::string> exec_argv = { + dex2oat_path, + "--runtime-arg", + "-Xms64m", + "--runtime-arg", + "-Xmx512m", + "--runtime-arg", + "-Xnorelocate", + "--boot-image=" + GetCoreArtLocation(), + "--instruction-set=" + std::string(GetInstructionSetString(kRuntimeISA)), + "--dex-file=" + GetTestDexFileName(GetAppBaseName().c_str()), + "--oat-file=" + GetAppOdexName(), + "--compiler-filter=speed" + }; + 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) { + close(pipe_fd); + int status = 0; + if (waitpid(pid, &status, 0) != -1) { + result = (status == 0); + } + } + return result; + } + // Run the test with custom arguments. bool Exec(Flavor flavor, Mode mode, const std::vector<std::string>& args, Display display, - std::string* error_msg) { - std::string file_path = GetOatDumpFilePath(flavor); + /*out*/ std::string* error_msg) { + std::string file_path = GetExecutableFilePath(flavor, "oatdump"); EXPECT_TRUE(OS::FileExists(file_path.c_str())) << file_path << " should be a valid file path"; @@ -133,6 +178,11 @@ class OatDumpTest : public CommonRuntimeTest { expected_prefixes.push_back("IMAGE LOCATION:"); expected_prefixes.push_back("IMAGE BEGIN:"); expected_prefixes.push_back("kDexCaches:"); + } else if (mode == kModeOatWithBootImage) { + exec_argv.push_back("--boot-image=" + GetCoreArtLocation()); + exec_argv.push_back("--instruction-set=" + std::string( + GetInstructionSetString(kRuntimeISA))); + exec_argv.push_back("--oat-file=" + GetAppOdexName()); } else { CHECK_EQ(static_cast<size_t>(mode), static_cast<size_t>(kModeOat)); exec_argv.push_back("--oat-file=" + core_oat_location_); @@ -140,39 +190,10 @@ class OatDumpTest : public CommonRuntimeTest { } exec_argv.insert(exec_argv.end(), args.begin(), args.end()); - bool result = true; - // We must set --android-root. - int link[2]; - if (pipe(link) == -1) { - *error_msg = strerror(errno); - return false; - } - - const pid_t pid = fork(); - if (pid == -1) { - *error_msg = strerror(errno); - return false; - } - - 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); - } else { - close(link[1]); + 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; @@ -188,7 +209,7 @@ class OatDumpTest : public CommonRuntimeTest { memmove(&line[0], &line[spaces], line_len); } ssize_t bytes_read = - TEMP_FAILURE_RETRY(read(link[0], &line[line_len], kLineMax - line_len)); + TEMP_FAILURE_RETRY(read(pipe_fd, &line[line_len], kLineMax - line_len)); if (bytes_read <= 0) { break; } @@ -219,7 +240,7 @@ class OatDumpTest : public CommonRuntimeTest { EXPECT_GT(total, 0u); } LOG(INFO) << "Processed bytes " << total; - close(link[0]); + close(pipe_fd); int status = 0; if (waitpid(pid, &status, 0) != -1) { result = (status == 0); @@ -236,6 +257,49 @@ class OatDumpTest : public CommonRuntimeTest { return result; } + 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; + } + + *pid = fork(); + if (*pid == -1) { + *error_msg = strerror(errno); + close(link[0]); + close(link[1]); + return false; + } + + 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(); + } else { + close(link[1]); + *pipe_fd = link[0]; + return true; + } + } + std::string tmp_dir_; private: |