Separate vdex versioning into two sections: verifier deps and dex code.

The layout is still the same, but this CL allows updating the cdex and
quickening encoding versions without having to update the verifier deps
version.

bug: 63920015
Test: test.py, dex2oat_test, oat_writer_test, oatdump_test
Change-Id: Ifd282b4c1856f7597d8d26577bf58b9ad87da084
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 73afbad..9b6771d 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1398,8 +1398,8 @@
       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 96dd319..094dfee 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -1834,7 +1834,7 @@
                                                   /*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 c72beea..089aa80 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -555,8 +555,9 @@
                                       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 @@
   // 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 @@
                               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 @@
   }
 
   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::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 @@
     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 @@
     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 00b9abe..0148a57 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -663,7 +663,8 @@
                       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 @@
 
   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 8069408..9a49fb4 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -567,7 +567,7 @@
 
     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 @@
       } 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/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 5888c37..38ca4c9 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -408,7 +408,7 @@
     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 ba64055..ec4dc41 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 @@
     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 @@
     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 72f03f2..77e1f2c 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -35,50 +35,52 @@
 // memory and provides tools for accessing its individual sections.
 //
 // File format:
-//   VdexFile::Header    fixed-length header
+//   VdexFile::VerifierDepsHeader    fixed-length header
+//      Dex file checksums
 //
-//   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]
+//   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]
+//
 //   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_); }
-    bool IsMagicValid() const;
-    bool IsVersionValid() const;
-    bool IsValid() const { return IsMagicValid() && IsVersionValid(); }
-
-    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();
+    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 IsVerifierDepsVersionValid() const;
+    bool IsDexSectionVersionValid() const;
+    bool IsValid() const {
+      return IsMagicValid() && IsVerifierDepsVersionValid() && IsDexSectionVersionValid();
+    }
+    bool HasDexSection() const;
+
+    uint32_t GetVerifierDepsSize() const { return verifier_deps_size_; }
+    uint32_t GetNumberOfDexFiles() const { return number_of_dex_files_; }
 
     size_t GetSizeOfChecksumsSection() const {
       return sizeof(VdexChecksum) * GetNumberOfDexFiles();
@@ -88,20 +90,62 @@
 
    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 @@
   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 @@
 
   // 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 @@
                                              uint32_t dex_method_idx) const;
 
   bool HasDexSection() const {
-    return GetHeader().GetDexSize() != 0;
+    return GetVerifierDepsHeader().HasDexSection();
   }
 
  private:
@@ -250,11 +318,13 @@
   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_;