diff options
| -rw-r--r-- | Android.mk | 20 | ||||
| -rw-r--r-- | build/Android.gtest.mk | 9 | ||||
| -rw-r--r-- | build/apex/Android.bp | 9 | ||||
| -rw-r--r-- | build/apex/ld.config.txt | 3 | ||||
| -rw-r--r-- | dexoptanalyzer/dexoptanalyzer.cc | 21 | ||||
| -rw-r--r-- | dexoptanalyzer/dexoptanalyzer_test.cc | 30 | ||||
| -rw-r--r-- | libdexfile/Android.bp | 71 | ||||
| -rw-r--r-- | libdexfile/external/dex_file_ext.cc | 38 | ||||
| -rw-r--r-- | libdexfile/external/dex_file_ext_c_test.c | 55 | ||||
| -rw-r--r-- | libdexfile/external/dex_file_supp.cc | 2 | ||||
| -rw-r--r-- | libdexfile/external/dex_file_supp_test.cc | 289 | ||||
| -rw-r--r-- | libdexfile/external/include/art_api/dex_file_external.h | 89 | ||||
| -rw-r--r-- | libdexfile/external/include/art_api/dex_file_support.h (renamed from libdexfile/external/include/art_api/ext_dex_file.h) | 111 | ||||
| -rw-r--r-- | runtime/dexopt_test.cc | 11 | ||||
| -rw-r--r-- | runtime/dexopt_test.h | 6 | ||||
| -rwxr-xr-x | test/etc/run-test-jar | 4 | ||||
| -rwxr-xr-x | test/run-test | 12 | ||||
| -rw-r--r-- | test/testrunner/env.py | 2 | ||||
| -rwxr-xr-x | test/testrunner/testrunner.py | 5 | ||||
| -rw-r--r-- | tools/art | 36 | ||||
| -rwxr-xr-x | tools/buildbot-build.sh | 17 | ||||
| -rw-r--r-- | tools/libcore_failures.txt | 2 |
22 files changed, 688 insertions, 154 deletions
diff --git a/Android.mk b/Android.mk index a2d8f640b2..1a5daffd84 100644 --- a/Android.mk +++ b/Android.mk @@ -488,6 +488,22 @@ build-art-target: $(TARGET_OUT_EXECUTABLES)/art $(ART_TARGET_DEPENDENCIES) $(TAR .PHONY: build-art-target-golem # Also include libartbenchmark, we always include it when running golem. # libstdc++ is needed when building for ART_TARGET_LINUX. +# +# Also include the bootstrap Bionic libraries (libc, libdl, libm). +# These are required as the "main" libc, libdl, and libm have moved to +# the Runtime APEX. This is a temporary change needed until Golem +# fully supports the Runtime APEX. +# TODO(b/121117762): Remove this when the ART Buildbot and Golem have +# full support for the Runtime APEX. +# +# Also include a copy of the ICU .dat prebuilt files in +# /system/etc/icu on target (see module `icu-data-art-test`), so that +# it can found even if the Runtime APEX is not available, by setting +# the environment variable `ART_TEST_ANDROID_RUNTIME_ROOT` to +# "/system" on device. This is a temporary change needed until Golem +# fully supports the Runtime APEX. +# TODO(b/121117762): Remove this when the ART Buildbot and Golem have +# full support for the Runtime APEX. ART_TARGET_SHARED_LIBRARY_BENCHMARK := $(TARGET_OUT_SHARED_LIBRARIES)/libartbenchmark.so build-art-target-golem: dex2oat dalvikvm linker libstdc++ \ $(TARGET_OUT_EXECUTABLES)/art \ @@ -496,7 +512,9 @@ build-art-target-golem: dex2oat dalvikvm linker libstdc++ \ $(ART_TARGET_SHARED_LIBRARY_DEPENDENCIES) \ $(ART_TARGET_SHARED_LIBRARY_BENCHMARK) \ $(TARGET_CORE_IMG_OUT_BASE).art \ - $(TARGET_CORE_IMG_OUT_BASE)-interpreter.art + $(TARGET_CORE_IMG_OUT_BASE)-interpreter.art \ + libc.bootstrap libdl.bootstrap libm.bootstrap \ + icu-data-art-test # remove debug libraries from public.libraries.txt because golem builds # won't have it. sed -i '/libartd.so/d' $(TARGET_OUT)/etc/public.libraries.txt diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index a926d9a686..f00da9c22e 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -371,8 +371,8 @@ LOCAL_PATH := art ART_TEST_MODULES := \ art_cmdline_tests \ - art_compiler_tests \ art_compiler_host_tests \ + art_compiler_tests \ art_dex2oat_tests \ art_dexanalyze_tests \ art_dexdiag_tests \ @@ -383,12 +383,14 @@ ART_TEST_MODULES := \ art_hiddenapi_tests \ art_imgdiag_tests \ art_libartbase_tests \ + art_libdexfile_external_tests \ + art_libdexfile_support_tests \ art_libdexfile_tests \ art_libprofile_tests \ art_oatdump_tests \ art_profman_tests \ - art_runtime_tests \ art_runtime_compiler_tests \ + art_runtime_tests \ art_sigchain_tests \ ART_TARGET_GTEST_FILES := $(foreach m,$(ART_TEST_MODULES),\ @@ -423,6 +425,9 @@ ifneq ($(ART_TEST_ANDROID_ROOT),) endif ART_GTEST_TARGET_ANDROID_RUNTIME_ROOT := '/apex/com.android.runtime' +ifneq ($(ART_TEST_ANDROID_RUNTIME_ROOT),) + ART_GTEST_TARGET_ANDROID_RUNTIME_ROOT := $(ART_TEST_ANDROID_RUNTIME_ROOT) +endif # Define a make rule for a target device gtest. # $(1): gtest name - the name of the test we're building such as leb128_test. diff --git a/build/apex/Android.bp b/build/apex/Android.bp index 79f67a2da7..47729c1aa3 100644 --- a/build/apex/Android.bp +++ b/build/apex/Android.bp @@ -43,11 +43,12 @@ art_runtime_debug_native_shared_libs = [ "libadbconnectiond", ] -// Files associated with bionic / managed core library time zone APIs. -art_runtime_time_zone_prebuilts = [ +// Data files associated with bionic / managed core library APIs. +art_runtime_data_file_prebuilts = [ "apex_tz_version", "apex_tzdata", "apex_tzlookup.xml", + "apex_icu.dat", ] // Modules listed in LOCAL_REQUIRED_MODULES for module art-tools in art/Android.mk. @@ -115,7 +116,7 @@ apex { binaries: [], } }, - prebuilts: art_runtime_time_zone_prebuilts + prebuilts: art_runtime_data_file_prebuilts + ["com.android.runtime.ld.config.txt"], key: "com.android.runtime.key", } @@ -145,7 +146,7 @@ apex { binaries: art_tools_device_binaries, } }, - prebuilts: art_runtime_time_zone_prebuilts + prebuilts: art_runtime_data_file_prebuilts + ["com.android.runtime.ld.config.txt"], key: "com.android.runtime.key", } diff --git a/build/apex/ld.config.txt b/build/apex/ld.config.txt index 014b1152c6..9e49d7627b 100644 --- a/build/apex/ld.config.txt +++ b/build/apex/ld.config.txt @@ -24,8 +24,7 @@ namespace.default.link.platform.allow_all_shared_libs = true namespace.platform.isolated = true namespace.platform.search.paths = /system/${LIB} namespace.platform.links = default -namespace.platform.link.default.shared_libs = libc.so:libdl.so:libm.so -namespace.platform.link.default.shared_libs += libart.so:libartd.so +namespace.platform.link.default.shared_libs = libart.so:libartd.so namespace.platform.link.default.shared_libs += libnativebridge.so namespace.platform.link.default.shared_libs += libnativehelper.so namespace.platform.link.default.shared_libs += libnativeloader.so diff --git a/dexoptanalyzer/dexoptanalyzer.cc b/dexoptanalyzer/dexoptanalyzer.cc index acf0f94572..92850f7590 100644 --- a/dexoptanalyzer/dexoptanalyzer.cc +++ b/dexoptanalyzer/dexoptanalyzer.cc @@ -202,11 +202,7 @@ class DexoptAnalyzer final { Usage("Invalid --zip-fd %d", zip_fd_); } } else if (option.starts_with("--class-loader-context=")) { - std::string context_str = option.substr(strlen("--class-loader-context=")).ToString(); - class_loader_context_ = ClassLoaderContext::Create(context_str); - if (class_loader_context_ == nullptr) { - Usage("Invalid --class-loader-context '%s'", context_str.c_str()); - } + context_str_ = option.substr(strlen("--class-loader-context=")).ToString(); } else { Usage("Unknown argument '%s'", option.data()); } @@ -264,6 +260,17 @@ class DexoptAnalyzer final { } std::unique_ptr<Runtime> runtime(Runtime::Current()); + // Only when the runtime is created can we create the class loader context: the + // class loader context will open dex file and use the MemMap global lock that the + // runtime owns. + std::unique_ptr<ClassLoaderContext> class_loader_context; + if (!context_str_.empty()) { + class_loader_context = ClassLoaderContext::Create(context_str_); + if (class_loader_context == nullptr) { + Usage("Invalid --class-loader-context '%s'", context_str_.c_str()); + } + } + std::unique_ptr<OatFileAssistant> oat_file_assistant; oat_file_assistant = std::make_unique<OatFileAssistant>(dex_file_.c_str(), isa_, @@ -279,7 +286,7 @@ class DexoptAnalyzer final { } int dexoptNeeded = oat_file_assistant->GetDexOptNeeded( - compiler_filter_, assume_profile_changed_, downgrade_, class_loader_context_.get()); + compiler_filter_, assume_profile_changed_, downgrade_, class_loader_context.get()); // Convert OatFileAssitant codes to dexoptanalyzer codes. switch (dexoptNeeded) { @@ -300,7 +307,7 @@ class DexoptAnalyzer final { std::string dex_file_; InstructionSet isa_; CompilerFilter::Filter compiler_filter_; - std::unique_ptr<ClassLoaderContext> class_loader_context_; + std::string context_str_; bool assume_profile_changed_; bool downgrade_; std::string image_; diff --git a/dexoptanalyzer/dexoptanalyzer_test.cc b/dexoptanalyzer/dexoptanalyzer_test.cc index f6fd1fb014..7b6b36c133 100644 --- a/dexoptanalyzer/dexoptanalyzer_test.cc +++ b/dexoptanalyzer/dexoptanalyzer_test.cc @@ -36,7 +36,8 @@ class DexoptAnalyzerTest : public DexoptTest { int Analyze(const std::string& dex_file, CompilerFilter::Filter compiler_filter, - bool assume_profile_changed) { + bool assume_profile_changed, + const std::string& class_loader_context) { std::string dexoptanalyzer_cmd = GetDexoptAnalyzerCmd(); std::vector<std::string> argv_str; argv_str.push_back(dexoptanalyzer_cmd); @@ -52,6 +53,9 @@ class DexoptAnalyzerTest : public DexoptTest { argv_str.push_back(GetClassPathOption("-Xbootclasspath-locations:", GetLibCoreDexLocations())); argv_str.push_back("--image=" + GetImageLocation()); argv_str.push_back("--android-data=" + android_data_); + if (!class_loader_context.empty()) { + argv_str.push_back("--class-loader-context=" + class_loader_context); + } std::string error; return ExecAndReturnCode(argv_str, &error); @@ -74,8 +78,10 @@ class DexoptAnalyzerTest : public DexoptTest { void Verify(const std::string& dex_file, CompilerFilter::Filter compiler_filter, bool assume_profile_changed = false, - bool downgrade = false) { - int dexoptanalyzerResult = Analyze(dex_file, compiler_filter, assume_profile_changed); + bool downgrade = false, + const std::string& class_loader_context = "") { + int dexoptanalyzerResult = Analyze( + dex_file, compiler_filter, assume_profile_changed, class_loader_context); dexoptanalyzerResult = DexoptanalyzerToOatFileAssistant(dexoptanalyzerResult); OatFileAssistant oat_file_assistant(dex_file.c_str(), kRuntimeISA, /*load_executable=*/ false); int assistantResult = oat_file_assistant.GetDexOptNeeded( @@ -305,4 +311,22 @@ TEST_F(DexoptAnalyzerTest, ShortDexLocation) { Verify(dex_location, CompilerFilter::kSpeed); } +// Case: We have a DEX file and up-to-date OAT file for it, and we check with +// a class loader context. +TEST_F(DexoptAnalyzerTest, ClassLoaderContext) { + std::string dex_location1 = GetScratchDir() + "/DexToAnalyze.jar"; + std::string odex_location1 = GetOdexDir() + "/DexToAnalyze.odex"; + std::string dex_location2 = GetScratchDir() + "/DexInContext.jar"; + Copy(GetDexSrc1(), dex_location1); + Copy(GetDexSrc2(), dex_location2); + + std::string class_loader_context = "PCL[" + dex_location2 + "]"; + std::string class_loader_context_option = "--class-loader-context=PCL[" + dex_location2 + "]"; + + // Generate the odex to get the class loader context also open the dex files. + GenerateOdexForTest(dex_location1, odex_location1, CompilerFilter::kSpeed, /* compilation_reason= */ nullptr, /* extra_args= */ { class_loader_context_option }); + + Verify(dex_location1, CompilerFilter::kSpeed, false, false, class_loader_context); +} + } // namespace art diff --git a/libdexfile/Android.bp b/libdexfile/Android.bp index 9c48aa2c1b..2f56a3d105 100644 --- a/libdexfile/Android.bp +++ b/libdexfile/Android.bp @@ -176,6 +176,36 @@ art_cc_library { }, } +art_cc_test { + name: "art_libdexfile_tests", + defaults: [ + "art_gtest_defaults", + ], + srcs: [ + "dex/art_dex_file_loader_test.cc", + "dex/class_accessor_test.cc", + "dex/code_item_accessors_test.cc", + "dex/compact_dex_file_test.cc", + "dex/compact_offset_table_test.cc", + "dex/descriptors_names_test.cc", + "dex/test_dex_file_builder_test.cc", + "dex/dex_file_loader_test.cc", + "dex/dex_file_verifier_test.cc", + "dex/dex_instruction_test.cc", + "dex/primitive_test.cc", + "dex/string_reference_test.cc", + "dex/type_lookup_table_test.cc", + "dex/utf_test.cc", + ], + shared_libs: [ + "libbacktrace", + "libziparchive", + ], + include_dirs: [ + "external/zlib", + ], +} + cc_library_headers { name: "libdexfile_external_headers", host_supported: true, @@ -227,6 +257,16 @@ cc_library { }, } +art_cc_test { + name: "art_libdexfile_external_tests", + host_supported: true, + test_per_src: true, // For consistency with other ART gtests. + srcs: [ + "external/dex_file_ext_c_test.c", + ], + header_libs: ["libdexfile_external_headers"], +} + // Support library with a C++ API for accessing the libdexfile API for external // (non-ART) users. They should link to their own instance of this (either // statically or through linker namespaces). @@ -242,31 +282,16 @@ cc_library { } art_cc_test { - name: "art_libdexfile_tests", - defaults: [ - "art_gtest_defaults", - ], + name: "art_libdexfile_support_tests", + host_supported: true, + test_per_src: true, // For consistency with other ART gtests. srcs: [ - "dex/art_dex_file_loader_test.cc", - "dex/class_accessor_test.cc", - "dex/code_item_accessors_test.cc", - "dex/compact_dex_file_test.cc", - "dex/compact_offset_table_test.cc", - "dex/descriptors_names_test.cc", - "dex/test_dex_file_builder_test.cc", - "dex/dex_file_loader_test.cc", - "dex/dex_file_verifier_test.cc", - "dex/dex_instruction_test.cc", - "dex/primitive_test.cc", - "dex/string_reference_test.cc", - "dex/type_lookup_table_test.cc", - "dex/utf_test.cc", + "external/dex_file_supp_test.cc", ], shared_libs: [ - "libbacktrace", - "libziparchive", - ], - include_dirs: [ - "external/zlib", + "libartbase", + "libbase", + "libdexfile_external", + "libdexfile_support", ], } diff --git a/libdexfile/external/dex_file_ext.cc b/libdexfile/external/dex_file_ext.cc index 5c353b5ad8..e1b787472d 100644 --- a/libdexfile/external/dex_file_ext.cc +++ b/libdexfile/external/dex_file_ext.cc @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "art_api/dex_file_external.h" + #include <inttypes.h> #include <stdint.h> #include <sys/mman.h> @@ -39,18 +41,9 @@ #include <dex/dex_file-inl.h> #include <dex/dex_file_loader.h> -#include "art_api/ext_dex_file.h" - -extern "C" class ExtDexFileString { - public: - const std::string str_; -}; - namespace art { namespace { -const ExtDexFileString empty_string{""}; - struct MethodCacheEntry { int32_t offset; // Offset relative to the start of the dex file header. int32_t len; @@ -77,11 +70,17 @@ class MappedFileContainer : public DexFileContainer { extern "C" { -const ExtDexFileString* ExtDexFileMakeString(const char* str) { - if (str[0] == '\0') { - return &art::empty_string; +struct ExtDexFileString { + const std::string str_; +}; + +static const ExtDexFileString empty_string{""}; + +const ExtDexFileString* ExtDexFileMakeString(const char* str, size_t size) { + if (size == 0) { + return &empty_string; } - return new ExtDexFileString{str}; + return new ExtDexFileString{std::string(str, size)}; } const char* ExtDexFileGetString(const ExtDexFileString* ext_string, /*out*/ size_t* size) { @@ -92,14 +91,15 @@ const char* ExtDexFileGetString(const ExtDexFileString* ext_string, /*out*/ size void ExtDexFileFreeString(const ExtDexFileString* ext_string) { DCHECK(ext_string != nullptr); - if (ext_string != &art::empty_string) { + if (ext_string != &empty_string) { delete (ext_string); } } // Wraps DexFile to add the caching needed by the external interface. This is // what gets passed over as ExtDexFile*. -class ExtDexFile { +struct ExtDexFile { + private: // Method cache for GetMethodInfoForOffset. This is populated as we iterate // sequentially through the class defs. MethodCacheEntry.name is only set for // methods returned by GetMethodInfoForOffset. @@ -226,7 +226,10 @@ int ExtDexFileOpenFromFd(int fd, if (length < offset + sizeof(art::DexFile::Header)) { *ext_error_msg = new ExtDexFileString{android::base::StringPrintf( - "Offset %" PRId64 " too large for '%s' of size %zu", int64_t{offset}, location, length)}; + "Offset %" PRId64 " too large for '%s' of size %zu", + int64_t{offset}, + location, + length)}; return false; } @@ -282,6 +285,7 @@ int ExtDexFileOpenFromFd(int fd, int ExtDexFileGetMethodInfoForOffset(ExtDexFile* ext_dex_file, int64_t dex_offset, + int with_signature, /*out*/ ExtDexFileMethodInfo* method_info) { if (!ext_dex_file->dex_file_->IsInDataSection(ext_dex_file->dex_file_->Begin() + dex_offset)) { return false; // The DEX offset is not within the bytecode of this dex file. @@ -304,7 +308,7 @@ int ExtDexFileGetMethodInfoForOffset(ExtDexFile* ext_dex_file, method_info->offset = entry->offset; method_info->len = entry->len; method_info->name = - new ExtDexFileString{ext_dex_file->dex_file_->PrettyMethod(entry->index, false)}; + new ExtDexFileString{ext_dex_file->dex_file_->PrettyMethod(entry->index, with_signature)}; return true; } diff --git a/libdexfile/external/dex_file_ext_c_test.c b/libdexfile/external/dex_file_ext_c_test.c new file mode 100644 index 0000000000..c448a169ec --- /dev/null +++ b/libdexfile/external/dex_file_ext_c_test.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2019 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 <errno.h> +#include <stdio.h> +#include <string.h> + +/* The main purpose of this test is to ensure this C header compiles in C, so + * that no C++ features inadvertently leak into the C ABI. */ +#include "art_api/dex_file_external.h" + +static const char gtest_output_arg[] = "--gtest_output=xml:"; +static const char gtest_output_xml[] = "\ +<?xml version=\"1.0\"?>\n\ +<testsuites tests=\"0\" failures=\"0\" disabled=\"0\" errors=\"0\" name=\"AllTests\">"; + +/* Writes a dummy gtest xml report to the given path. */ +static int write_gtest_output_xml(char* gtest_output_path) { + FILE* output_fd = fopen(gtest_output_path, "w"); + if (output_fd == NULL) { + fprintf(stderr, "Failed to open %s: %s\n", gtest_output_path, strerror(errno)); + return 1; + } + if (fprintf(output_fd, gtest_output_xml) != sizeof(gtest_output_xml) - 1) { + fprintf(stderr, "Failed to write %s: %s\n", gtest_output_path, strerror(errno)); + fclose(output_fd); + return 1; + } + if (fclose(output_fd) != 0) { + fprintf(stderr, "Failed to close %s: %s\n", gtest_output_path, strerror(errno)); + return 1; + } + return 0; +} + +int main(int argc, char** argv) { + if (argc >= 2 && strncmp(argv[1], gtest_output_arg, sizeof(gtest_output_arg) - 1) == 0) { + /* The ART gtest framework expects all tests to understand --gtest_output. */ + return write_gtest_output_xml(argv[1] + sizeof(gtest_output_arg) - 1); + } + return 0; +} diff --git a/libdexfile/external/dex_file_supp.cc b/libdexfile/external/dex_file_supp.cc index 6514c8abf3..5bd25fcbdc 100644 --- a/libdexfile/external/dex_file_supp.cc +++ b/libdexfile/external/dex_file_supp.cc @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "art_api/ext_dex_file.h" +#include "art_api/dex_file_support.h" namespace art_api { namespace dex { diff --git a/libdexfile/external/dex_file_supp_test.cc b/libdexfile/external/dex_file_supp_test.cc new file mode 100644 index 0000000000..2f7ad5080f --- /dev/null +++ b/libdexfile/external/dex_file_supp_test.cc @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2019 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 <sys/types.h> + +#include <memory> +#include <string> +#include <string_view> + +#include <android-base/file.h> +#include <dex/dex_file.h> +#include <gtest/gtest.h> + +#include "art_api/dex_file_support.h" + +namespace art_api { +namespace dex { + +static constexpr uint32_t kDexData[] = { + 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab, + 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070, + 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8, + 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146, + 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006, + 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000, + 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000, + 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004, + 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001, + 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67, + 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661, + 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e, + 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001, + 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0, + 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002, + 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003, + 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c, +}; + +TEST(DexStringTest, alloc_string) { + auto s = DexString("123"); + EXPECT_EQ(std::string_view(s), "123"); +} + +TEST(DexStringTest, alloc_empty_string) { + auto s = DexString(""); + EXPECT_TRUE(std::string_view(s).empty()); +} + +TEST(DexStringTest, move_construct) { + auto s1 = DexString("foo"); + auto s2 = DexString(std::move(s1)); + EXPECT_TRUE(std::string_view(s1).empty()); + EXPECT_EQ(std::string_view(s2), "foo"); +} + +TEST(DexStringTest, move_assign) { + auto s1 = DexString("foo"); + DexString s2; + EXPECT_TRUE(std::string_view(s2).empty()); + s2 = std::move(s1); + EXPECT_TRUE(std::string_view(s1).empty()); + EXPECT_EQ(std::string_view(s2), "foo"); +} + +TEST(DexStringTest, reassign) { + auto s = DexString("foo"); + s = DexString("bar"); + EXPECT_EQ(std::string_view(s), "bar"); +} + +TEST(DexStringTest, data_access) { + auto s = DexString("foo"); + EXPECT_STREQ(s.data(), "foo"); + EXPECT_STREQ(s.c_str(), "foo"); +} + +TEST(DexStringTest, size_access) { + auto s = DexString("foo"); + EXPECT_EQ(s.size(), size_t{3}); + EXPECT_EQ(s.length(), size_t{3}); +} + +TEST(DexStringTest, equality) { + auto s = DexString("foo"); + EXPECT_EQ(s, DexString("foo")); + EXPECT_FALSE(s == DexString("bar")); +} + +TEST(DexStringTest, equality_with_nul) { + auto s = DexString(std::string("foo\0bar", 7)); + EXPECT_EQ(s.size(), size_t{7}); + EXPECT_EQ(s, DexString(std::string("foo\0bar", 7))); + EXPECT_FALSE(s == DexString(std::string("foo\0baz", 7))); +} + +TEST(DexFileTest, from_memory_header_too_small) { + size_t size = sizeof(art::DexFile::Header) - 1; + std::string error_msg; + EXPECT_EQ(DexFile::OpenFromMemory(kDexData, &size, "", &error_msg), nullptr); + EXPECT_EQ(size, sizeof(art::DexFile::Header)); + EXPECT_TRUE(error_msg.empty()); +} + +TEST(DexFileTest, from_memory_file_too_small) { + size_t size = sizeof(art::DexFile::Header); + std::string error_msg; + EXPECT_EQ(DexFile::OpenFromMemory(kDexData, &size, "", &error_msg), nullptr); + EXPECT_EQ(size, sizeof(kDexData)); + EXPECT_TRUE(error_msg.empty()); +} + +static std::unique_ptr<DexFile> GetTestDexData() { + size_t size = sizeof(kDexData); + std::string error_msg; + std::unique_ptr<DexFile> dex_file = DexFile::OpenFromMemory(kDexData, &size, "", &error_msg); + EXPECT_TRUE(error_msg.empty()); + return dex_file; +} + +TEST(DexFileTest, from_memory) { + EXPECT_NE(GetTestDexData(), nullptr); +} + +TEST(DexFileTest, from_fd_header_too_small) { + TemporaryFile tf; + ASSERT_NE(tf.fd, -1); + ASSERT_EQ(sizeof(art::DexFile::Header) - 1, + static_cast<size_t>( + TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header) - 1)))); + + std::string error_msg; + EXPECT_EQ(DexFile::OpenFromFd(tf.fd, 0, tf.path, &error_msg), nullptr); + EXPECT_FALSE(error_msg.empty()); +} + +TEST(DexFileTest, from_fd_file_too_small) { + TemporaryFile tf; + ASSERT_NE(tf.fd, -1); + ASSERT_EQ(sizeof(art::DexFile::Header), + static_cast<size_t>( + TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header))))); + + std::string error_msg; + EXPECT_EQ(DexFile::OpenFromFd(tf.fd, 0, tf.path, &error_msg), nullptr); + EXPECT_FALSE(error_msg.empty()); +} + +TEST(DexFileTest, from_fd) { + TemporaryFile tf; + ASSERT_NE(tf.fd, -1); + ASSERT_EQ(sizeof(kDexData), + static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData))))); + + std::string error_msg; + EXPECT_NE(DexFile::OpenFromFd(tf.fd, 0, tf.path, &error_msg), nullptr); + EXPECT_TRUE(error_msg.empty()); +} + +TEST(DexFileTest, from_fd_non_zero_offset) { + TemporaryFile tf; + ASSERT_NE(tf.fd, -1); + ASSERT_EQ(0x100, lseek(tf.fd, 0x100, SEEK_SET)); + ASSERT_EQ(sizeof(kDexData), + static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData))))); + + std::string error_msg; + EXPECT_NE(DexFile::OpenFromFd(tf.fd, 0x100, tf.path, &error_msg), nullptr); + EXPECT_TRUE(error_msg.empty()); +} + +TEST(DexFileTest, get_method_info_for_offset_without_signature) { + std::unique_ptr<DexFile> dex_file = GetTestDexData(); + ASSERT_NE(dex_file, nullptr); + + MethodInfo info = dex_file->GetMethodInfoForOffset(0x102, false); + EXPECT_EQ(info.offset, int32_t{0x100}); + EXPECT_EQ(info.len, int32_t{8}); + EXPECT_STREQ(info.name.data(), "Main.<init>"); + + info = dex_file->GetMethodInfoForOffset(0x118, false); + EXPECT_EQ(info.offset, int32_t{0x118}); + EXPECT_EQ(info.len, int32_t{2}); + EXPECT_STREQ(info.name.data(), "Main.main"); + + // Retrieve a cached result. + info = dex_file->GetMethodInfoForOffset(0x104, false); + EXPECT_EQ(info.offset, int32_t{0x100}); + EXPECT_EQ(info.len, int32_t{8}); + EXPECT_STREQ(info.name.data(), "Main.<init>"); +} + +TEST(DexFileTest, get_method_info_for_offset_with_signature) { + std::unique_ptr<DexFile> dex_file = GetTestDexData(); + ASSERT_NE(dex_file, nullptr); + + MethodInfo info = dex_file->GetMethodInfoForOffset(0x102, true); + EXPECT_EQ(info.offset, int32_t{0x100}); + EXPECT_EQ(info.len, int32_t{8}); + EXPECT_STREQ(info.name.data(), "void Main.<init>()"); + + info = dex_file->GetMethodInfoForOffset(0x118, true); + EXPECT_EQ(info.offset, int32_t{0x118}); + EXPECT_EQ(info.len, int32_t{2}); + EXPECT_STREQ(info.name.data(), "void Main.main(java.lang.String[])"); + + // Retrieve a cached result. + info = dex_file->GetMethodInfoForOffset(0x104, true); + EXPECT_EQ(info.offset, int32_t{0x100}); + EXPECT_EQ(info.len, int32_t{8}); + EXPECT_STREQ(info.name.data(), "void Main.<init>()"); + + // with_signature doesn't affect the cache. + info = dex_file->GetMethodInfoForOffset(0x104, false); + EXPECT_EQ(info.offset, int32_t{0x100}); + EXPECT_EQ(info.len, int32_t{8}); + EXPECT_STREQ(info.name.data(), "Main.<init>"); +} + +TEST(DexFileTest, get_method_info_for_offset_boundaries) { + std::unique_ptr<DexFile> dex_file = GetTestDexData(); + ASSERT_NE(dex_file, nullptr); + + MethodInfo info = dex_file->GetMethodInfoForOffset(0x100000, false); + EXPECT_EQ(info.offset, int32_t{0}); + + info = dex_file->GetMethodInfoForOffset(0x99, false); + EXPECT_EQ(info.offset, int32_t{0}); + info = dex_file->GetMethodInfoForOffset(0x100, false); + EXPECT_EQ(info.offset, int32_t{0x100}); + info = dex_file->GetMethodInfoForOffset(0x107, false); + EXPECT_EQ(info.offset, int32_t{0x100}); + info = dex_file->GetMethodInfoForOffset(0x108, false); + EXPECT_EQ(info.offset, int32_t{0}); + + // Make sure that once the whole dex file has been cached, no problems occur. + info = dex_file->GetMethodInfoForOffset(0x98, false); + EXPECT_EQ(info.offset, int32_t{0}); + + // Choose a value that is in the cached map, but not in a valid method. + info = dex_file->GetMethodInfoForOffset(0x110, false); + EXPECT_EQ(info.offset, int32_t{0}); +} + +TEST(DexFileTest, get_all_method_infos_without_signature) { + std::unique_ptr<DexFile> dex_file = GetTestDexData(); + ASSERT_NE(dex_file, nullptr); + + std::vector<MethodInfo> infos; + infos.emplace_back(MethodInfo{0x100, 8, DexString("Main.<init>")}); + infos.emplace_back(MethodInfo{0x118, 2, DexString("Main.main")}); + ASSERT_EQ(dex_file->GetAllMethodInfos(false), infos); +} + +TEST(DexFileTest, get_all_method_infos_with_signature) { + std::unique_ptr<DexFile> dex_file = GetTestDexData(); + ASSERT_NE(dex_file, nullptr); + + std::vector<MethodInfo> infos; + infos.emplace_back(MethodInfo{0x100, 8, DexString("void Main.<init>()")}); + infos.emplace_back(MethodInfo{0x118, 2, DexString("void Main.main(java.lang.String[])")}); + ASSERT_EQ(dex_file->GetAllMethodInfos(true), infos); +} + +TEST(DexFileTest, move_construct) { + std::unique_ptr<DexFile> dex_file = GetTestDexData(); + ASSERT_NE(dex_file, nullptr); + + auto df1 = DexFile(std::move(*dex_file)); + auto df2 = DexFile(std::move(df1)); + + MethodInfo info = df2.GetMethodInfoForOffset(0x100, false); + EXPECT_EQ(info.offset, int32_t{0x100}); +} + +} // namespace dex +} // namespace art_api diff --git a/libdexfile/external/include/art_api/dex_file_external.h b/libdexfile/external/include/art_api/dex_file_external.h new file mode 100644 index 0000000000..b29e759644 --- /dev/null +++ b/libdexfile/external/include/art_api/dex_file_external.h @@ -0,0 +1,89 @@ +/* + * 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. + */ + +#ifndef ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_DEX_FILE_EXTERNAL_H_ +#define ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_DEX_FILE_EXTERNAL_H_ + +// Dex file external API + +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +// This is the stable C ABI that backs art_api::dex below. Structs and functions +// may only be added here. C++ users should use dex_file_support.h instead. + +// Opaque wrapper for an std::string allocated in libdexfile which must be freed +// using ExtDexFileFreeString. +struct ExtDexFileString; + +// Returns an ExtDexFileString initialized to the given string. +const struct ExtDexFileString* ExtDexFileMakeString(const char* str, size_t size); + +// Returns a pointer to the underlying null-terminated character array and its +// size for the given ExtDexFileString. +const char* ExtDexFileGetString(const struct ExtDexFileString* ext_string, /*out*/ size_t* size); + +// Frees an ExtDexFileString. +void ExtDexFileFreeString(const struct ExtDexFileString* ext_string); + +struct ExtDexFileMethodInfo { + int32_t offset; + int32_t len; + const struct ExtDexFileString* name; +}; + +struct ExtDexFile; + +// See art_api::dex::DexFile::OpenFromMemory. Returns true on success. +int ExtDexFileOpenFromMemory(const void* addr, + /*inout*/ size_t* size, + const char* location, + /*out*/ const struct ExtDexFileString** error_msg, + /*out*/ struct ExtDexFile** ext_dex_file); + +// See art_api::dex::DexFile::OpenFromFd. Returns true on success. +int ExtDexFileOpenFromFd(int fd, + off_t offset, + const char* location, + /*out*/ const struct ExtDexFileString** error_msg, + /*out*/ struct ExtDexFile** ext_dex_file); + +// See art_api::dex::DexFile::GetMethodInfoForOffset. Returns true on success. +int ExtDexFileGetMethodInfoForOffset(struct ExtDexFile* ext_dex_file, + int64_t dex_offset, + int with_signature, + /*out*/ struct ExtDexFileMethodInfo* method_info); + +typedef void ExtDexFileMethodInfoCallback(const struct ExtDexFileMethodInfo* ext_method_info, + void* user_data); + +// See art_api::dex::DexFile::GetAllMethodInfos. +void ExtDexFileGetAllMethodInfos(struct ExtDexFile* ext_dex_file, + int with_signature, + ExtDexFileMethodInfoCallback* method_info_cb, + void* user_data); + +// Frees an ExtDexFile. +void ExtDexFileFree(struct ExtDexFile* ext_dex_file); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_DEX_FILE_EXTERNAL_H_ diff --git a/libdexfile/external/include/art_api/ext_dex_file.h b/libdexfile/external/include/art_api/dex_file_support.h index 4a52a2b849..24222af4dc 100644 --- a/libdexfile/external/include/art_api/ext_dex_file.h +++ b/libdexfile/external/include/art_api/dex_file_support.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 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. @@ -14,83 +14,21 @@ * limitations under the License. */ -#ifndef ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_EXT_DEX_FILE_H_ -#define ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_EXT_DEX_FILE_H_ +#ifndef ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_DEX_FILE_SUPPORT_H_ +#define ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_DEX_FILE_SUPPORT_H_ -// Dex file external API - -#include <sys/types.h> +// C++ wrapper for the dex file external API. #include <cstring> #include <memory> #include <string> #include <string_view> +#include <utility> #include <vector> #include <android-base/macros.h> -extern "C" { - -// This is the stable C ABI that backs art_api::dex below. Structs and functions -// may only be added here. -// TODO(b/120978655): Move this to a separate pure C header. -// -// Clients should use the C++ wrappers in art_api::dex instead. - -// Opaque wrapper for an std::string allocated in libdexfile which must be freed -// using ExtDexFileFreeString. -class ExtDexFileString; - -// Returns an ExtDexFileString initialized to the given string. -const ExtDexFileString* ExtDexFileMakeString(const char* str); - -// Returns a pointer to the underlying null-terminated character array and its -// size for the given ExtDexFileString. -const char* ExtDexFileGetString(const ExtDexFileString* ext_string, /*out*/ size_t* size); - -// Frees an ExtDexFileString. -void ExtDexFileFreeString(const ExtDexFileString* ext_string); - -struct ExtDexFileMethodInfo { - int32_t offset; - int32_t len; - const ExtDexFileString* name; -}; - -class ExtDexFile; - -// See art_api::dex::DexFile::OpenFromMemory. Returns true on success. -int ExtDexFileOpenFromMemory(const void* addr, - /*inout*/ size_t* size, - const char* location, - /*out*/ const ExtDexFileString** error_msg, - /*out*/ ExtDexFile** ext_dex_file); - -// See art_api::dex::DexFile::OpenFromFd. Returns true on success. -int ExtDexFileOpenFromFd(int fd, - off_t offset, - const char* location, - /*out*/ const ExtDexFileString** error_msg, - /*out*/ ExtDexFile** ext_dex_file); - -// See art_api::dex::DexFile::GetMethodInfoForOffset. Returns true on success. -int ExtDexFileGetMethodInfoForOffset(ExtDexFile* ext_dex_file, - int64_t dex_offset, - /*out*/ ExtDexFileMethodInfo* method_info); - -typedef void ExtDexFileMethodInfoCallback(const ExtDexFileMethodInfo* ext_method_info, - void* user_data); - -// See art_api::dex::DexFile::GetAllMethodInfos. -void ExtDexFileGetAllMethodInfos(ExtDexFile* ext_dex_file, - int with_signature, - ExtDexFileMethodInfoCallback* method_info_cb, - void* user_data); - -// Frees an ExtDexFile. -void ExtDexFileFree(ExtDexFile* ext_dex_file); - -} // extern "C" +#include "art_api/dex_file_external.h" namespace art_api { namespace dex { @@ -98,12 +36,17 @@ namespace dex { // Minimal std::string look-alike for a string returned from libdexfile. class DexString final { public: - DexString(DexString&& dex_str) noexcept { ReplaceExtString(std::move(dex_str)); } - explicit DexString(const char* str = "") : ext_string_(ExtDexFileMakeString(str)) {} + DexString(DexString&& dex_str) noexcept : ext_string_(dex_str.ext_string_) { + dex_str.ext_string_ = ExtDexFileMakeString("", 0); + } + explicit DexString(const char* str = "") + : ext_string_(ExtDexFileMakeString(str, std::strlen(str))) {} + explicit DexString(std::string_view str) + : ext_string_(ExtDexFileMakeString(str.data(), str.size())) {} ~DexString() { ExtDexFileFreeString(ext_string_); } DexString& operator=(DexString&& dex_str) noexcept { - ReplaceExtString(std::move(dex_str)); + std::swap(ext_string_, dex_str.ext_string_); return *this; } @@ -132,11 +75,6 @@ class DexString final { explicit DexString(const ExtDexFileString* ext_string) : ext_string_(ext_string) {} const ExtDexFileString* ext_string_; // Owned instance. Never nullptr. - void ReplaceExtString(DexString&& dex_str) { - ext_string_ = dex_str.ext_string_; - dex_str.ext_string_ = ExtDexFileMakeString(""); - } - DISALLOW_COPY_AND_ASSIGN(DexString); }; @@ -211,10 +149,15 @@ class DexFile { // Given an offset relative to the start of the dex file header, if there is a // method whose instruction range includes that offset then returns info about - // it, otherwise returns a struct with offset == 0. - MethodInfo GetMethodInfoForOffset(int64_t dex_offset) { + // it, otherwise returns a struct with offset == 0. MethodInfo.name receives + // the full function signature if with_signature is set, otherwise it gets the + // class and method name only. + MethodInfo GetMethodInfoForOffset(int64_t dex_offset, bool with_signature) { ExtDexFileMethodInfo ext_method_info; - if (ExtDexFileGetMethodInfoForOffset(ext_dex_file_, dex_offset, &ext_method_info)) { + if (ExtDexFileGetMethodInfoForOffset(ext_dex_file_, + dex_offset, + with_signature, + &ext_method_info)) { return AbsorbMethodInfo(ext_method_info); } return {/*offset=*/0, /*len=*/0, /*name=*/DexString()}; @@ -223,10 +166,12 @@ class DexFile { // Returns info structs about all methods in the dex file. MethodInfo.name // receives the full function signature if with_signature is set, otherwise it // gets the class and method name only. - std::vector<MethodInfo> GetAllMethodInfos(bool with_signature = true) { + std::vector<MethodInfo> GetAllMethodInfos(bool with_signature) { MethodInfoVector res; - ExtDexFileGetAllMethodInfos( - ext_dex_file_, with_signature, AddMethodInfoCallback, static_cast<void*>(&res)); + ExtDexFileGetAllMethodInfos(ext_dex_file_, + with_signature, + AddMethodInfoCallback, + static_cast<void*>(&res)); return res; } @@ -245,4 +190,4 @@ class DexFile { } // namespace dex } // namespace art_api -#endif // ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_EXT_DEX_FILE_H_ +#endif // ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_DEX_FILE_SUPPORT_H_ diff --git a/runtime/dexopt_test.cc b/runtime/dexopt_test.cc index 7f697d1eb8..9c0ac8fc54 100644 --- a/runtime/dexopt_test.cc +++ b/runtime/dexopt_test.cc @@ -72,7 +72,8 @@ void DexoptTest::GenerateOatForTest(const std::string& dex_location, const std::string& oat_location, CompilerFilter::Filter filter, bool with_alternate_image, - const char* compilation_reason) { + const char* compilation_reason, + const std::vector<std::string>& extra_args) { std::string dalvik_cache = GetDalvikCache(GetInstructionSetString(kRuntimeISA)); std::string dalvik_cache_tmp = dalvik_cache + ".redirected"; @@ -101,6 +102,8 @@ void DexoptTest::GenerateOatForTest(const std::string& dex_location, args.push_back("--compilation-reason=" + std::string(compilation_reason)); } + args.insert(args.end(), extra_args.begin(), extra_args.end()); + std::string error_msg; ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg; @@ -136,12 +139,14 @@ void DexoptTest::GenerateOatForTest(const std::string& dex_location, void DexoptTest::GenerateOdexForTest(const std::string& dex_location, const std::string& odex_location, CompilerFilter::Filter filter, - const char* compilation_reason) { + const char* compilation_reason, + const std::vector<std::string>& extra_args) { GenerateOatForTest(dex_location, odex_location, filter, /*with_alternate_image=*/ false, - compilation_reason); + compilation_reason, + extra_args); } void DexoptTest::GenerateOatForTest(const char* dex_location, diff --git a/runtime/dexopt_test.h b/runtime/dexopt_test.h index efbdcbaa07..026fe55131 100644 --- a/runtime/dexopt_test.h +++ b/runtime/dexopt_test.h @@ -42,13 +42,15 @@ class DexoptTest : public Dex2oatEnvironmentTest { const std::string& oat_location, CompilerFilter::Filter filter, bool with_alternate_image, - const char* compilation_reason = nullptr); + const char* compilation_reason = nullptr, + const std::vector<std::string>& extra_args = {}); // Generate an odex file for the purposes of test. void GenerateOdexForTest(const std::string& dex_location, const std::string& odex_location, CompilerFilter::Filter filter, - const char* compilation_reason = nullptr); + const char* compilation_reason = nullptr, + const std::vector<std::string>& extra_args = {}); // Generate an oat file for the given dex location in its oat location (under // the dalvik cache). diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar index 25b8b4b55b..307476384a 100755 --- a/test/etc/run-test-jar +++ b/test/etc/run-test-jar @@ -319,6 +319,10 @@ while true; do shift ANDROID_ROOT="$1" shift + elif [ "x$1" = "x--android-runtime-root" ]; then + shift + ANDROID_RUNTIME_ROOT="$1" + shift elif [ "x$1" = "x--instruction-set-features" ]; then shift INSTRUCTION_SET_FEATURES="$1" diff --git a/test/run-test b/test/run-test index 83c726e9e5..67bcce7deb 100755 --- a/test/run-test +++ b/test/run-test @@ -386,6 +386,15 @@ while true; do android_root="$1" run_args="${run_args} --android-root $1" shift + elif [ "x$1" = "x--android-runtime-root" ]; then + shift + if [ "x$1" = "x" ]; then + echo "$0 missing argument to --android-runtime-root" 1>&2 + usage="yes" + break + fi + run_args="${run_args} --android-runtime-root $1" + shift elif [ "x$1" = "x--update" ]; then update_mode="yes" shift @@ -758,6 +767,9 @@ if [ "$usage" = "yes" ]; then echo " --never-clean Keep the test files even if the test succeeds." echo " --chroot [newroot] Run with root directory set to newroot." echo " --android-root [path] The path on target for the android root. (/system by default)." + echo " --android-runtime-root [path]" + echo " The path on target for the Android Runtime root." + echo " (/apex/com.android.runtime by default)." echo " --dex2oat-swap Use a dex2oat swap file." echo " --instruction-set-features [string]" echo " Set instruction-set-features for compilation." diff --git a/test/testrunner/env.py b/test/testrunner/env.py index 1f4b829989..c2d5e7d5fa 100644 --- a/test/testrunner/env.py +++ b/test/testrunner/env.py @@ -89,8 +89,8 @@ HOST_2ND_ARCH_PREFIX_DEX2OAT_HOST_INSTRUCTION_SET_FEATURES = _env.get( HOST_2ND_ARCH_PREFIX + 'DEX2OAT_HOST_INSTRUCTION_SET_FEATURES') ART_TEST_CHROOT = _env.get('ART_TEST_CHROOT') - ART_TEST_ANDROID_ROOT = _env.get('ART_TEST_ANDROID_ROOT') +ART_TEST_ANDROID_RUNTIME_ROOT = _env.get('ART_TEST_ANDROID_RUNTIME_ROOT') ART_TEST_WITH_STRACE = _getEnvBoolean('ART_TEST_DEBUG_GC', False) diff --git a/test/testrunner/testrunner.py b/test/testrunner/testrunner.py index 4e873c1ba2..0456fdb55c 100755 --- a/test/testrunner/testrunner.py +++ b/test/testrunner/testrunner.py @@ -400,12 +400,15 @@ def run_tests(tests): elif target == 'jvm': options_test += ' --jvm' - # Honor ART_TEST_CHROOT and ART_TEST_ANDROID_ROOT, but only for target tests. + # Honor ART_TEST_CHROOT, ART_TEST_ANDROID_ROOT and ART_TEST_ANDROID_RUNTIME_ROOT, + # but only for target tests. if target == 'target': if env.ART_TEST_CHROOT: options_test += ' --chroot ' + env.ART_TEST_CHROOT if env.ART_TEST_ANDROID_ROOT: options_test += ' --android-root ' + env.ART_TEST_ANDROID_ROOT + if env.ART_TEST_ANDROID_RUNTIME_ROOT: + options_test += ' --android-runtime-root ' + env.ART_TEST_ANDROID_RUNTIME_ROOT if run == 'ndebug': options_test += ' -O' @@ -199,6 +199,7 @@ function run_dex2oat() { # (see run_art function) verbose_run ANDROID_DATA=$ANDROID_DATA \ ANDROID_ROOT=$ANDROID_ROOT \ + ANDROID_RUNTIME_ROOT=$ANDROID_RUNTIME_ROOT \ LD_LIBRARY_PATH=$LD_LIBRARY_PATH \ PATH=$ANDROID_ROOT/bin:$PATH \ LD_USE_LOAD_BIAS=1 \ @@ -399,7 +400,36 @@ done PROG_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)" ANDROID_ROOT="$(cd $PROG_DIR/..; pwd -P)" -ANDROID_RUNTIME_ROOT=$ANDROID_ROOT/com.android.runtime +# This script is used on host and target (device). However, the (expected) +# default value `ANDROID_RUNTIME_ROOT` is not the same on host and target: +# - on host, `ANDROID_RUNTIME_ROOT` is expected to be "$ANDROID_ROOT/com.android.apex"; +# - on target, `ANDROID_RUNTIME_ROOT` is expected to be "$ANDROID_ROOT/../apex/com.android.apex". +# +# We use the presence/absence of the `$ANDROID_ROOT/../apex` directory to +# determine whether we are on target or host (this is brittle, but simple). +if [ -d "$ANDROID_ROOT/../apex" ]; then + # Target case. + # + # We should be setting `ANDROID_RUNTIME_ROOT` to + # "$ANDROID_ROOT/../apex/com.android.runtime" here. However, the Runtime APEX + # is not (yet) supported by the ART Buildbot setup (see b/121117762); and yet + # ICU code depends on `ANDROID_RUNTIME_ROOT` to find ICU .dat files. + # + # As a temporary workaround, we: + # - make the ART Buildbot build script (art/tools/buildbot-build.sh) also + # generate the ICU .dat files in `/system/etc/icu` on device (these files + # are normally only put in the Runtime APEX on device); + # - set `ANDROID_RUNTIME_ROOT` to `$ANDROID_ROOT` (i.e. "/system") here. + # + # TODO(b/121117762): Set `ANDROID_RUNTIME_ROOT` to + # "$ANDROID_ROOT/../apex/com.android.runtime" when the Runtime APEX is fully + # supported on the ART Buildbot and Golem. + ANDROID_RUNTIME_ROOT=$ANDROID_ROOT +else + # Host case. + ANDROID_RUNTIME_ROOT="$ANDROID_ROOT/com.android.runtime" +fi + ART_BINARY_PATH=$ANDROID_ROOT/bin/$ART_BINARY if [ ! -x "$ART_BINARY_PATH" ]; then @@ -434,7 +464,7 @@ ISA=$(LD_LIBRARY_PATH=$LD_LIBRARY_PATH $ART_BINARY_PATH -showversion | (read art # Extract the dex2oat flags from the list of arguments. # -Xcompiler-options arguments are stored in DEX2OAT_FLAGS array # -cp argument is split by ':' and stored in DEX2OAT_CLASSPATH -# -Ximage argument is stored in DEX2OAT_BOOTIMAGE +# -Ximage argument is stored in DEX2OAT_BOOT_IMAGE extract_dex2oat_flags "$@" # If ANDROID_DATA is the system ANDROID_DATA or is not set, use our own, @@ -456,7 +486,7 @@ if [[ "$DEX2OAT_BCP" = "" && "$DEX2OAT_BCP_LOCS" != "" ]]; then exit 1 fi -if [[ "$DEX2OAT_BOOT_IMAGE" = *core.art && "$DEX2OAT_BCP" = "" ]]; then +if [[ "$DEX2OAT_BOOT_IMAGE" = *core*.art && "$DEX2OAT_BCP" = "" ]]; then # Note: This must start with the CORE_IMG_JARS in Android.common_path.mk # because that's what we use for compiling the core.art image. # It may contain additional modules from TEST_CORE_JARS. diff --git a/tools/buildbot-build.sh b/tools/buildbot-build.sh index ce1a246aa9..755104b240 100755 --- a/tools/buildbot-build.sh +++ b/tools/buildbot-build.sh @@ -83,6 +83,23 @@ elif [[ $mode == "target" ]]; then fi # Build the Debug Runtime APEX (which is a superset of the Release Runtime APEX). make_command+=" com.android.runtime.debug" + # Build the bootstrap Bionic libraries (libc, libdl, libm). These are required + # as the "main" libc, libdl, and libm have moved to the Runtime APEX. This is + # a temporary change needed until both the ART Buildbot and Golem fully + # support the Runtime APEX. + # + # TODO(b/121117762): Remove this when the ART Buildbot and Golem have full + # support for the Runtime APEX. + make_command+=" libc.bootstrap libdl.bootstrap libm.bootstrap" + # Create a copy of the ICU .dat prebuilt files in /system/etc/icu on target, + # so that it can found even if the Runtime APEX is not available, by setting + # the environment variable `ART_TEST_ANDROID_RUNTIME_ROOT` to "/system" on + # device. This is a temporary change needed until both the ART Buildbot and + # Golem fully support the Runtime APEX. + # + # TODO(b/121117762): Remove this when the ART Buildbot and Golem have full + # support for the Runtime APEX. + make_command+=" icu-data-art-test" mode_suffix="-target" fi diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt index 3f9ceea878..a2777e8215 100644 --- a/tools/libcore_failures.txt +++ b/tools/libcore_failures.txt @@ -227,7 +227,7 @@ { description: "Apex related", result: EXEC_FAILED, - modes: [device], + modes: [device_testdex], bug: 122642227, names: [ "libcore.java.lang.SystemTest#testSystemProperties_mutable", |