diff options
-rw-r--r-- | build/Android.gtest.mk | 19 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.cc | 6 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.h | 6 | ||||
-rw-r--r-- | dex2oat/dex2oat.cc | 12 | ||||
-rw-r--r-- | dex2oat/dex2oat_test.cc | 15 | ||||
-rw-r--r-- | dex2oat/linker/image_test.h | 12 | ||||
-rw-r--r-- | dex2oat/linker/oat_writer.cc | 75 | ||||
-rw-r--r-- | dex2oat/linker/oat_writer.h | 6 | ||||
-rw-r--r-- | dex2oat/linker/oat_writer_test.cc | 8 | ||||
-rw-r--r-- | oatdump/oatdump.cc | 55 | ||||
-rw-r--r-- | runtime/dex/dex_file.h | 4 | ||||
-rw-r--r-- | runtime/oat_file.cc | 65 | ||||
-rw-r--r-- | runtime/oat_file.h | 9 | ||||
-rw-r--r-- | runtime/zip_archive.cc | 7 | ||||
-rw-r--r-- | runtime/zip_archive.h | 3 |
15 files changed, 234 insertions, 68 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index 4f5df03c19..a2052d5bd9 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -73,6 +73,11 @@ $(foreach dir,$(GTEST_DEX_DIRECTORIES), $(eval $(call build-art-test-dex,art-gte ART_TEST_HOST_GTEST_MainStripped_DEX := $(basename $(ART_TEST_HOST_GTEST_Main_DEX))Stripped$(suffix $(ART_TEST_HOST_GTEST_Main_DEX)) ART_TEST_TARGET_GTEST_MainStripped_DEX := $(basename $(ART_TEST_TARGET_GTEST_Main_DEX))Stripped$(suffix $(ART_TEST_TARGET_GTEST_Main_DEX)) +# Create rules for MainUncompressed, a copy of Main with the classes.dex uncompressed +# for the dex2oat tests. +ART_TEST_HOST_GTEST_MainUncompressed_DEX := $(basename $(ART_TEST_HOST_GTEST_Main_DEX))Uncompressed$(suffix $(ART_TEST_HOST_GTEST_Main_DEX)) +ART_TEST_TARGET_GTEST_MainUncompressed_DEX := $(basename $(ART_TEST_TARGET_GTEST_Main_DEX))Uncompressed$(suffix $(ART_TEST_TARGET_GTEST_Main_DEX)) + $(ART_TEST_HOST_GTEST_MainStripped_DEX): $(ART_TEST_HOST_GTEST_Main_DEX) cp $< $@ $(call dexpreopt-remove-classes.dex,$@) @@ -81,6 +86,16 @@ $(ART_TEST_TARGET_GTEST_MainStripped_DEX): $(ART_TEST_TARGET_GTEST_Main_DEX) cp $< $@ $(call dexpreopt-remove-classes.dex,$@) +$(ART_TEST_HOST_GTEST_MainUncompressed_DEX): $(ART_TEST_HOST_GTEST_Main_DEX) $(ZIPALIGN) + cp $< $@ + $(call uncompress-dexs, $@) + $(call align-package, $@) + +$(ART_TEST_TARGET_GTEST_MainUncompressed_DEX): $(ART_TEST_TARGET_GTEST_Main_DEX) $(ZIPALIGN) + cp $< $@ + $(call uncompress-dexs, $@) + $(call align-package, $@) + ART_TEST_GTEST_VerifierDeps_SRC := $(abspath $(wildcard $(LOCAL_PATH)/VerifierDeps/*.smali)) ART_TEST_GTEST_VerifierDepsMulti_SRC := $(abspath $(wildcard $(LOCAL_PATH)/VerifierDepsMulti/*.smali)) ART_TEST_HOST_GTEST_VerifierDeps_DEX := $(dir $(ART_TEST_HOST_GTEST_Main_DEX))$(subst Main,VerifierDeps,$(basename $(notdir $(ART_TEST_HOST_GTEST_Main_DEX))))$(suffix $(ART_TEST_HOST_GTEST_Main_DEX)) @@ -111,7 +126,7 @@ ART_GTEST_compiler_driver_test_DEX_DEPS := AbstractMethod StaticLeafMethods Prof ART_GTEST_dex_cache_test_DEX_DEPS := Main Packages MethodTypes ART_GTEST_dex_file_test_DEX_DEPS := GetMethodSignature Main Nested MultiDex ART_GTEST_dexlayout_test_DEX_DEPS := ManyMethods -ART_GTEST_dex2oat_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) ManyMethods Statics VerifierDeps +ART_GTEST_dex2oat_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) ManyMethods Statics VerifierDeps MainUncompressed ART_GTEST_dex2oat_image_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) Statics VerifierDeps ART_GTEST_exception_test_DEX_DEPS := ExceptionHandle ART_GTEST_hiddenapi_test_DEX_DEPS := HiddenApi @@ -719,6 +734,8 @@ $(foreach dir,$(GTEST_DEX_DIRECTORIES), $(eval ART_TEST_TARGET_GTEST_$(dir)_DEX $(foreach dir,$(GTEST_DEX_DIRECTORIES), $(eval ART_TEST_HOST_GTEST_$(dir)_DEX :=)) ART_TEST_HOST_GTEST_MainStripped_DEX := ART_TEST_TARGET_GTEST_MainStripped_DEX := +ART_TEST_HOST_GTEST_MainUncompressed_DEX := +ART_TEST_TARGET_GTEST_MainUncompressed_DEX := ART_TEST_GTEST_VerifierDeps_SRC := ART_TEST_HOST_GTEST_VerifierDeps_DEX := ART_TEST_TARGET_GTEST_VerifierDeps_DEX := diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 27cfe19dda..60537fd5c8 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -384,6 +384,12 @@ static optimizer::DexToDexCompiler::CompilationLevel GetDexToDexCompilationLevel Thread* self, const CompilerDriver& driver, Handle<mirror::ClassLoader> class_loader, const DexFile& dex_file, const DexFile::ClassDef& class_def) REQUIRES_SHARED(Locks::mutator_lock_) { + // When the dex file is uncompressed in the APK, we do not generate a copy in the .vdex + // file. As a result, dex2oat will map the dex file read-only, and we only need to check + // that to know if we can do quickening. + if (dex_file.GetContainer() != nullptr && dex_file.GetContainer()->IsReadOnly()) { + return optimizer::DexToDexCompiler::CompilationLevel::kDontDexToDexCompile; + } auto* const runtime = Runtime::Current(); DCHECK(driver.GetCompilerOptions().IsQuickeningCompilationEnabled()); const char* descriptor = dex_file.GetClassDescriptor(class_def); diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 773632cfc6..b51e0debbb 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -107,13 +107,13 @@ class CompilerDriver { ~CompilerDriver(); - // Set dex files that will be stored in the oat file after being compiled. + // Set dex files associated with the oat file being compiled. void SetDexFilesForOatFile(const std::vector<const DexFile*>& dex_files); // Set dex files classpath. void SetClasspathDexFiles(const std::vector<const DexFile*>& dex_files); - // Get dex file that will be stored in the oat file after being compiled. + // Get dex files associated with the the oat file being compiled. ArrayRef<const DexFile* const> GetDexFilesForOatFile() const { return ArrayRef<const DexFile* const>(dex_files_for_oat_file_); } @@ -530,7 +530,7 @@ class CompilerDriver { bool support_boot_image_fixup_; - // List of dex files that will be stored in the oat file. + // List of dex files associates with the oat file. std::vector<const DexFile*> dex_files_for_oat_file_; CompiledMethodStorage compiled_method_storage_; diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 34ba4b34e7..a836d75a72 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -1548,7 +1548,7 @@ class Dex2Oat FINAL { for (size_t i = 0, size = oat_writers_.size(); i != size; ++i) { rodata_.push_back(elf_writers_[i]->StartRoData()); // Unzip or copy dex files straight to the oat file. - std::unique_ptr<MemMap> opened_dex_files_map; + std::vector<std::unique_ptr<MemMap>> opened_dex_files_map; std::vector<std::unique_ptr<const DexFile>> opened_dex_files; // No need to verify the dex file for: // 1) Dexlayout since it does the verification. It also may not pass the verification since @@ -1568,14 +1568,16 @@ class Dex2Oat FINAL { return dex2oat::ReturnCode::kOther; } dex_files_per_oat_file_.push_back(MakeNonOwningPointerVector(opened_dex_files)); - if (opened_dex_files_map != nullptr) { - opened_dex_files_maps_.push_back(std::move(opened_dex_files_map)); + if (opened_dex_files_map.empty()) { + DCHECK(opened_dex_files.empty()); + } else { + for (std::unique_ptr<MemMap>& map : opened_dex_files_map) { + opened_dex_files_maps_.push_back(std::move(map)); + } for (std::unique_ptr<const DexFile>& dex_file : opened_dex_files) { dex_file_oat_index_map_.emplace(dex_file.get(), i); opened_dex_files_.push_back(std::move(dex_file)); } - } else { - DCHECK(opened_dex_files.empty()); } } } diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc index 8799540fd3..798e3f6d1c 100644 --- a/dex2oat/dex2oat_test.cc +++ b/dex2oat/dex2oat_test.cc @@ -1528,4 +1528,19 @@ TEST_F(Dex2oatDedupeCode, DedupeTest) { EXPECT_LT(dedupe_size, no_dedupe_size); } +TEST_F(Dex2oatTest, UncompressedTest) { + std::unique_ptr<const DexFile> dex(OpenTestDexFile("MainUncompressed")); + std::string out_dir = GetScratchDir(); + const std::string base_oat_name = out_dir + "/base.oat"; + GenerateOdexForTest(dex->GetLocation(), + base_oat_name, + CompilerFilter::Filter::kQuicken, + { }, + true, // expect_success + false, // use_fd + [](const OatFile& o) { + CHECK(!o.ContainsDexCode()); + }); +} + } // namespace art diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h index 637578e622..62519fc48e 100644 --- a/dex2oat/linker/image_test.h +++ b/dex2oat/linker/image_test.h @@ -253,7 +253,7 @@ inline void CompilationHelper::Compile(CompilerDriver* driver, } std::vector<OutputStream*> rodata; - std::vector<std::unique_ptr<MemMap>> opened_dex_files_map; + std::vector<std::unique_ptr<MemMap>> opened_dex_files_maps; std::vector<std::unique_ptr<const DexFile>> opened_dex_files; // Now that we have finalized key_value_store_, start writing the oat file. for (size_t i = 0, size = oat_writers.size(); i != size; ++i) { @@ -266,7 +266,7 @@ inline void CompilationHelper::Compile(CompilerDriver* driver, dex_file->GetLocation().c_str(), dex_file->GetLocationChecksum()); - std::unique_ptr<MemMap> cur_opened_dex_files_map; + std::vector<std::unique_ptr<MemMap>> cur_opened_dex_files_maps; std::vector<std::unique_ptr<const DexFile>> cur_opened_dex_files; bool dex_files_ok = oat_writers[i]->WriteAndOpenDexFiles( vdex_files[i].GetFile(), @@ -276,12 +276,14 @@ inline void CompilationHelper::Compile(CompilerDriver* driver, &key_value_store, /* verify */ false, // Dex files may be dex-to-dex-ed, don't verify. /* update_input_vdex */ false, - &cur_opened_dex_files_map, + &cur_opened_dex_files_maps, &cur_opened_dex_files); ASSERT_TRUE(dex_files_ok); - if (cur_opened_dex_files_map != nullptr) { - opened_dex_files_map.push_back(std::move(cur_opened_dex_files_map)); + if (!cur_opened_dex_files_maps.empty()) { + for (std::unique_ptr<MemMap>& cur_map : cur_opened_dex_files_maps) { + opened_dex_files_maps.push_back(std::move(cur_map)); + } for (std::unique_ptr<const DexFile>& cur_dex_file : cur_opened_dex_files) { // dex_file_oat_index_map_.emplace(dex_file.get(), i); opened_dex_files.push_back(std::move(cur_dex_file)); diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc index f790db2b6c..8e4820a00b 100644 --- a/dex2oat/linker/oat_writer.cc +++ b/dex2oat/linker/oat_writer.cc @@ -367,6 +367,7 @@ OatWriter::OatWriter(bool compiling_boot_image, compiler_driver_(nullptr), image_writer_(nullptr), compiling_boot_image_(compiling_boot_image), + only_contains_uncompressed_zip_entries_(false), dex_files_(nullptr), vdex_size_(0u), vdex_dex_files_offset_(0u), @@ -640,7 +641,7 @@ bool OatWriter::WriteAndOpenDexFiles( SafeMap<std::string, std::string>* key_value_store, bool verify, bool update_input_vdex, - /*out*/ std::unique_ptr<MemMap>* opened_dex_files_map, + /*out*/ std::vector<std::unique_ptr<MemMap>>* opened_dex_files_map, /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) { CHECK(write_state_ == WriteState::kAddingDexFileSources); @@ -649,7 +650,7 @@ bool OatWriter::WriteAndOpenDexFiles( return false; } - std::unique_ptr<MemMap> dex_files_map; + std::vector<std::unique_ptr<MemMap>> dex_files_map; std::vector<std::unique_ptr<const DexFile>> dex_files; // Initialize VDEX and OAT headers. @@ -2746,6 +2747,12 @@ class OatWriter::WriteQuickeningInfoOffsetsMethodVisitor { }; bool OatWriter::WriteQuickeningInfo(OutputStream* vdex_out) { + if (only_contains_uncompressed_zip_entries_) { + // Nothing to write. Leave `vdex_size_` untouched and unaligned. + vdex_quickening_info_offset_ = vdex_size_; + size_quickening_info_alignment_ = 0; + return true; + } size_t initial_offset = vdex_size_; // Make sure the table is properly aligned. size_t start_offset = RoundUp(initial_offset, 4u); @@ -3335,14 +3342,28 @@ bool OatWriter::WriteDexFiles(OutputStream* out, File* file, bool update_input_v vdex_dex_files_offset_ = vdex_size_; - // Write dex files. + only_contains_uncompressed_zip_entries_ = true; for (OatDexFile& oat_dex_file : oat_dex_files_) { - if (!WriteDexFile(out, file, &oat_dex_file, update_input_vdex)) { - return false; + if (!oat_dex_file.source_.IsZipEntry()) { + only_contains_uncompressed_zip_entries_ = false; + break; + } + ZipEntry* entry = oat_dex_file.source_.GetZipEntry(); + if (!entry->IsUncompressed() || !entry->IsAlignedToDexHeader()) { + only_contains_uncompressed_zip_entries_ = false; + break; + } + } + + if (!only_contains_uncompressed_zip_entries_) { + // Write dex files. + for (OatDexFile& oat_dex_file : oat_dex_files_) { + if (!WriteDexFile(out, file, &oat_dex_file, update_input_vdex)) { + return false; + } } } - CloseSources(); return true; } @@ -3682,7 +3703,7 @@ bool OatWriter::WriteDexFile(OutputStream* out, bool OatWriter::OpenDexFiles( File* file, bool verify, - /*out*/ std::unique_ptr<MemMap>* opened_dex_files_map, + /*out*/ std::vector<std::unique_ptr<MemMap>>* opened_dex_files_map, /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) { TimingLogger::ScopedTiming split("OpenDexFiles", timings_); @@ -3691,6 +3712,44 @@ bool OatWriter::OpenDexFiles( return true; } + if (only_contains_uncompressed_zip_entries_) { + std::vector<std::unique_ptr<const DexFile>> dex_files; + std::vector<std::unique_ptr<MemMap>> maps; + for (OatDexFile& oat_dex_file : oat_dex_files_) { + std::string error_msg; + MemMap* map = oat_dex_file.source_.GetZipEntry()->MapDirectlyFromFile( + oat_dex_file.dex_file_location_data_, &error_msg); + if (map == nullptr) { + LOG(ERROR) << error_msg; + return false; + } + maps.emplace_back(map); + // Now, open the dex file. + const ArtDexFileLoader dex_file_loader; + dex_files.emplace_back(dex_file_loader.Open(map->Begin(), + map->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; + return false; + } + oat_dex_file.class_offsets_.resize(dex_files.back()->GetHeader().class_defs_size_); + } + *opened_dex_files_map = std::move(maps); + *opened_dex_files = std::move(dex_files); + CloseSources(); + return true; + } + // We could have closed the sources at the point of writing the dex files, but to + // make it consistent with the case we're not writing the dex files, we close them now. + CloseSources(); + size_t map_offset = oat_dex_files_[0].dex_file_offset_; size_t length = vdex_size_ - map_offset; @@ -3750,7 +3809,7 @@ bool OatWriter::OpenDexFiles( oat_dex_file.class_offsets_.resize(dex_files.back()->GetHeader().class_defs_size_); } - *opened_dex_files_map = std::move(dex_files_map); + opened_dex_files_map->push_back(std::move(dex_files_map)); *opened_dex_files = std::move(dex_files); return true; } diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h index ac96bb8d56..c08c05a93b 100644 --- a/dex2oat/linker/oat_writer.h +++ b/dex2oat/linker/oat_writer.h @@ -174,7 +174,7 @@ class OatWriter { SafeMap<std::string, std::string>* key_value_store, bool verify, bool update_input_vdex, - /*out*/ std::unique_ptr<MemMap>* opened_dex_files_map, + /*out*/ std::vector<std::unique_ptr<MemMap>>* opened_dex_files_map, /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files); bool WriteQuickeningInfo(OutputStream* vdex_out); bool WriteVerifierDeps(OutputStream* vdex_out, verifier::VerifierDeps* verifier_deps); @@ -303,7 +303,7 @@ class OatWriter { bool update_input_vdex); bool OpenDexFiles(File* file, bool verify, - /*out*/ std::unique_ptr<MemMap>* opened_dex_files_map, + /*out*/ std::vector<std::unique_ptr<MemMap>>* opened_dex_files_map, /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files); size_t InitOatHeader(InstructionSet instruction_set, @@ -370,6 +370,8 @@ class OatWriter { const CompilerDriver* compiler_driver_; ImageWriter* image_writer_; const bool compiling_boot_image_; + // Whether the dex files being compiled are all uncompressed in the APK. + bool only_contains_uncompressed_zip_entries_; // note OatFile does not take ownership of the DexFiles const std::vector<const DexFile*>* dex_files_; diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc index 4e5fd72675..cd6ca51dda 100644 --- a/dex2oat/linker/oat_writer_test.cc +++ b/dex2oat/linker/oat_writer_test.cc @@ -188,7 +188,7 @@ class OatTest : public CommonCompilerTest { oat_file); elf_writer->Start(); OutputStream* oat_rodata = elf_writer->StartRoData(); - std::unique_ptr<MemMap> opened_dex_files_map; + std::vector<std::unique_ptr<MemMap>> opened_dex_files_maps; std::vector<std::unique_ptr<const DexFile>> opened_dex_files; if (!oat_writer.WriteAndOpenDexFiles(vdex_file, oat_rodata, @@ -197,7 +197,7 @@ class OatTest : public CommonCompilerTest { &key_value_store, verify, /* update_input_vdex */ false, - &opened_dex_files_map, + &opened_dex_files_maps, &opened_dex_files)) { return false; } @@ -257,7 +257,9 @@ class OatTest : public CommonCompilerTest { return false; } - opened_dex_files_maps_.emplace_back(std::move(opened_dex_files_map)); + for (std::unique_ptr<MemMap>& map : opened_dex_files_maps) { + opened_dex_files_maps_.emplace_back(std::move(map)); + } for (std::unique_ptr<const DexFile>& dex_file : opened_dex_files) { opened_dex_files_.emplace_back(dex_file.release()); } diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index fcbf2f1c0a..f2a69f3bb3 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -1055,14 +1055,19 @@ class OatDumper { os << StringPrintf("checksum: 0x%08x\n", oat_dex_file.GetDexFileLocationChecksum()); const uint8_t* const oat_file_begin = oat_dex_file.GetOatFile()->Begin(); - const uint8_t* const vdex_file_begin = oat_dex_file.GetOatFile()->DexBegin(); - - // Print data range of the dex file embedded inside the corresponding vdex file. - const uint8_t* const dex_file_pointer = oat_dex_file.GetDexFilePointer(); - uint32_t dex_offset = dchecked_integral_cast<uint32_t>(dex_file_pointer - vdex_file_begin); - os << StringPrintf("dex-file: 0x%08x..0x%08x\n", - dex_offset, - dchecked_integral_cast<uint32_t>(dex_offset + oat_dex_file.FileSize() - 1)); + if (oat_dex_file.GetOatFile()->ContainsDexCode()) { + const uint8_t* const vdex_file_begin = oat_dex_file.GetOatFile()->DexBegin(); + + // Print data range of the dex file embedded inside the corresponding vdex file. + const uint8_t* const dex_file_pointer = oat_dex_file.GetDexFilePointer(); + uint32_t dex_offset = dchecked_integral_cast<uint32_t>(dex_file_pointer - vdex_file_begin); + os << StringPrintf( + "dex-file: 0x%08x..0x%08x\n", + dex_offset, + dchecked_integral_cast<uint32_t>(dex_offset + oat_dex_file.FileSize() - 1)); + } else { + os << StringPrintf("dex-file not in VDEX file\n"); + } // Create the dex file early. A lot of print-out things depend on it. std::string error_msg; @@ -3041,8 +3046,15 @@ static int DumpOatWithoutRuntime(OatFile* oat_file, OatDumperOptions* options, s return (success) ? EXIT_SUCCESS : EXIT_FAILURE; } -static int DumpOat(Runtime* runtime, const char* oat_filename, OatDumperOptions* options, +static int DumpOat(Runtime* runtime, + const char* oat_filename, + const char* dex_filename, + OatDumperOptions* options, std::ostream* os) { + if (dex_filename == nullptr) { + LOG(WARNING) << "No dex filename provided, " + << "oatdump might fail if the oat file does not contain the dex code."; + } std::string error_msg; std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_filename, oat_filename, @@ -3050,7 +3062,7 @@ static int DumpOat(Runtime* runtime, const char* oat_filename, OatDumperOptions* nullptr, false, /*low_4gb*/false, - nullptr, + dex_filename, &error_msg)); if (oat_file == nullptr) { fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str()); @@ -3064,7 +3076,10 @@ static int DumpOat(Runtime* runtime, const char* oat_filename, OatDumperOptions* } } -static int SymbolizeOat(const char* oat_filename, std::string& output_name, bool no_bits) { +static int SymbolizeOat(const char* oat_filename, + const char* dex_filename, + std::string& output_name, + bool no_bits) { std::string error_msg; std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_filename, oat_filename, @@ -3072,7 +3087,7 @@ static int SymbolizeOat(const char* oat_filename, std::string& output_name, bool nullptr, false, /*low_4gb*/false, - nullptr, + dex_filename, &error_msg)); if (oat_file == nullptr) { fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str()); @@ -3102,7 +3117,8 @@ class IMTDumper { static bool Dump(Runtime* runtime, const std::string& imt_file, bool dump_imt_stats, - const char* oat_filename) { + const char* oat_filename, + const char* dex_filename) { Thread* self = Thread::Current(); ScopedObjectAccess soa(self); @@ -3118,7 +3134,7 @@ class IMTDumper { nullptr, false, /*low_4gb*/false, - nullptr, + dex_filename, &error_msg)); if (oat_file == nullptr) { fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str()); @@ -3553,6 +3569,8 @@ struct OatdumpArgs : public CmdlineArgs { if (option.starts_with("--oat-file=")) { oat_filename_ = option.substr(strlen("--oat-file=")).data(); + } else if (option.starts_with("--dex-file=")) { + dex_filename_ = option.substr(strlen("--dex-file=")).data(); } else if (option.starts_with("--image=")) { image_location_ = option.substr(strlen("--image=")).data(); } else if (option == "--no-dump:vmap") { @@ -3704,6 +3722,7 @@ struct OatdumpArgs : public CmdlineArgs { public: const char* oat_filename_ = nullptr; + const char* dex_filename_ = nullptr; const char* class_filter_ = ""; const char* method_filter_ = ""; const char* image_location_ = nullptr; @@ -3764,10 +3783,12 @@ struct OatdumpMain : public CmdlineMain<OatdumpArgs> { // This is what "strip --only-keep-debug" does when it creates separate ELF file // with only debug data. We use it in similar way to exclude .rodata and .text. bool no_bits = args_->only_keep_debug_; - return SymbolizeOat(args_->oat_filename_, args_->output_name_, no_bits) == EXIT_SUCCESS; + return SymbolizeOat(args_->oat_filename_, args_->dex_filename_, args_->output_name_, no_bits) + == EXIT_SUCCESS; } else { return DumpOat(nullptr, args_->oat_filename_, + args_->dex_filename_, oat_dumper_options_.get(), args_->os_) == EXIT_SUCCESS; } @@ -3780,12 +3801,14 @@ struct OatdumpMain : public CmdlineMain<OatdumpArgs> { return IMTDumper::Dump(runtime, args_->imt_dump_, args_->imt_stat_dump_, - args_->oat_filename_); + args_->oat_filename_, + args_->dex_filename_); } if (args_->oat_filename_ != nullptr) { return DumpOat(runtime, args_->oat_filename_, + args_->dex_filename_, oat_dumper_options_.get(), args_->os_) == EXIT_SUCCESS; } diff --git a/runtime/dex/dex_file.h b/runtime/dex/dex_file.h index 1ee48f71bc..511ce312cd 100644 --- a/runtime/dex/dex_file.h +++ b/runtime/dex/dex_file.h @@ -995,6 +995,10 @@ class DexFile { return Begin() <= addr && addr < Begin() + Size(); } + DexFileContainer* GetContainer() const { + return container_.get(); + } + protected: // First Dex format version supporting default methods. static const uint32_t kDefaultMethodsVersion = 37; diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index c03dbccbc4..9fd99057a1 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -620,14 +620,6 @@ bool OatFileBase::Setup(const char* abs_dex_location, std::string* error_msg) { dex_file_location.c_str()); return false; } - if (UNLIKELY(dex_file_offset == 0U)) { - *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with zero dex " - "file offset", - GetLocation().c_str(), - i, - dex_file_location.c_str()); - return false; - } if (UNLIKELY(dex_file_offset > DexSize())) { *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with dex file " "offset %u > %zu", @@ -638,20 +630,45 @@ bool OatFileBase::Setup(const char* abs_dex_location, std::string* error_msg) { DexSize()); return false; } - if (UNLIKELY(DexSize() - dex_file_offset < sizeof(DexFile::Header))) { - *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with dex file " - "offset %u of %zu but the size of dex file header is %zu", - GetLocation().c_str(), - i, - dex_file_location.c_str(), - dex_file_offset, - DexSize(), - sizeof(DexFile::Header)); - return false; + const uint8_t* dex_file_pointer = nullptr; + if (UNLIKELY(dex_file_offset == 0U)) { + if (uncompressed_dex_files_ == nullptr) { + uncompressed_dex_files_.reset(new std::vector<std::unique_ptr<const DexFile>>()); + // No dex files, load it from location. + const ArtDexFileLoader dex_file_loader; + if (!dex_file_loader.Open(dex_file_location.c_str(), + dex_file_location, + /* verify */ false, + /* verify_checksum */ false, + error_msg, + uncompressed_dex_files_.get())) { + if (Runtime::Current() == nullptr) { + // If there's no runtime, we're running oatdump, so return + // a half constructed oat file that oatdump knows how to deal with. + LOG(WARNING) << "Could not find associated dex files of oat file. " + << "Oatdump will only dump the header."; + return true; + } else { + return false; + } + } + } + dex_file_pointer = uncompressed_dex_files_.get()->at(i)->Begin(); + } else { + if (UNLIKELY(DexSize() - dex_file_offset < sizeof(DexFile::Header))) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with dex file " + "offset %u of %zu but the size of dex file header is %zu", + GetLocation().c_str(), + i, + dex_file_location.c_str(), + dex_file_offset, + DexSize(), + sizeof(DexFile::Header)); + return false; + } + dex_file_pointer = DexBegin() + dex_file_offset; } - const uint8_t* dex_file_pointer = DexBegin() + dex_file_offset; - const bool valid_magic = DexFileLoader::IsMagicValid(dex_file_pointer); if (UNLIKELY(!valid_magic)) { *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with invalid " @@ -672,7 +689,7 @@ bool OatFileBase::Setup(const char* abs_dex_location, std::string* error_msg) { return false; } const DexFile::Header* header = reinterpret_cast<const DexFile::Header*>(dex_file_pointer); - if (DexSize() - dex_file_offset < header->file_size_) { + if (dex_file_offset != 0 && (DexSize() - dex_file_offset < header->file_size_)) { *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with dex file " "offset %u and size %u truncated at %zu", GetLocation().c_str(), @@ -1297,13 +1314,15 @@ bool ElfOatFile::ElfFileOpen(File* file, std::string OatFile::ResolveRelativeEncodedDexLocation( const char* abs_dex_location, const std::string& rel_dex_location) { - if (abs_dex_location != nullptr && rel_dex_location[0] != '/') { + // For host, we still do resolution as the rel_dex_location might be absolute + // for a target dex (for example /system/foo/foo.apk). + if (abs_dex_location != nullptr && (rel_dex_location[0] != '/' || !kIsTargetBuild)) { // Strip :classes<N>.dex used for secondary multidex files. 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; + std::string target_suffix = ((rel_dex_location[0] != '/') ? "/" : "") + base; std::string abs_location(abs_dex_location); if (abs_location.size() > target_suffix.size()) { size_t pos = abs_location.size() - target_suffix.size(); diff --git a/runtime/oat_file.h b/runtime/oat_file.h index bf22e0b88b..50a706d1ba 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -328,6 +328,11 @@ class OatFile { return vdex_.get(); } + // Whether the OatFile embeds the Dex code. + bool ContainsDexCode() const { + return uncompressed_dex_files_ == nullptr; + } + protected: OatFile(const std::string& filename, bool executable); @@ -399,6 +404,10 @@ class OatFile { // elements. std::list<> and std::deque<> satisfy this requirement, std::vector<> doesn't. mutable std::list<std::string> string_cache_ GUARDED_BY(secondary_lookup_lock_); + // Cache of dex files mapped directly from a location, in case the OatFile does + // not embed the dex code. + std::unique_ptr<std::vector<std::unique_ptr<const DexFile>>> uncompressed_dex_files_; + friend class gc::collector::DummyOatFile; // For modifying begin_ and end_. friend class OatClass; friend class art::OatDexFile; diff --git a/runtime/zip_archive.cc b/runtime/zip_archive.cc index f3d4d77214..2caed4b391 100644 --- a/runtime/zip_archive.cc +++ b/runtime/zip_archive.cc @@ -29,6 +29,7 @@ #include "base/bit_utils.h" #include "base/unix_file/fd_file.h" +#include "dex/dex_file.h" namespace art { @@ -49,11 +50,15 @@ bool ZipEntry::IsUncompressed() { return zip_entry_->method == kCompressStored; } -bool ZipEntry::IsAlignedTo(size_t alignment) { +bool ZipEntry::IsAlignedTo(size_t alignment) const { DCHECK(IsPowerOfTwo(alignment)) << alignment; return IsAlignedParam(zip_entry_->offset, static_cast<int>(alignment)); } +bool ZipEntry::IsAlignedToDexHeader() const { + return IsAlignedTo(alignof(DexFile::Header)); +} + ZipEntry::~ZipEntry() { delete zip_entry_; } diff --git a/runtime/zip_archive.h b/runtime/zip_archive.h index 75f8757f6c..70518e1360 100644 --- a/runtime/zip_archive.h +++ b/runtime/zip_archive.h @@ -59,7 +59,8 @@ class ZipEntry { uint32_t GetCrc32(); bool IsUncompressed(); - bool IsAlignedTo(size_t alignment); + bool IsAlignedTo(size_t alignment) const; + bool IsAlignedToDexHeader() const; private: ZipEntry(ZipArchiveHandle handle, |