From 5d5a36bddbc008cd52a3207aa2b31177c47f9a49 Mon Sep 17 00:00:00 2001 From: David Brazdil Date: Wed, 14 Sep 2016 15:34:10 +0100 Subject: [PATCH] Write VerifierDeps into VDEX. This patch serializes VerifierDeps data and writes them into VDEX. It also extends the VDEX header with sizes of the DEX and verifier dependencies sections. Bug: 30937355 Change-Id: I5aa5fc5eb8678533117138e445b757fa771973fb --- compiler/oat_writer.cc | 74 ++++++++++++++++++++++++++++++++++++++++++++++---- compiler/oat_writer.h | 14 ++++++++-- dex2oat/dex2oat.cc | 25 +++++++++++++++++ runtime/vdex_file.cc | 4 ++- runtime/vdex_file.h | 7 ++++- 5 files changed, 114 insertions(+), 10 deletions(-) diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index d629c0c88..904581783 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -55,6 +55,7 @@ #include "utils/dex_cache_arrays_layout-inl.h" #include "vdex_file.h" #include "verifier/method_verifier.h" +#include "verifier/verifier_deps.h" #include "zip_archive.h" namespace art { @@ -297,6 +298,7 @@ OatWriter::OatWriter(bool compiling_boot_image, TimingLogger* timings) dex_files_(nullptr), vdex_size_(0u), vdex_dex_files_offset_(0u), + vdex_verifier_deps_offset_(0u), oat_size_(0u), bss_size_(0u), oat_data_offset_(0u), @@ -307,6 +309,8 @@ OatWriter::OatWriter(bool compiling_boot_image, TimingLogger* timings) size_oat_header_(0), size_oat_header_key_value_store_(0), size_dex_file_(0), + size_verifier_deps_(0), + size_verifier_deps_alignment_(0), size_interpreter_to_interpreter_bridge_(0), size_interpreter_to_compiled_code_bridge_(0), size_jni_dlsym_lookup_(0), @@ -476,11 +480,6 @@ bool OatWriter::WriteAndOpenDexFiles( !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) { return false; } - - // VDEX is finalized. Seek to the beginning of the file and write the header. - if (!WriteVdexHeader(vdex_out.get())) { - return false; - } } else { // Write DEX files into OAT, mmap and open them. if (!WriteDexFiles(oat_rodata, vdex_file) || @@ -1595,6 +1594,52 @@ bool OatWriter::WriteRodata(OutputStream* out) { return true; } +bool OatWriter::WriteVerifierDeps(OutputStream* vdex_out, verifier::VerifierDeps* verifier_deps) { + if (!kIsVdexEnabled) { + return true; + } + + if (verifier_deps == nullptr) { + // Nothing to write. Record the offset, but no need + // for alignment. + vdex_verifier_deps_offset_ = vdex_size_; + return true; + } + + size_t initial_offset = vdex_size_; + size_t start_offset = RoundUp(initial_offset, 4u); + + vdex_size_ = start_offset; + vdex_verifier_deps_offset_ = vdex_size_; + size_verifier_deps_alignment_ = start_offset - initial_offset; + + off_t actual_offset = vdex_out->Seek(start_offset, kSeekSet); + if (actual_offset != static_cast(start_offset)) { + PLOG(ERROR) << "Failed to seek to verifier deps section. Actual: " << actual_offset + << " Expected: " << start_offset + << " Output: " << vdex_out->GetLocation(); + return false; + } + + std::vector buffer; + verifier_deps->Encode(&buffer); + + if (!vdex_out->WriteFully(buffer.data(), buffer.size())) { + PLOG(ERROR) << "Failed to write verifier deps." + << " File: " << vdex_out->GetLocation(); + return false; + } + if (!vdex_out->Flush()) { + PLOG(ERROR) << "Failed to flush stream after writing verifier deps." + << " File: " << vdex_out->GetLocation(); + return false; + } + + size_verifier_deps_ = buffer.size(); + vdex_size_ += size_verifier_deps_; + return true; +} + bool OatWriter::WriteCode(OutputStream* out) { CHECK(write_state_ == WriteState::kWriteText); @@ -1638,6 +1683,8 @@ bool OatWriter::WriteCode(OutputStream* out) { DO_STAT(size_oat_header_); DO_STAT(size_oat_header_key_value_store_); DO_STAT(size_dex_file_); + DO_STAT(size_verifier_deps_); + DO_STAT(size_verifier_deps_alignment_); DO_STAT(size_interpreter_to_interpreter_bridge_); DO_STAT(size_interpreter_to_compiled_code_bridge_); DO_STAT(size_jni_dlsym_lookup_); @@ -2341,6 +2388,9 @@ bool OatWriter::WriteTypeLookupTables( } bool OatWriter::WriteVdexHeader(OutputStream* vdex_out) { + if (!kIsVdexEnabled) { + return true; + } off_t 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 @@ -2348,12 +2398,24 @@ bool OatWriter::WriteVdexHeader(OutputStream* vdex_out) { return false; } - VdexFile::Header vdex_header; + DCHECK_NE(vdex_dex_files_offset_, 0u); + DCHECK_NE(vdex_verifier_deps_offset_, 0u); + + size_t dex_section_size = vdex_verifier_deps_offset_ - vdex_dex_files_offset_; + size_t verifier_deps_section_size = vdex_size_ - vdex_verifier_deps_offset_; + + VdexFile::Header vdex_header(dex_section_size, verifier_deps_section_size); if (!vdex_out->WriteFully(&vdex_header, sizeof(VdexFile::Header))) { PLOG(ERROR) << "Failed to write vdex header. File: " << vdex_out->GetLocation(); return false; } + if (!vdex_out->Flush()) { + PLOG(ERROR) << "Failed to flush stream after writing to vdex file." + << " File: " << vdex_out->GetLocation(); + return false; + } + return true; } diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index dd7d699ee..670accbba 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -50,6 +50,10 @@ namespace linker { class MultiOatRelativePatcher; } // namespace linker +namespace verifier { + class VerifierDeps; +} // namespace verifier + // OatHeader variable length with count of D OatDexFiles // // OatDexFile[0] one variable sized OatDexFile with offsets to Dex and OatClasses @@ -149,6 +153,9 @@ class OatWriter { bool verify, /*out*/ std::unique_ptr* opened_dex_files_map, /*out*/ std::vector>* opened_dex_files); + bool WriteVerifierDeps(OutputStream* vdex_out, verifier::VerifierDeps* verifier_deps); + bool WriteVdexHeader(OutputStream* vdex_out); + // Prepare layout of remaining data. void PrepareLayout(const CompilerDriver* compiler, ImageWriter* image_writer, @@ -232,8 +239,6 @@ class OatWriter { // with a given DexMethodVisitor. bool VisitDexMethods(DexMethodVisitor* visitor); - bool WriteVdexHeader(OutputStream* vdex_out); - bool WriteDexFiles(OutputStream* out, File* file); bool WriteDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file); bool SeekToDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file); @@ -311,6 +316,9 @@ class OatWriter { // Offset of section holding Dex files inside Vdex. size_t vdex_dex_files_offset_; + // Offset of section holding VerifierDeps inside Vdex. + size_t vdex_verifier_deps_offset_; + // Size required for Oat data structures. size_t oat_size_; @@ -341,6 +349,8 @@ class OatWriter { uint32_t size_oat_header_; uint32_t size_oat_header_key_value_store_; uint32_t size_dex_file_; + uint32_t size_verifier_deps_; + uint32_t size_verifier_deps_alignment_; uint32_t size_interpreter_to_interpreter_bridge_; uint32_t size_interpreter_to_compiled_code_bridge_; uint32_t size_jni_dlsym_lookup_; diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index d99d2d615..245653d08 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -64,6 +64,8 @@ #include "interpreter/unstarted_runtime.h" #include "jit/offline_profiling_info.h" #include "leb128.h" +#include "linker/buffered_output_stream.h" +#include "linker/file_output_stream.h" #include "linker/multi_oat_relative_patcher.h" #include "mirror/class-inl.h" #include "mirror/class_loader.h" @@ -1753,6 +1755,28 @@ class Dex2Oat FINAL { } } + { + TimingLogger::ScopedTiming t2("dex2oat Write VDEX", timings_); + DCHECK(IsBootImage() || oat_files_.size() == 1u); + DCHECK_EQ(IsBootImage(), verifier_deps_ == nullptr); + for (size_t i = 0, size = oat_files_.size(); i != size; ++i) { + File* vdex_file = vdex_files_[i].get(); + std::unique_ptr vdex_out( + MakeUnique(MakeUnique(vdex_file))); + + if (!oat_writers_[i]->WriteVerifierDeps(vdex_out.get(), verifier_deps_.get())) { + LOG(ERROR) << "Failed to write verifier dependencies into VDEX " << vdex_file->GetPath(); + return false; + } + + // VDEX finalized, seek back to the beginning and write the header. + if (!oat_writers_[i]->WriteVdexHeader(vdex_out.get())) { + LOG(ERROR) << "Failed to write vdex header into VDEX " << vdex_file->GetPath(); + return false; + } + } + } + linker::MultiOatRelativePatcher patcher(instruction_set_, instruction_set_features_.get()); { TimingLogger::ScopedTiming t2("dex2oat Write ELF", timings_); @@ -2604,6 +2628,7 @@ class Dex2Oat FINAL { std::vector> elf_writers_; std::vector> oat_writers_; std::vector rodata_; + std::vector> vdex_out_; std::unique_ptr image_writer_; std::unique_ptr driver_; diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc index a71578b1c..9fbf87595 100644 --- a/runtime/vdex_file.cc +++ b/runtime/vdex_file.cc @@ -34,7 +34,9 @@ bool VdexFile::Header::IsVersionValid() const { return (memcmp(version_, kVdexVersion, sizeof(kVdexVersion)) == 0); } -VdexFile::Header::Header() { +VdexFile::Header::Header(uint32_t dex_size, uint32_t verifier_deps_size) + : dex_size_(dex_size), + verifier_deps_size_(verifier_deps_size) { memcpy(magic_, kVdexMagic, sizeof(kVdexMagic)); memcpy(version_, kVdexVersion, sizeof(kVdexVersion)); DCHECK(IsMagicValid()); diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h index 9215e52b0..6bea153d2 100644 --- a/runtime/vdex_file.h +++ b/runtime/vdex_file.h @@ -42,17 +42,22 @@ class VdexFile { public: struct Header { public: - Header(); + Header(uint32_t dex_size, uint32_t verifier_deps_size); bool IsMagicValid() const; bool IsVersionValid() const; + uint32_t GetDexSize() const { return dex_size_; } + uint32_t GetVerifierDepsSize() const { return verifier_deps_size_; } + private: static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' }; static constexpr uint8_t kVdexVersion[] = { '0', '0', '0', '\0' }; uint8_t magic_[4]; uint8_t version_[4]; + uint32_t dex_size_; + uint32_t verifier_deps_size_; }; static VdexFile* Open(const std::string& vdex_filename, -- 2.11.0