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
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index d629c0c..9045817 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 @@
     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 @@
     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 @@
         !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 @@
   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<off_t>(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<uint8_t> 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 @@
     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::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 @@
     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 dd7d699..670accb 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -50,6 +50,10 @@
 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 @@
                             bool verify,
                             /*out*/ std::unique_ptr<MemMap>* opened_dex_files_map,
                             /*out*/ std::vector<std::unique_ptr<const DexFile>>* 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 @@
   // 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 @@
   // 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 @@
   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 d99d2d6..245653d 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 @@
       }
     }
 
+    {
+      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<BufferedOutputStream> vdex_out(
+            MakeUnique<BufferedOutputStream>(MakeUnique<FileOutputStream>(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 @@
   std::vector<std::unique_ptr<ElfWriter>> elf_writers_;
   std::vector<std::unique_ptr<OatWriter>> oat_writers_;
   std::vector<OutputStream*> rodata_;
+  std::vector<std::unique_ptr<OutputStream>> vdex_out_;
   std::unique_ptr<ImageWriter> image_writer_;
   std::unique_ptr<CompilerDriver> driver_;
 
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index a71578b..9fbf875 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -34,7 +34,9 @@
   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 9215e52..6bea153 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -42,17 +42,22 @@
  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,