diff options
| -rw-r--r-- | dex2oat/dex2oat.cc | 4 | ||||
| -rw-r--r-- | dex2oat/dex2oat_test.cc | 2 | ||||
| -rw-r--r-- | dex2oat/linker/oat_writer.cc | 57 | ||||
| -rw-r--r-- | dex2oat/linker/oat_writer_test.cc | 5 | ||||
| -rw-r--r-- | oatdump/oatdump.cc | 8 | ||||
| -rw-r--r-- | patchoat/patchoat.cc | 56 | ||||
| -rw-r--r-- | runtime/gc/heap.cc | 16 | ||||
| -rw-r--r-- | runtime/gc/heap.h | 1 | ||||
| -rw-r--r-- | runtime/gc/heap_test.cc | 21 | ||||
| -rw-r--r-- | runtime/oat_file_assistant.cc | 2 | ||||
| -rw-r--r-- | runtime/vdex_file.cc | 59 | ||||
| -rw-r--r-- | runtime/vdex_file.h | 168 |
12 files changed, 274 insertions, 125 deletions
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 73afbad184..9b6771d3b5 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -1398,8 +1398,8 @@ class Dex2Oat FINAL { std::unique_ptr<linker::BufferedOutputStream> vdex_out = std::make_unique<linker::BufferedOutputStream>( std::make_unique<linker::FileOutputStream>(vdex_files_.back().get())); - if (!vdex_out->WriteFully(&VdexFile::Header::kVdexInvalidMagic, - arraysize(VdexFile::Header::kVdexInvalidMagic))) { + if (!vdex_out->WriteFully(&VdexFile::VerifierDepsHeader::kVdexInvalidMagic, + arraysize(VdexFile::VerifierDepsHeader::kVdexInvalidMagic))) { PLOG(ERROR) << "Failed to invalidate vdex header. File: " << vdex_out->GetLocation(); return false; } diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc index 96dd319946..094dfee3a6 100644 --- a/dex2oat/dex2oat_test.cc +++ b/dex2oat/dex2oat_test.cc @@ -1834,7 +1834,7 @@ TEST_F(Dex2oatTest, DontExtract) { /*unquicken*/ false, &error_msg)); ASSERT_TRUE(vdex != nullptr); - EXPECT_EQ(vdex->GetHeader().GetDexSize(), 0u) << output_; + EXPECT_FALSE(vdex->HasDexSection()) << output_; } std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(), odex_location.c_str(), diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc index c72beea6ce..089aa80ad4 100644 --- a/dex2oat/linker/oat_writer.cc +++ b/dex2oat/linker/oat_writer.cc @@ -555,8 +555,9 @@ bool OatWriter::AddVdexDexFilesSource(const VdexFile& vdex_file, const char* location, CreateTypeLookupTable create_type_lookup_table) { DCHECK(write_state_ == WriteState::kAddingDexFileSources); + DCHECK(vdex_file.HasDexSection()); const uint8_t* current_dex_data = nullptr; - for (size_t i = 0; i < vdex_file.GetHeader().GetNumberOfDexFiles(); ++i) { + for (size_t i = 0; i < vdex_file.GetVerifierDepsHeader().GetNumberOfDexFiles(); ++i) { current_dex_data = vdex_file.GetNextDexFileData(current_dex_data); if (current_dex_data == nullptr) { LOG(ERROR) << "Unexpected number of dex files in vdex " << location; @@ -659,7 +660,8 @@ bool OatWriter::WriteAndOpenDexFiles( // Initialize VDEX and OAT headers. // Reserve space for Vdex header and checksums. - vdex_size_ = sizeof(VdexFile::Header) + oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum); + vdex_size_ = sizeof(VdexFile::VerifierDepsHeader) + + oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum); oat_size_ = InitOatHeader(instruction_set, instruction_set_features, dchecked_integral_cast<uint32_t>(oat_dex_files_.size()), @@ -3333,8 +3335,6 @@ bool OatWriter::WriteDexFiles(OutputStream* out, CopyOption copy_dex_files) { TimingLogger::ScopedTiming split("Write Dex files", timings_); - vdex_dex_files_offset_ = vdex_size_; - // If extraction is enabled, only do it if not all the dex files are aligned and uncompressed. if (copy_dex_files == CopyOption::kOnlyIfCompressed) { extract_dex_files_into_vdex_ = false; @@ -3357,6 +3357,9 @@ bool OatWriter::WriteDexFiles(OutputStream* out, } if (extract_dex_files_into_vdex_) { + // Add the dex section header. + vdex_size_ += sizeof(VdexFile::DexSectionHeader); + vdex_dex_files_offset_ = vdex_size_; // Write dex files. for (OatDexFile& oat_dex_file : oat_dex_files_) { if (!WriteDexFile(out, file, &oat_dex_file, update_input_vdex)) { @@ -4076,8 +4079,9 @@ bool OatWriter::WriteDexLayoutSections( bool OatWriter::WriteChecksumsAndVdexHeader(OutputStream* vdex_out) { // Write checksums - off_t actual_offset = vdex_out->Seek(sizeof(VdexFile::Header), kSeekSet); - if (actual_offset != sizeof(VdexFile::Header)) { + off_t checksums_offset = sizeof(VdexFile::VerifierDepsHeader); + off_t actual_offset = vdex_out->Seek(checksums_offset, kSeekSet); + if (actual_offset != checksums_offset) { PLOG(ERROR) << "Failed to seek to the checksum location of vdex file. Actual: " << actual_offset << " File: " << vdex_out->GetLocation(); return false; @@ -4094,6 +4098,27 @@ bool OatWriter::WriteChecksumsAndVdexHeader(OutputStream* vdex_out) { size_vdex_checksums_ += sizeof(VdexFile::VdexChecksum); } + // Maybe write dex section header. + DCHECK_NE(vdex_verifier_deps_offset_, 0u); + DCHECK_NE(vdex_quickening_info_offset_, 0u); + + bool has_dex_section = extract_dex_files_into_vdex_; + if (has_dex_section) { + DCHECK_NE(vdex_dex_files_offset_, 0u); + size_t dex_section_size = vdex_dex_shared_data_offset_ - vdex_dex_files_offset_; + size_t dex_shared_data_size = vdex_verifier_deps_offset_ - vdex_dex_shared_data_offset_; + size_t quickening_info_section_size = vdex_size_ - vdex_quickening_info_offset_; + + VdexFile::DexSectionHeader dex_section_header(dex_section_size, + dex_shared_data_size, + quickening_info_section_size); + if (!vdex_out->WriteFully(&dex_section_header, sizeof(VdexFile::DexSectionHeader))) { + PLOG(ERROR) << "Failed to write vdex header. File: " << vdex_out->GetLocation(); + return false; + } + size_vdex_header_ += sizeof(VdexFile::DexSectionHeader); + } + // Write header. actual_offset = vdex_out->Seek(0, kSeekSet); if (actual_offset != 0) { @@ -4102,25 +4127,15 @@ bool OatWriter::WriteChecksumsAndVdexHeader(OutputStream* vdex_out) { return false; } - DCHECK_NE(vdex_dex_files_offset_, 0u); - DCHECK_NE(vdex_verifier_deps_offset_, 0u); - DCHECK_NE(vdex_quickening_info_offset_, 0u); - - size_t dex_section_size = vdex_dex_shared_data_offset_ - vdex_dex_files_offset_; - size_t dex_shared_data_size = vdex_verifier_deps_offset_ - vdex_dex_shared_data_offset_; size_t verifier_deps_section_size = vdex_quickening_info_offset_ - vdex_verifier_deps_offset_; - size_t quickening_info_section_size = vdex_size_ - vdex_quickening_info_offset_; - - VdexFile::Header vdex_header(oat_dex_files_.size(), - dex_section_size, - dex_shared_data_size, - verifier_deps_section_size, - quickening_info_section_size); - if (!vdex_out->WriteFully(&vdex_header, sizeof(VdexFile::Header))) { + + VdexFile::VerifierDepsHeader deps_header( + oat_dex_files_.size(), verifier_deps_section_size, has_dex_section); + if (!vdex_out->WriteFully(&deps_header, sizeof(VdexFile::VerifierDepsHeader))) { PLOG(ERROR) << "Failed to write vdex header. File: " << vdex_out->GetLocation(); return false; } - size_vdex_header_ = sizeof(VdexFile::Header); + size_vdex_header_ += sizeof(VdexFile::VerifierDepsHeader); if (!vdex_out->Flush()) { PLOG(ERROR) << "Failed to flush stream after writing to vdex file." diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc index 00b9abe69b..0148a5792c 100644 --- a/dex2oat/linker/oat_writer_test.cc +++ b/dex2oat/linker/oat_writer_test.cc @@ -663,7 +663,8 @@ void OatTest::TestDexFileInput(bool verify, bool low_4gb, bool use_profile) { dex_file2_data->GetHeader().file_size_)); ASSERT_EQ(dex_file2_data->GetLocation(), opened_dex_file2->GetLocation()); - const VdexFile::Header &vdex_header = opened_oat_file->GetVdexFile()->GetHeader(); + const VdexFile::DexSectionHeader &vdex_header = + opened_oat_file->GetVdexFile()->GetDexSectionHeader(); if (!compiler_driver_->GetCompilerOptions().IsQuickeningCompilationEnabled()) { // If quickening is enabled we will always write the table since there is no special logic that // checks for all methods not being quickened (not worth the complexity). @@ -672,7 +673,7 @@ void OatTest::TestDexFileInput(bool verify, bool low_4gb, bool use_profile) { int64_t actual_vdex_size = vdex_file.GetFile()->GetLength(); ASSERT_GE(actual_vdex_size, 0); - ASSERT_EQ((uint64_t) actual_vdex_size, vdex_header.GetComputedFileSize()); + ASSERT_EQ((uint64_t) actual_vdex_size, opened_oat_file->GetVdexFile()->GetComputedFileSize()); } TEST_F(OatTest, DexFileInputCheckOutput) { diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 8069408b5a..9a49fb4752 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -567,7 +567,7 @@ class OatDumper { if (!options_.dump_header_only_) { VariableIndentationOutputStream vios(&os); - VdexFile::Header vdex_header = oat_file_.GetVdexFile()->GetHeader(); + VdexFile::VerifierDepsHeader vdex_header = oat_file_.GetVdexFile()->GetVerifierDepsHeader(); if (vdex_header.IsValid()) { std::string error_msg; std::vector<const DexFile*> dex_files; @@ -584,8 +584,10 @@ class OatDumper { } else { os << "UNRECOGNIZED vdex file, magic " << vdex_header.GetMagic() - << ", version " - << vdex_header.GetVersion() + << ", verifier deps version " + << vdex_header.GetVerifierDepsVersion() + << ", dex section version " + << vdex_header.GetDexSectionVersion() << "\n"; } for (size_t i = 0; i < oat_dex_files_.size(); i++) { diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc index 3df640902a..b9a9a69ab5 100644 --- a/patchoat/patchoat.cc +++ b/patchoat/patchoat.cc @@ -65,6 +65,8 @@ namespace art { using android::base::StringPrintf; +namespace { + static const OatHeader* GetOatHeader(const ElfFile* elf_file) { uint64_t off = 0; if (!elf_file->GetSectionOffsetAndSize(".rodata", &off, nullptr)) { @@ -127,6 +129,38 @@ static bool SymlinkFile(const std::string& input_filename, const std::string& ou return true; } +// Holder class for runtime options and related objects. +class PatchoatRuntimeOptionsHolder { + public: + PatchoatRuntimeOptionsHolder(const std::string& image_location, InstructionSet isa) { + options_.push_back(std::make_pair("compilercallbacks", &callbacks_)); + img_ = "-Ximage:" + image_location; + options_.push_back(std::make_pair(img_.c_str(), nullptr)); + isa_name_ = GetInstructionSetString(isa); + options_.push_back(std::make_pair("imageinstructionset", + reinterpret_cast<const void*>(isa_name_.c_str()))); + options_.push_back(std::make_pair("-Xno-sig-chain", nullptr)); + // We do not want the runtime to attempt to patch the image. + options_.push_back(std::make_pair("-Xnorelocate", nullptr)); + // Don't try to compile. + options_.push_back(std::make_pair("-Xnoimage-dex2oat", nullptr)); + // Do not accept broken image. + options_.push_back(std::make_pair("-Xno-dex-file-fallback", nullptr)); + } + + const RuntimeOptions& GetRuntimeOptions() { + return options_; + } + + private: + RuntimeOptions options_; + NoopCompilerCallbacks callbacks_; + std::string isa_name_; + std::string img_; +}; + +} // namespace + bool PatchOat::GeneratePatch( const MemMap& original, const MemMap& relocated, @@ -440,17 +474,10 @@ bool PatchOat::Patch(const std::string& image_location, TimingLogger::ScopedTiming t("Runtime Setup", timings); CHECK_NE(isa, InstructionSet::kNone); - const char* isa_name = GetInstructionSetString(isa); // Set up the runtime - RuntimeOptions options; - NoopCompilerCallbacks callbacks; - options.push_back(std::make_pair("compilercallbacks", &callbacks)); - std::string img = "-Ximage:" + image_location; - options.push_back(std::make_pair(img.c_str(), nullptr)); - options.push_back(std::make_pair("imageinstructionset", reinterpret_cast<const void*>(isa_name))); - options.push_back(std::make_pair("-Xno-sig-chain", nullptr)); - if (!Runtime::Create(options, false)) { + PatchoatRuntimeOptionsHolder options_holder(image_location, isa); + if (!Runtime::Create(options_holder.GetRuntimeOptions(), false)) { LOG(ERROR) << "Unable to initialize runtime"; return false; } @@ -608,17 +635,10 @@ bool PatchOat::Verify(const std::string& image_location, TimingLogger::ScopedTiming t("Runtime Setup", timings); CHECK_NE(isa, InstructionSet::kNone); - const char* isa_name = GetInstructionSetString(isa); // Set up the runtime - RuntimeOptions options; - NoopCompilerCallbacks callbacks; - options.push_back(std::make_pair("compilercallbacks", &callbacks)); - std::string img = "-Ximage:" + image_location; - options.push_back(std::make_pair(img.c_str(), nullptr)); - options.push_back(std::make_pair("imageinstructionset", reinterpret_cast<const void*>(isa_name))); - options.push_back(std::make_pair("-Xno-sig-chain", nullptr)); - if (!Runtime::Create(options, false)) { + PatchoatRuntimeOptionsHolder options_holder(image_location, isa); + if (!Runtime::Create(options_holder.GetRuntimeOptions(), false)) { LOG(ERROR) << "Unable to initialize runtime"; return false; } diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 3dc2cb572e..3011c37f3a 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -145,15 +145,15 @@ static constexpr bool kUsePartialTlabs = true; #if defined(__LP64__) || !defined(ADDRESS_SANITIZER) // 300 MB (0x12c00000) - (default non-moving space capacity). -static uint8_t* const kPreferredAllocSpaceBegin = - reinterpret_cast<uint8_t*>(300 * MB - Heap::kDefaultNonMovingSpaceCapacity); +uint8_t* const Heap::kPreferredAllocSpaceBegin = + reinterpret_cast<uint8_t*>(300 * MB - kDefaultNonMovingSpaceCapacity); #else #ifdef __ANDROID__ // For 32-bit Android, use 0x20000000 because asan reserves 0x04000000 - 0x20000000. -static uint8_t* const kPreferredAllocSpaceBegin = reinterpret_cast<uint8_t*>(0x20000000); +uint8_t* const Heap::kPreferredAllocSpaceBegin = reinterpret_cast<uint8_t*>(0x20000000); #else // For 32-bit host, use 0x40000000 because asan uses most of the space below this. -static uint8_t* const kPreferredAllocSpaceBegin = reinterpret_cast<uint8_t*>(0x40000000); +uint8_t* const Heap::kPreferredAllocSpaceBegin = reinterpret_cast<uint8_t*>(0x40000000); #endif #endif @@ -382,10 +382,10 @@ Heap::Heap(size_t initial_size, const char* space_name = is_zygote ? kZygoteSpaceName : kNonMovingSpaceName; // Reserve the non moving mem map before the other two since it needs to be at a specific // address. - non_moving_space_mem_map.reset( - MemMap::MapAnonymous(space_name, requested_alloc_space_begin, - non_moving_space_capacity, PROT_READ | PROT_WRITE, true, false, - &error_str)); + non_moving_space_mem_map.reset(MapAnonymousPreferredAddress(space_name, + requested_alloc_space_begin, + non_moving_space_capacity, + &error_str)); CHECK(non_moving_space_mem_map != nullptr) << error_str; // Try to reserve virtual memory at a lower address if we have a separate non moving space. request_begin = kPreferredAllocSpaceBegin + non_moving_space_capacity; diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h index 4de03318a0..5ce01bc9d2 100644 --- a/runtime/gc/heap.h +++ b/runtime/gc/heap.h @@ -144,6 +144,7 @@ class Heap { static constexpr size_t kDefaultLargeObjectThreshold = kMinLargeObjectThreshold; // Whether or not parallel GC is enabled. If not, then we never create the thread pool. static constexpr bool kDefaultEnableParallelGC = false; + static uint8_t* const kPreferredAllocSpaceBegin; // Whether or not we use the free list large object space. Only use it if USE_ART_LOW_4G_ALLOCATOR // since this means that we have to use the slow msync loop in MemMap::MapAnonymous. diff --git a/runtime/gc/heap_test.cc b/runtime/gc/heap_test.cc index 2def52450b..c6b2120f5b 100644 --- a/runtime/gc/heap_test.cc +++ b/runtime/gc/heap_test.cc @@ -27,7 +27,26 @@ namespace art { namespace gc { -class HeapTest : public CommonRuntimeTest {}; +class HeapTest : public CommonRuntimeTest { + public: + void SetUp() OVERRIDE { + MemMap::Init(); + std::string error_msg; + // Reserve the preferred address to force the heap to use another one for testing. + reserved_.reset(MemMap::MapAnonymous("ReserveMap", + gc::Heap::kPreferredAllocSpaceBegin, + 16 * KB, + PROT_READ, + /*low_4gb*/ true, + /*reuse*/ false, + &error_msg)); + ASSERT_TRUE(reserved_ != nullptr) << error_msg; + CommonRuntimeTest::SetUp(); + } + + private: + std::unique_ptr<MemMap> reserved_; +}; TEST_F(HeapTest, ClearGrowthLimit) { Heap* heap = Runtime::Current()->GetHeap(); diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc index 5888c37582..38ca4c9623 100644 --- a/runtime/oat_file_assistant.cc +++ b/runtime/oat_file_assistant.cc @@ -408,7 +408,7 @@ bool OatFileAssistant::DexChecksumUpToDate(const VdexFile& file, std::string* er return true; } - uint32_t number_of_dex_files = file.GetHeader().GetNumberOfDexFiles(); + uint32_t number_of_dex_files = file.GetVerifierDepsHeader().GetNumberOfDexFiles(); if (required_dex_checksums->size() != number_of_dex_files) { *error_msg = StringPrintf("expected %zu dex files but found %u", required_dex_checksums->size(), diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc index ba640556df..ec4dc417d3 100644 --- a/runtime/vdex_file.cc +++ b/runtime/vdex_file.cc @@ -36,32 +36,52 @@ namespace art { -constexpr uint8_t VdexFile::Header::kVdexInvalidMagic[4]; -constexpr uint8_t VdexFile::Header::kVdexMagic[4]; -constexpr uint8_t VdexFile::Header::kVdexVersion[4]; +constexpr uint8_t VdexFile::VerifierDepsHeader::kVdexInvalidMagic[4]; +constexpr uint8_t VdexFile::VerifierDepsHeader::kVdexMagic[4]; +constexpr uint8_t VdexFile::VerifierDepsHeader::kVerifierDepsVersion[4]; +constexpr uint8_t VdexFile::VerifierDepsHeader::kDexSectionVersion[4]; +constexpr uint8_t VdexFile::VerifierDepsHeader::kDexSectionVersionEmpty[4]; -bool VdexFile::Header::IsMagicValid() const { +bool VdexFile::VerifierDepsHeader::IsMagicValid() const { return (memcmp(magic_, kVdexMagic, sizeof(kVdexMagic)) == 0); } -bool VdexFile::Header::IsVersionValid() const { - return (memcmp(version_, kVdexVersion, sizeof(kVdexVersion)) == 0); +bool VdexFile::VerifierDepsHeader::IsVerifierDepsVersionValid() const { + return (memcmp(verifier_deps_version_, kVerifierDepsVersion, sizeof(kVerifierDepsVersion)) == 0); } -VdexFile::Header::Header(uint32_t number_of_dex_files, - uint32_t dex_size, - uint32_t dex_shared_data_size, - uint32_t verifier_deps_size, - uint32_t quickening_info_size) +bool VdexFile::VerifierDepsHeader::IsDexSectionVersionValid() const { + return (memcmp(dex_section_version_, kDexSectionVersion, sizeof(kDexSectionVersion)) == 0) || + (memcmp(dex_section_version_, kDexSectionVersionEmpty, sizeof(kDexSectionVersionEmpty)) == 0); +} + +bool VdexFile::VerifierDepsHeader::HasDexSection() const { + return (memcmp(dex_section_version_, kDexSectionVersion, sizeof(kDexSectionVersion)) == 0); +} + +VdexFile::VerifierDepsHeader::VerifierDepsHeader(uint32_t number_of_dex_files, + uint32_t verifier_deps_size, + bool has_dex_section) : number_of_dex_files_(number_of_dex_files), - dex_size_(dex_size), - dex_shared_data_size_(dex_shared_data_size), - verifier_deps_size_(verifier_deps_size), - quickening_info_size_(quickening_info_size) { + verifier_deps_size_(verifier_deps_size) { memcpy(magic_, kVdexMagic, sizeof(kVdexMagic)); - memcpy(version_, kVdexVersion, sizeof(kVdexVersion)); + memcpy(verifier_deps_version_, kVerifierDepsVersion, sizeof(kVerifierDepsVersion)); + if (has_dex_section) { + memcpy(dex_section_version_, kDexSectionVersion, sizeof(kDexSectionVersion)); + } else { + memcpy(dex_section_version_, kDexSectionVersionEmpty, sizeof(kDexSectionVersionEmpty)); + } DCHECK(IsMagicValid()); - DCHECK(IsVersionValid()); + DCHECK(IsVerifierDepsVersionValid()); + DCHECK(IsDexSectionVersionValid()); +} + +VdexFile::DexSectionHeader::DexSectionHeader(uint32_t dex_size, + uint32_t dex_shared_data_size, + uint32_t quickening_info_size) + : dex_size_(dex_size), + dex_shared_data_size_(dex_shared_data_size), + quickening_info_size_(quickening_info_size) { } std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr, @@ -145,7 +165,7 @@ std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr, return nullptr; } - if (unquicken) { + if (unquicken && vdex->HasDexSection()) { std::vector<std::unique_ptr<const DexFile>> unique_ptr_dex_files; if (!vdex->OpenAllDexFiles(&unique_ptr_dex_files, error_msg)) { return nullptr; @@ -153,7 +173,8 @@ std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr, vdex->Unquicken(MakeNonOwningPointerVector(unique_ptr_dex_files), /* decompile_return_instruction */ false); // Update the quickening info size to pretend there isn't any. - reinterpret_cast<Header*>(vdex->mmap_->Begin())->quickening_info_size_ = 0; + size_t offset = vdex->GetDexSectionHeaderOffset(); + reinterpret_cast<DexSectionHeader*>(vdex->mmap_->Begin() + offset)->quickening_info_size_ = 0; } *error_msg = "Success"; diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h index 72f03f266a..77e1f2ccfe 100644 --- a/runtime/vdex_file.h +++ b/runtime/vdex_file.h @@ -35,51 +35,53 @@ class DexFile; // memory and provides tools for accessing its individual sections. // // File format: -// VdexFile::Header fixed-length header +// VdexFile::VerifierDepsHeader fixed-length header +// Dex file checksums +// +// Optionally: +// VdexFile::DexSectionHeader fixed-length header +// +// quicken_table_off[0] offset into QuickeningInfo section for offset table for DEX[0]. +// DEX[0] array of the input DEX files, the bytecode may have been quickened. +// quicken_table_off[1] +// DEX[1] +// ... +// DEX[D] // -// quicken_table_off[0] offset into QuickeningInfo section for offset table for DEX[0]. -// DEX[0] array of the input DEX files, the bytecode may have been quickened. -// quicken_table_off[1] -// DEX[1] -// ... -// DEX[D] // VerifierDeps // uint8[D][] verification dependencies -// QuickeningInfo -// uint8[D][] quickening data -// uint32[D][] quickening data offset tables +// +// Optionally: +// QuickeningInfo +// uint8[D][] quickening data +// uint32[D][] quickening data offset tables class VdexFile { public: - struct Header { + struct VerifierDepsHeader { public: - Header(uint32_t number_of_dex_files_, - uint32_t dex_size, - uint32_t dex_shared_data_size, - uint32_t verifier_deps_size, - uint32_t quickening_info_size); + VerifierDepsHeader(uint32_t number_of_dex_files_, + uint32_t verifier_deps_size, + bool has_dex_section); const char* GetMagic() const { return reinterpret_cast<const char*>(magic_); } - const char* GetVersion() const { return reinterpret_cast<const char*>(version_); } + const char* GetVerifierDepsVersion() const { + return reinterpret_cast<const char*>(verifier_deps_version_); + } + const char* GetDexSectionVersion() const { + return reinterpret_cast<const char*>(dex_section_version_); + } bool IsMagicValid() const; - bool IsVersionValid() const; - bool IsValid() const { return IsMagicValid() && IsVersionValid(); } + bool IsVerifierDepsVersionValid() const; + bool IsDexSectionVersionValid() const; + bool IsValid() const { + return IsMagicValid() && IsVerifierDepsVersionValid() && IsDexSectionVersionValid(); + } + bool HasDexSection() const; - uint32_t GetDexSize() const { return dex_size_; } - uint32_t GetDexSharedDataSize() const { return dex_shared_data_size_; } uint32_t GetVerifierDepsSize() const { return verifier_deps_size_; } - uint32_t GetQuickeningInfoSize() const { return quickening_info_size_; } uint32_t GetNumberOfDexFiles() const { return number_of_dex_files_; } - size_t GetComputedFileSize() const { - return sizeof(Header) + - GetSizeOfChecksumsSection() + - GetDexSize() + - GetDexSharedDataSize() + - GetVerifierDepsSize() + - GetQuickeningInfoSize(); - } - size_t GetSizeOfChecksumsSection() const { return sizeof(VdexChecksum) * GetNumberOfDexFiles(); } @@ -88,20 +90,62 @@ class VdexFile { private: static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' }; - // Last update: Change quickening info table format. - static constexpr uint8_t kVdexVersion[] = { '0', '1', '8', '\0' }; + + // The format version of the verifier deps header and the verifier deps. + // Last update: Add DexSectionHeader + static constexpr uint8_t kVerifierDepsVersion[] = { '0', '1', '9', '\0' }; + + // The format version of the dex section header and the dex section, containing + // both the dex code and the quickening data. + static constexpr uint8_t kDexSectionVersion[] = { '0', '0', '1', '\0' }; + + // If the .vdex file has no dex section (hence no dex code nor quickening data), + // we encode this magic version. + static constexpr uint8_t kDexSectionVersionEmpty[] = { '0', '0', '0', '\0' }; uint8_t magic_[4]; - uint8_t version_[4]; + uint8_t verifier_deps_version_[4]; + uint8_t dex_section_version_[4]; uint32_t number_of_dex_files_; + uint32_t verifier_deps_size_; + }; + + struct DexSectionHeader { + public: + DexSectionHeader(uint32_t dex_size, + uint32_t dex_shared_data_size, + uint32_t quickening_info_size); + + uint32_t GetDexSize() const { return dex_size_; } + uint32_t GetDexSharedDataSize() const { return dex_shared_data_size_; } + uint32_t GetQuickeningInfoSize() const { return quickening_info_size_; } + + size_t GetDexSectionSize() const { + return sizeof(DexSectionHeader) + + GetDexSize() + + GetDexSharedDataSize(); + } + + private: uint32_t dex_size_; uint32_t dex_shared_data_size_; - uint32_t verifier_deps_size_; uint32_t quickening_info_size_; - friend class VdexFile; + friend class VdexFile; // For updatig quickening_info_size_. }; + size_t GetComputedFileSize() const { + size_t size = sizeof(VerifierDepsHeader); + const VerifierDepsHeader& header = GetVerifierDepsHeader(); + size += header.GetVerifierDepsSize(); + size += header.GetSizeOfChecksumsSection(); + if (header.HasDexSection()) { + size += GetDexSectionHeader().GetDexSectionSize(); + size += GetDexSectionHeader().GetQuickeningInfoSize(); + } + return size; + } + // Note: The file is called "primary" to match the naming with profiles. static const constexpr char* kVdexNameInDmFile = "primary.vdex"; @@ -174,24 +218,48 @@ class VdexFile { const uint8_t* End() const { return mmap_->End(); } size_t Size() const { return mmap_->Size(); } - const Header& GetHeader() const { - return *reinterpret_cast<const Header*>(Begin()); + const VerifierDepsHeader& GetVerifierDepsHeader() const { + return *reinterpret_cast<const VerifierDepsHeader*>(Begin()); + } + + uint32_t GetDexSectionHeaderOffset() const { + return sizeof(VerifierDepsHeader) + GetVerifierDepsHeader().GetSizeOfChecksumsSection(); + } + + const DexSectionHeader& GetDexSectionHeader() const { + DCHECK(GetVerifierDepsHeader().HasDexSection()); + return *reinterpret_cast<const DexSectionHeader*>(Begin() + GetDexSectionHeaderOffset()); + } + + const uint8_t* GetVerifierDepsStart() const { + const uint8_t* result = Begin() + GetDexSectionHeaderOffset(); + if (GetVerifierDepsHeader().HasDexSection()) { + // When there is a dex section, the verifier deps are after it, but before the quickening. + return result + GetDexSectionHeader().GetDexSectionSize(); + } else { + // When there is no dex section, the verifier deps are just after the header. + return result; + } } ArrayRef<const uint8_t> GetVerifierDepsData() const { return ArrayRef<const uint8_t>( - DexBegin() + GetHeader().GetDexSize() + GetHeader().GetDexSharedDataSize(), - GetHeader().GetVerifierDepsSize()); + GetVerifierDepsStart(), + GetVerifierDepsHeader().GetVerifierDepsSize()); } ArrayRef<const uint8_t> GetQuickeningInfo() const { - return ArrayRef<const uint8_t>( - GetVerifierDepsData().data() + GetHeader().GetVerifierDepsSize(), - GetHeader().GetQuickeningInfoSize()); + if (GetVerifierDepsHeader().HasDexSection()) { + return ArrayRef<const uint8_t>( + GetVerifierDepsData().data() + GetVerifierDepsHeader().GetVerifierDepsSize(), + GetDexSectionHeader().GetQuickeningInfoSize()); + } else { + return ArrayRef<const uint8_t>(); + } } bool IsValid() const { - return mmap_->Size() >= sizeof(Header) && GetHeader().IsValid(); + return mmap_->Size() >= sizeof(VerifierDepsHeader) && GetVerifierDepsHeader().IsValid(); } // This method is for iterating over the dex files in the vdex. If `cursor` is null, @@ -202,8 +270,8 @@ class VdexFile { // Get the location checksum of the dex file number `dex_file_index`. uint32_t GetLocationChecksum(uint32_t dex_file_index) const { - DCHECK_LT(dex_file_index, GetHeader().GetNumberOfDexFiles()); - return reinterpret_cast<const uint32_t*>(Begin() + sizeof(Header))[dex_file_index]; + DCHECK_LT(dex_file_index, GetVerifierDepsHeader().GetNumberOfDexFiles()); + return reinterpret_cast<const uint32_t*>(Begin() + sizeof(VerifierDepsHeader))[dex_file_index]; } // Open all the dex files contained in this vdex file. @@ -228,7 +296,7 @@ class VdexFile { uint32_t dex_method_idx) const; bool HasDexSection() const { - return GetHeader().GetDexSize() != 0; + return GetVerifierDepsHeader().HasDexSection(); } private: @@ -250,11 +318,13 @@ class VdexFile { bool ContainsDexFile(const DexFile& dex_file) const; const uint8_t* DexBegin() const { - return Begin() + sizeof(Header) + GetHeader().GetSizeOfChecksumsSection(); + DCHECK(HasDexSection()); + return Begin() + GetDexSectionHeaderOffset() + sizeof(DexSectionHeader); } const uint8_t* DexEnd() const { - return DexBegin() + GetHeader().GetDexSize(); + DCHECK(HasDexSection()); + return DexBegin() + GetDexSectionHeader().GetDexSize(); } std::unique_ptr<MemMap> mmap_; |