Rewrite OatFileManager::OpenDexFilesFromOat.

- Remove obsolete option -Xno-dex-file-fallback
- Only load an oat file when class loader context matches.
- Remove obsolete duplicate class check code.

Bug: 132357300
Bug: 156250899
Change-Id: I78e645806e0de2f35ce2614285f1a7cbc705484c
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index f374883..9c169e6 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -305,8 +305,8 @@
   return true;
 }
 
-bool OatFileAssistant::HasOriginalDexFiles() {
-  ScopedTrace trace("HasOriginalDexFiles");
+bool OatFileAssistant::HasDexFiles() {
+  ScopedTrace trace("HasDexFiles");
   // Ensure GetRequiredDexChecksums has been run so that
   // has_original_dex_files_ is initialized. We don't care about the result of
   // GetRequiredDexChecksums.
@@ -633,20 +633,7 @@
   if (!result) {
     VLOG(oat) << "Failed to verify checksums of oat file " << oat_file.GetLocation()
         << " error: " << error_msg;
-
-    if (HasOriginalDexFiles()) {
-      return false;
-    }
-
-    // If there is no original dex file to fall back to, grudgingly accept
-    // the oat file. This could technically lead to crashes, but there's no
-    // way we could find a better oat file to use for this dex location,
-    // and it's better than being stuck in a boot loop with no way out.
-    // The problem will hopefully resolve itself the next time the runtime
-    // starts up.
-    LOG(WARNING) << "Dex location " << dex_location_ << " does not seem to include dex file. "
-        << "Allow oat file use. This is potentially dangerous.";
-    return true;
+    return false;
   }
 
   // This checksum has been validated, so save it.
@@ -683,13 +670,6 @@
     return odex_;
   }
 
-  // The oat file is not usable and the odex file is not up to date.
-  // However we have access to the original dex file which means we can make
-  // the oat location up to date.
-  if (HasOriginalDexFiles()) {
-    return oat_;
-  }
-
   // We got into the worst situation here:
   // - the oat location is not usable
   // - the prebuild odex location is not up to date
@@ -822,10 +802,10 @@
     }
   }
 
-  if (oat_file_assistant_->HasOriginalDexFiles()) {
+  if (oat_file_assistant_->HasDexFiles()) {
     return kDex2OatFromScratch;
   } else {
-    // Otherwise there is nothing we can do, even if we want to.
+    // No dex file, there is nothing we need to do.
     return kNoDexOptNeeded;
   }
 }
@@ -969,27 +949,6 @@
     return ReleaseFile();
   }
 
-  VLOG(oat) << "Oat File Assistant: No relocated oat file found,"
-    << " attempting to fall back to interpreting oat file instead.";
-
-  switch (Status()) {
-    case kOatBootImageOutOfDate:
-      // OutOfDate may be either a mismatched image, or a missing image.
-      if (oat_file_assistant_->HasOriginalDexFiles()) {
-        // If there are original dex files, it is better to use them (to avoid a potential
-        // quickening mismatch because the boot image changed).
-        break;
-      }
-      // If we do not accept the oat file, we may not have access to dex bytecode at all. Grudgingly
-      // go forward.
-      FALLTHROUGH_INTENDED;
-
-    case kOatUpToDate:
-    case kOatCannotOpen:
-    case kOatDexOutOfDate:
-      break;
-  }
-
   return std::unique_ptr<OatFile>();
 }
 
@@ -1030,11 +989,8 @@
     case kOatBootImageOutOfDate:
       FALLTHROUGH_INTENDED;
     case kOatDexOutOfDate:
-      if (oat_file_assistant.HasOriginalDexFiles()) {
-        *out_compilation_filter = "run-from-apk-fallback";
-      } else {
-        *out_compilation_filter = "run-from-vdex-fallback";
-      }
+      DCHECK(oat_file_assistant.HasDexFiles());
+      *out_compilation_filter = "run-from-apk-fallback";
       return;
   }
   LOG(FATAL) << "Unreachable";
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index aa4d83b..069e6fa 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -200,11 +200,8 @@
                            const std::string& dex_location,
                            std::vector<std::unique_ptr<const DexFile>>* out_dex_files);
 
-  // Returns true if there are dex files in the original dex location that can
-  // be compiled with dex2oat for this dex location.
-  // Returns false if there is no original dex file, or if the original dex
-  // file is an apk/zip without a classes.dex entry.
-  bool HasOriginalDexFiles();
+  // Returns whether this is an apk/zip wit a classes.dex entry.
+  bool HasDexFiles();
 
   // If the dex file has been installed with a compiled oat file alongside
   // it, the compiled oat file will have the extension .odex, and is referred
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 7b1a5eb..92347b1 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -242,7 +242,7 @@
   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
-  EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+  EXPECT_TRUE(oat_file_assistant.HasDexFiles());
 
   VerifyOptimizationStatus(dex_location, "run-from-apk", "unknown");
 }
@@ -256,7 +256,7 @@
 
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
-  EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
+  EXPECT_FALSE(oat_file_assistant.HasDexFiles());
 
   // Trying to get the best oat file should fail, but not crash.
   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
@@ -287,7 +287,7 @@
   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
-  EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+  EXPECT_TRUE(oat_file_assistant.HasDexFiles());
 
   VerifyOptimizationStatus(dex_location, CompilerFilter::kSpeed, "install");
 }
@@ -319,7 +319,7 @@
   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
-  EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+  EXPECT_TRUE(oat_file_assistant.HasDexFiles());
 
   VerifyOptimizationStatus(dex_location, CompilerFilter::kSpeed, "install");
 }
@@ -354,7 +354,7 @@
   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
-  EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+  EXPECT_TRUE(oat_file_assistant.HasDexFiles());
 }
 
 // Case: We have a DEX file and up-to-date OAT file for it.
@@ -388,7 +388,7 @@
   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
-  EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+  EXPECT_TRUE(oat_file_assistant.HasDexFiles());
 
   VerifyOptimizationStatus(dex_location, CompilerFilter::kSpeed, "unknown");
 }
@@ -429,7 +429,7 @@
   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
-  EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+  EXPECT_TRUE(oat_file_assistant.HasDexFiles());
 }
 
 // Case: Passing invalid odex fd and valid vdex and zip fds.
