Merge "Reland "Bionic libs are located at /system/lib"""
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index a926d9a..00055b2 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),\
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..85cd46e
--- /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 >= 1 && 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..3dd08c0
--- /dev/null
+++ b/libdexfile/external/dex_file_supp_test.cc
@@ -0,0 +1,283 @@
+/*
+ * 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, 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.release()));
+ 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 64%
rename from libdexfile/external/include/art_api/ext_dex_file.h
rename to libdexfile/external/include/art_api/dex_file_support.h
index 4a52a2b..ddd9143 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,12 +14,10 @@
* 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>
@@ -29,68 +27,7 @@
#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 {
@@ -99,7 +36,10 @@
class DexString final {
public:
DexString(DexString&& dex_str) noexcept { ReplaceExtString(std::move(dex_str)); }
- explicit DexString(const char* str = "") : ext_string_(ExtDexFileMakeString(str)) {}
+ 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 {
@@ -134,7 +74,7 @@
void ReplaceExtString(DexString&& dex_str) {
ext_string_ = dex_str.ext_string_;
- dex_str.ext_string_ = ExtDexFileMakeString("");
+ dex_str.ext_string_ = ExtDexFileMakeString("", 0);
}
DISALLOW_COPY_AND_ASSIGN(DexString);
@@ -211,10 +151,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 +168,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 +192,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/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/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",