Revert "Remove old unquickening of vdex logic."

This reverts commit 537f477453823db37130f9c1562f328ad3360b6a.

Bug: 170086509

Reason for revert: Fails some tests.

Change-Id: I965884b5039f4bce42450091fce04d2c87129c02
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 1486fad..81db30d 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1237,6 +1237,7 @@
           input_vdex_file_ = VdexFile::Open(input_vdex_,
                                             /* writable */ false,
                                             /* low_4gb */ false,
+                                            DoEagerUnquickeningOfVdex(),
                                             &error_msg);
         }
 
@@ -1245,8 +1246,8 @@
             ? ReplaceFileExtension(oat_filename, "vdex")
             : output_vdex_;
         if (vdex_filename == input_vdex_ && output_vdex_.empty()) {
-          use_existing_vdex_ = true;
-          std::unique_ptr<File> vdex_file(OS::OpenFileForReading(vdex_filename.c_str()));
+          update_input_vdex_ = true;
+          std::unique_ptr<File> vdex_file(OS::OpenFileReadWrite(vdex_filename.c_str()));
           vdex_files_.push_back(std::move(vdex_file));
         } else {
           std::unique_ptr<File> vdex_file(OS::CreateEmptyFile(vdex_filename.c_str()));
@@ -1288,6 +1289,7 @@
                                             "vdex",
                                             /* writable */ false,
                                             /* low_4gb */ false,
+                                            DoEagerUnquickeningOfVdex(),
                                             &error_msg);
           // If there's any problem with the passed vdex, just warn and proceed
           // without it.
@@ -1299,20 +1301,15 @@
 
       DCHECK_NE(output_vdex_fd_, -1);
       std::string vdex_location = ReplaceFileExtension(oat_location_, "vdex");
-      if (input_vdex_file_ != nullptr && output_vdex_fd_ == input_vdex_fd_) {
-        use_existing_vdex_ = true;
-      }
-
-      std::unique_ptr<File> vdex_file(new File(DupCloexec(output_vdex_fd_),
-                                               vdex_location,
-                                               /* check_usage= */ true,
-                                               /* read_only_mode= */ use_existing_vdex_));
+      std::unique_ptr<File> vdex_file(new File(
+          DupCloexec(output_vdex_fd_), vdex_location, /* check_usage */ true));
       if (!vdex_file->IsOpened()) {
         PLOG(ERROR) << "Failed to create vdex file: " << vdex_location;
         return false;
       }