@@ -463,7 +463,7 @@
   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
   EXPECT_EQ(OatFileAssistant::kOatBootImageOutOfDate, oat_file_assistant.OdexFileStatus());
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
-  EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+  EXPECT_TRUE(oat_file_assistant.HasDexFiles());
 }
 
 // Case: Passing invalid vdex fd and valid odex and zip fds.
@@ -494,7 +494,7 @@
   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
-  EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+  EXPECT_TRUE(oat_file_assistant.HasDexFiles());
 }
 
 // Case: Passing invalid vdex and odex fd with valid zip fd.
@@ -626,7 +626,7 @@
   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
-  EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+  EXPECT_TRUE(oat_file_assistant.HasDexFiles());
 }
 
 // Case: We have a MultiDEX file and up-to-date OAT file for it.
@@ -648,7 +648,7 @@
   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
-  EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+  EXPECT_TRUE(oat_file_assistant.HasDexFiles());
 
   // Verify we can load both dex files.
   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
@@ -684,38 +684,7 @@
   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
-  EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
-}
-
-// Case: We have a stripped MultiDEX file where the non-main multidex entry is
-// out of date with respect to the odex file.
-TEST_F(OatFileAssistantTest, StrippedMultiDexNonMainOutOfDate) {
-  std::string dex_location = GetScratchDir() + "/StrippedMultiDexNonMainOutOfDate.jar";
-  std::string odex_location = GetOdexDir() + "/StrippedMultiDexNonMainOutOfDate.odex";
-
-  // Compile the oat from GetMultiDexSrc1.
-  Copy(GetMultiDexSrc1(), dex_location);
-  GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
-
-  // Compile the odex from GetMultiDexSrc2, which has a different non-main
-  // dex checksum.
-  Copy(GetMultiDexSrc2(), dex_location);
-  GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kQuicken);
-
-  // Strip the dex file.
-  Copy(GetStrippedDexSrc1(), dex_location);
-
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, /*load_executable=*/false);
-
-  // Because the dex file is stripped, the odex file is considered the source
-  // of truth for the dex checksums. The oat file should be considered
-  // unusable.
-  std::unique_ptr<OatFile> best_file = oat_file_assistant.GetBestOatFile();
-  ASSERT_TRUE(best_file.get() != nullptr);
-  EXPECT_EQ(best_file->GetLocation(), odex_location);
-  EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
-  EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
-  EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus());
+  EXPECT_TRUE(oat_file_assistant.HasDexFiles());
 }
 
 // Case: We have a DEX file and an OAT file out of date with respect to the
@@ -747,7 +716,7 @@
   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
   EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus());
-  EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+  EXPECT_TRUE(oat_file_assistant.HasDexFiles());
 }
 
 // Case: We have a DEX file and an (ODEX) VDEX file out of date with respect
@@ -814,7 +783,7 @@
   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
   EXPECT_EQ(OatFileAssistant::kOatBootImageOutOfDate, oat_file_assistant.OatFileStatus());
-  EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+  EXPECT_TRUE(oat_file_assistant.HasDexFiles());
 }
 
 // Case: We have a DEX file and a verify-at-runtime OAT file out of date with
@@ -847,7 +816,7 @@
   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
-  EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+  EXPECT_TRUE(oat_file_assistant.HasDexFiles());
 }
 
 // Case: We have a DEX file and an ODEX file, but no OAT file.
@@ -870,86 +839,14 @@
   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
-  EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+  EXPECT_TRUE(oat_file_assistant.HasDexFiles());
 
   // We should still be able to get the non-executable odex file to run from.
   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
   ASSERT_TRUE(oat_file.get() != nullptr);
 }
 
-// Case: We have a stripped DEX file and a PIC ODEX file, but no OAT file.
-TEST_F(OatFileAssistantTest, StrippedDexOdexNoOat) {
-  std::string dex_location = GetScratchDir() + "/StrippedDexOdexNoOat.jar";
-  std::string odex_location = GetOdexDir() + "/StrippedDexOdexNoOat.odex";
-
-  // Create the dex and odex files
-  Copy(GetDexSrc1(), dex_location);
-  GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
-
-  // Strip the dex file
-  Copy(GetStrippedDexSrc1(), dex_location);
-
-  // Verify the status.
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
-
-  EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
-      GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
-
-  EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
-  EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
-  EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
-  EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
-
-  // Verify we can load the dex files from it.
-  std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
-  ASSERT_TRUE(oat_file.get() != nullptr);
-  EXPECT_TRUE(oat_file->IsExecutable());
-  std::vector<std::unique_ptr<const DexFile>> dex_files;
-  dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
-  EXPECT_EQ(1u, dex_files.size());
-}
-
-// Case: We have a stripped DEX file, a PIC ODEX file, and an out-of-date OAT file.
-TEST_F(OatFileAssistantTest, StrippedDexOdexOat) {
-  std::string dex_location = GetScratchDir() + "/StrippedDexOdexOat.jar";
-  std::string odex_location = GetOdexDir() + "/StrippedDexOdexOat.odex";
-
-  // Create the oat file from a different dex file so it looks out of date.
-  Copy(GetDexSrc2(), dex_location);
-  GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
-
-  // Create the odex file
-  Copy(GetDexSrc1(), dex_location);
-  GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
-
-  // Strip the dex file.
-  Copy(GetStrippedDexSrc1(), dex_location);
-
-  // Verify the status.
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
-
-  EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
-      GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
-  EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
-      GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
-  EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,  // Compiling from the .vdex file
-      GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kEverything));
-
-  EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
-  EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
-  EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus());
-  EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
-
-  // Verify we can load the dex files from it.
-  std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
-  ASSERT_TRUE(oat_file.get() != nullptr);
-  EXPECT_TRUE(oat_file->IsExecutable());
-  std::vector<std::unique_ptr<const DexFile>> dex_files;
-  dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
-  EXPECT_EQ(1u, dex_files.size());
-}
-
-// Case: We have a stripped (or resource-only) DEX file, no ODEX file and no
+// Case: We have a resource-only DEX file, no ODEX file and no
 // OAT file. Expect: The status is kNoDexOptNeeded.
 TEST_F(OatFileAssistantTest, ResourceOnlyDex) {
   std::string dex_location = GetScratchDir() + "/ResourceOnlyDex.jar";
@@ -969,7 +866,7 @@
   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
-  EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
+  EXPECT_FALSE(oat_file_assistant.HasDexFiles());
 
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -977,7 +874,7 @@
   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
-  EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
+  EXPECT_FALSE(oat_file_assistant.HasDexFiles());
 }
 
 // Case: We have a DEX file, an ODEX file and an OAT file.
