diff options
| -rw-r--r-- | build/Android.gtest.mk | 33 | ||||
| -rw-r--r-- | dex2oat/dex2oat.cc | 64 | ||||
| -rw-r--r-- | dex2oat/dex2oat_test.cc | 287 | ||||
| -rw-r--r-- | runtime/common_runtime_test.cc | 2 | ||||
| -rw-r--r-- | runtime/common_runtime_test.h | 2 | ||||
| -rw-r--r-- | runtime/dex2oat_environment_test.h | 188 | ||||
| -rw-r--r-- | runtime/oat_file_assistant_test.cc | 151 |
7 files changed, 550 insertions, 177 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index c09116ff5d..424aa7a7eb 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -65,15 +65,18 @@ $(ART_TEST_TARGET_GTEST_MainStripped_DEX): $(ART_TEST_TARGET_GTEST_Main_DEX) $(call dexpreopt-remove-classes.dex,$@) # Dex file dependencies for each gtest. +ART_GTEST_dex2oat_environment_tests_DEX_DEPS := Main MainStripped MultiDex MultiDexModifiedSecondary Nested + ART_GTEST_class_linker_test_DEX_DEPS := Interfaces MultiDex MyClass Nested Statics StaticsFromCode ART_GTEST_compiler_driver_test_DEX_DEPS := AbstractMethod StaticLeafMethods ProfileTestMultiDex ART_GTEST_dex_cache_test_DEX_DEPS := Main ART_GTEST_dex_file_test_DEX_DEPS := GetMethodSignature Main Nested +ART_GTEST_dex2oat_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) ART_GTEST_exception_test_DEX_DEPS := ExceptionHandle ART_GTEST_instrumentation_test_DEX_DEPS := Instrumentation ART_GTEST_jni_compiler_test_DEX_DEPS := MyClassNatives ART_GTEST_jni_internal_test_DEX_DEPS := AllFields StaticLeafMethods -ART_GTEST_oat_file_assistant_test_DEX_DEPS := Main MainStripped MultiDex MultiDexModifiedSecondary Nested +ART_GTEST_oat_file_assistant_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) ART_GTEST_oat_file_test_DEX_DEPS := Main MultiDex ART_GTEST_oat_test_DEX_DEPS := Main ART_GTEST_object_test_DEX_DEPS := ProtoCompare ProtoCompare2 StaticsFromCode XandY @@ -89,14 +92,25 @@ ART_GTEST_type_lookup_table_test_DEX_DEPS := Lookup ART_GTEST_elf_writer_test_HOST_DEPS := $(HOST_CORE_IMAGE_default_no-pic_64) $(HOST_CORE_IMAGE_default_no-pic_32) ART_GTEST_elf_writer_test_TARGET_DEPS := $(TARGET_CORE_IMAGE_default_no-pic_64) $(TARGET_CORE_IMAGE_default_no-pic_32) -ART_GTEST_oat_file_assistant_test_HOST_DEPS := \ +ART_GTEST_dex2oat_environment_tests_HOST_DEPS := \ $(HOST_CORE_IMAGE_default_no-pic_64) \ - $(HOST_CORE_IMAGE_default_no-pic_32) \ - $(HOST_OUT_EXECUTABLES)/patchoatd -ART_GTEST_oat_file_assistant_test_TARGET_DEPS := \ + $(HOST_CORE_IMAGE_default_no-pic_32) +ART_GTEST_dex2oat_environment_tests_TARGET_DEPS := \ $(TARGET_CORE_IMAGE_default_no-pic_64) \ - $(TARGET_CORE_IMAGE_default_no-pic_32) \ - $(TARGET_OUT_EXECUTABLES)/patchoatd + $(TARGET_CORE_IMAGE_default_no-pic_32) + +ART_GTEST_oat_file_assistant_test_HOST_DEPS := \ + $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS) \ + $(HOST_OUT_EXECUTABLES)/patchoatd +ART_GTEST_oat_file_assistant_test_TARGET_DEPS := \ + $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS) \ + $(TARGET_OUT_EXECUTABLES)/patchoatd + + +ART_GTEST_dex2oat_test_HOST_DEPS := \ + $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS) +ART_GTEST_dex2oat_test_TARGET_DEPS := \ + $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS) # TODO: document why this is needed. ART_GTEST_proxy_test_HOST_DEPS := $(HOST_CORE_IMAGE_default_no-pic_64) $(HOST_CORE_IMAGE_default_no-pic_32) @@ -157,6 +171,7 @@ RUNTIME_GTEST_COMMON_SRC_FILES := \ cmdline/cmdline_parser_test.cc \ dexdump/dexdump_test.cc \ dexlist/dexlist_test.cc \ + dex2oat/dex2oat_test.cc \ imgdiag/imgdiag_test.cc \ oatdump/oatdump_test.cc \ profman/profile_assistant_test.cc \ @@ -808,11 +823,15 @@ ART_GTEST_jni_internal_test_DEX_DEPS := ART_GTEST_oat_file_assistant_test_DEX_DEPS := ART_GTEST_oat_file_assistant_test_HOST_DEPS := ART_GTEST_oat_file_assistant_test_TARGET_DEPS := +ART_GTEST_dex2oat_test_DEX_DEPS := +ART_GTEST_dex2oat_test_HOST_DEPS := +ART_GTEST_dex2oat_test_TARGET_DEPS := ART_GTEST_object_test_DEX_DEPS := ART_GTEST_proxy_test_DEX_DEPS := ART_GTEST_reflection_test_DEX_DEPS := ART_GTEST_stub_test_DEX_DEPS := ART_GTEST_transaction_test_DEX_DEPS := +ART_GTEST_dex2oat_environment_tests_DEX_DEPS := ART_VALGRIND_DEPENDENCIES := ART_VALGRIND_TARGET_DEPENDENCIES := $(foreach dir,$(GTEST_DEX_DIRECTORIES), $(eval ART_TEST_TARGET_GTEST_$(dir)_DEX :=)) diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 24a4d586a2..437aba7ad1 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -81,6 +81,9 @@ namespace art { +static constexpr size_t kDefaultMinDexFilesForSwap = 2; +static constexpr size_t kDefaultMinDexFileCumulativeSizeForSwap = 20 * MB; + static int original_argc; static char** original_argv; @@ -351,6 +354,16 @@ NO_RETURN static void Usage(const char* fmt, ...) { UsageError(" --swap-fd=<file-descriptor>: specifies a file to use for swap (by descriptor)."); UsageError(" Example: --swap-fd=10"); UsageError(""); + UsageError(" --swap-dex-size-threshold=<size>: specifies the minimum total dex file size in"); + UsageError(" bytes to allow the use of swap."); + UsageError(" Example: --swap-dex-size-threshold=1000000"); + UsageError(" Default: %zu", kDefaultMinDexFileCumulativeSizeForSwap); + UsageError(""); + UsageError(" --swap-dex-count-threshold=<count>: specifies the minimum number of dex files to"); + UsageError(" allow the use of swap."); + UsageError(" Example: --swap-dex-count-threshold=10"); + UsageError(" Default: %zu", kDefaultMinDexFilesForSwap); + UsageError(""); UsageError(" --app-image-fd=<file-descriptor>: specify output file descriptor for app image."); UsageError(" Example: --app-image-fd=10"); UsageError(""); @@ -473,25 +486,6 @@ class WatchDog { pthread_t pthread_; }; -static constexpr size_t kMinDexFilesForSwap = 2; -static constexpr size_t kMinDexFileCumulativeSizeForSwap = 20 * MB; - -static bool UseSwap(bool is_image, std::vector<const DexFile*>& dex_files) { - if (is_image) { - // Don't use swap, we know generation should succeed, and we don't want to slow it down. - return false; - } - if (dex_files.size() < kMinDexFilesForSwap) { - // If there are less dex files than the threshold, assume it's gonna be fine. - return false; - } - size_t dex_files_size = 0; - for (const auto* dex_file : dex_files) { - dex_files_size += dex_file->GetHeader().file_size_; - } - return dex_files_size >= kMinDexFileCumulativeSizeForSwap; -} - class Dex2Oat FINAL { public: explicit Dex2Oat(TimingLogger* timings) : @@ -1132,6 +1126,16 @@ class Dex2Oat FINAL { swap_file_name_ = option.substr(strlen("--swap-file=")).data(); } else if (option.starts_with("--swap-fd=")) { ParseUintOption(option, "--swap-fd", &swap_fd_, Usage); + } else if (option.starts_with("--swap-dex-size-threshold=")) { + ParseUintOption(option, + "--swap-dex-size-threshold", + &min_dex_file_cumulative_size_for_swap_, + Usage); + } else if (option.starts_with("--swap-dex-count-threshold=")) { + ParseUintOption(option, + "--swap-dex-count-threshold", + &min_dex_files_for_swap_, + Usage); } else if (option.starts_with("--app-image-file=")) { app_image_file_name_ = option.substr(strlen("--app-image-file=")).data(); } else if (option.starts_with("--app-image-fd=")) { @@ -1842,10 +1846,6 @@ class Dex2Oat FINAL { } } - CompilerOptions* GetCompilerOptions() const { - return compiler_options_.get(); - } - bool IsImage() const { return IsAppImage() || IsBootImage(); } @@ -1897,6 +1897,22 @@ class Dex2Oat FINAL { } private: + bool UseSwap(bool is_image, const std::vector<const DexFile*>& dex_files) { + if (is_image) { + // Don't use swap, we know generation should succeed, and we don't want to slow it down. + return false; + } + if (dex_files.size() < min_dex_files_for_swap_) { + // If there are less dex files than the threshold, assume it's gonna be fine. + return false; + } + size_t dex_files_size = 0; + for (const auto* dex_file : dex_files) { + dex_files_size += dex_file->GetHeader().file_size_; + } + return dex_files_size >= min_dex_file_cumulative_size_for_swap_; + } + template <typename T> static std::vector<T*> MakeNonOwningPointerVector(const std::vector<std::unique_ptr<T>>& src) { std::vector<T*> result; @@ -2486,6 +2502,8 @@ class Dex2Oat FINAL { bool dump_slow_timing_; std::string swap_file_name_; int swap_fd_; + size_t min_dex_files_for_swap_ = kDefaultMinDexFilesForSwap; + size_t min_dex_file_cumulative_size_for_swap_ = kDefaultMinDexFileCumulativeSizeForSwap; std::string app_image_file_name_; int app_image_fd_; std::string profile_file_; diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc new file mode 100644 index 0000000000..de3aed9d05 --- /dev/null +++ b/dex2oat/dex2oat_test.cc @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2016 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 <string> +#include <vector> +#include <sstream> + +#include "common_runtime_test.h" + +#include "base/logging.h" +#include "base/macros.h" +#include "base/stringprintf.h" +#include "dex2oat_environment_test.h" +#include "utils.h" + +#include <sys/wait.h> +#include <unistd.h> + +namespace art { + +class Dex2oatTest : public Dex2oatEnvironmentTest { + public: + virtual void TearDown() OVERRIDE { + Dex2oatEnvironmentTest::TearDown(); + + output_ = ""; + error_msg_ = ""; + success_ = false; + } + + protected: + void GenerateOdexForTest(const std::string& dex_location, + const std::string& odex_location, + CompilerFilter::Filter filter, + const std::vector<std::string>& extra_args = {}, + bool expect_success = true) { + std::vector<std::string> args; + args.push_back("--dex-file=" + dex_location); + args.push_back("--oat-file=" + odex_location); + args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter)); + args.push_back("--runtime-arg"); + args.push_back("-Xnorelocate"); + + args.insert(args.end(), extra_args.begin(), extra_args.end()); + + std::string error_msg; + bool success = Dex2Oat(args, &error_msg); + + if (expect_success) { + ASSERT_TRUE(success) << error_msg; + + // Verify the odex file was generated as expected. + std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(), + odex_location.c_str(), + nullptr, + nullptr, + false, + /*low_4gb*/false, + dex_location.c_str(), + &error_msg)); + ASSERT_TRUE(odex_file.get() != nullptr) << error_msg; + + CheckFilter(filter, odex_file->GetCompilerFilter()); + } else { + ASSERT_FALSE(success) << output_; + + error_msg_ = error_msg; + + // Verify there's no loadable odex file. + std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(), + odex_location.c_str(), + nullptr, + nullptr, + false, + /*low_4gb*/false, + dex_location.c_str(), + &error_msg)); + ASSERT_TRUE(odex_file.get() == nullptr); + } + } + + // Check the input compiler filter against the generated oat file's filter. Mayb be overridden + // in subclasses when equality is not expected. + virtual void CheckFilter(CompilerFilter::Filter expected, CompilerFilter::Filter actual) { + EXPECT_EQ(expected, actual); + } + + bool Dex2Oat(const std::vector<std::string>& dex2oat_args, std::string* error_msg) { + Runtime* runtime = Runtime::Current(); + + const std::vector<gc::space::ImageSpace*>& image_spaces = + runtime->GetHeap()->GetBootImageSpaces(); + if (image_spaces.empty()) { + *error_msg = "No image location found for Dex2Oat."; + return false; + } + std::string image_location = image_spaces[0]->GetImageLocation(); + + std::vector<std::string> argv; + argv.push_back(runtime->GetCompilerExecutable()); + argv.push_back("--runtime-arg"); + argv.push_back("-classpath"); + argv.push_back("--runtime-arg"); + std::string class_path = runtime->GetClassPathString(); + if (class_path == "") { + class_path = OatFile::kSpecialSharedLibrary; + } + argv.push_back(class_path); + if (runtime->IsDebuggable()) { + argv.push_back("--debuggable"); + } + runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv); + + if (!runtime->IsVerificationEnabled()) { + argv.push_back("--compiler-filter=verify-none"); + } + + if (runtime->MustRelocateIfPossible()) { + argv.push_back("--runtime-arg"); + argv.push_back("-Xrelocate"); + } else { + argv.push_back("--runtime-arg"); + argv.push_back("-Xnorelocate"); + } + + if (!kIsTargetBuild) { + argv.push_back("--host"); + } + + argv.push_back("--boot-image=" + image_location); + + std::vector<std::string> compiler_options = runtime->GetCompilerOptions(); + argv.insert(argv.end(), compiler_options.begin(), compiler_options.end()); + + argv.insert(argv.end(), dex2oat_args.begin(), dex2oat_args.end()); + + // We must set --android-root. + const char* android_root = getenv("ANDROID_ROOT"); + CHECK(android_root != nullptr); + argv.push_back("--android-root=" + std::string(android_root)); + + std::string command_line(Join(argv, ' ')); + + // We need to fix up the '&' being used for "do not check classpath." + size_t ampersand = command_line.find(" &"); + CHECK_NE(ampersand, std::string::npos); + command_line = command_line.replace(ampersand, 2, " \\&"); + + command_line += " 2>&1"; + + // We need dex2oat to actually log things. + setenv("ANDROID_LOG_TAGS", "*:d", 1); + + FILE* pipe = popen(command_line.c_str(), "r"); + + setenv("ANDROID_LOG_TAGS", "*:e", 1); + + if (pipe == nullptr) { + success_ = false; + } else { + char buffer[128]; + + while (fgets(buffer, 128, pipe) != nullptr) { + output_ += buffer; + } + + int result = pclose(pipe); + success_ = result == 0; + } + return success_; + } + + std::string output_ = ""; + std::string error_msg_ = ""; + bool success_ = false; +}; + +class Dex2oatSwapTest : public Dex2oatTest { + protected: + void RunTest(bool use_fd, bool expect_use, const std::vector<std::string>& extra_args = {}) { + std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar"; + std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex"; + + Copy(GetDexSrc1(), dex_location); + + std::vector<std::string> copy(extra_args); + + std::unique_ptr<ScratchFile> sf; + if (use_fd) { + sf.reset(new ScratchFile()); + copy.push_back(StringPrintf("--swap-fd=%d", sf->GetFd())); + } else { + std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap"; + copy.push_back("--swap-file=" + swap_location); + } + GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, copy); + + CheckValidity(); + ASSERT_TRUE(success_); + CheckResult(expect_use); + } + + void CheckResult(bool expect_use) { + if (kIsTargetBuild) { + CheckTargetResult(expect_use); + } else { + CheckHostResult(expect_use); + } + } + + void CheckTargetResult(bool expect_use ATTRIBUTE_UNUSED) { + // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do + // something for variants with file descriptor where we can control the lifetime of + // the swap file and thus take a look at it. + } + + void CheckHostResult(bool expect_use) { + if (!kIsTargetBuild) { + if (expect_use) { + EXPECT_NE(output_.find("Large app, accepted running with swap."), std::string::npos) + << output_; + } else { + EXPECT_EQ(output_.find("Large app, accepted running with swap."), std::string::npos) + << output_; + } + } + } + + // Check whether the dex2oat run was really successful. + void CheckValidity() { + if (kIsTargetBuild) { + CheckTargetValidity(); + } else { + CheckHostValidity(); + } + } + + void CheckTargetValidity() { + // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do + // something for variants with file descriptor where we can control the lifetime of + // the swap file and thus take a look at it. + } + + // On the host, we can get the dex2oat output. Here, look for "dex2oat took." + void CheckHostValidity() { + EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_; + } +}; + +TEST_F(Dex2oatSwapTest, DoNotUseSwapDefaultSingleSmall) { + RunTest(false /* use_fd */, false /* expect_use */); + RunTest(true /* use_fd */, false /* expect_use */); +} + +TEST_F(Dex2oatSwapTest, DoNotUseSwapSingle) { + RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" }); + RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" }); +} + +TEST_F(Dex2oatSwapTest, DoNotUseSwapSmall) { + RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" }); + RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" }); +} + +TEST_F(Dex2oatSwapTest, DoUseSwapSingleSmall) { + RunTest(false /* use_fd */, + true /* expect_use */, + { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" }); + RunTest(true /* use_fd */, + true /* expect_use */, + { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" }); +} + +} // namespace art diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc index 3509d9aef9..741b682996 100644 --- a/runtime/common_runtime_test.cc +++ b/runtime/common_runtime_test.cc @@ -463,7 +463,7 @@ std::string CommonRuntimeTestImpl::GetTestAndroidRoot() { #define ART_TARGET_NATIVETEST_DIR_STRING "" #endif -std::string CommonRuntimeTestImpl::GetTestDexFileName(const char* name) { +std::string CommonRuntimeTestImpl::GetTestDexFileName(const char* name) const { CHECK(name != nullptr); std::string filename; if (IsHost()) { diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h index 0ce40e8e22..b68eb19f2a 100644 --- a/runtime/common_runtime_test.h +++ b/runtime/common_runtime_test.h @@ -111,7 +111,7 @@ class CommonRuntimeTestImpl { std::string GetTestAndroidRoot(); - std::string GetTestDexFileName(const char* name); + std::string GetTestDexFileName(const char* name) const; std::vector<std::unique_ptr<const DexFile>> OpenTestDexFiles(const char* name) SHARED_REQUIRES(Locks::mutator_lock_); diff --git a/runtime/dex2oat_environment_test.h b/runtime/dex2oat_environment_test.h new file mode 100644 index 0000000000..743fbb9c68 --- /dev/null +++ b/runtime/dex2oat_environment_test.h @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2014 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. + */ + +#ifndef ART_RUNTIME_DEX2OAT_ENVIRONMENT_TEST_H_ +#define ART_RUNTIME_DEX2OAT_ENVIRONMENT_TEST_H_ + +#include <fstream> +#include <string> +#include <vector> + +#include <gtest/gtest.h> + +#include "common_runtime_test.h" +#include "compiler_callbacks.h" +#include "gc/heap.h" +#include "gc/space/image_space.h" +#include "oat_file_assistant.h" +#include "os.h" +#include "runtime.h" +#include "utils.h" + +namespace art { + +// Test class that provides some helpers to set a test up for compilation using dex2oat. +class Dex2oatEnvironmentTest : public CommonRuntimeTest { + public: + virtual void SetUp() OVERRIDE { + CommonRuntimeTest::SetUp(); + + // Create a scratch directory to work from. + scratch_dir_ = android_data_ + "/Dex2oatEnvironmentTest"; + ASSERT_EQ(0, mkdir(scratch_dir_.c_str(), 0700)); + + // Create a subdirectory in scratch for odex files. + odex_oat_dir_ = scratch_dir_ + "/oat"; + ASSERT_EQ(0, mkdir(odex_oat_dir_.c_str(), 0700)); + + odex_dir_ = odex_oat_dir_ + "/" + std::string(GetInstructionSetString(kRuntimeISA)); + ASSERT_EQ(0, mkdir(odex_dir_.c_str(), 0700)); + + // Verify the environment is as we expect + uint32_t checksum; + std::string error_msg; + ASSERT_TRUE(OS::FileExists(GetSystemImageFile().c_str())) + << "Expected pre-compiled boot image to be at: " << GetSystemImageFile(); + ASSERT_TRUE(OS::FileExists(GetDexSrc1().c_str())) + << "Expected dex file to be at: " << GetDexSrc1(); + ASSERT_TRUE(OS::FileExists(GetStrippedDexSrc1().c_str())) + << "Expected stripped dex file to be at: " << GetStrippedDexSrc1(); + ASSERT_FALSE(DexFile::GetChecksum(GetStrippedDexSrc1().c_str(), &checksum, &error_msg)) + << "Expected stripped dex file to be stripped: " << GetStrippedDexSrc1(); + ASSERT_TRUE(OS::FileExists(GetDexSrc2().c_str())) + << "Expected dex file to be at: " << GetDexSrc2(); + + // GetMultiDexSrc2 should have the same primary dex checksum as + // GetMultiDexSrc1, but a different secondary dex checksum. + static constexpr bool kVerifyChecksum = true; + std::vector<std::unique_ptr<const DexFile>> multi1; + ASSERT_TRUE(DexFile::Open(GetMultiDexSrc1().c_str(), + GetMultiDexSrc1().c_str(), kVerifyChecksum, &error_msg, &multi1)) << error_msg; + ASSERT_GT(multi1.size(), 1u); + + std::vector<std::unique_ptr<const DexFile>> multi2; + ASSERT_TRUE(DexFile::Open(GetMultiDexSrc2().c_str(), + GetMultiDexSrc2().c_str(), kVerifyChecksum, &error_msg, &multi2)) << error_msg; + ASSERT_GT(multi2.size(), 1u); + + ASSERT_EQ(multi1[0]->GetLocationChecksum(), multi2[0]->GetLocationChecksum()); + ASSERT_NE(multi1[1]->GetLocationChecksum(), multi2[1]->GetLocationChecksum()); + } + + virtual void SetUpRuntimeOptions(RuntimeOptions* options) OVERRIDE { + // options->push_back(std::make_pair("-verbose:oat", nullptr)); + + // Set up the image location. + options->push_back(std::make_pair("-Ximage:" + GetImageLocation(), + nullptr)); + // Make sure compilercallbacks are not set so that relocation will be + // enabled. + callbacks_.reset(); + } + + virtual void TearDown() OVERRIDE { + ClearDirectory(odex_dir_.c_str()); + ASSERT_EQ(0, rmdir(odex_dir_.c_str())); + + ClearDirectory(odex_oat_dir_.c_str()); + ASSERT_EQ(0, rmdir(odex_oat_dir_.c_str())); + + ClearDirectory(scratch_dir_.c_str()); + ASSERT_EQ(0, rmdir(scratch_dir_.c_str())); + + CommonRuntimeTest::TearDown(); + } + + static void Copy(const std::string& src, const std::string& dst) { + std::ifstream src_stream(src, std::ios::binary); + std::ofstream dst_stream(dst, std::ios::binary); + + dst_stream << src_stream.rdbuf(); + } + + // Returns the directory where the pre-compiled core.art can be found. + // TODO: We should factor out this into common tests somewhere rather than + // re-hardcoding it here (This was copied originally from the elf writer + // test). + std::string GetImageDirectory() const { + if (IsHost()) { + const char* host_dir = getenv("ANDROID_HOST_OUT"); + CHECK(host_dir != nullptr); + return std::string(host_dir) + "/framework"; + } else { + return std::string("/data/art-test"); + } + } + + std::string GetImageLocation() const { + return GetImageDirectory() + "/core.art"; + } + + std::string GetSystemImageFile() const { + return GetImageDirectory() + "/" + GetInstructionSetString(kRuntimeISA) + + "/core.art"; + } + + bool GetCachedImageFile(/*out*/std::string* image, std::string* error_msg) const { + std::string cache = GetDalvikCache(GetInstructionSetString(kRuntimeISA), true); + return GetDalvikCacheFilename(GetImageLocation().c_str(), cache.c_str(), image, error_msg); + } + + std::string GetDexSrc1() const { + return GetTestDexFileName("Main"); + } + + // Returns the path to a dex file equivalent to GetDexSrc1, but with the dex + // file stripped. + std::string GetStrippedDexSrc1() const { + return GetTestDexFileName("MainStripped"); + } + + std::string GetMultiDexSrc1() const { + return GetTestDexFileName("MultiDex"); + } + + // Returns the path to a multidex file equivalent to GetMultiDexSrc2, but + // with the contents of the secondary dex file changed. + std::string GetMultiDexSrc2() const { + return GetTestDexFileName("MultiDexModifiedSecondary"); + } + + std::string GetDexSrc2() const { + return GetTestDexFileName("Nested"); + } + + // Scratch directory, for dex and odex files (oat files will go in the + // dalvik cache). + const std::string& GetScratchDir() const { + return scratch_dir_; + } + + // Odex directory is the subdirectory in the scratch directory where odex + // files should be located. + const std::string& GetOdexDir() const { + return odex_dir_; + } + + private: + std::string scratch_dir_; + std::string odex_oat_dir_; + std::string odex_dir_; +}; + +} // namespace art + +#endif // ART_RUNTIME_DEX2OAT_ENVIRONMENT_TEST_H_ diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc index e3cc77f2c0..a1d3ed9241 100644 --- a/runtime/oat_file_assistant_test.cc +++ b/runtime/oat_file_assistant_test.cc @@ -14,8 +14,6 @@ * limitations under the License. */ -#include "oat_file_assistant.h" - #include <algorithm> #include <fstream> #include <string> @@ -29,8 +27,10 @@ #include "class_linker-inl.h" #include "common_runtime_test.h" #include "compiler_callbacks.h" +#include "dex2oat_environment_test.h" #include "gc/space/image_space.h" #include "mem_map.h" +#include "oat_file_assistant.h" #include "oat_file_manager.h" #include "os.h" #include "scoped_thread_state_change.h" @@ -39,52 +39,11 @@ namespace art { -class OatFileAssistantTest : public CommonRuntimeTest { +class OatFileAssistantTest : public Dex2oatEnvironmentTest { public: - virtual void SetUp() { + virtual void SetUp() OVERRIDE { ReserveImageSpace(); - CommonRuntimeTest::SetUp(); - - // Create a scratch directory to work from. - scratch_dir_ = android_data_ + "/OatFileAssistantTest"; - ASSERT_EQ(0, mkdir(scratch_dir_.c_str(), 0700)); - - // Create a subdirectory in scratch for odex files. - odex_oat_dir_ = scratch_dir_ + "/oat"; - ASSERT_EQ(0, mkdir(odex_oat_dir_.c_str(), 0700)); - - odex_dir_ = odex_oat_dir_ + "/" + std::string(GetInstructionSetString(kRuntimeISA)); - ASSERT_EQ(0, mkdir(odex_dir_.c_str(), 0700)); - - // Verify the environment is as we expect - uint32_t checksum; - std::string error_msg; - ASSERT_TRUE(OS::FileExists(GetSystemImageFile().c_str())) - << "Expected pre-compiled boot image to be at: " << GetSystemImageFile(); - ASSERT_TRUE(OS::FileExists(GetDexSrc1().c_str())) - << "Expected dex file to be at: " << GetDexSrc1(); - ASSERT_TRUE(OS::FileExists(GetStrippedDexSrc1().c_str())) - << "Expected stripped dex file to be at: " << GetStrippedDexSrc1(); - ASSERT_FALSE(DexFile::GetChecksum(GetStrippedDexSrc1().c_str(), &checksum, &error_msg)) - << "Expected stripped dex file to be stripped: " << GetStrippedDexSrc1(); - ASSERT_TRUE(OS::FileExists(GetDexSrc2().c_str())) - << "Expected dex file to be at: " << GetDexSrc2(); - - // GetMultiDexSrc2 should have the same primary dex checksum as - // GetMultiDexSrc1, but a different secondary dex checksum. - static constexpr bool kVerifyChecksum = true; - std::vector<std::unique_ptr<const DexFile>> multi1; - ASSERT_TRUE(DexFile::Open(GetMultiDexSrc1().c_str(), - GetMultiDexSrc1().c_str(), kVerifyChecksum, &error_msg, &multi1)) << error_msg; - ASSERT_GT(multi1.size(), 1u); - - std::vector<std::unique_ptr<const DexFile>> multi2; - ASSERT_TRUE(DexFile::Open(GetMultiDexSrc2().c_str(), - GetMultiDexSrc2().c_str(), kVerifyChecksum, &error_msg, &multi2)) << error_msg; - ASSERT_GT(multi2.size(), 1u); - - ASSERT_EQ(multi1[0]->GetLocationChecksum(), multi2[0]->GetLocationChecksum()); - ASSERT_NE(multi1[1]->GetLocationChecksum(), multi2[1]->GetLocationChecksum()); + Dex2oatEnvironmentTest::SetUp(); } // Pre-Relocate the image to a known non-zero offset so we don't have to @@ -108,17 +67,6 @@ class OatFileAssistantTest : public CommonRuntimeTest { return Exec(argv, error_msg); } - virtual void SetUpRuntimeOptions(RuntimeOptions* options) { - // options->push_back(std::make_pair("-verbose:oat", nullptr)); - - // Set up the image location. - options->push_back(std::make_pair("-Ximage:" + GetImageLocation(), - nullptr)); - // Make sure compilercallbacks are not set so that relocation will be - // enabled. - callbacks_.reset(); - } - virtual void PreRuntimeCreate() { std::string error_msg; ASSERT_TRUE(PreRelocateImage(&error_msg)) << error_msg; @@ -126,94 +74,10 @@ class OatFileAssistantTest : public CommonRuntimeTest { UnreserveImageSpace(); } - virtual void PostRuntimeCreate() { + virtual void PostRuntimeCreate() OVERRIDE { ReserveImageSpace(); } - virtual void TearDown() { - ClearDirectory(odex_dir_.c_str()); - ASSERT_EQ(0, rmdir(odex_dir_.c_str())); - - ClearDirectory(odex_oat_dir_.c_str()); - ASSERT_EQ(0, rmdir(odex_oat_dir_.c_str())); - - ClearDirectory(scratch_dir_.c_str()); - ASSERT_EQ(0, rmdir(scratch_dir_.c_str())); - - CommonRuntimeTest::TearDown(); - } - - void Copy(std::string src, std::string dst) { - std::ifstream src_stream(src, std::ios::binary); - std::ofstream dst_stream(dst, std::ios::binary); - - dst_stream << src_stream.rdbuf(); - } - - // Returns the directory where the pre-compiled core.art can be found. - // TODO: We should factor out this into common tests somewhere rather than - // re-hardcoding it here (This was copied originally from the elf writer - // test). - std::string GetImageDirectory() { - if (IsHost()) { - const char* host_dir = getenv("ANDROID_HOST_OUT"); - CHECK(host_dir != nullptr); - return std::string(host_dir) + "/framework"; - } else { - return std::string("/data/art-test"); - } - } - - std::string GetImageLocation() { - return GetImageDirectory() + "/core.art"; - } - - std::string GetSystemImageFile() { - return GetImageDirectory() + "/" + GetInstructionSetString(kRuntimeISA) - + "/core.art"; - } - - bool GetCachedImageFile(/*out*/std::string* image, std::string* error_msg) { - std::string cache = GetDalvikCache(GetInstructionSetString(kRuntimeISA), true); - return GetDalvikCacheFilename(GetImageLocation().c_str(), cache.c_str(), image, error_msg); - } - - std::string GetDexSrc1() { - return GetTestDexFileName("Main"); - } - - // Returns the path to a dex file equivalent to GetDexSrc1, but with the dex - // file stripped. - std::string GetStrippedDexSrc1() { - return GetTestDexFileName("MainStripped"); - } - - std::string GetMultiDexSrc1() { - return GetTestDexFileName("MultiDex"); - } - - // Returns the path to a multidex file equivalent to GetMultiDexSrc2, but - // with the contents of the secondary dex file changed. - std::string GetMultiDexSrc2() { - return GetTestDexFileName("MultiDexModifiedSecondary"); - } - - std::string GetDexSrc2() { - return GetTestDexFileName("Nested"); - } - - // Scratch directory, for dex and odex files (oat files will go in the - // dalvik cache). - std::string GetScratchDir() { - return scratch_dir_; - } - - // Odex directory is the subdirectory in the scratch directory where odex - // files should be located. - std::string GetOdexDir() { - return odex_dir_; - } - // Generate a non-PIC odex file for the purposes of test. // The generated odex file will be un-relocated. void GenerateOdexForTest(const std::string& dex_location, @@ -334,9 +198,6 @@ class OatFileAssistantTest : public CommonRuntimeTest { image_reservation_.clear(); } - std::string scratch_dir_; - std::string odex_oat_dir_; - std::string odex_dir_; std::vector<std::unique_ptr<MemMap>> image_reservation_; }; |