Merge "Refactor image relocation"
diff --git a/Android.mk b/Android.mk
index a2d8f64..1a5daff 100644
--- a/Android.mk
+++ b/Android.mk
@@ -488,6 +488,22 @@
.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 @@
$(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 a926d9a..f00da9c 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -371,8 +371,8 @@
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_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 @@
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 79f67a2..47729c1 100644
--- a/build/apex/Android.bp
+++ b/build/apex/Android.bp
@@ -43,11 +43,12 @@
"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 @@
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 @@
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 014b115..9e49d76 100644
--- a/build/apex/ld.config.txt
+++ b/build/apex/ld.config.txt
@@ -24,8 +24,7 @@
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/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index 7733cb7..15ced72 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -2429,7 +2429,9 @@
size_t bin_offset = image_objects_offset_begin_;
// Need to visit the objects in bin order since alignment requirements might change the
// section sizes.
- using BinPair = std::pair<BinSlot, ObjPtr<mirror::Object>>;
+ // Avoid using ObjPtr since VisitObjects invalidates. This is safe since concurrent GC can not
+ // occur during image writing.
+ using BinPair = std::pair<BinSlot, mirror::Object*>;
std::vector<BinPair> objects;
heap->VisitObjects([&](mirror::Object* obj)
REQUIRES_SHARED(Locks::mutator_lock_) {
diff --git a/dexoptanalyzer/dexoptanalyzer.cc b/dexoptanalyzer/dexoptanalyzer.cc
index acf0f94..92850f7 100644
--- a/dexoptanalyzer/dexoptanalyzer.cc
+++ b/dexoptanalyzer/dexoptanalyzer.cc
@@ -202,11 +202,7 @@
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 @@
}
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 @@
}
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 @@
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 f6fd1fb..7b6b36c 100644
--- a/dexoptanalyzer/dexoptanalyzer_test.cc
+++ b/dexoptanalyzer/dexoptanalyzer_test.cc
@@ -36,7 +36,8 @@
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 @@
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 @@
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 @@
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 9c48aa2..2f56a3d 100644
--- a/libdexfile/Android.bp
+++ b/libdexfile/Android.bp
@@ -176,6 +176,36 @@
},
}
+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 @@
},
}
+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 @@
}
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 5c353b5..e1b7874 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 @@
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 @@
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 @@
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 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 @@
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 0000000..c448a16
--- /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 6514c8a..5bd25fc 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 0000000..2f7ad50
--- /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 0000000..b29e759
--- /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
similarity index 62%
rename from libdexfile/external/include/art_api/ext_dex_file.h
rename to libdexfile/external/include/art_api/dex_file_support.h
index 4a52a2b..24222af 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 @@
// 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 @@
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 @@
// 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 @@
// 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 @@
} // 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 7f697d1..9c0ac8f 100644
--- a/runtime/dexopt_test.cc
+++ b/runtime/dexopt_test.cc
@@ -72,7 +72,8 @@
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 @@
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::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 efbdcba..026fe55 100644
--- a/runtime/dexopt_test.h
+++ b/runtime/dexopt_test.h
@@ -42,13 +42,15 @@
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/runtime/gc/heap.h b/runtime/gc/heap.h
index 341f16a..52c9386 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -441,6 +441,10 @@
return process_cpu_start_time_ns_;
}
+ uint64_t GetPostGCLastProcessCpuTime() const {
+ return post_gc_last_process_cpu_time_ns_;
+ }
+
// Set target ideal heap utilization ratio, implements
// dalvik.system.VMRuntime.setTargetHeapUtilization.
void SetTargetHeapUtilization(float target);
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index eea7c67..d79793b 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -324,7 +324,6 @@
if (dump_gc_performance_on_shutdown_) {
heap_->CalculatePreGcWeightedAllocatedBytes();
- heap_->CalculatePostGcWeightedAllocatedBytes();
uint64_t process_cpu_end_time = ProcessCpuNanoTime();
ScopedLogSeverity sls(LogSeverity::INFO);
// This can't be called from the Heap destructor below because it
@@ -341,8 +340,12 @@
<< "\n";
double pre_gc_weighted_allocated_bytes =
heap_->GetPreGcWeightedAllocatedBytes() / process_cpu_time;
+ // Here we don't use process_cpu_time for normalization, because VM shutdown is not a real
+ // GC. Both numerator and denominator take into account until the end of the last GC,
+ // instead of the whole process life time like pre_gc_weighted_allocated_bytes.
double post_gc_weighted_allocated_bytes =
- heap_->GetPostGcWeightedAllocatedBytes() / process_cpu_time;
+ heap_->GetPostGcWeightedAllocatedBytes() /
+ (heap_->GetPostGCLastProcessCpuTime() - heap_->GetProcessCpuStartTime());
LOG_STREAM(INFO) << "Average bytes allocated at GC start, weighted by CPU time between GCs: "
<< static_cast<uint64_t>(pre_gc_weighted_allocated_bytes)
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 25b8b4b..3074763 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -319,6 +319,10 @@
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 83c726e..67bcce7 100755
--- a/test/run-test
+++ b/test/run-test
@@ -386,6 +386,15 @@
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 @@
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 1f4b829..c2d5e7d 100644
--- a/test/testrunner/env.py
+++ b/test/testrunner/env.py
@@ -89,8 +89,8 @@
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 4e873c1..0456fdb 100755
--- a/test/testrunner/testrunner.py
+++ b/test/testrunner/testrunner.py
@@ -400,12 +400,15 @@
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'
diff --git a/tools/art b/tools/art
index 6e43863..d99e2d8 100644
--- a/tools/art
+++ b/tools/art
@@ -199,6 +199,7 @@
# (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 @@
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 @@
# 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 @@
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 ce1a246..755104b 100755
--- a/tools/buildbot-build.sh
+++ b/tools/buildbot-build.sh
@@ -83,6 +83,23 @@
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 3f9ceea..a2777e8 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",