From f54e5df37cb42d9a83fc54b375da5ef335d604a9 Mon Sep 17 00:00:00 2001 From: Nicolas Geoffray Date: Thu, 1 Dec 2016 10:45:08 +0000 Subject: Set the location checksum in vdex. The checksum we check against at runtime isn't the dex checksum if we are compiling a jar/apk, but the crc32 of the entry. This is to optimize the check at startup and avoid reading the contents of the zip file. Because with vdex we do not want to open the zip file, (the test has been done already in getDexOptNeeded), and cannot rely on the .oat file for fetching it, put the location checksum in the vdex directly. Note for later refactorings: the dex checksum location is now in the vdex file, but also in the oat file. This can be revisited after we eventually cleanup OatDexFile. Test: 629-vdex bug: 30937355 Change-Id: I7af8ca63b889370c660d694dd4eb95e78f566a1c --- compiler/image_test.cc | 12 ++++++++++++ compiler/oat_test.cc | 13 +++++++++++++ compiler/oat_writer.cc | 50 ++++++++++++++++++++++++++++++++++++++++++-------- compiler/oat_writer.h | 5 +++-- 4 files changed, 70 insertions(+), 10 deletions(-) (limited to 'compiler') diff --git a/compiler/image_test.cc b/compiler/image_test.cc index 5629dffce5..9bbe595fa9 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -29,6 +29,8 @@ #include "elf_writer_quick.h" #include "gc/space/image_space.h" #include "image_writer.h" +#include "linker/buffered_output_stream.h" +#include "linker/file_output_stream.h" #include "linker/multi_oat_relative_patcher.h" #include "lock_word.h" #include "mirror/object-inl.h" @@ -256,6 +258,16 @@ void CompilationHelper::Compile(CompilerDriver* driver, bool image_space_ok = writer->PrepareImageAddressSpace(); ASSERT_TRUE(image_space_ok); + if (kIsVdexEnabled) { + for (size_t i = 0, size = vdex_files.size(); i != size; ++i) { + std::unique_ptr vdex_out( + MakeUnique( + MakeUnique(vdex_files[i].GetFile()))); + oat_writers[i]->WriteVerifierDeps(vdex_out.get(), nullptr); + oat_writers[i]->WriteChecksumsAndVdexHeader(vdex_out.get()); + } + } + for (size_t i = 0, size = oat_files.size(); i != size; ++i) { linker::MultiOatRelativePatcher patcher(driver->GetInstructionSet(), driver->GetInstructionSetFeatures()); diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index 94585769b4..0a778b0954 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -30,6 +30,8 @@ #include "elf_writer.h" #include "elf_writer_quick.h" #include "entrypoints/quick/quick_entrypoints.h" +#include "linker/buffered_output_stream.h" +#include "linker/file_output_stream.h" #include "linker/multi_oat_relative_patcher.h" #include "linker/vector_output_stream.h" #include "mirror/class-inl.h" @@ -218,6 +220,17 @@ class OatTest : public CommonCompilerTest { oat_writer.GetBssSize(), oat_writer.GetBssRootsOffset()); + if (kIsVdexEnabled) { + std::unique_ptr vdex_out( + MakeUnique(MakeUnique(vdex_file))); + if (!oat_writer.WriteVerifierDeps(vdex_out.get(), nullptr)) { + return false; + } + if (!oat_writer.WriteChecksumsAndVdexHeader(vdex_out.get())) { + return false; + } + } + if (!oat_writer.WriteRodata(oat_rodata)) { return false; } diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index 153aff40dc..337ea80791 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -300,6 +300,7 @@ OatWriter::OatWriter(bool compiling_boot_image, TimingLogger* timings, ProfileCo oat_data_offset_(0u), oat_header_(nullptr), size_vdex_header_(0), + size_vdex_checksums_(0), size_dex_file_alignment_(0), size_executable_offset_alignment_(0), size_oat_header_(0), @@ -409,10 +410,11 @@ bool OatWriter::AddVdexDexFilesSource(const VdexFile& vdex_file, CreateTypeLookupTable create_type_lookup_table) { DCHECK(write_state_ == WriteState::kAddingDexFileSources); const uint8_t* current_dex_data = nullptr; - for (size_t i = 0; ; ++i) { + for (size_t i = 0; i < vdex_file.GetHeader().GetNumberOfDexFiles(); ++i) { current_dex_data = vdex_file.GetNextDexFileData(current_dex_data); if (current_dex_data == nullptr) { - break; + LOG(ERROR) << "Unexpected number of dex files in vdex " << location; + return false; } if (!DexFile::IsMagicValid(current_dex_data)) { LOG(ERROR) << "Invalid magic in vdex file created from " << location; @@ -424,7 +426,14 @@ bool OatWriter::AddVdexDexFilesSource(const VdexFile& vdex_file, oat_dex_files_.emplace_back(full_location, DexFileSource(current_dex_data), create_type_lookup_table); + oat_dex_files_.back().dex_file_location_checksum_ = vdex_file.GetLocationChecksum(i); } + + if (vdex_file.GetNextDexFileData(current_dex_data) != nullptr) { + LOG(ERROR) << "Unexpected number of dex files in vdex " << location; + return false; + } + if (oat_dex_files_.empty()) { LOG(ERROR) << "No dex files in vdex file created from " << location; return false; @@ -488,8 +497,8 @@ bool OatWriter::WriteAndOpenDexFiles( // Initialize VDEX and OAT headers. if (kIsVdexEnabled) { - size_vdex_header_ = sizeof(VdexFile::Header); - vdex_size_ = size_vdex_header_; + // Reserve space for Vdex header and checksums. + vdex_size_ = sizeof(VdexFile::Header) + oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum); } size_t oat_data_offset = InitOatHeader(instruction_set, instruction_set_features, @@ -1837,6 +1846,7 @@ bool OatWriter::WriteCode(OutputStream* out) { size_total += (x); DO_STAT(size_vdex_header_); + DO_STAT(size_vdex_checksums_); DO_STAT(size_dex_file_alignment_); DO_STAT(size_executable_offset_alignment_); DO_STAT(size_oat_header_); @@ -2383,6 +2393,7 @@ bool OatWriter::WriteDexFile(OutputStream* out, // Update dex file size and resize class offsets in the OatDexFile. // Note: For raw data, the checksum is passed directly to AddRawDexFileSource(). + // Note: For vdex, the checksum is copied from the existing vdex file. oat_dex_file->dex_file_size_ = header->file_size_; oat_dex_file->class_offsets_.resize(header->class_defs_size_); return true; @@ -2592,11 +2603,31 @@ bool OatWriter::WriteTypeLookupTables( return true; } -bool OatWriter::WriteVdexHeader(OutputStream* vdex_out) { +bool OatWriter::WriteChecksumsAndVdexHeader(OutputStream* vdex_out) { if (!kIsVdexEnabled) { return true; } - off_t actual_offset = vdex_out->Seek(0, kSeekSet); + // Write checksums + off_t actual_offset = vdex_out->Seek(sizeof(VdexFile::Header), kSeekSet); + if (actual_offset != sizeof(VdexFile::Header)) { + PLOG(ERROR) << "Failed to seek to the checksum location of vdex file. Actual: " << actual_offset + << " File: " << vdex_out->GetLocation(); + return false; + } + + for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) { + OatDexFile* oat_dex_file = &oat_dex_files_[i]; + if (!vdex_out->WriteFully( + &oat_dex_file->dex_file_location_checksum_, sizeof(VdexFile::VdexChecksum))) { + PLOG(ERROR) << "Failed to write dex file location checksum. File: " + << vdex_out->GetLocation(); + return false; + } + size_vdex_checksums_ += sizeof(VdexFile::VdexChecksum); + } + + // Write header. + actual_offset = vdex_out->Seek(0, kSeekSet); if (actual_offset != 0) { PLOG(ERROR) << "Failed to seek to the beginning of vdex file. Actual: " << actual_offset << " File: " << vdex_out->GetLocation(); @@ -2610,12 +2641,15 @@ bool OatWriter::WriteVdexHeader(OutputStream* vdex_out) { 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( - dex_section_size, verifier_deps_section_size, quickening_info_section_size); + VdexFile::Header vdex_header(oat_dex_files_.size(), + dex_section_size, + verifier_deps_section_size, + quickening_info_section_size); if (!vdex_out->WriteFully(&vdex_header, sizeof(VdexFile::Header))) { PLOG(ERROR) << "Failed to write vdex header. File: " << vdex_out->GetLocation(); return false; } + size_vdex_header_ = sizeof(VdexFile::Header); if (!vdex_out->Flush()) { PLOG(ERROR) << "Failed to flush stream after writing to vdex file." diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index 0dcf79e54e..da221d6029 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -124,7 +124,7 @@ class OatWriter { // - Initialize() // - WriteVerifierDeps() // - WriteQuickeningInfo() - // - WriteVdexHeader() + // - WriteChecksumsAndVdexHeader() // - PrepareLayout(), // - WriteRodata(), // - WriteCode(), @@ -168,7 +168,7 @@ class OatWriter { /*out*/ std::vector>* opened_dex_files); bool WriteQuickeningInfo(OutputStream* vdex_out); bool WriteVerifierDeps(OutputStream* vdex_out, verifier::VerifierDeps* verifier_deps); - bool WriteVdexHeader(OutputStream* vdex_out); + bool WriteChecksumsAndVdexHeader(OutputStream* vdex_out); // Initialize the writer with the given parameters. void Initialize(const CompilerDriver* compiler, ImageWriter* image_writer, @@ -387,6 +387,7 @@ class OatWriter { // output stats uint32_t size_vdex_header_; + uint32_t size_vdex_checksums_; uint32_t size_dex_file_alignment_; uint32_t size_executable_offset_alignment_; uint32_t size_oat_header_; -- cgit v1.2.3-59-g8ed1b