@@ -1000,7 +897,7 @@
   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
-  EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+  EXPECT_TRUE(oat_file_assistant.HasDexFiles());
 
   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
   ASSERT_TRUE(oat_file.get() != nullptr);
@@ -1032,7 +929,7 @@
   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
-  EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+  EXPECT_TRUE(oat_file_assistant.HasDexFiles());
 }
 
 // Case: We have a DEX file and up-to-date OAT file for it.
@@ -1184,7 +1081,7 @@
       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
-  EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
+  EXPECT_FALSE(oat_file_assistant.HasDexFiles());
 }
 
 // Case: Non-standard extension for dex file.
@@ -1589,7 +1486,7 @@
       &error_msgs);
 
   EXPECT_FALSE(dex_files.empty());
-  EXPECT_NE(oat_file, nullptr);
+  ASSERT_NE(oat_file, nullptr);
   EXPECT_FALSE(oat_file->IsExecutable());
 }
 
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index 29c130d..85992ea 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -169,234 +169,19 @@
   return oat_files;
 }
 
-class TypeIndexInfo {
- public:
-  explicit TypeIndexInfo(const DexFile* dex_file)
-      : type_indexes_(GenerateTypeIndexes(dex_file)),
-        iter_(type_indexes_.Indexes().begin()),
-        end_(type_indexes_.Indexes().end()) { }
-
-  BitVector& GetTypeIndexes() {
-    return type_indexes_;
-  }
-  BitVector::IndexIterator& GetIterator() {
-    return iter_;
-  }
-  BitVector::IndexIterator& GetIteratorEnd() {
-    return end_;
-  }
-  void AdvanceIterator() {
-    iter_++;
-  }
-
- private:
-  static BitVector GenerateTypeIndexes(const DexFile* dex_file) {
-    BitVector type_indexes(/*start_bits=*/0, /*expandable=*/true, Allocator::GetMallocAllocator());
-    for (uint16_t i = 0; i < dex_file->NumClassDefs(); ++i) {
-      const dex::ClassDef& class_def = dex_file->GetClassDef(i);
-      uint16_t type_idx = class_def.class_idx_.index_;
-      type_indexes.SetBit(type_idx);
-    }
-    return type_indexes;
-  }
-
-  // BitVector with bits set for the type indexes of all classes in the input dex file.
-  BitVector type_indexes_;
-  BitVector::IndexIterator iter_;
-  BitVector::IndexIterator end_;
-};
-
-class DexFileAndClassPair : ValueObject {
- public:
-  DexFileAndClassPair(const DexFile* dex_file, TypeIndexInfo* type_info, bool from_loaded_oat)
-     : type_info_(type_info),
-       dex_file_(dex_file),
-       cached_descriptor_(dex_file_->StringByTypeIdx(dex::TypeIndex(*type_info->GetIterator()))),
-       from_loaded_oat_(from_loaded_oat) {
-    type_info_->AdvanceIterator();
-  }
-
-  DexFileAndClassPair(const DexFileAndClassPair& rhs) = default;
-
-  DexFileAndClassPair& operator=(const DexFileAndClassPair& rhs) = default;
-
-  const char* GetCachedDescriptor() const {
-    return cached_descriptor_;
-  }
-
-  bool operator<(const DexFileAndClassPair& rhs) const {
-    const int cmp = strcmp(cached_descriptor_, rhs.cached_descriptor_);
-    if (cmp != 0) {
-      // Note that the order must be reversed. We want to iterate over the classes in dex files.
-      // They are sorted lexicographically. Thus, the priority-queue must be a min-queue.
-      return cmp > 0;
-    }
-    return dex_file_ < rhs.dex_file_;
-  }
-
-  bool DexFileHasMoreClasses() const {
-    return type_info_->GetIterator() != type_info_->GetIteratorEnd();
-  }
-
-  void Next() {
-    cached_descriptor_ = dex_file_->StringByTypeIdx(dex::TypeIndex(*type_info_->GetIterator()));
-    type_info_->AdvanceIterator();
-  }
-
-  bool FromLoadedOat() const {
-    return from_loaded_oat_;
-  }
-
-  const DexFile* GetDexFile() const {
-    return dex_file_;
-  }
-
- private:
-  TypeIndexInfo* type_info_;
-  const DexFile* dex_file_;
-  const char* cached_descriptor_;
-  bool from_loaded_oat_;  // We only need to compare mismatches between what we load now
-                          // and what was loaded before. Any old duplicates must have been
-                          // OK, and any new "internal" duplicates are as well (they must
-                          // be from multidex, which resolves correctly).
-};
-
-static void AddDexFilesFromOat(
-    const OatFile* oat_file,
-    /*out*/std::vector<const DexFile*>* dex_files,
-    std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
-  for (const OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) {
-    std::string error;
-    std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error);
-    if (dex_file == nullptr) {
-      LOG(WARNING) << "Could not create dex file from oat file: " << error;
-    } else if (dex_file->NumClassDefs() > 0U) {
-      dex_files->push_back(dex_file.get());
-      opened_dex_files->push_back(std::move(dex_file));
-    }
-  }
-}
-
-static void AddNext(/*inout*/DexFileAndClassPair& original,
-                    /*inout*/std::priority_queue<DexFileAndClassPair>& heap) {
-  if (original.DexFileHasMoreClasses()) {
-    original.Next();
-    heap.push(std::move(original));
-  }
-}
-
-static bool CheckClassCollision(const OatFile* oat_file,
-    const ClassLoaderContext* context,
-    std::string* error_msg /*out*/) {
-  std::vector<const DexFile*> dex_files_loaded = context->FlattenOpenedDexFiles();
-
-  // Vector that holds the newly opened dex files live, this is done to prevent leaks.
-  std::vector<std::unique_ptr<const DexFile>> opened_dex_files;
-
-  ScopedTrace st("Collision check");
-  // Add dex files from the oat file to check.
-  std::vector<const DexFile*> dex_files_unloaded;
-  AddDexFilesFromOat(oat_file, &dex_files_unloaded, &opened_dex_files);
-
-  // Generate type index information for each dex file.
-  std::vector<TypeIndexInfo> loaded_types;
-  loaded_types.reserve(dex_files_loaded.size());
-  for (const DexFile* dex_file : dex_files_loaded) {
-    loaded_types.push_back(TypeIndexInfo(dex_file));
-  }
-  std::vector<TypeIndexInfo> unloaded_types;
-  unloaded_types.reserve(dex_files_unloaded.size());
-  for (const DexFile* dex_file : dex_files_unloaded) {
-    unloaded_types.push_back(TypeIndexInfo(dex_file));
-  }
-
-  // Populate the queue of dex file and class pairs with the loaded and unloaded dex files.
-  std::priority_queue<DexFileAndClassPair> queue;
-  for (size_t i = 0; i < dex_files_loaded.size(); ++i) {
-    if (loaded_types[i].GetIterator() != loaded_types[i].GetIteratorEnd()) {
-      queue.emplace(dex_files_loaded[i], &loaded_types[i], /*from_loaded_oat=*/true);
-    }
-  }
-  for (size_t i = 0; i < dex_files_unloaded.size(); ++i) {
-    if (unloaded_types[i].GetIterator() != unloaded_types[i].GetIteratorEnd()) {
-      queue.emplace(dex_files_unloaded[i], &unloaded_types[i], /*from_loaded_oat=*/false);
-    }
-  }
-
-  // Now drain the queue.
-  bool has_duplicates = false;
-  error_msg->clear();
-  while (!queue.empty()) {
-    // Modifying the top element is only safe if we pop right after.
-    DexFileAndClassPair compare_pop(queue.top());
-    queue.pop();
-
-    // Compare against the following elements.
-    while (!queue.empty()) {
-      DexFileAndClassPair top(queue.top());
-      if (strcmp(compare_pop.GetCachedDescriptor(), top.GetCachedDescriptor()) == 0) {
-        // Same descriptor. Check whether it's crossing old-oat-files to new-oat-files.
-        if (compare_pop.FromLoadedOat() != top.FromLoadedOat()) {
-          error_msg->append(
-              StringPrintf("Found duplicated class when checking oat files: '%s' in %s and %s\n",
-                           compare_pop.GetCachedDescriptor(),
-                           compare_pop.GetDexFile()->GetLocation().c_str(),
-                           top.GetDexFile()->GetLocation().c_str()));
-          if (!VLOG_IS_ON(oat)) {
-            return true;
-          }
-          has_duplicates = true;
-        }
-        queue.pop();
-        AddNext(top, queue);
-      } else {
-        // Something else. Done here.
-        break;
-      }
-    }
-    AddNext(compare_pop, queue);
-  }
-
-  return has_duplicates;
-}
-
-// Check for class-def collisions in dex files.
-//
-// This first walks the class loader chain present in the given context, getting all the dex files
-// from the class loader.
-//
-// If the context is null (which means the initial class loader was null or unsupported)
-// this returns false. b/37777332.
-//
-// This first checks whether all class loaders in the context have the same type and
-// classpath. If so, we exit early. Otherwise, we do the collision check.
-//
-// The collision check works by maintaining a heap with one class from each dex file, sorted by the
-// class descriptor. Then a dex-file/class pair is continually removed from the heap and compared
-// against the following top element. If the descriptor is the same, it is now checked whether
-// the two elements agree on whether their dex file was from an already-loaded oat-file or the
-// new oat file. Any disagreement indicates a collision.
-OatFileManager::CheckCollisionResult OatFileManager::CheckCollision(
+static bool ClassLoaderContextMatches(
     const OatFile* oat_file,
     const ClassLoaderContext* context,
-    /*out*/ std::string* error_msg) const {
+    bool* is_special_shared_library,
+    /*out*/ std::string* error_msg) {
   DCHECK(oat_file != nullptr);
   DCHECK(error_msg != nullptr);
-
-  // The context might be null if there are unrecognized class loaders in the chain or they
-  // don't meet sensible sanity conditions. In this case we assume that the app knows what it's
-  // doing and accept the oat file.
-  // Note that this has correctness implications as we cannot guarantee that the class resolution
-  // used during compilation is OK (b/37777332).
-  if (context == nullptr) {
-    LOG(WARNING) << "Skipping duplicate class check due to unsupported classloader";
-    return CheckCollisionResult::kSkippedUnsupportedClassLoader;
-  }
+  DCHECK(context != nullptr);
 
   if (!CompilerFilter::IsVerificationEnabled(oat_file->GetCompilerFilter())) {
-    // If verification is not enabled we don't need to check for collisions as the oat file
-    // is either extracted or assumed verified.
-    return CheckCollisionResult::kSkippedVerificationDisabled;
+    // If verification is not enabled we don't need to check if class loader context matches
+    // as the oat file is either extracted or assumed verified.
+    return true;
   }
 
   // If the oat file loading context matches the context used during compilation then we accept
@@ -407,48 +192,21 @@
       /*verify_checksums=*/ true);
   switch (result) {
     case ClassLoaderContext::VerificationResult::kForcedToSkipChecks:
-      return CheckCollisionResult::kSkippedClassLoaderContextSharedLibrary;
+      *is_special_shared_library = true;
+      return true;
     case ClassLoaderContext::VerificationResult::kMismatch:
-      // Mismatched context, do the actual collision check.
-      break;
+      *is_special_shared_library = false;
+      return false;
     case ClassLoaderContext::VerificationResult::kVerifies:
-      return CheckCollisionResult::kClassLoaderContextMatches;
+      *is_special_shared_library = false;
+      return true;
   }
-
-  // The class loader context does not match. Perform a full duplicate classes check.
-  return CheckClassCollision(oat_file, context, error_msg)
-      ? CheckCollisionResult::kPerformedHasCollisions : CheckCollisionResult::kNoCollisions;
+  LOG(FATAL) << "Unreachable";
 }
 
