Add DexFileLoader class
Added DexFileLoader class, moved functionality from DexFile there:
- Multidex loading logic
- DexFile opening logic for Zip and etc
- Some other helpers
Bug: 63756964
Test: test-art-host
Change-Id: Ic3dfa458947d4b69912dea5cdd836e7e8f55061c
diff --git a/compiler/utils/test_dex_file_builder.h b/compiler/utils/test_dex_file_builder.h
index 8ef9882..e6501e0 100644
--- a/compiler/utils/test_dex_file_builder.h
+++ b/compiler/utils/test_dex_file_builder.h
@@ -26,6 +26,7 @@
#include "base/bit_utils.h"
#include "base/logging.h"
+#include "dex_file_loader.h"
#include "native_dex_file.h"
namespace art {
@@ -231,7 +232,7 @@
static constexpr bool kVerify = false;
static constexpr bool kVerifyChecksum = false;
std::string error_msg;
- std::unique_ptr<const DexFile> dex_file(DexFile::Open(
+ std::unique_ptr<const DexFile> dex_file(DexFileLoader::Open(
&dex_file_data_[0],
dex_file_data_.size(),
dex_location,
diff --git a/dex2oat/dex2oat_image_test.cc b/dex2oat/dex2oat_image_test.cc
index f20e934..ae7ebe2 100644
--- a/dex2oat/dex2oat_image_test.cc
+++ b/dex2oat/dex2oat_image_test.cc
@@ -28,6 +28,7 @@
#include "base/macros.h"
#include "base/unix_file/fd_file.h"
#include "dex_file-inl.h"
+#include "dex_file_loader.h"
#include "jit/profile_compilation_info.h"
#include "method_reference.h"
#include "runtime.h"
@@ -62,7 +63,11 @@
for (const std::string& dex : GetLibCoreDexFileNames()) {
std::vector<std::unique_ptr<const DexFile>> dex_files;
std::string error_msg;
- CHECK(DexFile::Open(dex.c_str(), dex, /*verify_checksum*/ false, &error_msg, &dex_files))
+ CHECK(DexFileLoader::Open(dex.c_str(),
+ dex,
+ /*verify_checksum*/ false,
+ &error_msg,
+ &dex_files))
<< error_msg;
for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
for (size_t i = 0; i < dex_file->NumMethodIds(); ++i) {
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 5bf3513..1b731fc 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -33,6 +33,7 @@
#include "dex2oat_environment_test.h"
#include "dex2oat_return_codes.h"
#include "dex_file-inl.h"
+#include "dex_file_loader.h"
#include "jit/profile_compilation_info.h"
#include "oat.h"
#include "oat_file.h"
@@ -677,7 +678,7 @@
const char* location = dex_location.c_str();
std::string error_msg;
std::vector<std::unique_ptr<const DexFile>> dex_files;
- ASSERT_TRUE(DexFile::Open(location, location, true, &error_msg, &dex_files));
+ ASSERT_TRUE(DexFileLoader::Open(location, location, true, &error_msg, &dex_files));
EXPECT_EQ(dex_files.size(), 1U);
std::unique_ptr<const DexFile>& dex_file = dex_files[0];
GenerateProfile(profile_location,
@@ -811,7 +812,7 @@
const char* location = dex_location.c_str();
std::vector<std::unique_ptr<const DexFile>> dex_files;
- ASSERT_TRUE(DexFile::Open(location, location, true, &error_msg, &dex_files));
+ ASSERT_TRUE(DexFileLoader::Open(location, location, true, &error_msg, &dex_files));
EXPECT_EQ(dex_files.size(), 1U);
std::unique_ptr<const DexFile>& old_dex_file = dex_files[0];
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 8ef5e62..05af442 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -34,6 +34,7 @@
#include "debug/method_debug_info.h"
#include "dex/verification_results.h"
#include "dex_file-inl.h"
+#include "dex_file_loader.h"
#include "dex_file_types.h"
#include "dexlayout.h"
#include "driver/compiler_driver-inl.h"
@@ -416,7 +417,7 @@
if (fd.Fd() == -1) {
PLOG(ERROR) << "Failed to read magic number from dex file: '" << filename << "'";
return false;
- } else if (DexFile::IsValidMagic(magic)) {
+ } else if (DexFileLoader::IsValidMagic(magic)) {
// The file is open for reading, not writing, so it's OK to let the File destructor
// close it without checking for explicit Close(), so pass checkUsage = false.
raw_dex_files_.emplace_back(new File(fd.Release(), location, /* checkUsage */ false));
@@ -448,13 +449,13 @@
return false;
}
for (size_t i = 0; ; ++i) {
- std::string entry_name = DexFile::GetMultiDexClassesDexName(i);
+ std::string entry_name = DexFileLoader::GetMultiDexClassesDexName(i);
std::unique_ptr<ZipEntry> entry(zip_archive->Find(entry_name.c_str(), &error_msg));
if (entry == nullptr) {
break;
}
zipped_dex_files_.push_back(std::move(entry));
- zipped_dex_file_locations_.push_back(DexFile::GetMultiDexLocation(i, location));
+ zipped_dex_file_locations_.push_back(DexFileLoader::GetMultiDexLocation(i, location));
const char* full_location = zipped_dex_file_locations_.back().c_str();
oat_dex_files_.emplace_back(full_location,
DexFileSource(zipped_dex_files_.back().get()),
@@ -479,12 +480,13 @@
LOG(ERROR) << "Unexpected number of dex files in vdex " << location;
return false;
}
- if (!DexFile::IsValidMagic(current_dex_data)) {
+
+ if (!DexFileLoader::IsValidMagic(current_dex_data)) {
LOG(ERROR) << "Invalid magic in vdex file created from " << location;
return false;
}
// We used `zipped_dex_file_locations_` to keep the strings in memory.
- zipped_dex_file_locations_.push_back(DexFile::GetMultiDexLocation(i, location));
+ zipped_dex_file_locations_.push_back(DexFileLoader::GetMultiDexLocation(i, location));
const char* full_location = zipped_dex_file_locations_.back().c_str();
oat_dex_files_.emplace_back(full_location,
DexFileSource(current_dex_data),
@@ -3244,12 +3246,12 @@
LOG(ERROR) << "Failed to extract dex file to mem map for layout: " << error_msg;
return false;
}
- dex_file = DexFile::Open(location,
- zip_entry->GetCrc32(),
- std::move(mem_map),
- /* verify */ true,
- /* verify_checksum */ true,
- &error_msg);
+ dex_file = DexFileLoader::Open(location,
+ zip_entry->GetCrc32(),
+ std::move(mem_map),
+ /* verify */ true,
+ /* verify_checksum */ true,
+ &error_msg);
} else if (oat_dex_file->source_.IsRawFile()) {
File* raw_file = oat_dex_file->source_.GetRawFile();
int dup_fd = dup(raw_file->Fd());
@@ -3257,7 +3259,7 @@
PLOG(ERROR) << "Failed to dup dex file descriptor (" << raw_file->Fd() << ") at " << location;
return false;
}
- dex_file = DexFile::OpenDex(dup_fd, location, /* verify_checksum */ true, &error_msg);
+ dex_file = DexFileLoader::OpenDex(dup_fd, location, /* verify_checksum */ true, &error_msg);
} else {
// The source data is a vdex file.
CHECK(oat_dex_file->source_.IsRawData())
@@ -3269,14 +3271,14 @@
DCHECK(ValidateDexFileHeader(raw_dex_file, oat_dex_file->GetLocation()));
const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file);
// Since the source may have had its layout changed, or may be quickened, don't verify it.
- dex_file = DexFile::Open(raw_dex_file,
- header->file_size_,
- location,
- oat_dex_file->dex_file_location_checksum_,
- nullptr,
- /* verify */ false,
- /* verify_checksum */ false,
- &error_msg);
+ dex_file = DexFileLoader::Open(raw_dex_file,
+ header->file_size_,
+ location,
+ oat_dex_file->dex_file_location_checksum_,
+ nullptr,
+ /* verify */ false,
+ /* verify_checksum */ false,
+ &error_msg);
}
if (dex_file == nullptr) {
LOG(ERROR) << "Failed to open dex file for layout: " << error_msg;
@@ -3534,14 +3536,14 @@
}
// Now, open the dex file.
- dex_files.emplace_back(DexFile::Open(raw_dex_file,
- oat_dex_file.dex_file_size_,
- oat_dex_file.GetLocation(),
- oat_dex_file.dex_file_location_checksum_,
- /* oat_dex_file */ nullptr,
- verify,
- verify,
- &error_msg));
+ dex_files.emplace_back(DexFileLoader::Open(raw_dex_file,
+ oat_dex_file.dex_file_size_,
+ oat_dex_file.GetLocation(),
+ oat_dex_file.dex_file_location_checksum_,
+ /* oat_dex_file */ nullptr,
+ verify,
+ verify,
+ &error_msg));
if (dex_files.back() == nullptr) {
LOG(ERROR) << "Failed to open dex file from oat file. File: " << oat_dex_file.GetLocation()
<< " Error: " << error_msg;
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index 50434ef..a19057a 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -26,6 +26,7 @@
#include "compiled_method-inl.h"
#include "compiler.h"
#include "debug/method_debug_info.h"
+#include "dex_file_loader.h"
#include "dex/quick_compiler_callbacks.h"
#include "dex/verification_results.h"
#include "driver/compiler_driver.h"
@@ -745,14 +746,14 @@
ASSERT_EQ(0, memcmp(&dex_file1_data->GetHeader(),
&opened_dex_file1->GetHeader(),
dex_file1_data->GetHeader().file_size_));
- ASSERT_EQ(DexFile::GetMultiDexLocation(0, zip_file.GetFilename().c_str()),
+ ASSERT_EQ(DexFileLoader::GetMultiDexLocation(0, zip_file.GetFilename().c_str()),
opened_dex_file1->GetLocation());
ASSERT_EQ(dex_file2_data->GetHeader().file_size_, opened_dex_file2->GetHeader().file_size_);
ASSERT_EQ(0, memcmp(&dex_file2_data->GetHeader(),
&opened_dex_file2->GetHeader(),
dex_file2_data->GetHeader().file_size_));
- ASSERT_EQ(DexFile::GetMultiDexLocation(1, zip_file.GetFilename().c_str()),
+ ASSERT_EQ(DexFileLoader::GetMultiDexLocation(1, zip_file.GetFilename().c_str()),
opened_dex_file2->GetLocation());
}
}
@@ -794,14 +795,14 @@
ASSERT_EQ(0, memcmp(&dex_file1_data->GetHeader(),
&opened_dex_file1->GetHeader(),
dex_file1_data->GetHeader().file_size_));
- ASSERT_EQ(DexFile::GetMultiDexLocation(0, zip_file.GetFilename().c_str()),
+ ASSERT_EQ(DexFileLoader::GetMultiDexLocation(0, zip_file.GetFilename().c_str()),
opened_dex_file1->GetLocation());
ASSERT_EQ(dex_file2_data->GetHeader().file_size_, opened_dex_file2->GetHeader().file_size_);
ASSERT_EQ(0, memcmp(&dex_file2_data->GetHeader(),
&opened_dex_file2->GetHeader(),
dex_file2_data->GetHeader().file_size_));
- ASSERT_EQ(DexFile::GetMultiDexLocation(1, zip_file.GetFilename().c_str()),
+ ASSERT_EQ(DexFileLoader::GetMultiDexLocation(1, zip_file.GetFilename().c_str()),
opened_dex_file2->GetLocation());
}
}
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 7599d23..3648a3e 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -45,6 +45,7 @@
#include "android-base/stringprintf.h"
#include "dex_file-inl.h"
+#include "dex_file_loader.h"
#include "dex_file_types.h"
#include "dex_instruction-inl.h"
#include "dexdump_cfg.h"
@@ -1825,7 +1826,7 @@
fputs("Opened '", gOutFile);
fputs(fileName, gOutFile);
if (n > 1) {
- fprintf(gOutFile, ":%s", DexFile::GetMultiDexClassesDexName(i).c_str());
+ fprintf(gOutFile, ":%s", DexFileLoader::GetMultiDexClassesDexName(i).c_str());
}
fprintf(gOutFile, "', DEX version '%.3s'\n", pDexFile->GetHeader().magic_ + 4);
}
@@ -1882,7 +1883,7 @@
const bool kVerifyChecksum = !gOptions.ignoreBadChecksum;
std::string error_msg;
std::vector<std::unique_ptr<const DexFile>> dex_files;
- if (!DexFile::Open(fileName, fileName, kVerifyChecksum, &error_msg, &dex_files)) {
+ if (!DexFileLoader::Open(fileName, fileName, kVerifyChecksum, &error_msg, &dex_files)) {
// Display returned error message to user. Note that this error behavior
// differs from the error messages shown by the original Dalvik dexdump.
fputs(error_msg.c_str(), stderr);
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index 095c960..ade0072 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -35,6 +35,7 @@
#include "dex_file-inl.h"
#include "dex_file_layout.h"
+#include "dex_file_loader.h"
#include "dex_file_types.h"
#include "dex_file_verifier.h"
#include "dex_instruction-inl.h"
@@ -1929,14 +1930,14 @@
// Verify the output dex file's structure for debug builds.
if (kIsDebugBuild) {
std::string location = "memory mapped file for " + dex_file_location;
- std::unique_ptr<const DexFile> output_dex_file(DexFile::Open(mem_map_->Begin(),
- mem_map_->Size(),
- location,
- header_->Checksum(),
- /*oat_dex_file*/ nullptr,
- /*verify*/ true,
- /*verify_checksum*/ false,
- &error_msg));
+ std::unique_ptr<const DexFile> output_dex_file(DexFileLoader::Open(mem_map_->Begin(),
+ mem_map_->Size(),
+ location,
+ header_->Checksum(),
+ /*oat_dex_file*/ nullptr,
+ /*verify*/ true,
+ /*verify_checksum*/ false,
+ &error_msg));
DCHECK(output_dex_file != nullptr) << "Failed to re-open output file:" << error_msg;
}
// Do IR-level comparison between input and output. This check ignores potential differences
@@ -1998,7 +1999,7 @@
const bool verify_checksum = !options_.ignore_bad_checksum_;
std::string error_msg;
std::vector<std::unique_ptr<const DexFile>> dex_files;
- if (!DexFile::Open(file_name, file_name, verify_checksum, &error_msg, &dex_files)) {
+ if (!DexFileLoader::Open(file_name, file_name, verify_checksum, &error_msg, &dex_files)) {
// Display returned error message to user. Note that this error behavior
// differs from the error messages shown by the original Dalvik dexdump.
fputs(error_msg.c_str(), stderr);
diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc
index 336eb5f..f8fa893 100644
--- a/dexlayout/dexlayout_test.cc
+++ b/dexlayout/dexlayout_test.cc
@@ -24,6 +24,7 @@
#include "base/unix_file/fd_file.h"
#include "common_runtime_test.h"
#include "dex_file-inl.h"
+#include "dex_file_loader.h"
#include "exec_utils.h"
#include "jit/profile_compilation_info.h"
#include "utils.h"
@@ -322,11 +323,11 @@
const std::string& dex_location) {
std::vector<std::unique_ptr<const DexFile>> dex_files;
std::string error_msg;
- bool result = DexFile::Open(input_dex.c_str(),
- input_dex,
- false,
- &error_msg,
- &dex_files);
+ bool result = DexFileLoader::Open(input_dex.c_str(),
+ input_dex,
+ false,
+ &error_msg,
+ &dex_files);
ASSERT_TRUE(result) << error_msg;
ASSERT_GE(dex_files.size(), 1u);
diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc
index 6a1e22a..e587052 100644
--- a/dexlist/dexlist.cc
+++ b/dexlist/dexlist.cc
@@ -27,6 +27,7 @@
#include <stdlib.h>
#include "dex_file-inl.h"
+#include "dex_file_loader.h"
#include "mem_map.h"
#include "runtime.h"
@@ -178,7 +179,7 @@
static constexpr bool kVerifyChecksum = true;
std::string error_msg;
std::vector<std::unique_ptr<const DexFile>> dex_files;
- if (!DexFile::Open(fileName, fileName, kVerifyChecksum, &error_msg, &dex_files)) {
+ if (!DexFileLoader::Open(fileName, fileName, kVerifyChecksum, &error_msg, &dex_files)) {
fputs(error_msg.c_str(), stderr);
fputc('\n', stderr);
return -1;
diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc
index 5bfa5ca..c498869 100644
--- a/openjdkjvmti/fixed_up_dex_file.cc
+++ b/openjdkjvmti/fixed_up_dex_file.cc
@@ -30,6 +30,7 @@
*/
#include "fixed_up_dex_file.h"
+#include "dex_file_loader.h"
#include "dex_file-inl.h"
// Runtime includes.
@@ -68,7 +69,7 @@
data.resize(original.Size());
memcpy(data.data(), original.Begin(), original.Size());
std::string error;
- std::unique_ptr<const art::DexFile> new_dex_file(art::DexFile::Open(
+ std::unique_ptr<const art::DexFile> new_dex_file(art::DexFileLoader::Open(
data.data(),
data.size(),
/*location*/"Unquickening_dexfile.dex",
diff --git a/openjdkjvmti/ti_class.cc b/openjdkjvmti/ti_class.cc
index daf4a8b..5f29416 100644
--- a/openjdkjvmti/ti_class.cc
+++ b/openjdkjvmti/ti_class.cc
@@ -43,6 +43,7 @@
#include "class_table-inl.h"
#include "common_throws.h"
#include "dex_file_annotations.h"
+#include "dex_file_loader.h"
#include "events-inl.h"
#include "fixed_up_dex_file.h"
#include "gc/heap-visit-objects-inl.h"
@@ -106,12 +107,12 @@
}
uint32_t checksum = reinterpret_cast<const art::DexFile::Header*>(map->Begin())->checksum_;
std::string map_name = map->GetName();
- std::unique_ptr<const art::DexFile> dex_file(art::DexFile::Open(map_name,
- checksum,
- std::move(map),
- /*verify*/true,
- /*verify_checksum*/true,
- &error_msg));
+ std::unique_ptr<const art::DexFile> dex_file(art::DexFileLoader::Open(map_name,
+ checksum,
+ std::move(map),
+ /*verify*/true,
+ /*verify_checksum*/true,
+ &error_msg));
if (dex_file.get() == nullptr) {
LOG(WARNING) << "Unable to load modified dex file for " << descriptor << ": " << error_msg;
art::ThrowClassFormatError(nullptr,
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc
index 98fad80..53abfbc 100644
--- a/openjdkjvmti/ti_redefine.cc
+++ b/openjdkjvmti/ti_redefine.cc
@@ -44,6 +44,7 @@
#include "class_linker-inl.h"
#include "debugger.h"
#include "dex_file.h"
+#include "dex_file_loader.h"
#include "dex_file_types.h"
#include "events-inl.h"
#include "gc/allocation_listener.h"
@@ -425,12 +426,12 @@
return ERR(INVALID_CLASS_FORMAT);
}
uint32_t checksum = reinterpret_cast<const art::DexFile::Header*>(map->Begin())->checksum_;
- std::unique_ptr<const art::DexFile> dex_file(art::DexFile::Open(map->GetName(),
- checksum,
- std::move(map),
- /*verify*/true,
- /*verify_checksum*/true,
- error_msg_));
+ std::unique_ptr<const art::DexFile> dex_file(art::DexFileLoader::Open(map->GetName(),
+ checksum,
+ std::move(map),
+ /*verify*/true,
+ /*verify_checksum*/true,
+ error_msg_));
if (dex_file.get() == nullptr) {
os << "Unable to load modified dex file for " << def.GetName() << ": " << *error_msg_;
*error_msg_ = os.str();
diff --git a/openjdkjvmti/ti_search.cc b/openjdkjvmti/ti_search.cc
index 25bc5d6..bafc855 100644
--- a/openjdkjvmti/ti_search.cc
+++ b/openjdkjvmti/ti_search.cc
@@ -39,6 +39,7 @@
#include "base/macros.h"
#include "class_linker.h"
#include "dex_file.h"
+#include "dex_file_loader.h"
#include "jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/object.h"
@@ -226,7 +227,7 @@
std::string error_msg;
std::vector<std::unique_ptr<const art::DexFile>> dex_files;
- if (!art::DexFile::Open(segment, segment, true, &error_msg, &dex_files)) {
+ if (!art::DexFileLoader::Open(segment, segment, true, &error_msg, &dex_files)) {
LOG(WARNING) << "Could not open " << segment << " for boot classpath extension: " << error_msg;
return ERR(ILLEGAL_ARGUMENT);
}
diff --git a/profman/profman.cc b/profman/profman.cc
index 9b4f579..8ccf7b4 100644
--- a/profman/profman.cc
+++ b/profman/profman.cc
@@ -39,6 +39,7 @@
#include "boot_image_profile.h"
#include "bytecode_utils.h"
#include "dex_file.h"
+#include "dex_file_loader.h"
#include "dex_file_types.h"
#include "jit/profile_compilation_info.h"
#include "profile_assistant.h"
@@ -328,21 +329,21 @@
std::string error_msg;
std::vector<std::unique_ptr<const DexFile>> dex_files_for_location;
if (use_apk_fd_list) {
- if (DexFile::OpenZip(apks_fd_[i],
- dex_locations_[i],
- kVerifyChecksum,
- &error_msg,
- &dex_files_for_location)) {
+ if (DexFileLoader::OpenZip(apks_fd_[i],
+ dex_locations_[i],
+ kVerifyChecksum,
+ &error_msg,
+ &dex_files_for_location)) {
} else {
LOG(WARNING) << "OpenZip failed for '" << dex_locations_[i] << "' " << error_msg;
continue;
}
} else {
- if (DexFile::Open(apk_files_[i].c_str(),
- dex_locations_[i],
- kVerifyChecksum,
- &error_msg,
- &dex_files_for_location)) {
+ if (DexFileLoader::Open(apk_files_[i].c_str(),
+ dex_locations_[i],
+ kVerifyChecksum,
+ &error_msg,
+ &dex_files_for_location)) {
} else {
LOG(WARNING) << "Open failed for '" << dex_locations_[i] << "' " << error_msg;
continue;
@@ -795,7 +796,7 @@
const DexFile* dex_file = class_ref.dex_file;
const auto& dex_resolved_classes = resolved_class_set.emplace(
dex_file->GetLocation(),
- dex_file->GetBaseLocation(),
+ DexFileLoader::GetBaseLocation(dex_file->GetLocation()),
dex_file->GetLocationChecksum(),
dex_file->NumMethodIds());
dex_resolved_classes.first->AddClass(class_ref.TypeIndex());
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 28ae5e4..ed9906a 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -55,6 +55,7 @@
"compiler_filter.cc",
"debugger.cc",
"dex_file.cc",
+ "dex_file_loader.cc",
"dex_file_annotations.cc",
"dex_file_layout.cc",
"dex_file_tracking_registrar.cc",
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 0cc2622..fe91272 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -51,6 +51,7 @@
#include "compiler_callbacks.h"
#include "debugger.h"
#include "dex_file-inl.h"
+#include "dex_file_loader.h"
#include "entrypoints/entrypoint_utils.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "experimental_flags.h"
@@ -8714,10 +8715,11 @@
const DexFile& dex_file = klass->GetDexFile();
if (&dex_file != last_dex_file_) {
last_dex_file_ = &dex_file;
- DexCacheResolvedClasses resolved_classes(dex_file.GetLocation(),
- dex_file.GetBaseLocation(),
- dex_file.GetLocationChecksum(),
- dex_file.NumMethodIds());
+ DexCacheResolvedClasses resolved_classes(
+ dex_file.GetLocation(),
+ DexFileLoader::GetBaseLocation(dex_file.GetLocation()),
+ dex_file.GetLocationChecksum(),
+ dex_file.NumMethodIds());
last_resolved_classes_ = result_->find(resolved_classes);
if (last_resolved_classes_ == result_->end()) {
last_resolved_classes_ = result_->insert(resolved_classes).first;
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 2282da0..167533d 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -25,6 +25,7 @@
#include "class_linker.h"
#include "class_loader_utils.h"
#include "dex_file.h"
+#include "dex_file_loader.h"
#include "handle_scope-inl.h"
#include "jni_internal.h"
#include "oat_file_assistant.h"
@@ -227,11 +228,11 @@
std::string error_msg;
// When opening the dex files from the context we expect their checksum to match their
// contents. So pass true to verify_checksum.
- if (!DexFile::Open(location.c_str(),
- location.c_str(),
- /*verify_checksum*/ true,
- &error_msg,
- &info.opened_dex_files)) {
+ if (!DexFileLoader::Open(location.c_str(),
+ location.c_str(),
+ /*verify_checksum*/ true,
+ &error_msg,
+ &info.opened_dex_files)) {
// If we fail to open the dex file because it's been stripped, try to open the dex file
// from its corresponding oat file.
// This could happen when we need to recompile a pre-build whose dex code has been stripped.
@@ -282,7 +283,7 @@
std::set<std::string> canonical_locations;
for (const std::string& location : locations) {
- canonical_locations.insert(DexFile::GetDexCanonicalLocation(location.c_str()));
+ canonical_locations.insert(DexFileLoader::GetDexCanonicalLocation(location.c_str()));
}
bool removed_locations = false;
for (ClassLoaderInfo& info : class_loader_chain_) {
@@ -292,7 +293,7 @@
info.classpath.end(),
[canonical_locations](const std::string& location) {
return ContainsElement(canonical_locations,
- DexFile::GetDexCanonicalLocation(location.c_str()));
+ DexFileLoader::GetDexCanonicalLocation(location.c_str()));
});
info.classpath.erase(kept_it, info.classpath.end());
if (initial_size != info.classpath.size()) {
@@ -340,7 +341,8 @@
if (for_dex2oat) {
// dex2oat only needs the base location. It cannot accept multidex locations.
// So ensure we only add each file once.
- bool new_insert = seen_locations.insert(dex_file->GetBaseLocation()).second;
+ bool new_insert = seen_locations.insert(
+ DexFileLoader::GetBaseLocation(dex_file->GetLocation())).second;
if (!new_insert) {
continue;
}
diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc
index ae3dcec..be6acde 100644
--- a/runtime/class_loader_context_test.cc
+++ b/runtime/class_loader_context_test.cc
@@ -100,12 +100,13 @@
info.opened_dex_files[cur_open_dex_index++];
std::unique_ptr<const DexFile>& expected_dex_file = (*all_dex_files)[k];
- std::string expected_location = expected_dex_file->GetBaseLocation();
+ std::string expected_location =
+ DexFileLoader::GetBaseLocation(expected_dex_file->GetLocation());
UniqueCPtr<const char[]> expected_real_location(
realpath(expected_location.c_str(), nullptr));
ASSERT_TRUE(expected_real_location != nullptr) << expected_location;
expected_location.assign(expected_real_location.get());
- expected_location += DexFile::GetMultiDexSuffix(expected_dex_file->GetLocation());
+ expected_location += DexFileLoader::GetMultiDexSuffix(expected_dex_file->GetLocation());
ASSERT_EQ(expected_location, opened_dex_file->GetLocation());
ASSERT_EQ(expected_dex_file->GetLocationChecksum(), opened_dex_file->GetLocationChecksum());
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 29b376a..0c2e490 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -34,6 +34,7 @@
#include "class_linker.h"
#include "compiler_callbacks.h"
#include "dex_file-inl.h"
+#include "dex_file_loader.h"
#include "gc/heap.h"
#include "gc_root-inl.h"
#include "gtest/gtest.h"
@@ -372,7 +373,7 @@
std::string error_msg;
MemMap::Init();
static constexpr bool kVerifyChecksum = true;
- if (!DexFile::Open(location, location, kVerifyChecksum, &error_msg, &dex_files)) {
+ if (!DexFileLoader::Open(location, location, kVerifyChecksum, &error_msg, &dex_files)) {
LOG(FATAL) << "Could not open .dex file '" << location << "': " << error_msg << "\n";
UNREACHABLE();
} else {
@@ -571,7 +572,7 @@
static constexpr bool kVerifyChecksum = true;
std::string error_msg;
std::vector<std::unique_ptr<const DexFile>> dex_files;
- bool success = DexFile::Open(
+ bool success = DexFileLoader::Open(
filename.c_str(), filename.c_str(), kVerifyChecksum, &error_msg, &dex_files);
CHECK(success) << "Failed to open '" << filename << "': " << error_msg;
for (auto& dex_file : dex_files) {
diff --git a/runtime/dex2oat_environment_test.h b/runtime/dex2oat_environment_test.h
index 93daa45..a9bb954 100644
--- a/runtime/dex2oat_environment_test.h
+++ b/runtime/dex2oat_environment_test.h
@@ -26,6 +26,7 @@
#include "base/stl_util.h"
#include "common_runtime_test.h"
#include "compiler_callbacks.h"
+#include "dex_file_loader.h"
#include "exec_utils.h"
#include "gc/heap.h"
#include "gc/space/image_space.h"
@@ -71,7 +72,8 @@
<< "Expected dex file to be at: " << GetDexSrc1();
ASSERT_TRUE(OS::FileExists(GetStrippedDexSrc1().c_str()))
<< "Expected stripped dex file to be at: " << GetStrippedDexSrc1();
- ASSERT_FALSE(DexFile::GetMultiDexChecksums(GetStrippedDexSrc1().c_str(), &checksums, &error_msg))
+ ASSERT_FALSE(
+ DexFileLoader::GetMultiDexChecksums(GetStrippedDexSrc1().c_str(), &checksums, &error_msg))
<< "Expected stripped dex file to be stripped: " << GetStrippedDexSrc1();
ASSERT_TRUE(OS::FileExists(GetDexSrc2().c_str()))
<< "Expected dex file to be at: " << GetDexSrc2();
@@ -80,13 +82,19 @@
// GetMultiDexSrc1, but a different secondary dex checksum.
static constexpr bool kVerifyChecksum = true;
std::vector<std::unique_ptr<const DexFile>> multi1;
- ASSERT_TRUE(DexFile::Open(GetMultiDexSrc1().c_str(),
- GetMultiDexSrc1().c_str(), kVerifyChecksum, &error_msg, &multi1)) << error_msg;
+ ASSERT_TRUE(DexFileLoader::Open(GetMultiDexSrc1().c_str(),
+ GetMultiDexSrc1().c_str(),
+ kVerifyChecksum,
+ &error_msg,
+ &multi1)) << error_msg;
ASSERT_GT(multi1.size(), 1u);
std::vector<std::unique_ptr<const DexFile>> multi2;
- ASSERT_TRUE(DexFile::Open(GetMultiDexSrc2().c_str(),
- GetMultiDexSrc2().c_str(), kVerifyChecksum, &error_msg, &multi2)) << error_msg;
+ ASSERT_TRUE(DexFileLoader::Open(GetMultiDexSrc2().c_str(),
+ GetMultiDexSrc2().c_str(),
+ kVerifyChecksum,
+ &error_msg,
+ &multi2)) << error_msg;
ASSERT_GT(multi2.size(), 1u);
ASSERT_EQ(multi1[0]->GetLocationChecksum(), multi2[0]->GetLocationChecksum());
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 303dd89..f6b3428 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -23,7 +23,6 @@
#include <string.h>
#include <sys/file.h>
#include <sys/mman.h> // For the PROT_* and MAP_* constants.
-#include <sys/stat.h>
#include <zlib.h>
#include <memory>
@@ -33,20 +32,17 @@
#include "android-base/stringprintf.h"
#include "base/enums.h"
-#include "base/file_magic.h"
#include "base/logging.h"
#include "base/stl_util.h"
-#include "base/systrace.h"
-#include "base/unix_file/fd_file.h"
#include "dex_file-inl.h"
-#include "dex_file_verifier.h"
+#include "dex_file_loader.h"
#include "jvalue.h"
#include "leb128.h"
+#include "mem_map.h"
#include "native_dex_file.h"
#include "os.h"
#include "utf-inl.h"
#include "utils.h"
-#include "zip_archive.h"
namespace art {
@@ -57,10 +53,6 @@
static_assert(sizeof(dex::TypeIndex) == sizeof(uint16_t), "TypeIndex size is wrong");
static_assert(std::is_trivially_copyable<dex::TypeIndex>::value, "TypeIndex not trivial");
-static constexpr OatDexFile* kNoOatDexFile = nullptr;
-
-const char* DexFile::kClassesDex = "classes.dex";
-
uint32_t DexFile::CalculateChecksum() const {
const uint32_t non_sum = OFFSETOF_MEMBER(DexFile::Header, signature_);
const uint8_t* non_sum_ptr = Begin() + non_sum;
@@ -72,63 +64,6 @@
uint8_t type_;
};
-bool DexFile::IsValidMagic(uint32_t magic) {
- return IsValidMagic(reinterpret_cast<uint8_t*>(&magic));
-}
-
-bool DexFile::IsValidMagic(const uint8_t* magic) {
- return NativeDexFile::IsMagicValid(magic);
-}
-
-bool DexFile::GetMultiDexChecksums(const char* filename,
- std::vector<uint32_t>* checksums,
- std::string* error_msg) {
- CHECK(checksums != nullptr);
- uint32_t magic;
-
- File fd = OpenAndReadMagic(filename, &magic, error_msg);
- if (fd.Fd() == -1) {
- DCHECK(!error_msg->empty());
- return false;
- }
- if (IsZipMagic(magic)) {
- std::unique_ptr<ZipArchive> zip_archive(
- ZipArchive::OpenFromFd(fd.Release(), filename, error_msg));
- if (zip_archive.get() == nullptr) {
- *error_msg = StringPrintf("Failed to open zip archive '%s' (error msg: %s)", filename,
- error_msg->c_str());
- return false;
- }
-
- uint32_t i = 0;
- std::string zip_entry_name = GetMultiDexClassesDexName(i++);
- std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(zip_entry_name.c_str(), error_msg));
- if (zip_entry.get() == nullptr) {
- *error_msg = StringPrintf("Zip archive '%s' doesn't contain %s (error msg: %s)", filename,
- zip_entry_name.c_str(), error_msg->c_str());
- return false;
- }
-
- do {
- checksums->push_back(zip_entry->GetCrc32());
- zip_entry_name = DexFile::GetMultiDexClassesDexName(i++);
- zip_entry.reset(zip_archive->Find(zip_entry_name.c_str(), error_msg));
- } while (zip_entry.get() != nullptr);
- return true;
- }
- if (IsValidMagic(magic)) {
- std::unique_ptr<const DexFile> dex_file(
- DexFile::OpenFile(fd.Release(), filename, false, false, error_msg));
- if (dex_file.get() == nullptr) {
- return false;
- }
- checksums->push_back(dex_file->GetHeader().checksum_);
- return true;
- }
- *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
- return false;
-}
-
int DexFile::GetPermissions() const {
if (mem_map_.get() == nullptr) {
return 0;
@@ -159,365 +94,6 @@
}
}
-std::unique_ptr<const DexFile> DexFile::Open(const uint8_t* base,
- size_t size,
- const std::string& location,
- uint32_t location_checksum,
- const OatDexFile* oat_dex_file,
- bool verify,
- bool verify_checksum,
- std::string* error_msg) {
- ScopedTrace trace(std::string("Open dex file from RAM ") + location);
- return OpenCommon(base,
- size,
- location,
- location_checksum,
- oat_dex_file,
- verify,
- verify_checksum,
- error_msg);
-}
-
-std::unique_ptr<const DexFile> DexFile::Open(const std::string& location,
- uint32_t location_checksum,
- std::unique_ptr<MemMap> map,
- bool verify,
- bool verify_checksum,
- std::string* error_msg) {
- ScopedTrace trace(std::string("Open dex file from mapped-memory ") + location);
- CHECK(map.get() != nullptr);
-
- if (map->Size() < sizeof(DexFile::Header)) {
- *error_msg = StringPrintf(
- "DexFile: failed to open dex file '%s' that is too short to have a header",
- location.c_str());
- return nullptr;
- }
-
- std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
- map->Size(),
- location,
- location_checksum,
- kNoOatDexFile,
- verify,
- verify_checksum,
- error_msg);
- if (dex_file != nullptr) {
- dex_file->mem_map_ = std::move(map);
- }
- return dex_file;
-}
-
-bool DexFile::Open(const char* filename,
- const std::string& location,
- bool verify_checksum,
- std::string* error_msg,
- std::vector<std::unique_ptr<const DexFile>>* dex_files) {
- ScopedTrace trace(std::string("Open dex file ") + std::string(location));
- DCHECK(dex_files != nullptr) << "DexFile::Open: out-param is nullptr";
- uint32_t magic;
- File fd = OpenAndReadMagic(filename, &magic, error_msg);
- if (fd.Fd() == -1) {
- DCHECK(!error_msg->empty());
- return false;
- }
- if (IsZipMagic(magic)) {
- return DexFile::OpenZip(fd.Release(), location, verify_checksum, error_msg, dex_files);
- }
- if (IsValidMagic(magic)) {
- std::unique_ptr<const DexFile> dex_file(DexFile::OpenFile(fd.Release(),
- location,
- /* verify */ true,
- verify_checksum,
- error_msg));
- if (dex_file.get() != nullptr) {
- dex_files->push_back(std::move(dex_file));
- return true;
- } else {
- return false;
- }
- }
- *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
- return false;
-}
-
-std::unique_ptr<const DexFile> DexFile::OpenDex(int fd,
- const std::string& location,
- bool verify_checksum,
- std::string* error_msg) {
- ScopedTrace trace("Open dex file " + std::string(location));
- return OpenFile(fd, location, true /* verify */, verify_checksum, error_msg);
-}
-
-bool DexFile::OpenZip(int fd,
- const std::string& location,
- bool verify_checksum,
- std::string* error_msg,
- std::vector<std::unique_ptr<const DexFile>>* dex_files) {
- ScopedTrace trace("Dex file open Zip " + std::string(location));
- DCHECK(dex_files != nullptr) << "DexFile::OpenZip: out-param is nullptr";
- std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, location.c_str(), error_msg));
- if (zip_archive.get() == nullptr) {
- DCHECK(!error_msg->empty());
- return false;
- }
- return DexFile::OpenAllDexFilesFromZip(*zip_archive,
- location,
- verify_checksum,
- error_msg,
- dex_files);
-}
-
-std::unique_ptr<const DexFile> DexFile::OpenFile(int fd,
- const std::string& location,
- bool verify,
- bool verify_checksum,
- std::string* error_msg) {
- ScopedTrace trace(std::string("Open dex file ") + std::string(location));
- CHECK(!location.empty());
- std::unique_ptr<MemMap> map;
- {
- File delayed_close(fd, /* check_usage */ false);
- struct stat sbuf;
- memset(&sbuf, 0, sizeof(sbuf));
- if (fstat(fd, &sbuf) == -1) {
- *error_msg = StringPrintf("DexFile: fstat '%s' failed: %s", location.c_str(),
- strerror(errno));
- return nullptr;
- }
- if (S_ISDIR(sbuf.st_mode)) {
- *error_msg = StringPrintf("Attempt to mmap directory '%s'", location.c_str());
- return nullptr;
- }
- size_t length = sbuf.st_size;
- map.reset(MemMap::MapFile(length,
- PROT_READ,
- MAP_PRIVATE,
- fd,
- 0,
- /*low_4gb*/false,
- location.c_str(),
- error_msg));
- if (map == nullptr) {
- DCHECK(!error_msg->empty());
- return nullptr;
- }
- }
-
- if (map->Size() < sizeof(DexFile::Header)) {
- *error_msg = StringPrintf(
- "DexFile: failed to open dex file '%s' that is too short to have a header",
- location.c_str());
- return nullptr;
- }
-
- const Header* dex_header = reinterpret_cast<const Header*>(map->Begin());
-
- std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
- map->Size(),
- location,
- dex_header->checksum_,
- kNoOatDexFile,
- verify,
- verify_checksum,
- error_msg);
- if (dex_file != nullptr) {
- dex_file->mem_map_ = std::move(map);
- }
-
- return dex_file;
-}
-
-std::unique_ptr<const DexFile> DexFile::OpenOneDexFileFromZip(const ZipArchive& zip_archive,
- const char* entry_name,
- const std::string& location,
- bool verify_checksum,
- std::string* error_msg,
- ZipOpenErrorCode* error_code) {
- ScopedTrace trace("Dex file open from Zip Archive " + std::string(location));
- CHECK(!location.empty());
- std::unique_ptr<ZipEntry> zip_entry(zip_archive.Find(entry_name, error_msg));
- if (zip_entry == nullptr) {
- *error_code = ZipOpenErrorCode::kEntryNotFound;
- return nullptr;
- }
- if (zip_entry->GetUncompressedLength() == 0) {
- *error_msg = StringPrintf("Dex file '%s' has zero length", location.c_str());
- *error_code = ZipOpenErrorCode::kDexFileError;
- return nullptr;
- }
-
- std::unique_ptr<MemMap> map;
- if (zip_entry->IsUncompressed()) {
- if (!zip_entry->IsAlignedTo(alignof(Header))) {
- // Do not mmap unaligned ZIP entries because
- // doing so would fail dex verification which requires 4 byte alignment.
- LOG(WARNING) << "Can't mmap dex file " << location << "!" << entry_name << " directly; "
- << "please zipalign to " << alignof(Header) << " bytes. "
- << "Falling back to extracting file.";
- } else {
- // Map uncompressed files within zip as file-backed to avoid a dirty copy.
- map.reset(zip_entry->MapDirectlyFromFile(location.c_str(), /*out*/error_msg));
- if (map == nullptr) {
- LOG(WARNING) << "Can't mmap dex file " << location << "!" << entry_name << " directly; "
- << "is your ZIP file corrupted? Falling back to extraction.";
- // Try again with Extraction which still has a chance of recovery.
- }
- }
- }
-
- if (map == nullptr) {
- // Default path for compressed ZIP entries,
- // and fallback for stored ZIP entries.
- map.reset(zip_entry->ExtractToMemMap(location.c_str(), entry_name, error_msg));
- }
-
- if (map == nullptr) {
- *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", entry_name, location.c_str(),
- error_msg->c_str());
- *error_code = ZipOpenErrorCode::kExtractToMemoryError;
- return nullptr;
- }
- VerifyResult verify_result;
- std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
- map->Size(),
- location,
- zip_entry->GetCrc32(),
- kNoOatDexFile,
- /* verify */ true,
- verify_checksum,
- error_msg,
- &verify_result);
- if (dex_file == nullptr) {
- if (verify_result == VerifyResult::kVerifyNotAttempted) {
- *error_code = ZipOpenErrorCode::kDexFileError;
- } else {
- *error_code = ZipOpenErrorCode::kVerifyError;
- }
- return nullptr;
- }
- dex_file->mem_map_ = std::move(map);
- if (!dex_file->DisableWrite()) {
- *error_msg = StringPrintf("Failed to make dex file '%s' read only", location.c_str());
- *error_code = ZipOpenErrorCode::kMakeReadOnlyError;
- return nullptr;
- }
- CHECK(dex_file->IsReadOnly()) << location;
- if (verify_result != VerifyResult::kVerifySucceeded) {
- *error_code = ZipOpenErrorCode::kVerifyError;
- return nullptr;
- }
- *error_code = ZipOpenErrorCode::kNoError;
- return dex_file;
-}
-
-// Technically we do not have a limitation with respect to the number of dex files that can be in a
-// multidex APK. However, it's bad practice, as each dex file requires its own tables for symbols
-// (types, classes, methods, ...) and dex caches. So warn the user that we open a zip with what
-// seems an excessive number.
-static constexpr size_t kWarnOnManyDexFilesThreshold = 100;
-
-bool DexFile::OpenAllDexFilesFromZip(const ZipArchive& zip_archive,
- const std::string& location,
- bool verify_checksum,
- std::string* error_msg,
- std::vector<std::unique_ptr<const DexFile>>* dex_files) {
- ScopedTrace trace("Dex file open from Zip " + std::string(location));
- DCHECK(dex_files != nullptr) << "DexFile::OpenFromZip: out-param is nullptr";
- ZipOpenErrorCode error_code;
- std::unique_ptr<const DexFile> dex_file(OpenOneDexFileFromZip(zip_archive,
- kClassesDex,
- location,
- verify_checksum,
- error_msg,
- &error_code));
- if (dex_file.get() == nullptr) {
- return false;
- } else {
- // Had at least classes.dex.
- dex_files->push_back(std::move(dex_file));
-
- // Now try some more.
-
- // We could try to avoid std::string allocations by working on a char array directly. As we
- // do not expect a lot of iterations, this seems too involved and brittle.
-
- for (size_t i = 1; ; ++i) {
- std::string name = GetMultiDexClassesDexName(i);
- std::string fake_location = GetMultiDexLocation(i, location.c_str());
- std::unique_ptr<const DexFile> next_dex_file(OpenOneDexFileFromZip(zip_archive,
- name.c_str(),
- fake_location,
- verify_checksum,
- error_msg,
- &error_code));
- if (next_dex_file.get() == nullptr) {
- if (error_code != ZipOpenErrorCode::kEntryNotFound) {
- LOG(WARNING) << "Zip open failed: " << *error_msg;
- }
- break;
- } else {
- dex_files->push_back(std::move(next_dex_file));
- }
-
- if (i == kWarnOnManyDexFilesThreshold) {
- LOG(WARNING) << location << " has in excess of " << kWarnOnManyDexFilesThreshold
- << " dex files. Please consider coalescing and shrinking the number to "
- " avoid runtime overhead.";
- }
-
- if (i == std::numeric_limits<size_t>::max()) {
- LOG(ERROR) << "Overflow in number of dex files!";
- break;
- }
- }
-
- return true;
- }
-}
-
-std::unique_ptr<DexFile> DexFile::OpenCommon(const uint8_t* base,
- size_t size,
- const std::string& location,
- uint32_t location_checksum,
- const OatDexFile* oat_dex_file,
- bool verify,
- bool verify_checksum,
- std::string* error_msg,
- VerifyResult* verify_result) {
- if (verify_result != nullptr) {
- *verify_result = VerifyResult::kVerifyNotAttempted;
- }
- std::unique_ptr<DexFile> dex_file;
- if (NativeDexFile::IsMagicValid(base)) {
- dex_file.reset(new NativeDexFile(base, size, location, location_checksum, oat_dex_file));
- }
- if (dex_file == nullptr) {
- *error_msg = StringPrintf("Failed to open dex file '%s' from memory: %s", location.c_str(),
- error_msg->c_str());
- return nullptr;
- }
- if (!dex_file->Init(error_msg)) {
- dex_file.reset();
- return nullptr;
- }
- if (verify && !DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- location.c_str(),
- verify_checksum,
- error_msg)) {
- if (verify_result != nullptr) {
- *verify_result = VerifyResult::kVerifyFailed;
- }
- return nullptr;
- }
- if (verify_result != nullptr) {
- *verify_result = VerifyResult::kVerifySucceeded;
- }
- return dex_file;
-}
-
DexFile::DexFile(const uint8_t* base,
size_t size,
const std::string& location,
@@ -1199,41 +775,6 @@
}
}
-bool DexFile::IsMultiDexLocation(const char* location) {
- return strrchr(location, kMultiDexSeparator) != nullptr;
-}
-
-std::string DexFile::GetMultiDexClassesDexName(size_t index) {
- if (index == 0) {
- return "classes.dex";
- } else {
- return StringPrintf("classes%zu.dex", index + 1);
- }
-}
-
-std::string DexFile::GetMultiDexLocation(size_t index, const char* dex_location) {
- if (index == 0) {
- return dex_location;
- } else {
- return StringPrintf("%s" kMultiDexSeparatorString "classes%zu.dex", dex_location, index + 1);
- }
-}
-
-std::string DexFile::GetDexCanonicalLocation(const char* dex_location) {
- CHECK_NE(dex_location, static_cast<const char*>(nullptr));
- std::string base_location = GetBaseLocation(dex_location);
- const char* suffix = dex_location + base_location.size();
- DCHECK(suffix[0] == 0 || suffix[0] == kMultiDexSeparator);
- UniqueCPtr<const char[]> path(realpath(base_location.c_str(), nullptr));
- if (path != nullptr && path.get() != base_location) {
- return std::string(path.get()) + suffix;
- } else if (suffix[0] == 0) {
- return base_location;
- } else {
- return dex_location;
- }
-}
-
// Read a signed integer. "zwidth" is the zero-based byte count.
int32_t DexFile::ReadSignedInt(const uint8_t* ptr, int zwidth) {
int32_t val = 0;
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index c2b901e..5759684 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -42,7 +42,8 @@
// Dex file is the API that exposes native dex files (ordinary dex files) and CompactDex.
// Originally, the dex file format used by ART was mostly the same as APKs. The only change was
// quickened opcodes and layout optimizations.
-// With CompactDex, ART needs to support both native dex files and CompactDex files.
+// Since ART needs to support both native dex files and CompactDex files, the DexFile interface
+// provides an abstraction to facilitate this.
class DexFile {
public:
// Number of bytes in the dex file magic.
@@ -57,19 +58,9 @@
static constexpr size_t kSha1DigestSize = 20;
static constexpr uint32_t kDexEndianConstant = 0x12345678;
- // name of the DexFile entry within a zip archive
- static const char* kClassesDex;
-
// The value of an invalid index.
static const uint16_t kDexNoIndex16 = 0xFFFF;
- // The separator character in MultiDex locations.
- static constexpr char kMultiDexSeparator = '!';
-
- // A string version of the previous. This is a define so that we can merge string literals in the
- // preprocessor.
- #define kMultiDexSeparatorString "!"
-
// Raw header_item.
struct Header {
uint8_t magic_[8];
@@ -436,57 +427,6 @@
struct AnnotationValue;
- // Returns the checksums of a file for comparison with GetLocationChecksum().
- // For .dex files, this is the single header checksum.
- // For zip files, this is the zip entry CRC32 checksum for classes.dex and
- // each additional multidex entry classes2.dex, classes3.dex, etc.
- // Return true if the checksums could be found, false otherwise.
- static bool GetMultiDexChecksums(const char* filename,
- std::vector<uint32_t>* checksums,
- std::string* error_msg);
-
- // Check whether a location denotes a multidex dex file. This is a very simple check: returns
- // whether the string contains the separator character.
- static bool IsMultiDexLocation(const char* location);
-
- // Opens .dex file, backed by existing memory
- static std::unique_ptr<const DexFile> Open(const uint8_t* base,
- size_t size,
- const std::string& location,
- uint32_t location_checksum,
- const OatDexFile* oat_dex_file,
- bool verify,
- bool verify_checksum,
- std::string* error_msg);
-
- // Opens .dex file that has been memory-mapped by the caller.
- static std::unique_ptr<const DexFile> Open(const std::string& location,
- uint32_t location_checkum,
- std::unique_ptr<MemMap> mem_map,
- bool verify,
- bool verify_checksum,
- std::string* error_msg);
-
- // Opens all .dex files found in the file, guessing the container format based on file extension.
- static bool Open(const char* filename,
- const std::string& location,
- bool verify_checksum,
- std::string* error_msg,
- std::vector<std::unique_ptr<const DexFile>>* dex_files);
-
- // Open a single dex file from an fd. This function closes the fd.
- static std::unique_ptr<const DexFile> OpenDex(int fd,
- const std::string& location,
- bool verify_checksum,
- std::string* error_msg);
-
- // Opens dex files from within a .jar, .zip, or .apk file
- static bool OpenZip(int fd,
- const std::string& location,
- bool verify_checksum,
- std::string* error_msg,
- std::vector<std::unique_ptr<const DexFile>>* dex_files);
-
// Closes a .dex file.
virtual ~DexFile();
@@ -494,30 +434,6 @@
return location_;
}
- // For normal dex files, location and base location coincide. If a dex file is part of a multidex
- // archive, the base location is the name of the originating jar/apk, stripped of any internal
- // classes*.dex path.
- static std::string GetBaseLocation(const char* location) {
- const char* pos = strrchr(location, kMultiDexSeparator);
- return (pos == nullptr) ? location : std::string(location, pos - location);
- }
-
- static std::string GetBaseLocation(const std::string& location) {
- return GetBaseLocation(location.c_str());
- }
-
- // Returns the '!classes*.dex' part of the dex location. Returns an empty
- // string if there is no multidex suffix for the given location.
- // The kMultiDexSeparator is included in the returned suffix.
- static std::string GetMultiDexSuffix(const std::string& location) {
- size_t pos = location.rfind(kMultiDexSeparator);
- return (pos == std::string::npos) ? std::string() : location.substr(pos);
- }
-
- std::string GetBaseLocation() const {
- return GetBaseLocation(location_);
- }
-
// For DexFiles directly from .dex files, this is the checksum from the DexFile::Header.
// For DexFiles opened from a zip files, this will be the ZipEntry CRC32 of classes.dex.
uint32_t GetLocationChecksum() const {
@@ -540,9 +456,6 @@
// Returns true if the byte string after the magic is the correct value.
virtual bool IsVersionValid() const = 0;
- static bool IsValidMagic(uint32_t magic);
- static bool IsValidMagic(const uint8_t* magic);
-
// Returns the number of string identifiers in the .dex file.
size_t NumStringIds() const {
DCHECK(header_ != nullptr) << GetLocation();
@@ -1017,29 +930,6 @@
return size_;
}
- // Return the name of the index-th classes.dex in a multidex zip file. This is classes.dex for
- // index == 0, and classes{index + 1}.dex else.
- static std::string GetMultiDexClassesDexName(size_t index);
-
- // Return the (possibly synthetic) dex location for a multidex entry. This is dex_location for
- // index == 0, and dex_location + multi-dex-separator + GetMultiDexClassesDexName(index) else.
- static std::string GetMultiDexLocation(size_t index, const char* dex_location);
-
- // Returns the canonical form of the given dex location.
- //
- // There are different flavors of "dex locations" as follows:
- // the file name of a dex file:
- // The actual file path that the dex file has on disk.
- // dex_location:
- // This acts as a key for the class linker to know which dex file to load.
- // It may correspond to either an old odex file or a particular dex file
- // inside an oat file. In the first case it will also match the file name
- // of the dex file. In the second case (oat) it will include the file name
- // and possibly some multidex annotation to uniquely identify it.
- // canonical_dex_location:
- // the dex_location where it's file name part has been made canonical.
- static std::string GetDexCanonicalLocation(const char* dex_location);
-
const OatDexFile* GetOatDexFile() const {
return oat_dex_file_;
}
@@ -1066,63 +956,6 @@
std::string PrettyType(dex::TypeIndex type_idx) const;
protected:
- static std::unique_ptr<const DexFile> OpenFile(int fd,
- const std::string& location,
- bool verify,
- bool verify_checksum,
- std::string* error_msg);
-
- enum class ZipOpenErrorCode { // private
- kNoError,
- kEntryNotFound,
- kExtractToMemoryError,
- kDexFileError,
- kMakeReadOnlyError,
- kVerifyError
- };
-
- // Open all classesXXX.dex files from a zip archive.
- static bool OpenAllDexFilesFromZip(const ZipArchive& zip_archive,
- const std::string& location,
- bool verify_checksum,
- std::string* error_msg,
- std::vector<std::unique_ptr<const DexFile>>* dex_files);
-
- // Opens .dex file from the entry_name in a zip archive. error_code is undefined when non-null
- // return.
- static std::unique_ptr<const DexFile> OpenOneDexFileFromZip(const ZipArchive& zip_archive,
- const char* entry_name,
- const std::string& location,
- bool verify_checksum,
- std::string* error_msg,
- ZipOpenErrorCode* error_code);
-
- enum class VerifyResult { // private
- kVerifyNotAttempted,
- kVerifySucceeded,
- kVerifyFailed
- };
-
- static std::unique_ptr<DexFile> OpenCommon(const uint8_t* base,
- size_t size,
- const std::string& location,
- uint32_t location_checksum,
- const OatDexFile* oat_dex_file,
- bool verify,
- bool verify_checksum,
- std::string* error_msg,
- VerifyResult* verify_result = nullptr);
-
-
- // Opens a .dex file at the given address, optionally backed by a MemMap
- static std::unique_ptr<const DexFile> OpenMemory(const uint8_t* dex_file,
- size_t size,
- const std::string& location,
- uint32_t location_checksum,
- std::unique_ptr<MemMap> mem_map,
- const OatDexFile* oat_dex_file,
- std::string* error_msg);
-
DexFile(const uint8_t* base,
size_t size,
const std::string& location,
@@ -1193,6 +1026,7 @@
// null.
mutable const OatDexFile* oat_dex_file_;
+ friend class DexFileLoader;
friend class DexFileVerifierTest;
friend class OatWriter;
};
diff --git a/runtime/dex_file_loader.cc b/runtime/dex_file_loader.cc
new file mode 100644
index 0000000..3ccb755
--- /dev/null
+++ b/runtime/dex_file_loader.cc
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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 "dex_file_loader.h"
+
+#include <sys/mman.h> // For the PROT_* and MAP_* constants.
+#include <sys/stat.h>
+
+#include "android-base/stringprintf.h"
+
+#include "base/file_magic.h"
+#include "base/stl_util.h"
+#include "base/systrace.h"
+#include "base/unix_file/fd_file.h"
+#include "dex_file.h"
+#include "dex_file_verifier.h"
+#include "native_dex_file.h"
+#include "zip_archive.h"
+
+namespace art {
+
+using android::base::StringPrintf;
+
+static constexpr OatDexFile* kNoOatDexFile = nullptr;
+
+
+bool DexFileLoader::IsValidMagic(uint32_t magic) {
+ return IsValidMagic(reinterpret_cast<uint8_t*>(&magic));
+}
+
+bool DexFileLoader::IsValidMagic(const uint8_t* magic) {
+ return NativeDexFile::IsMagicValid(magic);
+}
+
+bool DexFileLoader::GetMultiDexChecksums(const char* filename,
+ std::vector<uint32_t>* checksums,
+ std::string* error_msg) {
+ CHECK(checksums != nullptr);
+ uint32_t magic;
+
+ File fd = OpenAndReadMagic(filename, &magic, error_msg);
+ if (fd.Fd() == -1) {
+ DCHECK(!error_msg->empty());
+ return false;
+ }
+ if (IsZipMagic(magic)) {
+ std::unique_ptr<ZipArchive> zip_archive(
+ ZipArchive::OpenFromFd(fd.Release(), filename, error_msg));
+ if (zip_archive.get() == nullptr) {
+ *error_msg = StringPrintf("Failed to open zip archive '%s' (error msg: %s)", filename,
+ error_msg->c_str());
+ return false;
+ }
+
+ uint32_t i = 0;
+ std::string zip_entry_name = GetMultiDexClassesDexName(i++);
+ std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(zip_entry_name.c_str(), error_msg));
+ if (zip_entry.get() == nullptr) {
+ *error_msg = StringPrintf("Zip archive '%s' doesn't contain %s (error msg: %s)", filename,
+ zip_entry_name.c_str(), error_msg->c_str());
+ return false;
+ }
+
+ do {
+ checksums->push_back(zip_entry->GetCrc32());
+ zip_entry_name = GetMultiDexClassesDexName(i++);
+ zip_entry.reset(zip_archive->Find(zip_entry_name.c_str(), error_msg));
+ } while (zip_entry.get() != nullptr);
+ return true;
+ }
+ if (IsValidMagic(magic)) {
+ std::unique_ptr<const DexFile> dex_file(
+ OpenFile(fd.Release(), filename, false, false, error_msg));
+ if (dex_file == nullptr) {
+ return false;
+ }
+ checksums->push_back(dex_file->GetHeader().checksum_);
+ return true;
+ }
+ *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
+ return false;
+}
+
+bool DexFileLoader::IsMultiDexLocation(const char* location) {
+ return strrchr(location, kMultiDexSeparator) != nullptr;
+}
+
+std::string DexFileLoader::GetMultiDexClassesDexName(size_t index) {
+ return (index == 0) ? "classes.dex" : StringPrintf("classes%zu.dex", index + 1);
+}
+
+std::string DexFileLoader::GetMultiDexLocation(size_t index, const char* dex_location) {
+ return (index == 0)
+ ? dex_location
+ : StringPrintf("%s%cclasses%zu.dex", dex_location, kMultiDexSeparator, index + 1);
+}
+
+std::string DexFileLoader::GetDexCanonicalLocation(const char* dex_location) {
+ CHECK_NE(dex_location, static_cast<const char*>(nullptr));
+ std::string base_location = GetBaseLocation(dex_location);
+ const char* suffix = dex_location + base_location.size();
+ DCHECK(suffix[0] == 0 || suffix[0] == kMultiDexSeparator);
+ UniqueCPtr<const char[]> path(realpath(base_location.c_str(), nullptr));
+ if (path != nullptr && path.get() != base_location) {
+ return std::string(path.get()) + suffix;
+ } else if (suffix[0] == 0) {
+ return base_location;
+ } else {
+ return dex_location;
+ }
+}
+
+std::unique_ptr<const DexFile> DexFileLoader::Open(const uint8_t* base,
+ size_t size,
+ const std::string& location,
+ uint32_t location_checksum,
+ const OatDexFile* oat_dex_file,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg) {
+ ScopedTrace trace(std::string("Open dex file from RAM ") + location);
+ return OpenCommon(base,
+ size,
+ location,
+ location_checksum,
+ oat_dex_file,
+ verify,
+ verify_checksum,
+ error_msg);
+}
+
+std::unique_ptr<const DexFile> DexFileLoader::Open(const std::string& location,
+ uint32_t location_checksum,
+ std::unique_ptr<MemMap> map,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg) {
+ ScopedTrace trace(std::string("Open dex file from mapped-memory ") + location);
+ CHECK(map.get() != nullptr);
+
+ if (map->Size() < sizeof(DexFile::Header)) {
+ *error_msg = StringPrintf(
+ "DexFile: failed to open dex file '%s' that is too short to have a header",
+ location.c_str());
+ return nullptr;
+ }
+
+ std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
+ map->Size(),
+ location,
+ location_checksum,
+ kNoOatDexFile,
+ verify,
+ verify_checksum,
+ error_msg);
+ if (dex_file != nullptr) {
+ dex_file->mem_map_ = std::move(map);
+ }
+ return dex_file;
+}
+
+bool DexFileLoader::Open(const char* filename,
+ const std::string& location,
+ bool verify_checksum,
+ std::string* error_msg,
+ std::vector<std::unique_ptr<const DexFile>>* dex_files) {
+ ScopedTrace trace(std::string("Open dex file ") + std::string(location));
+ DCHECK(dex_files != nullptr) << "DexFile::Open: out-param is nullptr";
+ uint32_t magic;
+ File fd = OpenAndReadMagic(filename, &magic, error_msg);
+ if (fd.Fd() == -1) {
+ DCHECK(!error_msg->empty());
+ return false;
+ }
+ if (IsZipMagic(magic)) {
+ return OpenZip(fd.Release(), location, verify_checksum, error_msg, dex_files);
+ }
+ if (IsValidMagic(magic)) {
+ std::unique_ptr<const DexFile> dex_file(OpenFile(fd.Release(),
+ location,
+ /* verify */ true,
+ verify_checksum,
+ error_msg));
+ if (dex_file.get() != nullptr) {
+ dex_files->push_back(std::move(dex_file));
+ return true;
+ } else {
+ return false;
+ }
+ }
+ *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
+ return false;
+}
+
+std::unique_ptr<const DexFile> DexFileLoader::OpenDex(int fd,
+ const std::string& location,
+ bool verify_checksum,
+ std::string* error_msg) {
+ ScopedTrace trace("Open dex file " + std::string(location));
+ return OpenFile(fd, location, true /* verify */, verify_checksum, error_msg);
+}
+
+bool DexFileLoader::OpenZip(int fd,
+ const std::string& location,
+ bool verify_checksum,
+ std::string* error_msg,
+ std::vector<std::unique_ptr<const DexFile>>* dex_files) {
+ ScopedTrace trace("Dex file open Zip " + std::string(location));
+ DCHECK(dex_files != nullptr) << "DexFile::OpenZip: out-param is nullptr";
+ std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, location.c_str(), error_msg));
+ if (zip_archive.get() == nullptr) {
+ DCHECK(!error_msg->empty());
+ return false;
+ }
+ return OpenAllDexFilesFromZip(*zip_archive, location, verify_checksum, error_msg, dex_files);
+}
+
+std::unique_ptr<const DexFile> DexFileLoader::OpenFile(int fd,
+ const std::string& location,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg) {
+ ScopedTrace trace(std::string("Open dex file ") + std::string(location));
+ CHECK(!location.empty());
+ std::unique_ptr<MemMap> map;
+ {
+ File delayed_close(fd, /* check_usage */ false);
+ struct stat sbuf;
+ memset(&sbuf, 0, sizeof(sbuf));
+ if (fstat(fd, &sbuf) == -1) {
+ *error_msg = StringPrintf("DexFile: fstat '%s' failed: %s", location.c_str(),
+ strerror(errno));
+ return nullptr;
+ }
+ if (S_ISDIR(sbuf.st_mode)) {
+ *error_msg = StringPrintf("Attempt to mmap directory '%s'", location.c_str());
+ return nullptr;
+ }
+ size_t length = sbuf.st_size;
+ map.reset(MemMap::MapFile(length,
+ PROT_READ,
+ MAP_PRIVATE,
+ fd,
+ 0,
+ /*low_4gb*/false,
+ location.c_str(),
+ error_msg));
+ if (map == nullptr) {
+ DCHECK(!error_msg->empty());
+ return nullptr;
+ }
+ }
+
+ if (map->Size() < sizeof(DexFile::Header)) {
+ *error_msg = StringPrintf(
+ "DexFile: failed to open dex file '%s' that is too short to have a header",
+ location.c_str());
+ return nullptr;
+ }
+
+ const DexFile::Header* dex_header = reinterpret_cast<const DexFile::Header*>(map->Begin());
+
+ std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
+ map->Size(),
+ location,
+ dex_header->checksum_,
+ kNoOatDexFile,
+ verify,
+ verify_checksum,
+ error_msg);
+ if (dex_file != nullptr) {
+ dex_file->mem_map_ = std::move(map);
+ }
+
+ return dex_file;
+}
+
+std::unique_ptr<const DexFile> DexFileLoader::OpenOneDexFileFromZip(
+ const ZipArchive& zip_archive,
+ const char* entry_name,
+ const std::string& location,
+ bool verify_checksum,
+ std::string* error_msg,
+ ZipOpenErrorCode* error_code) {
+ ScopedTrace trace("Dex file open from Zip Archive " + std::string(location));
+ CHECK(!location.empty());
+ std::unique_ptr<ZipEntry> zip_entry(zip_archive.Find(entry_name, error_msg));
+ if (zip_entry == nullptr) {
+ *error_code = ZipOpenErrorCode::kEntryNotFound;
+ return nullptr;
+ }
+ if (zip_entry->GetUncompressedLength() == 0) {
+ *error_msg = StringPrintf("Dex file '%s' has zero length", location.c_str());
+ *error_code = ZipOpenErrorCode::kDexFileError;
+ return nullptr;
+ }
+
+ std::unique_ptr<MemMap> map;
+ if (zip_entry->IsUncompressed()) {
+ if (!zip_entry->IsAlignedTo(alignof(DexFile::Header))) {
+ // Do not mmap unaligned ZIP entries because
+ // doing so would fail dex verification which requires 4 byte alignment.
+ LOG(WARNING) << "Can't mmap dex file " << location << "!" << entry_name << " directly; "
+ << "please zipalign to " << alignof(DexFile::Header) << " bytes. "
+ << "Falling back to extracting file.";
+ } else {
+ // Map uncompressed files within zip as file-backed to avoid a dirty copy.
+ map.reset(zip_entry->MapDirectlyFromFile(location.c_str(), /*out*/error_msg));
+ if (map == nullptr) {
+ LOG(WARNING) << "Can't mmap dex file " << location << "!" << entry_name << " directly; "
+ << "is your ZIP file corrupted? Falling back to extraction.";
+ // Try again with Extraction which still has a chance of recovery.
+ }
+ }
+ }
+
+ if (map == nullptr) {
+ // Default path for compressed ZIP entries,
+ // and fallback for stored ZIP entries.
+ map.reset(zip_entry->ExtractToMemMap(location.c_str(), entry_name, error_msg));
+ }
+
+ if (map == nullptr) {
+ *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", entry_name, location.c_str(),
+ error_msg->c_str());
+ *error_code = ZipOpenErrorCode::kExtractToMemoryError;
+ return nullptr;
+ }
+ VerifyResult verify_result;
+ std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
+ map->Size(),
+ location,
+ zip_entry->GetCrc32(),
+ kNoOatDexFile,
+ /* verify */ true,
+ verify_checksum,
+ error_msg,
+ &verify_result);
+ if (dex_file == nullptr) {
+ if (verify_result == VerifyResult::kVerifyNotAttempted) {
+ *error_code = ZipOpenErrorCode::kDexFileError;
+ } else {
+ *error_code = ZipOpenErrorCode::kVerifyError;
+ }
+ return nullptr;
+ }
+ dex_file->mem_map_ = std::move(map);
+ if (!dex_file->DisableWrite()) {
+ *error_msg = StringPrintf("Failed to make dex file '%s' read only", location.c_str());
+ *error_code = ZipOpenErrorCode::kMakeReadOnlyError;
+ return nullptr;
+ }
+ CHECK(dex_file->IsReadOnly()) << location;
+ if (verify_result != VerifyResult::kVerifySucceeded) {
+ *error_code = ZipOpenErrorCode::kVerifyError;
+ return nullptr;
+ }
+ *error_code = ZipOpenErrorCode::kNoError;
+ return dex_file;
+}
+
+// Technically we do not have a limitation with respect to the number of dex files that can be in a
+// multidex APK. However, it's bad practice, as each dex file requires its own tables for symbols
+// (types, classes, methods, ...) and dex caches. So warn the user that we open a zip with what
+// seems an excessive number.
+static constexpr size_t kWarnOnManyDexFilesThreshold = 100;
+
+bool DexFileLoader::OpenAllDexFilesFromZip(const ZipArchive& zip_archive,
+ const std::string& location,
+ bool verify_checksum,
+ std::string* error_msg,
+ std::vector<std::unique_ptr<const DexFile>>* dex_files) {
+ ScopedTrace trace("Dex file open from Zip " + std::string(location));
+ DCHECK(dex_files != nullptr) << "DexFile::OpenFromZip: out-param is nullptr";
+ ZipOpenErrorCode error_code;
+ std::unique_ptr<const DexFile> dex_file(OpenOneDexFileFromZip(zip_archive,
+ kClassesDex,
+ location,
+ verify_checksum,
+ error_msg,
+ &error_code));
+ if (dex_file.get() == nullptr) {
+ return false;
+ } else {
+ // Had at least classes.dex.
+ dex_files->push_back(std::move(dex_file));
+
+ // Now try some more.
+
+ // We could try to avoid std::string allocations by working on a char array directly. As we
+ // do not expect a lot of iterations, this seems too involved and brittle.
+
+ for (size_t i = 1; ; ++i) {
+ std::string name = GetMultiDexClassesDexName(i);
+ std::string fake_location = GetMultiDexLocation(i, location.c_str());
+ std::unique_ptr<const DexFile> next_dex_file(OpenOneDexFileFromZip(zip_archive,
+ name.c_str(),
+ fake_location,
+ verify_checksum,
+ error_msg,
+ &error_code));
+ if (next_dex_file.get() == nullptr) {
+ if (error_code != ZipOpenErrorCode::kEntryNotFound) {
+ LOG(WARNING) << "Zip open failed: " << *error_msg;
+ }
+ break;
+ } else {
+ dex_files->push_back(std::move(next_dex_file));
+ }
+
+ if (i == kWarnOnManyDexFilesThreshold) {
+ LOG(WARNING) << location << " has in excess of " << kWarnOnManyDexFilesThreshold
+ << " dex files. Please consider coalescing and shrinking the number to "
+ " avoid runtime overhead.";
+ }
+
+ if (i == std::numeric_limits<size_t>::max()) {
+ LOG(ERROR) << "Overflow in number of dex files!";
+ break;
+ }
+ }
+
+ return true;
+ }
+}
+
+std::unique_ptr<DexFile> DexFileLoader::OpenCommon(const uint8_t* base,
+ size_t size,
+ const std::string& location,
+ uint32_t location_checksum,
+ const OatDexFile* oat_dex_file,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg,
+ VerifyResult* verify_result) {
+ if (verify_result != nullptr) {
+ *verify_result = VerifyResult::kVerifyNotAttempted;
+ }
+ std::unique_ptr<DexFile> dex_file;
+ if (NativeDexFile::IsMagicValid(base)) {
+ dex_file.reset(new NativeDexFile(base, size, location, location_checksum, oat_dex_file));
+ } else {
+ return nullptr;
+ }
+ if (dex_file == nullptr) {
+ *error_msg = StringPrintf("Failed to open dex file '%s' from memory: %s", location.c_str(),
+ error_msg->c_str());
+ return nullptr;
+ }
+ if (!dex_file->Init(error_msg)) {
+ dex_file.reset();
+ return nullptr;
+ }
+ if (verify && !DexFileVerifier::Verify(dex_file.get(),
+ dex_file->Begin(),
+ dex_file->Size(),
+ location.c_str(),
+ verify_checksum,
+ error_msg)) {
+ if (verify_result != nullptr) {
+ *verify_result = VerifyResult::kVerifyFailed;
+ }
+ return nullptr;
+ }
+ if (verify_result != nullptr) {
+ *verify_result = VerifyResult::kVerifySucceeded;
+ }
+ return dex_file;
+}
+
+} // namespace art
diff --git a/runtime/dex_file_loader.h b/runtime/dex_file_loader.h
new file mode 100644
index 0000000..61b5c71
--- /dev/null
+++ b/runtime/dex_file_loader.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_DEX_FILE_LOADER_H_
+#define ART_RUNTIME_DEX_FILE_LOADER_H_
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace art {
+
+class DexFile;
+class MemMap;
+class OatDexFile;
+class ZipArchive;
+
+// Class that is used to open dex files and deal with corresponding multidex and location logic.
+class DexFileLoader {
+ public:
+ // name of the DexFile entry within a zip archive
+ static constexpr const char* kClassesDex = "classes.dex";
+
+ // The separator character in MultiDex locations.
+ static constexpr char kMultiDexSeparator = '!';
+
+ // Return true if the magic is valid for dex or cdex.
+ static bool IsValidMagic(uint32_t magic);
+ static bool IsValidMagic(const uint8_t* magic);
+
+ // Returns the checksums of a file for comparison with GetLocationChecksum().
+ // For .dex files, this is the single header checksum.
+ // For zip files, this is the zip entry CRC32 checksum for classes.dex and
+ // each additional multidex entry classes2.dex, classes3.dex, etc.
+ // Return true if the checksums could be found, false otherwise.
+ static bool GetMultiDexChecksums(const char* filename,
+ std::vector<uint32_t>* checksums,
+ std::string* error_msg);
+
+ // Check whether a location denotes a multidex dex file. This is a very simple check: returns
+ // whether the string contains the separator character.
+ static bool IsMultiDexLocation(const char* location);
+
+ // Opens .dex file, backed by existing memory
+ static std::unique_ptr<const DexFile> Open(const uint8_t* base,
+ size_t size,
+ const std::string& location,
+ uint32_t location_checksum,
+ const OatDexFile* oat_dex_file,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg);
+
+ // Opens .dex file that has been memory-mapped by the caller.
+ static std::unique_ptr<const DexFile> Open(const std::string& location,
+ uint32_t location_checkum,
+ std::unique_ptr<MemMap> mem_map,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg);
+
+ // Opens all .dex files found in the file, guessing the container format based on file extension.
+ static bool Open(const char* filename,
+ const std::string& location,
+ bool verify_checksum,
+ std::string* error_msg,
+ std::vector<std::unique_ptr<const DexFile>>* dex_files);
+
+ // Open a single dex file from an fd. This function closes the fd.
+ static std::unique_ptr<const DexFile> OpenDex(int fd,
+ const std::string& location,
+ bool verify_checksum,
+ std::string* error_msg);
+
+ // Opens dex files from within a .jar, .zip, or .apk file
+ static bool OpenZip(int fd,
+ const std::string& location,
+ bool verify_checksum,
+ std::string* error_msg,
+ std::vector<std::unique_ptr<const DexFile>>* dex_files);
+
+ // Return the name of the index-th classes.dex in a multidex zip file. This is classes.dex for
+ // index == 0, and classes{index + 1}.dex else.
+ static std::string GetMultiDexClassesDexName(size_t index);
+
+ // Return the (possibly synthetic) dex location for a multidex entry. This is dex_location for
+ // index == 0, and dex_location + multi-dex-separator + GetMultiDexClassesDexName(index) else.
+ static std::string GetMultiDexLocation(size_t index, const char* dex_location);
+
+ // Returns the canonical form of the given dex location.
+ //
+ // There are different flavors of "dex locations" as follows:
+ // the file name of a dex file:
+ // The actual file path that the dex file has on disk.
+ // dex_location:
+ // This acts as a key for the class linker to know which dex file to load.
+ // It may correspond to either an old odex file or a particular dex file
+ // inside an oat file. In the first case it will also match the file name
+ // of the dex file. In the second case (oat) it will include the file name
+ // and possibly some multidex annotation to uniquely identify it.
+ // canonical_dex_location:
+ // the dex_location where it's file name part has been made canonical.
+ static std::string GetDexCanonicalLocation(const char* dex_location);
+
+ // For normal dex files, location and base location coincide. If a dex file is part of a multidex
+ // archive, the base location is the name of the originating jar/apk, stripped of any internal
+ // classes*.dex path.
+ static std::string GetBaseLocation(const char* location) {
+ const char* pos = strrchr(location, kMultiDexSeparator);
+ return (pos == nullptr) ? location : std::string(location, pos - location);
+ }
+
+ static std::string GetBaseLocation(const std::string& location) {
+ return GetBaseLocation(location.c_str());
+ }
+
+ // Returns the '!classes*.dex' part of the dex location. Returns an empty
+ // string if there is no multidex suffix for the given location.
+ // The kMultiDexSeparator is included in the returned suffix.
+ static std::string GetMultiDexSuffix(const std::string& location) {
+ size_t pos = location.rfind(kMultiDexSeparator);
+ return (pos == std::string::npos) ? std::string() : location.substr(pos);
+ }
+
+ private:
+ static std::unique_ptr<const DexFile> OpenFile(int fd,
+ const std::string& location,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg);
+
+ enum class ZipOpenErrorCode {
+ kNoError,
+ kEntryNotFound,
+ kExtractToMemoryError,
+ kDexFileError,
+ kMakeReadOnlyError,
+ kVerifyError
+ };
+
+ // Open all classesXXX.dex files from a zip archive.
+ static bool OpenAllDexFilesFromZip(const ZipArchive& zip_archive,
+ const std::string& location,
+ bool verify_checksum,
+ std::string* error_msg,
+ std::vector<std::unique_ptr<const DexFile>>* dex_files);
+
+ // Opens .dex file from the entry_name in a zip archive. error_code is undefined when non-null
+ // return.
+ static std::unique_ptr<const DexFile> OpenOneDexFileFromZip(const ZipArchive& zip_archive,
+ const char* entry_name,
+ const std::string& location,
+ bool verify_checksum,
+ std::string* error_msg,
+ ZipOpenErrorCode* error_code);
+
+ enum class VerifyResult { // private
+ kVerifyNotAttempted,
+ kVerifySucceeded,
+ kVerifyFailed
+ };
+
+ static std::unique_ptr<DexFile> OpenCommon(const uint8_t* base,
+ size_t size,
+ const std::string& location,
+ uint32_t location_checksum,
+ const OatDexFile* oat_dex_file,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg,
+ VerifyResult* verify_result = nullptr);
+
+
+ // Opens a .dex file at the given address, optionally backed by a MemMap
+ static std::unique_ptr<const DexFile> OpenMemory(const uint8_t* dex_file,
+ size_t size,
+ const std::string& location,
+ uint32_t location_checksum,
+ std::unique_ptr<MemMap> mem_map,
+ const OatDexFile* oat_dex_file,
+ std::string* error_msg);
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_DEX_FILE_LOADER_H_
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index 67cd428..b301137 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -24,6 +24,7 @@
#include "base/unix_file/fd_file.h"
#include "common_runtime_test.h"
#include "dex_file-inl.h"
+#include "dex_file_loader.h"
#include "mem_map.h"
#include "os.h"
#include "scoped_thread_state_change-inl.h"
@@ -235,7 +236,7 @@
ScopedObjectAccess soa(Thread::Current());
static constexpr bool kVerifyChecksum = true;
std::vector<std::unique_ptr<const DexFile>> tmp;
- bool success = DexFile::Open(location, location, kVerifyChecksum, error_msg, &tmp);
+ bool success = DexFileLoader::Open(location, location, kVerifyChecksum, error_msg, &tmp);
if (success) {
for (std::unique_ptr<const DexFile>& dex_file : tmp) {
EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
@@ -274,12 +275,12 @@
/* reuse */ false,
&error_message));
memcpy(region->Begin(), dex_bytes.data(), dex_bytes.size());
- std::unique_ptr<const DexFile> dex_file(DexFile::Open(location,
- location_checksum,
- std::move(region),
- /* verify */ true,
- /* verify_checksum */ true,
- &error_message));
+ std::unique_ptr<const DexFile> dex_file(DexFileLoader::Open(location,
+ location_checksum,
+ std::move(region),
+ /* verify */ true,
+ /* verify_checksum */ true,
+ &error_message));
if (expect_success) {
CHECK(dex_file != nullptr) << error_message;
} else {
@@ -365,7 +366,7 @@
static constexpr bool kVerifyChecksum = true;
std::string error_msg;
std::vector<std::unique_ptr<const DexFile>> dex_files;
- ASSERT_FALSE(DexFile::Open(location, location, kVerifyChecksum, &error_msg, &dex_files));
+ ASSERT_FALSE(DexFileLoader::Open(location, location, kVerifyChecksum, &error_msg, &dex_files));
}
TEST_F(DexFileTest, Version41Rejected) {
@@ -377,7 +378,7 @@
static constexpr bool kVerifyChecksum = true;
std::string error_msg;
std::vector<std::unique_ptr<const DexFile>> dex_files;
- ASSERT_FALSE(DexFile::Open(location, location, kVerifyChecksum, &error_msg, &dex_files));
+ ASSERT_FALSE(DexFileLoader::Open(location, location, kVerifyChecksum, &error_msg, &dex_files));
}
TEST_F(DexFileTest, ZeroLengthDexRejected) {
@@ -389,7 +390,7 @@
static constexpr bool kVerifyChecksum = true;
std::string error_msg;
std::vector<std::unique_ptr<const DexFile>> dex_files;
- ASSERT_FALSE(DexFile::Open(location, location, kVerifyChecksum, &error_msg, &dex_files));
+ ASSERT_FALSE(DexFileLoader::Open(location, location, kVerifyChecksum, &error_msg, &dex_files));
}
TEST_F(DexFileTest, GetLocationChecksum) {
@@ -402,7 +403,9 @@
std::vector<uint32_t> checksums;
ScopedObjectAccess soa(Thread::Current());
std::string error_msg;
- EXPECT_TRUE(DexFile::GetMultiDexChecksums(GetLibCoreDexFileNames()[0].c_str(), &checksums, &error_msg))
+ EXPECT_TRUE(DexFileLoader::GetMultiDexChecksums(GetLibCoreDexFileNames()[0].c_str(),
+ &checksums,
+ &error_msg))
<< error_msg;
ASSERT_EQ(1U, checksums.size());
EXPECT_EQ(java_lang_dex_file_->GetLocationChecksum(), checksums[0]);
@@ -412,18 +415,18 @@
std::string error_msg;
std::vector<uint32_t> checksums;
std::string multidex_file = GetTestDexFileName("MultiDex");
- EXPECT_TRUE(DexFile::GetMultiDexChecksums(multidex_file.c_str(),
- &checksums,
- &error_msg)) << error_msg;
+ EXPECT_TRUE(DexFileLoader::GetMultiDexChecksums(multidex_file.c_str(),
+ &checksums,
+ &error_msg)) << error_msg;
std::vector<std::unique_ptr<const DexFile>> dexes = OpenTestDexFiles("MultiDex");
ASSERT_EQ(2U, dexes.size());
ASSERT_EQ(2U, checksums.size());
- EXPECT_EQ(dexes[0]->GetLocation(), DexFile::GetMultiDexLocation(0, multidex_file.c_str()));
+ EXPECT_EQ(dexes[0]->GetLocation(), DexFileLoader::GetMultiDexLocation(0, multidex_file.c_str()));
EXPECT_EQ(dexes[0]->GetLocationChecksum(), checksums[0]);
- EXPECT_EQ(dexes[1]->GetLocation(), DexFile::GetMultiDexLocation(1, multidex_file.c_str()));
+ EXPECT_EQ(dexes[1]->GetLocation(), DexFileLoader::GetMultiDexLocation(1, multidex_file.c_str()));
EXPECT_EQ(dexes[1]->GetLocationChecksum(), checksums[1]);
}
@@ -625,20 +628,20 @@
}
TEST_F(DexFileTest, GetMultiDexClassesDexName) {
- ASSERT_EQ("classes.dex", DexFile::GetMultiDexClassesDexName(0));
- ASSERT_EQ("classes2.dex", DexFile::GetMultiDexClassesDexName(1));
- ASSERT_EQ("classes3.dex", DexFile::GetMultiDexClassesDexName(2));
- ASSERT_EQ("classes100.dex", DexFile::GetMultiDexClassesDexName(99));
+ ASSERT_EQ("classes.dex", DexFileLoader::GetMultiDexClassesDexName(0));
+ ASSERT_EQ("classes2.dex", DexFileLoader::GetMultiDexClassesDexName(1));
+ ASSERT_EQ("classes3.dex", DexFileLoader::GetMultiDexClassesDexName(2));
+ ASSERT_EQ("classes100.dex", DexFileLoader::GetMultiDexClassesDexName(99));
}
TEST_F(DexFileTest, GetMultiDexLocation) {
std::string dex_location_str = "/system/app/framework.jar";
const char* dex_location = dex_location_str.c_str();
- ASSERT_EQ("/system/app/framework.jar", DexFile::GetMultiDexLocation(0, dex_location));
+ ASSERT_EQ("/system/app/framework.jar", DexFileLoader::GetMultiDexLocation(0, dex_location));
ASSERT_EQ("/system/app/framework.jar!classes2.dex",
- DexFile::GetMultiDexLocation(1, dex_location));
+ DexFileLoader::GetMultiDexLocation(1, dex_location));
ASSERT_EQ("/system/app/framework.jar!classes101.dex",
- DexFile::GetMultiDexLocation(100, dex_location));
+ DexFileLoader::GetMultiDexLocation(100, dex_location));
}
TEST_F(DexFileTest, GetDexCanonicalLocation) {
@@ -646,28 +649,30 @@
UniqueCPtr<const char[]> dex_location_real(realpath(file.GetFilename().c_str(), nullptr));
std::string dex_location(dex_location_real.get());
- ASSERT_EQ(dex_location, DexFile::GetDexCanonicalLocation(dex_location.c_str()));
- std::string multidex_location = DexFile::GetMultiDexLocation(1, dex_location.c_str());
- ASSERT_EQ(multidex_location, DexFile::GetDexCanonicalLocation(multidex_location.c_str()));
+ ASSERT_EQ(dex_location, DexFileLoader::GetDexCanonicalLocation(dex_location.c_str()));
+ std::string multidex_location = DexFileLoader::GetMultiDexLocation(1, dex_location.c_str());
+ ASSERT_EQ(multidex_location, DexFileLoader::GetDexCanonicalLocation(multidex_location.c_str()));
std::string dex_location_sym = dex_location + "symlink";
ASSERT_EQ(0, symlink(dex_location.c_str(), dex_location_sym.c_str()));
- ASSERT_EQ(dex_location, DexFile::GetDexCanonicalLocation(dex_location_sym.c_str()));
+ ASSERT_EQ(dex_location, DexFileLoader::GetDexCanonicalLocation(dex_location_sym.c_str()));
- std::string multidex_location_sym = DexFile::GetMultiDexLocation(1, dex_location_sym.c_str());
- ASSERT_EQ(multidex_location, DexFile::GetDexCanonicalLocation(multidex_location_sym.c_str()));
+ std::string multidex_location_sym = DexFileLoader::GetMultiDexLocation(
+ 1, dex_location_sym.c_str());
+ ASSERT_EQ(multidex_location,
+ DexFileLoader::GetDexCanonicalLocation(multidex_location_sym.c_str()));
ASSERT_EQ(0, unlink(dex_location_sym.c_str()));
}
TEST(DexFileUtilsTest, GetBaseLocationAndMultiDexSuffix) {
- EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar"));
- EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar!classes2.dex"));
- EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar!classes8.dex"));
- EXPECT_EQ("", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar"));
- EXPECT_EQ("!classes2.dex", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar!classes2.dex"));
- EXPECT_EQ("!classes8.dex", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar!classes8.dex"));
+ EXPECT_EQ("/foo/bar/baz.jar", DexFileLoader::GetBaseLocation("/foo/bar/baz.jar"));
+ EXPECT_EQ("/foo/bar/baz.jar", DexFileLoader::GetBaseLocation("/foo/bar/baz.jar!classes2.dex"));
+ EXPECT_EQ("/foo/bar/baz.jar", DexFileLoader::GetBaseLocation("/foo/bar/baz.jar!classes8.dex"));
+ EXPECT_EQ("", DexFileLoader::GetMultiDexSuffix("/foo/bar/baz.jar"));
+ EXPECT_EQ("!classes2.dex", DexFileLoader::GetMultiDexSuffix("/foo/bar/baz.jar!classes2.dex"));
+ EXPECT_EQ("!classes8.dex", DexFileLoader::GetMultiDexSuffix("/foo/bar/baz.jar!classes8.dex"));
}
TEST_F(DexFileTest, ZipOpenClassesPresent) {
diff --git a/runtime/dex_file_verifier_test.cc b/runtime/dex_file_verifier_test.cc
index 02528f0..af2d535 100644
--- a/runtime/dex_file_verifier_test.cc
+++ b/runtime/dex_file_verifier_test.cc
@@ -27,6 +27,7 @@
#include "base/unix_file/fd_file.h"
#include "common_runtime_test.h"
#include "dex_file-inl.h"
+#include "dex_file_loader.h"
#include "dex_file_types.h"
#include "leb128.h"
#include "native_dex_file.h"
@@ -113,7 +114,7 @@
// read dex file
ScopedObjectAccess soa(Thread::Current());
std::vector<std::unique_ptr<const DexFile>> tmp;
- bool success = DexFile::Open(location, location, true, error_msg, &tmp);
+ bool success = DexFileLoader::Open(location, location, true, error_msg, &tmp);
CHECK(success) << *error_msg;
EXPECT_EQ(1U, tmp.size());
std::unique_ptr<const DexFile> dex_file = std::move(tmp[0]);
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 732c707..f0eada3 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -35,6 +35,7 @@
#include "base/stl_util.h"
#include "base/systrace.h"
#include "base/time_utils.h"
+#include "dex_file_loader.h"
#include "exec_utils.h"
#include "gc/accounting/space_bitmap-inl.h"
#include "image-inl.h"
@@ -1829,12 +1830,12 @@
// Skip multidex locations - These will be checked when we visit their
// corresponding primary non-multidex location.
- if (DexFile::IsMultiDexLocation(dex_file_location.c_str())) {
+ if (DexFileLoader::IsMultiDexLocation(dex_file_location.c_str())) {
continue;
}
std::vector<uint32_t> checksums;
- if (!DexFile::GetMultiDexChecksums(dex_file_location.c_str(), &checksums, error_msg)) {
+ if (!DexFileLoader::GetMultiDexChecksums(dex_file_location.c_str(), &checksums, error_msg)) {
*error_msg = StringPrintf("ValidateOatFile failed to get checksums of dex file '%s' "
"referenced by oat file %s: %s",
dex_file_location.c_str(),
@@ -1855,7 +1856,9 @@
// Verify checksums for any related multidex entries.
for (size_t i = 1; i < checksums.size(); i++) {
- std::string multi_dex_location = DexFile::GetMultiDexLocation(i, dex_file_location.c_str());
+ std::string multi_dex_location = DexFileLoader::GetMultiDexLocation(
+ i,
+ dex_file_location.c_str());
const OatFile::OatDexFile* multi_dex = oat_file.GetOatDexFile(multi_dex_location.c_str(),
nullptr,
error_msg);
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index e122c6d..47615f5 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -26,6 +26,7 @@
#include "base/time_utils.h"
#include "cha.h"
#include "debugger_interface.h"
+#include "dex_file_loader.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "gc/accounting/bitmap-inl.h"
#include "gc/scoped_gc_critical_section.h"
@@ -1350,7 +1351,8 @@
for (const ProfilingInfo* info : profiling_infos_) {
ArtMethod* method = info->GetMethod();
const DexFile* dex_file = method->GetDexFile();
- if (!ContainsElement(dex_base_locations, dex_file->GetBaseLocation())) {
+ const std::string base_location = DexFileLoader::GetBaseLocation(dex_file->GetLocation());
+ if (!ContainsElement(dex_base_locations, base_location)) {
// Skip dex files which are not profiled.
continue;
}
@@ -1404,7 +1406,8 @@
is_missing_types = true;
continue;
}
- if (ContainsElement(dex_base_locations, class_dex_file->GetBaseLocation())) {
+ if (ContainsElement(dex_base_locations,
+ DexFileLoader::GetBaseLocation(class_dex_file->GetLocation()))) {
// Only consider classes from the same apk (including multidex).
profile_classes.emplace_back(/*ProfileMethodInfo::ProfileClassReference*/
class_dex_file, type_index);
diff --git a/runtime/jit/profile_compilation_info.cc b/runtime/jit/profile_compilation_info.cc
index f9603a7..1fad28d 100644
--- a/runtime/jit/profile_compilation_info.cc
+++ b/runtime/jit/profile_compilation_info.cc
@@ -40,6 +40,7 @@
#include "base/systrace.h"
#include "base/time_utils.h"
#include "base/unix_file/fd_file.h"
+#include "dex_file_loader.h"
#include "jit/profiling_info.h"
#include "os.h"
#include "safe_map.h"
@@ -1537,7 +1538,7 @@
os << dex_data->profile_key;
} else {
// Replace the (empty) multidex suffix of the first key with a substitute for easier reading.
- std::string multidex_suffix = DexFile::GetMultiDexSuffix(dex_data->profile_key);
+ std::string multidex_suffix = DexFileLoader::GetMultiDexSuffix(dex_data->profile_key);
os << (multidex_suffix.empty() ? kFirstDexFileKeySubstitute : multidex_suffix);
}
os << " [index=" << static_cast<uint32_t>(dex_data->profile_index) << "]";
@@ -1696,7 +1697,7 @@
const uint16_t kFavorSplit = 2;
for (uint16_t i = 0; i < number_of_dex_files; i++) {
- std::string dex_location = DexFile::GetMultiDexLocation(i, base_dex_location.c_str());
+ std::string dex_location = DexFileLoader::GetMultiDexLocation(i, base_dex_location.c_str());
std::string profile_key = GetProfileDexFileKey(dex_location);
for (uint16_t m = 0; m < number_of_methods; m++) {
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index 2bf8d8b..01853de 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -31,6 +31,7 @@
#include "base/time_utils.h"
#include "class_table-inl.h"
#include "compiler_filter.h"
+#include "dex_file_loader.h"
#include "dex_reference_collection.h"
#include "gc/collector_type.h"
#include "gc/gc_cause.h"
@@ -414,7 +415,8 @@
const std::set<std::string>& locations = it.second;
for (const auto& pair : hot_methods.GetMap()) {
const DexFile* const dex_file = pair.first;
- if (locations.find(dex_file->GetBaseLocation()) != locations.end()) {
+ const std::string base_location = DexFileLoader::GetBaseLocation(dex_file->GetLocation());
+ if (locations.find(base_location) != locations.end()) {
const MethodReferenceCollection::IndexVector& indices = pair.second;
uint8_t flags = Hotness::kFlagHot;
flags |= startup ? Hotness::kFlagStartup : Hotness::kFlagPostStartup;
@@ -427,7 +429,8 @@
}
for (const auto& pair : sampled_methods.GetMap()) {
const DexFile* const dex_file = pair.first;
- if (locations.find(dex_file->GetBaseLocation()) != locations.end()) {
+ const std::string base_location = DexFileLoader::GetBaseLocation(dex_file->GetLocation());
+ if (locations.find(base_location) != locations.end()) {
const MethodReferenceCollection::IndexVector& indices = pair.second;
cached_info->AddMethodsForDex(startup ? Hotness::kFlagStartup : Hotness::kFlagPostStartup,
dex_file,
@@ -437,14 +440,15 @@
}
for (const auto& pair : resolved_classes.GetMap()) {
const DexFile* const dex_file = pair.first;
- if (locations.find(dex_file->GetBaseLocation()) != locations.end()) {
+ const std::string base_location = DexFileLoader::GetBaseLocation(dex_file->GetLocation());
+ if (locations.find(base_location) != locations.end()) {
const TypeReferenceCollection::IndexVector& classes = pair.second;
VLOG(profiler) << "Added " << classes.size() << " classes for location "
- << dex_file->GetBaseLocation()
+ << base_location
<< " (" << dex_file->GetLocation() << ")";
cached_info->AddClassesForDex(dex_file, classes.begin(), classes.end());
} else {
- VLOG(profiler) << "Location not found " << dex_file->GetBaseLocation()
+ VLOG(profiler) << "Location not found " << base_location
<< " (" << dex_file->GetLocation() << ")";
}
}
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index d40e6d9..e75d097 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -26,6 +26,7 @@
#include "common_throws.h"
#include "compiler_filter.h"
#include "dex_file-inl.h"
+#include "dex_file_loader.h"
#include "jni_internal.h"
#include "mirror/class_loader.h"
#include "mirror/object-inl.h"
@@ -185,12 +186,12 @@
dex_mem_map->Begin(),
dex_mem_map->End());
std::string error_message;
- std::unique_ptr<const DexFile> dex_file(DexFile::Open(location,
- 0,
- std::move(dex_mem_map),
- /* verify */ true,
- /* verify_location */ true,
- &error_message));
+ std::unique_ptr<const DexFile> dex_file(DexFileLoader::Open(location,
+ 0,
+ std::move(dex_mem_map),
+ /* verify */ true,
+ /* verify_location */ true,
+ &error_message));
if (dex_file == nullptr) {
ScopedObjectAccess soa(env);
ThrowWrappedIOException("%s", error_message.c_str());
diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc
index 4034e8c..413149c 100644
--- a/runtime/native/java_lang_VMClassLoader.cc
+++ b/runtime/native/java_lang_VMClassLoader.cc
@@ -17,6 +17,7 @@
#include "java_lang_VMClassLoader.h"
#include "class_linker.h"
+#include "dex_file_loader.h"
#include "jni_internal.h"
#include "mirror/class_loader.h"
#include "mirror/object-inl.h"
@@ -135,7 +136,7 @@
const DexFile* dex_file = path[i];
// For multidex locations, e.g., x.jar!classes2.dex, we want to look into x.jar.
- const std::string& location(dex_file->GetBaseLocation());
+ const std::string location(DexFileLoader::GetBaseLocation(dex_file->GetLocation()));
ScopedLocalRef<jstring> javaPath(env, env->NewStringUTF(location.c_str()));
if (javaPath.get() == nullptr) {
diff --git a/runtime/native_dex_file.h b/runtime/native_dex_file.h
index c03718d..8f09e6d 100644
--- a/runtime/native_dex_file.h
+++ b/runtime/native_dex_file.h
@@ -48,7 +48,7 @@
const OatDexFile* oat_dex_file)
: DexFile(base, size, location, location_checksum, oat_dex_file) {}
- friend class DexFile;
+ friend class DexFileLoader;
friend class DexFileVerifierTest;
ART_FRIEND_TEST(ClassLinkerTest, RegisterDexFileName); // for constructor
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index c122830..d3d566f 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -41,6 +41,7 @@
#include "base/systrace.h"
#include "base/unix_file/fd_file.h"
#include "dex_file_types.h"
+#include "dex_file_loader.h"
#include "elf_file.h"
#include "elf_utils.h"
#include "gc_root.h"
@@ -614,7 +615,8 @@
reinterpret_cast<const DexFile::Header*>(dex_file_pointer)->method_ids_size_);
}
- std::string canonical_location = DexFile::GetDexCanonicalLocation(dex_file_location.c_str());
+ std::string canonical_location =
+ DexFileLoader::GetDexCanonicalLocation(dex_file_location.c_str());
// Create the OatDexFile and add it to the owning container.
OatDexFile* oat_dex_file = new OatDexFile(this,
@@ -1099,8 +1101,8 @@
const char* abs_dex_location, const std::string& rel_dex_location) {
if (abs_dex_location != nullptr && rel_dex_location[0] != '/') {
// Strip :classes<N>.dex used for secondary multidex files.
- std::string base = DexFile::GetBaseLocation(rel_dex_location);
- std::string multidex_suffix = DexFile::GetMultiDexSuffix(rel_dex_location);
+ std::string base = DexFileLoader::GetBaseLocation(rel_dex_location);
+ std::string multidex_suffix = DexFileLoader::GetMultiDexSuffix(rel_dex_location);
// Check if the base is a suffix of the provided abs_dex_location.
std::string target_suffix = "/" + base;
@@ -1327,7 +1329,7 @@
oat_dex_file = secondary_lb->second; // May be null.
} else {
// We haven't seen this dex_location before, we must check the canonical location.
- std::string dex_canonical_location = DexFile::GetDexCanonicalLocation(dex_location);
+ std::string dex_canonical_location = DexFileLoader::GetDexCanonicalLocation(dex_location);
if (dex_canonical_location != dex_location) {
StringPiece canonical_key(dex_canonical_location);
auto canonical_it = oat_dex_files_.find(canonical_key);
@@ -1345,7 +1347,7 @@
if (oat_dex_file == nullptr) {
if (error_msg != nullptr) {
- std::string dex_canonical_location = DexFile::GetDexCanonicalLocation(dex_location);
+ std::string dex_canonical_location = DexFileLoader::GetDexCanonicalLocation(dex_location);
*error_msg = "Failed to find OatDexFile for DexFile " + std::string(dex_location)
+ " (canonical path " + dex_canonical_location + ") in OatFile " + GetLocation();
}
@@ -1355,7 +1357,7 @@
if (dex_location_checksum != nullptr &&
oat_dex_file->GetDexFileLocationChecksum() != *dex_location_checksum) {
if (error_msg != nullptr) {
- std::string dex_canonical_location = DexFile::GetDexCanonicalLocation(dex_location);
+ std::string dex_canonical_location = DexFileLoader::GetDexCanonicalLocation(dex_location);
std::string checksum = StringPrintf("0x%08x", oat_dex_file->GetDexFileLocationChecksum());
std::string required_checksum = StringPrintf("0x%08x", *dex_location_checksum);
*error_msg = "OatDexFile for DexFile " + std::string(dex_location)
@@ -1411,14 +1413,14 @@
ScopedTrace trace(__PRETTY_FUNCTION__);
static constexpr bool kVerify = false;
static constexpr bool kVerifyChecksum = false;
- return DexFile::Open(dex_file_pointer_,
- FileSize(),
- dex_file_location_,
- dex_file_location_checksum_,
- this,
- kVerify,
- kVerifyChecksum,
- error_msg);
+ return DexFileLoader::Open(dex_file_pointer_,
+ FileSize(),
+ dex_file_location_,
+ dex_file_location_checksum_,
+ this,
+ kVerify,
+ kVerifyChecksum,
+ error_msg);
}
uint32_t OatFile::OatDexFile::GetOatClassOffset(uint16_t class_def_index) const {
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index f3a0725..71b9ca4 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -27,6 +27,7 @@
#include "base/stl_util.h"
#include "class_linker.h"
#include "compiler_filter.h"
+#include "dex_file_loader.h"
#include "exec_utils.h"
#include "gc/heap.h"
#include "gc/space/image_space.h"
@@ -349,7 +350,7 @@
// Load the rest of the multidex entries
for (size_t i = 1;; i++) {
- std::string multidex_dex_location = DexFile::GetMultiDexLocation(i, dex_location.c_str());
+ std::string multidex_dex_location = DexFileLoader::GetMultiDexLocation(i, dex_location.c_str());
oat_dex_file = oat_file.GetOatDexFile(multidex_dex_location.c_str(), nullptr);
if (oat_dex_file == nullptr) {
// There are no more multidex entries to load.
@@ -401,7 +402,7 @@
uint32_t expected_checksum = (*required_dex_checksums)[i];
uint32_t actual_checksum = file.GetLocationChecksum(i);
if (expected_checksum != actual_checksum) {
- std::string dex = DexFile::GetMultiDexLocation(i, dex_location_.c_str());
+ std::string dex = DexFileLoader::GetMultiDexLocation(i, dex_location_.c_str());
*error_msg = StringPrintf("Dex checksum does not match for dex: %s."
"Expected: %u, actual: %u",
dex.c_str(),
@@ -430,7 +431,7 @@
}
for (uint32_t i = 0; i < number_of_dex_files; i++) {
- std::string dex = DexFile::GetMultiDexLocation(i, dex_location_.c_str());
+ std::string dex = DexFileLoader::GetMultiDexLocation(i, dex_location_.c_str());
uint32_t expected_checksum = (*required_dex_checksums)[i];
const OatFile::OatDexFile* oat_dex_file = file.GetOatDexFile(dex.c_str(), nullptr);
if (oat_dex_file == nullptr) {
@@ -863,9 +864,9 @@
required_dex_checksums_found_ = false;
cached_required_dex_checksums_.clear();
std::string error_msg;
- if (DexFile::GetMultiDexChecksums(dex_location_.c_str(),
- &cached_required_dex_checksums_,
- &error_msg)) {
+ if (DexFileLoader::GetMultiDexChecksums(dex_location_.c_str(),
+ &cached_required_dex_checksums_,
+ &error_msg)) {
required_dex_checksums_found_ = true;
has_original_dex_files_ = true;
} else {
@@ -879,7 +880,7 @@
if (odex_file != nullptr) {
required_dex_checksums_found_ = true;
for (size_t i = 0; i < odex_file->GetOatHeader().GetDexFileCount(); i++) {
- std::string dex = DexFile::GetMultiDexLocation(i, dex_location_.c_str());
+ std::string dex = DexFileLoader::GetMultiDexLocation(i, dex_location_.c_str());
const OatFile::OatDexFile* odex_dex_file = odex_file->GetOatDexFile(dex.c_str(), nullptr);
if (odex_dex_file == nullptr) {
required_dex_checksums_found_ = false;
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index 66b24a9..1e7cf72 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -31,6 +31,7 @@
#include "class_linker.h"
#include "class_loader_context.h"
#include "dex_file-inl.h"
+#include "dex_file_loader.h"
#include "dex_file_tracking_registrar.h"
#include "gc/scoped_gc_critical_section.h"
#include "gc/space/image_space.h"
@@ -94,7 +95,7 @@
for (const std::unique_ptr<const OatFile>& oat_file : oat_files_) {
const std::vector<const OatDexFile*>& oat_dex_files = oat_file->GetOatDexFiles();
for (const OatDexFile* oat_dex_file : oat_dex_files) {
- if (DexFile::GetBaseLocation(oat_dex_file->GetDexFileLocation()) == dex_base_location) {
+ if (DexFileLoader::GetBaseLocation(oat_dex_file->GetDexFileLocation()) == dex_base_location) {
return oat_file.get();
}
}
@@ -596,7 +597,7 @@
if (oat_file_assistant.HasOriginalDexFiles()) {
if (Runtime::Current()->IsDexFileFallbackEnabled()) {
static constexpr bool kVerifyChecksum = true;
- if (!DexFile::Open(
+ if (!DexFileLoader::Open(
dex_location, dex_location, kVerifyChecksum, /*out*/ &error_msg, &dex_files)) {
LOG(WARNING) << error_msg;
error_msgs->push_back("Failed to open dex files from " + std::string(dex_location)
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 7c05cb6..a4ed21e 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -67,6 +67,7 @@
#include "class_linker-inl.h"
#include "compiler_callbacks.h"
#include "debugger.h"
+#include "dex_file_loader.h"
#include "elf_file.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "experimental_flags.h"
@@ -1020,7 +1021,7 @@
LOG(WARNING) << "Skipping non-existent dex file '" << dex_filename << "'";
continue;
}
- if (!DexFile::Open(dex_filename, dex_location, kVerifyChecksum, &error_msg, dex_files)) {
+ if (!DexFileLoader::Open(dex_filename, dex_location, kVerifyChecksum, &error_msg, dex_files)) {
LOG(WARNING) << "Failed to open .dex from file '" << dex_filename << "': " << error_msg;
++failure_count;
}
diff --git a/runtime/utils.cc b/runtime/utils.cc
index b72dec6..1f6bd74 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -48,6 +48,7 @@
#include "base/stl_util.h"
#include "base/unix_file/fd_file.h"
#include "dex_file-inl.h"
+#include "dex_file_loader.h"
#include "dex_instruction.h"
#include "oat_quick_method_header.h"
#include "os.h"
@@ -858,7 +859,7 @@
!android::base::EndsWith(location, ".art") &&
!android::base::EndsWith(location, ".oat")) {
cache_file += "/";
- cache_file += DexFile::kClassesDex;
+ cache_file += DexFileLoader::kClassesDex;
}
std::replace(cache_file.begin(), cache_file.end(), '/', '@');
*filename = StringPrintf("%s/%s", cache_location, cache_file.c_str());
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index b955220..55bc9ec 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -25,6 +25,7 @@
#include "base/stl_util.h"
#include "base/unix_file/fd_file.h"
#include "dex_file.h"
+#include "dex_file_loader.h"
#include "dex_to_dex_decompiler.h"
namespace art {
@@ -151,15 +152,15 @@
size_t size = reinterpret_cast<const DexFile::Header*>(dex_file_start)->file_size_;
// TODO: Supply the location information for a vdex file.
static constexpr char kVdexLocation[] = "";
- std::string location = DexFile::GetMultiDexLocation(i, kVdexLocation);
- std::unique_ptr<const DexFile> dex(DexFile::Open(dex_file_start,
- size,
- location,
- GetLocationChecksum(i),
- nullptr /*oat_dex_file*/,
- false /*verify*/,
- false /*verify_checksum*/,
- error_msg));
+ std::string location = DexFileLoader::GetMultiDexLocation(i, kVdexLocation);
+ std::unique_ptr<const DexFile> dex(DexFileLoader::Open(dex_file_start,
+ size,
+ location,
+ GetLocationChecksum(i),
+ nullptr /*oat_dex_file*/,
+ false /*verify*/,
+ false /*verify_checksum*/,
+ error_msg));
if (dex == nullptr) {
return false;
}
diff --git a/test/983-source-transform-verify/source_transform.cc b/test/983-source-transform-verify/source_transform.cc
index 570ade3..ef67ace 100644
--- a/test/983-source-transform-verify/source_transform.cc
+++ b/test/983-source-transform-verify/source_transform.cc
@@ -29,6 +29,7 @@
#include "base/macros.h"
#include "bytecode_utils.h"
#include "dex_file.h"
+#include "dex_file_loader.h"
#include "dex_instruction.h"
#include "jit/jit.h"
#include "native_stack_dump.h"
@@ -66,14 +67,14 @@
return;
}
std::string error;
- std::unique_ptr<const DexFile> dex(DexFile::Open(class_data,
- class_data_len,
- "fake_location.dex",
- /*location_checksum*/ 0,
- /*oat_dex_file*/ nullptr,
- /*verify*/ true,
- /*verify_checksum*/ true,
- &error));
+ std::unique_ptr<const DexFile> dex(DexFileLoader::Open(class_data,
+ class_data_len,
+ "fake_location.dex",
+ /*location_checksum*/ 0,
+ /*oat_dex_file*/ nullptr,
+ /*verify*/ true,
+ /*verify_checksum*/ true,
+ &error));
if (dex.get() == nullptr) {
std::cout << "Failed to verify dex file for " << name << " because " << error << std::endl;
return;