diff options
40 files changed, 947 insertions, 827 deletions
diff --git a/compiler/utils/test_dex_file_builder.h b/compiler/utils/test_dex_file_builder.h index 8ef98829df..e6501e0b83 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 @@ class TestDexFileBuilder { 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 f20e934f58..ae7ebe2da1 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 @@ class Dex2oatImageTest : public CommonRuntimeTest { 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 5bf35139cb..1b731fc7f6 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 @@ class Dex2oatLayoutTest : public Dex2oatTest { 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 @@ class Dex2oatLayoutTest : public Dex2oatTest { 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 8ef5e6216e..05af442a3a 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 @@ bool OatWriter::AddDexFileSource(const char* filename, 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 @@ bool OatWriter::AddZippedDexFilesSource(File&& zip_fd, 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 @@ bool OatWriter::AddVdexDexFilesSource(const VdexFile& vdex_file, 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 @@ bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_fil 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 @@ bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_fil 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 @@ bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_fil 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 @@ bool OatWriter::OpenDexFiles( } // 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 50434efa25..a19057a0ed 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 @@ void OatTest::TestZipFileInput(bool verify) { 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 @@ void OatTest::TestZipFileInput(bool verify) { 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 7599d230d2..3648a3edd0 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 @@ static void processDexFile(const char* fileName, 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 @@ int processFile(const char* fileName) { 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 095c960bc0..ade00723fd 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 @@ void DexLayout::OutputDexFile(const DexFile* dex_file) { // 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 @@ int DexLayout::ProcessFile(const char* file_name) { 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 336eb5fbcc..f8fa893069 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 @@ class DexLayoutTest : public CommonRuntimeTest { 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 6a1e22a525..e5870522a3 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 int processFile(const char* fileName) { 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 5bfa5ca491..c4988695f1 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 @@ std::unique_ptr<FixedUpDexFile> FixedUpDexFile::Create(const art::DexFile& origi 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 daf4a8b7f2..5f29416134 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 @@ static std::unique_ptr<const art::DexFile> MakeSingleDexFile(art::Thread* self, } 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 98fad80051..53abfbca00 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 @@ jvmtiError Redefiner::AddRedefinition(ArtJvmTiEnv* env, const ArtClassDefinition 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 25bc5d6eb3..bafc8552b1 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 @@ jvmtiError SearchUtil::AddToBootstrapClassLoaderSearch(jvmtiEnv* env ATTRIBUTE_U 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 9b4f5794b7..8ccf7b4c1d 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 @@ class ProfMan FINAL { 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 @@ class ProfMan FINAL { 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 28ae5e4028..ed9906a5ec 100644 --- a/runtime/Android.bp +++ b/runtime/Android.bp @@ -55,6 +55,7 @@ cc_defaults { "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 0cc2622450..fe91272ef7 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 @@ class GetResolvedClassesVisitor : public ClassVisitor { 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 2282da048f..167533d68a 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 @@ bool ClassLoaderContext::OpenDexFiles(InstructionSet isa, const std::string& cla 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 @@ bool ClassLoaderContext::RemoveLocationsFromClassPaths( 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 @@ bool ClassLoaderContext::RemoveLocationsFromClassPaths( 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 @@ std::string ClassLoaderContext::EncodeContext(const std::string& base_dir, 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 ae3dcecb4a..be6acde4a9 100644 --- a/runtime/class_loader_context_test.cc +++ b/runtime/class_loader_context_test.cc @@ -100,12 +100,13 @@ class ClassLoaderContextTest : public CommonRuntimeTest { 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 29b376a21c..0c2e49010e 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::unique_ptr<const DexFile> CommonRuntimeTestImpl::LoadExpectSingleDexFile( 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 @@ std::vector<std::unique_ptr<const DexFile>> CommonRuntimeTestImpl::OpenTestDexFi 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 93daa45519..a9bb95480e 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 @@ class Dex2oatEnvironmentTest : public CommonRuntimeTest { << "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 @@ class Dex2oatEnvironmentTest : public CommonRuntimeTest { // 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 303dd89e08..f6b3428208 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(std::is_trivially_copyable<dex::StringIndex>::value, "StringIndex 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 @@ struct DexFile::AnnotationValue { 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 @@ bool DexFile::DisableWrite() const { } } -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::LineNumForPcCb(void* raw_context, const PositionInfo& entry) { } } -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 c2b901e30f..5759684c55 100644 --- a/runtime/dex_file.h +++ b/runtime/dex_file.h @@ -42,7 +42,8 @@ class ZipArchive; // 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 @@ class DexFile { 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 @@ class DexFile { 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 @@ class DexFile { 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 @@ class DexFile { // 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 @@ class DexFile { 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 @@ class DexFile { 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 @@ class DexFile { // 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 0000000000..3ccb755f58 --- /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 0000000000..61b5c71726 --- /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 67cd42803d..b3011379c6 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 @@ static bool OpenDexFilesBase64(const char* base64, 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 @@ static std::unique_ptr<const DexFile> OpenDexFileInMemoryBase64(const char* base /* 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 @@ TEST_F(DexFileTest, Version40Rejected) { 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 @@ TEST_F(DexFileTest, Version41Rejected) { 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 @@ TEST_F(DexFileTest, ZeroLengthDexRejected) { 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 @@ TEST_F(DexFileTest, GetChecksum) { 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 @@ TEST_F(DexFileTest, GetMultiDexChecksums) { 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, FindFieldId) { } 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 @@ TEST_F(DexFileTest, GetDexCanonicalLocation) { 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 02528f061f..af2d53585e 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 @@ static std::unique_ptr<const DexFile> OpenDexFileBase64(const char* base64, // 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 732c707670..f0eada3cb4 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 @@ bool ImageSpace::ValidateOatFile(const OatFile& oat_file, std::string* error_msg // 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 @@ bool ImageSpace::ValidateOatFile(const OatFile& oat_file, std::string* error_msg // 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 e122c6da20..47615f56fe 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 @@ void JitCodeCache::GetProfiledMethods(const std::set<std::string>& dex_base_loca 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 @@ void JitCodeCache::GetProfiledMethods(const std::set<std::string>& dex_base_loca 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 f9603a7df8..1fad28d1f7 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 @@ std::string ProfileCompilationInfo::DumpInfo(const std::vector<const DexFile*>* 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 @@ bool ProfileCompilationInfo::GenerateTestProfile(int fd, 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 2bf8d8b8f8..01853de403 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 @@ void ProfileSaver::FetchAndCacheResolvedClassesAndMethods(bool startup) { 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 @@ void ProfileSaver::FetchAndCacheResolvedClassesAndMethods(bool startup) { } 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 @@ void ProfileSaver::FetchAndCacheResolvedClassesAndMethods(bool startup) { } 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 d40e6d94c9..e75d097220 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 @@ static const DexFile* CreateDexFile(JNIEnv* env, std::unique_ptr<MemMap> dex_mem 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 4034e8c837..413149c510 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 @@ static jobjectArray VMClassLoader_getBootClassPathEntries(JNIEnv* env, jclass) { 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 c03718d48a..8f09e6d7fc 100644 --- a/runtime/native_dex_file.h +++ b/runtime/native_dex_file.h @@ -48,7 +48,7 @@ class NativeDexFile : public DexFile { 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 c122830eaf..d3d566f440 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 @@ bool OatFileBase::Setup(const char* abs_dex_location, std::string* error_msg) { 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 @@ std::string OatFile::ResolveRelativeEncodedDexLocation( 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 @@ const OatFile::OatDexFile* OatFile::GetOatDexFile(const char* dex_location, 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 @@ const OatFile::OatDexFile* OatFile::GetOatDexFile(const char* dex_location, 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 @@ const OatFile::OatDexFile* OatFile::GetOatDexFile(const char* dex_location, 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 @@ std::unique_ptr<const DexFile> OatFile::OatDexFile::OpenDexFile(std::string* err 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 f3a0725f79..71b9ca4bd5 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 @@ bool OatFileAssistant::LoadDexFiles( // 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 @@ bool OatFileAssistant::DexChecksumUpToDate(const VdexFile& file, std::string* er 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 @@ bool OatFileAssistant::DexChecksumUpToDate(const OatFile& file, std::string* err } 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 @@ const std::vector<uint32_t>* OatFileAssistant::GetRequiredDexChecksums() { 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 @@ const std::vector<uint32_t>* OatFileAssistant::GetRequiredDexChecksums() { 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 66b24a963f..1e7cf723dc 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 @@ const OatFile* OatFileManager::FindOpenedOatFileFromDexLocation( 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 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( 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 7c05cb6174..a4ed21e450 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 @@ static size_t OpenDexFiles(const std::vector<std::string>& dex_filenames, 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 b72dec62bd..1f6bd742b6 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 @@ bool GetDalvikCacheFilename(const char* location, const char* cache_location, !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 b95522062e..55bc9ecac5 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 @@ bool VdexFile::OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_ 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 570ade364d..ef67acec98 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 @@ void JNICALL CheckDexFileHook(jvmtiEnv* jvmti_env ATTRIBUTE_UNUSED, 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; |