-bool OatFileManager::AcceptOatFile(CheckCollisionResult result) const {
-  // Take the file only if it has no collisions, or we must take it because of preopting.
-  // Also accept oat files for shared libraries and unsupported class loaders.
-  return result != CheckCollisionResult::kPerformedHasCollisions;
-}
-
-bool OatFileManager::ShouldLoadAppImage(CheckCollisionResult check_collision_result,
-                                        const OatFile* source_oat_file,
-                                        ClassLoaderContext* context,
-                                        std::string* error_msg) {
+bool OatFileManager::ShouldLoadAppImage(const OatFile* source_oat_file) const {
   Runtime* const runtime = Runtime::Current();
-  if (kEnableAppImage && (!runtime->IsJavaDebuggable() || source_oat_file->IsDebuggable())) {
-    // If we verified the class loader context (skipping due to the special marker doesn't
-    // count), then also avoid the collision check.
-    bool load_image = check_collision_result == CheckCollisionResult::kNoCollisions
-        || check_collision_result == CheckCollisionResult::kClassLoaderContextMatches;
-    // If we skipped the collision check, we need to reverify to be sure its OK to load the
-    // image.
-    if (!load_image &&
-        check_collision_result ==
-            CheckCollisionResult::kSkippedClassLoaderContextSharedLibrary) {
-      // We can load the app image only if there are no collisions. If we know the
-      // class loader but didn't do the full collision check in HasCollisions(),
-      // do it now. b/77342775
-      load_image = !CheckClassCollision(source_oat_file, context, error_msg);
-    }
-    return load_image;
-  }
-  return false;
+  return kEnableAppImage && (!runtime->IsJavaDebuggable() || source_oat_file->IsDebuggable());
 }
 
 std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
@@ -461,204 +219,197 @@
   CHECK(dex_location != nullptr);
   CHECK(error_msgs != nullptr);
 
-  // Verify we aren't holding the mutator lock, which could starve GC if we
-  // have to generate or relocate an oat file.
+  // Verify we aren't holding the mutator lock, which could starve GC when
+  // hitting the disk.
   Thread* const self = Thread::Current();
   Locks::mutator_lock_->AssertNotHeld(self);
   Runtime* const runtime = Runtime::Current();
 
-  std::unique_ptr<ClassLoaderContext> context;
+  std::vector<std::unique_ptr<const DexFile>> dex_files;
+
   // If the class_loader is null there's not much we can do. This happens if a dex files is loaded
   // directly with DexFile APIs instead of using class loaders.
   if (class_loader == nullptr) {
     LOG(WARNING) << "Opening an oat file without a class loader. "
                  << "Are you using the deprecated DexFile APIs?";
-    context = nullptr;
   } else {
-    context = ClassLoaderContext::CreateContextForClassLoader(class_loader, dex_elements);
-  }
+    std::unique_ptr<ClassLoaderContext> context(
+        ClassLoaderContext::CreateContextForClassLoader(class_loader, dex_elements));
 
-  OatFileAssistant oat_file_assistant(dex_location,
-                                      kRuntimeISA,
-                                      runtime->GetOatFilesExecutable(),
-                                      only_use_system_oat_files_);
+    OatFileAssistant oat_file_assistant(dex_location,
+                                        kRuntimeISA,
+                                        runtime->GetOatFilesExecutable(),
+                                        only_use_system_oat_files_);
 
-  // Get the oat file on disk.
-  std::unique_ptr<const OatFile> oat_file(oat_file_assistant.GetBestOatFile().release());
-  VLOG(oat) << "OatFileAssistant(" << dex_location << ").GetBestOatFile()="
-            << reinterpret_cast<uintptr_t>(oat_file.get())
-            << " (executable=" << (oat_file != nullptr ? oat_file->IsExecutable() : false) << ")";
+    // Get the oat file on disk.
+    std::unique_ptr<const OatFile> oat_file(oat_file_assistant.GetBestOatFile().release());
+    VLOG(oat) << "OatFileAssistant(" << dex_location << ").GetBestOatFile()="
+              << reinterpret_cast<uintptr_t>(oat_file.get())
+              << " (executable=" << (oat_file != nullptr ? oat_file->IsExecutable() : false) << ")";
 
-  const OatFile* source_oat_file = nullptr;
-  CheckCollisionResult check_collision_result = CheckCollisionResult::kPerformedHasCollisions;
-  std::string error_msg;
-  bool accept_oat_file = false;
-  if ((class_loader != nullptr || dex_elements != nullptr) && oat_file != nullptr) {
-    // Prevent oat files from being loaded if no class_loader or dex_elements are provided.
-    // This can happen when the deprecated DexFile.<init>(String) is called directly, and it
-    // could load oat files without checking the classpath, which would be incorrect.
-    // Take the file only if it has no collisions, or we must take it because of preopting.
-    check_collision_result = CheckCollision(oat_file.get(), context.get(), /*out*/ &error_msg);
-    accept_oat_file = AcceptOatFile(check_collision_result);
-    if (!accept_oat_file) {
-      // Failed the collision check. Print warning.
-      if (runtime->IsDexFileFallbackEnabled()) {
-        if (!oat_file_assistant.HasOriginalDexFiles()) {
-          // We need to fallback but don't have original dex files. We have to
-          // fallback to opening the existing oat file. This is potentially
-          // unsafe so we warn about it.
-          accept_oat_file = true;
+    const OatFile* source_oat_file = nullptr;
+    std::string error_msg;
+    bool is_special_shared_library = false;
+    bool class_loader_context_matches = false;
+    if (oat_file != nullptr &&
+        context != nullptr &&
+        ClassLoaderContextMatches(oat_file.get(),
+                                  context.get(),
+                                  /*out*/ &is_special_shared_library,
+                                  /*out*/ &error_msg)) {
+      class_loader_context_matches = true;
+      // Load the dex files from the oat file.
+      bool added_image_space = false;
+      if (oat_file->IsExecutable()) {
+        ScopedTrace app_image_timing("AppImage:Loading");
 
-          LOG(WARNING) << "Dex location " << dex_location << " does not seem to include dex file. "
-                       << "Allow oat file use. This is potentially dangerous.";
-        } else {
-          // We have to fallback and found original dex files - extract them from an APK.
-          // Also warn about this operation because it's potentially wasteful.
-          LOG(WARNING) << "Found duplicate classes, falling back to extracting from APK : "
-                       << dex_location;
-          LOG(WARNING) << "NOTE: This wastes RAM and hurts startup performance.";
+        // We need to throw away the image space if we are debuggable but the oat-file source of the
+        // image is not otherwise we might get classes with inlined methods or other such things.
+        std::unique_ptr<gc::space::ImageSpace> image_space;
+        if (!is_special_shared_library && ShouldLoadAppImage(oat_file.get())) {
+          image_space = oat_file_assistant.OpenImageSpace(oat_file.get());
         }
-      } else {
-        // TODO: We should remove this. The fact that we're here implies -Xno-dex-file-fallback
-        // was set, which means that we should never fallback. If we don't have original dex
-        // files, we should just fail resolution as the flag intended.
-        if (!oat_file_assistant.HasOriginalDexFiles()) {
-          accept_oat_file = true;
-        }
-
-        LOG(WARNING) << "Found duplicate classes, dex-file-fallback disabled, will be failing to "
-                        " load classes for " << dex_location;
-      }
-
-      LOG(WARNING) << error_msg;
-    }
-  }
-
-  std::vector<std::unique_ptr<const DexFile>> dex_files;
-
-  // Load the dex files from the oat file.
-  bool added_image_space = false;
-  if (accept_oat_file) {
-    if (oat_file->IsExecutable()) {
-      ScopedTrace app_image_timing("AppImage:Loading");
-
-      // We need to throw away the image space if we are debuggable but the oat-file source of the
-      // image is not otherwise we might get classes with inlined methods or other such things.
-      std::unique_ptr<gc::space::ImageSpace> image_space;
-      if (ShouldLoadAppImage(check_collision_result,
-                             oat_file.get(),
-                             context.get(),
-                             &error_msg)) {
-        image_space = oat_file_assistant.OpenImageSpace(oat_file.get());
-      }
-      if (image_space != nullptr) {
-        ScopedObjectAccess soa(self);
-        StackHandleScope<1> hs(self);
-        Handle<mirror::ClassLoader> h_loader(
-            hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
-        // Can not load app image without class loader.
-        if (h_loader != nullptr) {
-          std::string temp_error_msg;
-          // Add image space has a race condition since other threads could be reading from the
-          // spaces array.
-          {
-            ScopedThreadSuspension sts(self, kSuspended);
-            gc::ScopedGCCriticalSection gcs(self,
-                                            gc::kGcCauseAddRemoveAppImageSpace,
-                                            gc::kCollectorTypeAddRemoveAppImageSpace);
-            ScopedSuspendAll ssa("Add image space");
-            runtime->GetHeap()->AddSpace(image_space.get());
-          }
-          {
-            ScopedTrace trace2(StringPrintf("Adding image space for location %s", dex_location));
-            added_image_space = runtime->GetClassLinker()->AddImageSpace(image_space.get(),
-                                                                         h_loader,
-                                                                         /*out*/&dex_files,
-                                                                         /*out*/&temp_error_msg);
-          }
-          if (added_image_space) {
-            // Successfully added image space to heap, release the map so that it does not get
-            // freed.
-            image_space.release();  // NOLINT b/117926937
-
-            // Register for tracking.
-            for (const auto& dex_file : dex_files) {
-              dex::tracking::RegisterDexFile(dex_file.get());
-            }
-          } else {
-            LOG(INFO) << "Failed to add image file " << temp_error_msg;
-            dex_files.clear();
+        if (image_space != nullptr) {
+          ScopedObjectAccess soa(self);
+          StackHandleScope<1> hs(self);
+          Handle<mirror::ClassLoader> h_loader(
+              hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
+          // Can not load app image without class loader.
+          if (h_loader != nullptr) {
+            std::string temp_error_msg;
+            // Add image space has a race condition since other threads could be reading from the
+            // spaces array.
             {
               ScopedThreadSuspension sts(self, kSuspended);
               gc::ScopedGCCriticalSection gcs(self,
                                               gc::kGcCauseAddRemoveAppImageSpace,
                                               gc::kCollectorTypeAddRemoveAppImageSpace);
-              ScopedSuspendAll ssa("Remove image space");
-              runtime->GetHeap()->RemoveSpace(image_space.get());
+              ScopedSuspendAll ssa("Add image space");
+              runtime->GetHeap()->AddSpace(image_space.get());
             }
-            // Non-fatal, don't update error_msg.
+            {
+              ScopedTrace image_space_timing(
+                  StringPrintf("Adding image space for location %s", dex_location));
+              added_image_space = runtime->GetClassLinker()->AddImageSpace(image_space.get(),
+                                                                           h_loader,
+                                                                           /*out*/&dex_files,
+                                                                           /*out*/&temp_error_msg);
+            }
+            if (added_image_space) {
+              // Successfully added image space to heap, release the map so that it does not get
+              // freed.
+              image_space.release();  // NOLINT b/117926937
+
+              // Register for tracking.
+              for (const auto& dex_file : dex_files) {
+                dex::tracking::RegisterDexFile(dex_file.get());
+              }
+            } else {
+              LOG(INFO) << "Failed to add image file " << temp_error_msg;
+              dex_files.clear();
+              {
+                ScopedThreadSuspension sts(self, kSuspended);
+                gc::ScopedGCCriticalSection gcs(self,
+                                                gc::kGcCauseAddRemoveAppImageSpace,
+                                                gc::kCollectorTypeAddRemoveAppImageSpace);
+                ScopedSuspendAll ssa("Remove image space");
+                runtime->GetHeap()->RemoveSpace(image_space.get());
+              }
+              // Non-fatal, don't update error_msg.
+            }
           }
         }
       }
-    }
-    if (!added_image_space) {
-      DCHECK(dex_files.empty());
+      if (!added_image_space) {
+        DCHECK(dex_files.empty());
 
-      if (oat_file->RequiresImage()) {
-        // If we could not load the image, but the OAT file requires it, we have to reload the OAT
-        // file as non-executable.
-        OatFileAssistant nonexecutable_oat_file_assistant(dex_location,
-                                                          kRuntimeISA,
-                                                          /*load_executable=*/false,
-                                                          only_use_system_oat_files_);
-        oat_file.reset(nonexecutable_oat_file_assistant.GetBestOatFile().release());
+        if (oat_file->RequiresImage()) {
+          VLOG(oat) << "Loading "
+                    << oat_file->GetLocation()
+                    << "non-executable as it requires an image which we failed to load";
+          // file as non-executable.
+          OatFileAssistant nonexecutable_oat_file_assistant(dex_location,
+                                                            kRuntimeISA,
+                                                            /*load_executable=*/false,
+                                                            only_use_system_oat_files_);
+          oat_file.reset(nonexecutable_oat_file_assistant.GetBestOatFile().release());
+        }
+
+        dex_files = oat_file_assistant.LoadDexFiles(*oat_file.get(), dex_location);
+
+        // Register for tracking.
+        for (const auto& dex_file : dex_files) {
+          dex::tracking::RegisterDexFile(dex_file.get());
+        }
+      }
+      if (dex_files.empty()) {
+        error_msgs->push_back("Failed to open dex files from " + oat_file->GetLocation());
+      } else {
+        // Opened dex files from an oat file, madvise them to their loaded state.
+         for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
+           OatDexFile::MadviseDexFile(*dex_file, MadviseState::kMadviseStateAtLoad);
+         }
       }
 
-      dex_files = oat_file_assistant.LoadDexFiles(*oat_file.get(), dex_location);
+      VLOG(class_linker) << "Registering " << oat_file->GetLocation();
+      source_oat_file = RegisterOatFile(std::move(oat_file));
+      *out_oat_file = source_oat_file;
+    } else if (!error_msg.empty()) {
+      LOG(WARNING) << error_msg;
+    }
 
-      // Register for tracking.
-      for (const auto& dex_file : dex_files) {
-        dex::tracking::RegisterDexFile(dex_file.get());
+    // Verify if any of the dex files being loaded is already in the class path.
+    // If so, report an error with the current stack trace.
+    // Most likely the developer didn't intend to do this because it will waste
+    // performance and memory.
+    if (context != nullptr && !class_loader_context_matches) {
+      std::set<const DexFile*> already_exists_in_classpath =
+          context->CheckForDuplicateDexFiles(MakeNonOwningPointerVector(dex_files));
+      if (!already_exists_in_classpath.empty()) {
+        auto duplicate_it = already_exists_in_classpath.begin();
+        std::string duplicates = (*duplicate_it)->GetLocation();
+        for (duplicate_it++ ; duplicate_it != already_exists_in_classpath.end(); duplicate_it++) {
+          duplicates += "," + (*duplicate_it)->GetLocation();
+        }
+
+        std::ostringstream out;
+        out << "Trying to load dex files which is already loaded in the same ClassLoader "
+            << "hierarchy.\n"
+            << "This is a strong indication of bad ClassLoader construct which leads to poor "
+            << "performance and wastes memory.\n"
+            << "The list of duplicate dex files is: " << duplicates << "\n"
+            << "The current class loader context is: "
+            << context->EncodeContextForOatFile("") << "\n"
+            << "Java stack trace:\n";
+
+        {
+          ScopedObjectAccess soa(self);
+          self->DumpJavaStack(out);
+        }
+
+        // We log this as an ERROR to stress the fact that this is most likely unintended.
+        // Note that ART cannot do anything about it. It is up to the app to fix their logic.
+        // Here we are trying to give a heads up on why the app might have performance issues.
+        LOG(ERROR) << out.str();
       }
     }
-    if (dex_files.empty()) {
-      error_msgs->push_back("Failed to open dex files from " + oat_file->GetLocation());
-    } else {
-      // Opened dex files from an oat file, madvise them to their loaded state.
-       for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
-         OatDexFile::MadviseDexFile(*dex_file, MadviseState::kMadviseStateAtLoad);
-       }
-    }
-
-    VLOG(class_linker) << "Registering " << oat_file->GetLocation();
-    source_oat_file = RegisterOatFile(std::move(oat_file));
-    *out_oat_file = source_oat_file;
   }
 
-  // Fall back to running out of the original dex file if we couldn't load any
-  // dex_files from the oat file.
+  // If we arrive here with an empty dex files list, it means we fail to load
+  // it/them through an .oat file.
   if (dex_files.empty()) {
-    if (oat_file_assistant.HasOriginalDexFiles()) {
-      if (Runtime::Current()->IsDexFileFallbackEnabled()) {
-        static constexpr bool kVerifyChecksum = true;
-        const ArtDexFileLoader dex_file_loader;
-        if (!dex_file_loader.Open(dex_location,
-                                  dex_location,
-                                  Runtime::Current()->IsVerificationEnabled(),
-                                  kVerifyChecksum,
-                                  /*out*/ &error_msg,
-                                  &dex_files)) {
-          LOG(WARNING) << error_msg;
-          error_msgs->push_back("Failed to open dex files from " + std::string(dex_location)
-                                + " because: " + error_msg);
-        }
-      } else {
-        error_msgs->push_back("Fallback mode disabled, skipping dex files.");
-      }
-    } else {
-      std::string msg = StringPrintf("No original dex files found for dex location (%s) %s",
-          GetInstructionSetString(kRuntimeISA), dex_location);
-      error_msgs->push_back(msg);
+    std::string error_msg;
+    static constexpr bool kVerifyChecksum = true;
+    const ArtDexFileLoader dex_file_loader;
+    if (!dex_file_loader.Open(dex_location,
+                              dex_location,
+                              Runtime::Current()->IsVerificationEnabled(),
+                              kVerifyChecksum,
+                              /*out*/ &error_msg,
+                              &dex_files)) {
+      LOG(WARNING) << error_msg;
+      error_msgs->push_back("Failed to open dex files from " + std::string(dex_location)
+                            + " because: " + error_msg);
     }
   }
 
@@ -666,42 +417,6 @@
     Runtime::Current()->GetJit()->RegisterDexFiles(dex_files, class_loader);
   }
 
-  // Verify if any of the dex files being loaded is already in the class path.
-  // If so, report an error with the current stack trace.
-  // Most likely the developer didn't intend to do this because it will waste
-  // performance and memory.
-  // We perform the check only if the class loader context match failed or did
-  // not run (e.g. not that we do not run the check if we don't have an oat file).
-  if (context != nullptr
-          && check_collision_result != CheckCollisionResult::kClassLoaderContextMatches) {
-    std::set<const DexFile*> already_exists_in_classpath =
-        context->CheckForDuplicateDexFiles(MakeNonOwningPointerVector(dex_files));
-    if (!already_exists_in_classpath.empty()) {
-      auto duplicate_it = already_exists_in_classpath.begin();
-      std::string duplicates = (*duplicate_it)->GetLocation();
-      for (duplicate_it++ ; duplicate_it != already_exists_in_classpath.end(); duplicate_it++) {
-        duplicates += "," + (*duplicate_it)->GetLocation();
-      }
-
-      std::ostringstream out;
-      out << "Trying to load dex files which is already loaded in the same ClassLoader hierarchy.\n"
-        << "This is a strong indication of bad ClassLoader construct which leads to poor "
-        << "performance and wastes memory.\n"
-        << "The list of duplicate dex files is: " << duplicates << "\n"
-        << "The current class loader context is: " << context->EncodeContextForOatFile("") << "\n"
-        << "Java stack trace:\n";
-
-      {
-        ScopedObjectAccess soa(self);
-        self->DumpJavaStack(out);
-      }
-
-      // We log this as an ERROR to stress the fact that this is most likely unintended.
-      // Note that ART cannot do anything about it. It is up to the app to fix their logic.
-      // Here we are trying to give a heads up on why the app might have performance issues.
-      LOG(ERROR) << out.str();
-    }
-  }
   return dex_files;
 }
 
diff --git a/runtime/oat_file_manager.h b/runtime/oat_file_manager.h
index 9c3a38a..11eabe2 100644
--- a/runtime/oat_file_manager.h
+++ b/runtime/oat_file_manager.h
@@ -141,15 +141,6 @@
   static constexpr size_t kAnonymousVdexCacheSize = 8u;
 
  private:
-  enum class CheckCollisionResult {
-    kSkippedUnsupportedClassLoader,
-    kSkippedClassLoaderContextSharedLibrary,
-    kSkippedVerificationDisabled,
-    kNoCollisions,
-    kPerformedHasCollisions,
-    kClassLoaderContextMatches
-  };
-
   std::vector<std::unique_ptr<const DexFile>> OpenDexFilesFromOat_Impl(
       std::vector<MemMap>&& dex_mem_maps,
       jobject class_loader,
@@ -158,31 +149,11 @@
       /*out*/ std::vector<std::string>* error_msgs)
       REQUIRES(!Locks::oat_file_manager_lock_, !Locks::mutator_lock_);
 
-  // Check that the class loader context of the given oat file matches the given context.
-  // This will perform a check that all class loaders in the chain have the same type and
-  // classpath.
-  // If the context is null (which means the initial class loader was null or unsupported)
-  // this returns kSkippedUnsupportedClassLoader.
-  // If the context does not validate the method will check for duplicate class definitions of
-  // the given oat file against the oat files (either from the class loaders if possible or all
-  // non-boot oat files otherwise).
-  // Return kPerformedHasCollisions if there are any class definition collisions in the oat_file.
-  CheckCollisionResult CheckCollision(const OatFile* oat_file,
-                                      const ClassLoaderContext* context,
-                                      /*out*/ std::string* error_msg) const
-      REQUIRES(!Locks::oat_file_manager_lock_);
-
   const OatFile* FindOpenedOatFileFromOatLocationLocked(const std::string& oat_location) const
       REQUIRES(Locks::oat_file_manager_lock_);
 
-  // Return true if we should accept the oat file.
-  bool AcceptOatFile(CheckCollisionResult result) const;
-
   // Return true if we should attempt to load the app image.
-  bool ShouldLoadAppImage(CheckCollisionResult check_collision_result,
-                          const OatFile* source_oat_file,
-                          ClassLoaderContext* context,
-                          std::string* error_msg);
+  bool ShouldLoadAppImage(const OatFile* source_oat_file) const;
 
   std::set<std::unique_ptr<const OatFile>> oat_files_ GUARDED_BY(Locks::oat_file_manager_lock_);
 
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index c62caa9..5bb9ed6 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -321,8 +321,6 @@
       .Define("-Xzygote-max-boot-retry=_")
           .WithType<unsigned int>()
           .IntoKey(M::ZygoteMaxFailedBoots)
-      .Define("-Xno-dex-file-fallback")
-          .IntoKey(M::NoDexFileFallback)
       .Define("-Xno-sig-chain")
           .IntoKey(M::NoSigChain)
       .Define("--cpu-abilist=_")
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 1c1159a..fc1a3c8 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -268,7 +268,6 @@
       dump_gc_performance_on_shutdown_(false),
       preinitialization_transactions_(),
       verify_(verifier::VerifyMode::kNone),
-      allow_dex_file_fallback_(true),
       target_sdk_version_(static_cast<uint32_t>(SdkVersion::kUnset)),
       implicit_null_checks_(false),
       implicit_so_checks_(false),
@@ -1315,7 +1314,6 @@
   intern_table_ = new InternTable;
 
   verify_ = runtime_options.GetOrDefault(Opt::Verify);
-  allow_dex_file_fallback_ = !runtime_options.Exists(Opt::NoDexFileFallback);
 
   target_sdk_version_ = runtime_options.GetOrDefault(Opt::TargetSdkVersion);
 
@@ -1419,11 +1417,6 @@
                        runtime_options.Exists(Opt::DumpRegionInfoAfterGC),
                        image_space_loading_order_);
 
-  if (!heap_->HasBootImageSpace() && !allow_dex_file_fallback_) {
-    LOG(ERROR) << "Dex file fallback disabled, cannot continue without image.";
-    return false;
-  }
-
   dump_gc_performance_on_shutdown_ = runtime_options.Exists(Opt::DumpGCPerformanceOnShutdown);
 
   jdwp_options_ = runtime_options.GetOrDefault(Opt::JdwpOptions);
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 822c0ac..594edaa 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -656,10 +656,6 @@
     }
   }
 
-  bool IsDexFileFallbackEnabled() const {
-    return allow_dex_file_fallback_;
-  }
-
   const std::vector<std::string>& GetCpuAbilist() const {
     return cpu_abilist_;
   }
@@ -1172,10 +1168,6 @@
   // If kNone, verification is disabled. kEnable by default.
   verifier::VerifyMode verify_;
 
-  // If true, the runtime may use dex files directly with the interpreter if an oat file is not
-  // available/usable.
-  bool allow_dex_file_fallback_;
-
   // List of supported cpu abis.
   std::vector<std::string> cpu_abilist_;
 
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index 5707a33..a342973 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -133,7 +133,6 @@
                                           hiddenapi::EnforcementPolicy::kDisabled)
 RUNTIME_OPTIONS_KEY (std::string,         NativeBridge)
 RUNTIME_OPTIONS_KEY (unsigned int,        ZygoteMaxFailedBoots,           10)
-RUNTIME_OPTIONS_KEY (Unit,                NoDexFileFallback)
 RUNTIME_OPTIONS_KEY (std::string,         CpuAbiList)
 RUNTIME_OPTIONS_KEY (std::string,         Fingerprint)
 RUNTIME_OPTIONS_KEY (ExperimentalFlags,   Experimental,     ExperimentalFlags::kNone) // -Xexperimental:{...}