-
-      if (!use_existing_vdex_) {
+      if (input_vdex_file_ != nullptr && output_vdex_fd_ == input_vdex_fd_) {
+        update_input_vdex_ = true;
+      } else {
         if (vdex_file->SetLength(0) != 0) {
           PLOG(ERROR) << "Truncating vdex file " << vdex_location << " failed.";
           vdex_file->Erase();
@@ -1324,6 +1321,26 @@
       oat_filenames_.push_back(oat_location_);
     }
 
+    // If we're updating in place a vdex file, be defensive and put an invalid vdex magic in case
+    // dex2oat gets killed.
+    // Note: we're only invalidating the magic data in the file, as dex2oat needs the rest of
+    // the information to remain valid.
+    if (update_input_vdex_) {
+      File* vdex_file = vdex_files_.back().get();
+      if (!vdex_file->PwriteFully(&VdexFile::VdexFileHeader::kVdexInvalidMagic,
+                                  arraysize(VdexFile::VdexFileHeader::kVdexInvalidMagic),
+                                  /*offset=*/ 0u)) {
+        PLOG(ERROR) << "Failed to invalidate vdex header. File: " << vdex_file->GetPath();
+        return false;
+      }
+
+      if (vdex_file->Flush() != 0) {
+        PLOG(ERROR) << "Failed to flush stream after invalidating header of vdex file."
+                    << " File: " << vdex_file->GetPath();
+        return false;
+      }
+    }
+
     if (dm_fd_ != -1 || !dm_file_location_.empty()) {
       std::string error_msg;
       if (dm_fd_ != -1) {
@@ -1372,12 +1389,9 @@
   void EraseOutputFiles() {
     for (auto& files : { &vdex_files_, &oat_files_ }) {
       for (size_t i = 0; i < files->size(); ++i) {
-        auto& file = (*files)[i];
-        if (file != nullptr) {
-          if (!file->ReadOnlyMode()) {
-            file->Erase();
-          }
-          file.reset();
+        if ((*files)[i].get() != nullptr) {
+          (*files)[i]->Erase();
+          (*files)[i].reset();
         }
       }
     }
@@ -1441,7 +1455,7 @@
         if (!oat_writers_[i]->WriteAndOpenDexFiles(
             vdex_files_[i].get(),
             verify,
-            use_existing_vdex_,
+            update_input_vdex_,
             copy_dex_files_,
             &opened_dex_files_map,
             &opened_dex_files)) {
@@ -1690,15 +1704,12 @@
     }
 
     // Setup VerifierDeps for compilation and report if we fail to parse the data.
-    // When we do profile guided optimizations, the compiler currently needs to run
-    // full verification.
-    if (!DoProfileGuidedOptimizations() && input_vdex_file_ != nullptr) {
+    if (!DoEagerUnquickeningOfVdex() && input_vdex_file_ != nullptr) {
       std::unique_ptr<verifier::VerifierDeps> verifier_deps(
           new verifier::VerifierDeps(dex_files, /*output_only=*/ false));
       if (!verifier_deps->ParseStoredData(dex_files, input_vdex_file_->GetVerifierDepsData())) {
         return dex2oat::ReturnCode::kOther;
       }
-      // We can do fast verification.
       callbacks_->SetVerifierDeps(verifier_deps.release());
     } else {
       // Create the main VerifierDeps, here instead of in the compiler since we want to aggregate
@@ -1781,7 +1792,7 @@
     // This means extract, no-vdex verify, and quicken, will use the individual compilation
     // mode (to reduce RAM used by the compiler).
     return compile_individually_ &&
-           (!IsImage() && !use_existing_vdex_ &&
+           (!IsImage() && !update_input_vdex_ &&
             compiler_options_->dex_files_for_oat_file_.size() > 1 &&
             !CompilerFilter::IsAotCompilationEnabled(compiler_options_->GetCompilerFilter()));
   }
@@ -2058,7 +2069,7 @@
       oat_writer->Initialize(driver_.get(), image_writer_.get(), dex_files);
     }
 
-    if (!use_existing_vdex_) {
+    {
       TimingLogger::ScopedTiming t2("dex2oat Write VDEX", timings_);
       DCHECK(IsBootImage() || IsBootImageExtension() || oat_files_.size() == 1u);
       verifier::VerifierDeps* verifier_deps = callbacks_->GetVerifierDeps();
@@ -2314,6 +2325,16 @@
     return DoProfileGuidedOptimizations();
   }
 
+  bool MayInvalidateVdexMetadata() const {
+    // DexLayout can invalidate the vdex metadata if changing the class def order is enabled, so
+    // we need to unquicken the vdex file eagerly, before passing it to dexlayout.
+    return DoDexLayoutOptimizations();
+  }
+
+  bool DoEagerUnquickeningOfVdex() const {
+    return MayInvalidateVdexMetadata() && dm_file_ == nullptr;
+  }
+
   bool LoadProfile() {
     DCHECK(HasProfileInput());
     profile_load_attempted_ = true;
@@ -2908,7 +2929,7 @@
   std::string classpath_dir_;
 
   // Whether the given input vdex is also the output.
-  bool use_existing_vdex_ = false;
+  bool update_input_vdex_ = false;
 
   // By default, copy the dex to the vdex file only if dex files are
   // compressed in APK.
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 3cab12d..083e1c9 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -1762,6 +1762,7 @@
     std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_location.c_str(),
                                                   /*writable=*/ false,
                                                   /*low_4gb=*/ false,
+                                                  /*unquicken=*/ false,
                                                   &error_msg));
     ASSERT_TRUE(vdex != nullptr);
     EXPECT_FALSE(vdex->HasDexSection()) << output_;
diff --git a/dex2oat/dex2oat_vdex_test.cc b/dex2oat/dex2oat_vdex_test.cc
index 895e9c2..1f486e6 100644
--- a/dex2oat/dex2oat_vdex_test.cc
+++ b/dex2oat/dex2oat_vdex_test.cc
@@ -73,6 +73,7 @@
     std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_location.c_str(),
                                                   /*writable=*/ false,
                                                   /*low_4gb=*/ false,
+                                                  /*unquicken=*/ false,
                                                   &error_msg_));
     // Check the vdex doesn't have dex.
     if (vdex->HasDexSection()) {
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 7e7bca5..5ac2bbf 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -683,7 +683,7 @@
 bool OatWriter::WriteAndOpenDexFiles(
     File* vdex_file,
     bool verify,
-    bool use_existing_vdex,
+    bool update_input_vdex,
     CopyOption copy_dex_files,
     /*out*/ std::vector<MemMap>* opened_dex_files_map,
     /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
@@ -697,7 +697,7 @@
   // Write DEX files into VDEX, mmap and open them.
   std::vector<MemMap> dex_files_map;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
-  if (!WriteDexFiles(vdex_file, use_existing_vdex, copy_dex_files, &dex_files_map) ||
+  if (!WriteDexFiles(vdex_file, update_input_vdex, copy_dex_files, &dex_files_map) ||
       !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
     return false;
   }
@@ -3103,7 +3103,7 @@
 }
 
 bool OatWriter::WriteDexFiles(File* file,
-                              bool use_existing_vdex,
+                              bool update_input_vdex,
                               CopyOption copy_dex_files,
                               /*out*/ std::vector<MemMap>* opened_dex_files_map) {
   TimingLogger::ScopedTiming split("Write Dex files", timings_);
@@ -3136,8 +3136,8 @@
     if (profile_compilation_info_ != nullptr ||
         compact_dex_level_ != CompactDexLevel::kCompactDexLevelNone) {
       for (OatDexFile& oat_dex_file : oat_dex_files_) {
-        // use_existing_vdex should not be used with compact dex and layout.
-        CHECK(!use_existing_vdex)
+        // update_input_vdex disables compact dex and layout.
+        CHECK(!update_input_vdex)
             << "We should never update the input vdex when doing dexlayout or compact dex";
         if (!LayoutDexFile(&oat_dex_file)) {
           return false;
@@ -3202,7 +3202,7 @@
     // Extend the file and include the full page at the end as we need to write
     // additional data there and do not want to mmap that page twice.
     size_t page_aligned_size = RoundUp(vdex_size_with_dex_files, kPageSize);
-    if (!use_existing_vdex) {
+    if (!update_input_vdex) {
       if (file->SetLength(page_aligned_size) != 0) {
         PLOG(ERROR) << "Failed to resize vdex file " << file->GetPath();
         return false;
@@ -3233,7 +3233,7 @@
       vdex_size_ = RoundUp(vdex_size_, 4u);
       size_dex_file_alignment_ += vdex_size_ - old_vdex_size;
       // Write the actual dex file.
-      if (!WriteDexFile(file, &oat_dex_file, use_existing_vdex)) {
+      if (!WriteDexFile(file, &oat_dex_file, update_input_vdex)) {
         return false;
       }
     }
@@ -3241,27 +3241,27 @@
     // Write shared dex file data section and fix up the dex file headers.
     if (shared_data_size != 0u) {
       DCHECK_EQ(RoundUp(vdex_size_, 4u), vdex_dex_shared_data_offset_);
-      if (!use_existing_vdex) {
+      if (!update_input_vdex) {
         memset(vdex_begin_ + vdex_size_, 0, vdex_dex_shared_data_offset_ - vdex_size_);
       }
       size_dex_file_alignment_ += vdex_dex_shared_data_offset_ - vdex_size_;
       vdex_size_ = vdex_dex_shared_data_offset_;
 
       if (dex_container_ != nullptr) {
-        CHECK(!use_existing_vdex) << "Use existing vdex should have empty dex container";
+        CHECK(!update_input_vdex) << "Update input vdex should have empty dex container";
         CHECK(compact_dex_level_ != CompactDexLevel::kCompactDexLevelNone);
         DexContainer::Section* const section = dex_container_->GetDataSection();
         DCHECK_EQ(shared_data_size, section->Size());
         memcpy(vdex_begin_ + vdex_size_, section->Begin(), shared_data_size);
         section->Clear();
         dex_container_.reset();
-      } else if (!use_existing_vdex) {
+      } else if (!update_input_vdex) {
         // If we are not updating the input vdex, write out the shared data section.
         memcpy(vdex_begin_ + vdex_size_, raw_dex_file_shared_data_begin, shared_data_size);
       }
       vdex_size_ += shared_data_size;
       size_dex_file_ += shared_data_size;
-      if (!use_existing_vdex) {
+      if (!update_input_vdex) {
         // Fix up the dex headers to have correct offsets to the data section.
         for (OatDexFile& oat_dex_file : oat_dex_files_) {
           DexFile::Header* header =
@@ -3297,22 +3297,22 @@
 
 bool OatWriter::WriteDexFile(File* file,
                              OatDexFile* oat_dex_file,
-                             bool use_existing_vdex) {
+                             bool update_input_vdex) {
   DCHECK_EQ(vdex_size_, oat_dex_file->dex_file_offset_);
   if (oat_dex_file->source_.IsZipEntry()) {
-    DCHECK(!use_existing_vdex);
+    DCHECK(!update_input_vdex);
     if (!WriteDexFile(file, oat_dex_file, oat_dex_file->source_.GetZipEntry())) {
       return false;
     }
   } else if (oat_dex_file->source_.IsRawFile()) {
-    DCHECK(!use_existing_vdex);
+    DCHECK(!update_input_vdex);
     if (!WriteDexFile(file, oat_dex_file, oat_dex_file->source_.GetRawFile())) {
       return false;
     }
   } else {
     DCHECK(oat_dex_file->source_.IsRawData());
     const uint8_t* raw_data = oat_dex_file->source_.GetRawData();
-    if (!WriteDexFile(oat_dex_file, raw_data, use_existing_vdex)) {
+    if (!WriteDexFile(oat_dex_file, raw_data, update_input_vdex)) {
       return false;
     }
   }
@@ -3447,14 +3447,14 @@
 
 bool OatWriter::WriteDexFile(OatDexFile* oat_dex_file,
                              const uint8_t* dex_file,
-                             bool use_existing_vdex) {
+                             bool update_input_vdex) {
   // Note: The raw data has already been checked to contain the header
   // and all the data that the header specifies as the file size.
   DCHECK(dex_file != nullptr);
   DCHECK(ValidateDexFileHeader(dex_file, oat_dex_file->GetLocation()));
   DCHECK_EQ(oat_dex_file->dex_file_size_, AsUnalignedDexFileHeader(dex_file)->file_size_);
 
-  if (use_existing_vdex) {
+  if (update_input_vdex) {
     // The vdex already contains the dex code, no need to write it again.
   } else {
     uint8_t* raw_output = vdex_begin_ + oat_dex_file->dex_file_offset_;
diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h
index ad14d60..87174eb 100644
--- a/dex2oat/linker/oat_writer.h
+++ b/dex2oat/linker/oat_writer.h
@@ -157,11 +157,11 @@
   // Write raw dex files to the vdex file, mmap the file and open the dex files from it.
   // The `verify` setting dictates whether the dex file verifier should check the dex files.
   // This is generally the case, and should only be false for tests.
-  // If `use_existing_vdex` is true, then this method won't actually write the dex files,
+  // If `update_input_vdex` is true, then this method won't actually write the dex files,
   // and the compiler will just re-use the existing vdex file.
   bool WriteAndOpenDexFiles(File* vdex_file,
                             bool verify,
-                            bool use_existing_vdex,
+                            bool update_input_vdex,
                             CopyOption copy_dex_files,
                             /*out*/ std::vector<MemMap>* opened_dex_files_map,
                             /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files);
@@ -276,12 +276,12 @@
   // If `update_input_vdex` is true, then this method won't actually write the dex files,
   // and the compiler will just re-use the existing vdex file.
   bool WriteDexFiles(File* file,
-                     bool use_existing_vdex,
+                     bool update_input_vdex,
                      CopyOption copy_dex_files,
                      /*out*/ std::vector<MemMap>* opened_dex_files_map);
   bool WriteDexFile(File* file,
                     OatDexFile* oat_dex_file,
-                    bool use_existing_vdex);
+                    bool update_input_vdex);
   bool LayoutDexFile(OatDexFile* oat_dex_file);
   bool WriteDexFile(File* file,
                     OatDexFile* oat_dex_file,
@@ -291,7 +291,7 @@
                     File* dex_file);
   bool WriteDexFile(OatDexFile* oat_dex_file,
                     const uint8_t* dex_file,
-                    bool use_existing_vdex);
+                    bool update_input_vdex);
   bool OpenDexFiles(File* file,
                     bool verify,
                     /*inout*/ std::vector<MemMap>* opened_dex_files_map,
diff --git a/dexlayout/dexdiag.cc b/dexlayout/dexdiag.cc
index 9aa0353..a9ea27d 100644
--- a/dexlayout/dexdiag.cc
+++ b/dexlayout/dexdiag.cc
@@ -330,6 +330,7 @@
   std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_name,
                                                 /*writable=*/ false,
                                                 /*low_4gb=*/ false,
+                                                /*unquicken= */ false,
                                                 &error_msg /*out*/));
   if (vdex == nullptr) {
     std::cerr << "Could not open vdex file "
diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h
index bdc7863..9bb7b8b 100644
--- a/dexlayout/dexlayout.h
+++ b/dexlayout/dexlayout.h
@@ -99,10 +99,7 @@
 
   // Setting this to false disables class def layout entirely, which is stronger than strictly
   // necessary to ensure the partial order w.r.t. class derivation. TODO: Re-enable (b/68317550).
-  // This should never be set for a device build, as changing class defs ids
-  // conflict with profiles and verification passed by Play.
   static constexpr bool kChangeClassDefOrder = false;
-  static_assert(!(kIsTargetBuild && kChangeClassDefOrder), "Never set class reordering on target");
 
   DexLayout(Options& options,
             ProfileCompilationInfo* info,
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index c80feaf..54e3712 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -190,6 +190,10 @@
   }
 
  private:
+  // Returns true if we want to remove quickened opcodes before loading the VDEX file, false
+  // otherwise.
+  bool ShouldUnquickenVDex() const;
+
   DISALLOW_COPY_AND_ASSIGN(OatFileBase);
 };
 
@@ -276,6 +280,23 @@
   return ret.release();
 }
 
+bool OatFileBase::ShouldUnquickenVDex() const {
+  // We sometimes load oat files without a runtime (eg oatdump) and don't want to do anything in
+  // that case. If we are debuggable there are no -quick opcodes to unquicken. If the runtime is not
+  // debuggable we don't care whether there are -quick opcodes or not so no need to do anything.
+  Runtime* runtime = Runtime::Current();
+  return (runtime != nullptr && runtime->IsJavaDebuggable()) &&
+         // Note: This is called before `OatFileBase::Setup()` where we validate the
+         // oat file contents. Check that we have at least a valid header, including
+         // oat file version, to avoid parsing the key-value store for a different
+         // version (out-of-date oat file) which can lead to crashes. b/179221298.
+         // TODO: While this is a poor workaround and the correct solution would be
+         // to postpone the unquickening check until after `OatFileBase::Setup()`,
+         // we prefer to avoid larger rewrites because quickening is deprecated and
+         // should be removed completely anyway. b/170086509
+         (GetOatHeader().IsValid() && !IsDebuggable());
+}
+
 bool OatFileBase::LoadVdex(const std::string& vdex_filename,
                            bool writable,
                            bool low_4gb,
@@ -286,6 +307,7 @@
                                   vdex_filename,
                                   writable,
                                   low_4gb,
+                                  ShouldUnquickenVDex(),
                                   error_msg);
   if (vdex_.get() == nullptr) {
     *error_msg = StringPrintf("Failed to load vdex file '%s' %s",
@@ -316,6 +338,7 @@
           vdex_filename,
           writable,
           low_4gb,
+          ShouldUnquickenVDex(),
           error_msg);
       if (vdex_.get() == nullptr) {
         *error_msg = "Failed opening vdex file.";
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index c303a7b..414b24e 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -877,6 +877,7 @@
                                 filename_,
                                 /*writable=*/ false,
                                 /*low_4gb=*/ false,
+                                /*unquicken=*/ false,
                                 &error_msg);
         }
       }
@@ -884,6 +885,7 @@
       vdex = VdexFile::Open(filename_,
                             /*writable=*/ false,
                             /*low_4gb=*/ false,
+                            /*unquicken=*/ false,
                             &error_msg);
     }
     if (vdex == nullptr) {
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index aaa6600..f172ee0 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -497,6 +497,7 @@
     vdex_file = VdexFile::Open(vdex_path,
                                /* writable= */ false,
                                /* low_4gb= */ false,
+                               /* unquicken= */ false,
                                &error_msg);
     if (vdex_file == nullptr) {
       LOG(WARNING) << "Failed to open vdex " << vdex_path << ": " << error_msg;
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index ba80886..0afa131 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -72,6 +72,7 @@
                                                   const std::string& vdex_filename,
                                                   bool writable,
                                                   bool low_4gb,
+                                                  bool unquicken,
                                                   std::string* error_msg) {
   ScopedTrace trace(("VdexFile::OpenAtAddress " + vdex_filename).c_str());
   if (!OS::FileExists(vdex_filename.c_str())) {
@@ -105,6 +106,7 @@
                        vdex_filename,
                        writable,
                        low_4gb,
+                       unquicken,
                        error_msg);
 }
 
@@ -116,6 +118,7 @@
                                                   const std::string& vdex_filename,
                                                   bool writable,
                                                   bool low_4gb,
+                                                  bool unquicken,
                                                   std::string* error_msg) {
   if (mmap_addr != nullptr && mmap_size < vdex_length) {
     LOG(WARNING) << "Insufficient pre-allocated space to mmap vdex.";
@@ -123,6 +126,7 @@
     mmap_reuse = false;
   }
   CHECK(!mmap_reuse || mmap_addr != nullptr);
+  CHECK(!(writable && unquicken)) << "We don't want to be writing unquickened files out to disk!";
   // Start as PROT_WRITE so we can mprotect back to it if we want to.
   MemMap mmap = MemMap::MapFileAtAddress(
       mmap_addr,
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index 3ccbfa5..35be4fb 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -194,6 +194,7 @@
                                                  const std::string& vdex_filename,
                                                  bool writable,
                                                  bool low_4gb,
+                                                 bool unquicken,
                                                  std::string* error_msg);
 
   // Returns nullptr if the vdex file cannot be opened or is not valid.
@@ -206,12 +207,14 @@
                                                  const std::string& vdex_filename,
                                                  bool writable,
                                                  bool low_4gb,
+                                                 bool unquicken,
                                                  std::string* error_msg);
 
   // Returns nullptr if the vdex file cannot be opened or is not valid.
   static std::unique_ptr<VdexFile> Open(const std::string& vdex_filename,
                                         bool writable,
                                         bool low_4gb,
+                                        bool unquicken,
                                         std::string* error_msg) {
     return OpenAtAddress(nullptr,
                          0,
@@ -219,6 +222,7 @@
                          vdex_filename,
                          writable,
                          low_4gb,
+                         unquicken,
                          error_msg);
   }
 
@@ -228,6 +232,7 @@
                                         const std::string& vdex_filename,
                                         bool writable,
                                         bool low_4gb,
+                                        bool unquicken,
                                         std::string* error_msg) {
     return OpenAtAddress(nullptr,
                          0,
@@ -237,6 +242,7 @@
                          vdex_filename,
                          writable,
                          low_4gb,
+                         unquicken,
                          error_msg);
   }
 
diff --git a/runtime/vdex_file_test.cc b/runtime/vdex_file_test.cc
index 565487e..9d92b42 100644
--- a/runtime/vdex_file_test.cc
+++ b/runtime/vdex_file_test.cc
@@ -36,11 +36,12 @@
                                                   tmp.GetFilename(),
                                                   /*writable=*/false,
                                                   /*low_4gb=*/false,
+                                                  /*unquicken=*/false,
                                                   &error_msg);
   EXPECT_TRUE(vdex == nullptr);
 
   vdex = VdexFile::Open(
-      tmp.GetFilename(), /*writable=*/false, /*low_4gb=*/false, &error_msg);
+      tmp.GetFilename(), /*writable=*/false, /*low_4gb=*/false, /*unquicken=*/ false, &error_msg);
   EXPECT_TRUE(vdex == nullptr);
 }