Integrate ClassLoaderContext check in OatFileAssistant::GetBestOatFile.

This reduces some code duplication between
OatFileManager::OpenDexFilesFromOat and GetDexoptNeeded.

It also gives the chance for OatFileAssistant and GetDexoptNeeded to
find the real best oat file.

Test: test.py
Bug: 176960283
Change-Id: Id366aef7a9e91833d8edaea965abda4cfdcd8455
diff --git a/dexoptanalyzer/dexoptanalyzer.cc b/dexoptanalyzer/dexoptanalyzer.cc
index 5f501d6..998f41a 100644
--- a/dexoptanalyzer/dexoptanalyzer.cc
+++ b/dexoptanalyzer/dexoptanalyzer.cc
@@ -298,10 +298,23 @@
         Usage("Invalid --class-loader-context '%s'", context_str_.c_str());
       }
     }
+    if (class_loader_context != nullptr) {
+      size_t dir_index = dex_file_.rfind('/');
+      std::string classpath_dir = (dir_index != std::string::npos)
+          ? dex_file_.substr(0, dir_index)
+          : "";
+
+      if (!class_loader_context->OpenDexFiles(classpath_dir,
+                                              context_fds_,
+                                              /*only_read_checksums=*/ true)) {
+        return ReturnCode::kDex2OatFromScratch;
+      }
+    }
 
     std::unique_ptr<OatFileAssistant> oat_file_assistant;
     oat_file_assistant = std::make_unique<OatFileAssistant>(dex_file_.c_str(),
                                                             isa_,
+                                                            class_loader_context.get(),
                                                             /*load_executable=*/ false,
                                                             /*only_load_system_executable=*/ false,
                                                             vdex_fd_,
@@ -314,8 +327,6 @@
     }
 
     int dexoptNeeded = oat_file_assistant->GetDexOptNeeded(compiler_filter_,
-                                                           class_loader_context.get(),
-                                                           context_fds_,
                                                            assume_profile_changed_,
                                                            downgrade_);
 
diff --git a/dexoptanalyzer/dexoptanalyzer_test.cc b/dexoptanalyzer/dexoptanalyzer_test.cc
index 42be473..ef6282a 100644
--- a/dexoptanalyzer/dexoptanalyzer_test.cc
+++ b/dexoptanalyzer/dexoptanalyzer_test.cc
@@ -79,18 +79,23 @@
               bool assume_profile_changed = false,
               bool downgrade = false,
               const char* class_loader_context = "PCL[]") {
-    int dexoptanalyzerResult = Analyze(
-        dex_file, compiler_filter, assume_profile_changed, class_loader_context);
-    dexoptanalyzerResult = DexoptanalyzerToOatFileAssistant(dexoptanalyzerResult);
-    OatFileAssistant oat_file_assistant(dex_file.c_str(), kRuntimeISA, /*load_executable=*/ false);
-    std::vector<int> context_fds;
-
     std::unique_ptr<ClassLoaderContext> context = class_loader_context == nullptr
         ? nullptr
         : ClassLoaderContext::Create(class_loader_context);
+    if (context != nullptr) {
+      std::vector<int> context_fds;
+      ASSERT_TRUE(context->OpenDexFiles("", context_fds, /*only_read_checksums*/ true));
+    }
 
+    int dexoptanalyzerResult = Analyze(
+        dex_file, compiler_filter, assume_profile_changed, class_loader_context);
+    dexoptanalyzerResult = DexoptanalyzerToOatFileAssistant(dexoptanalyzerResult);
+    OatFileAssistant oat_file_assistant(dex_file.c_str(),
+                                        kRuntimeISA,
+                                        context.get(),
+                                        /*load_executable=*/ false);
     int assistantResult = oat_file_assistant.GetDexOptNeeded(
-        compiler_filter, context.get(), context_fds, assume_profile_changed, downgrade);
+        compiler_filter, assume_profile_changed, downgrade);
     EXPECT_EQ(assistantResult, dexoptanalyzerResult);
   }
 };
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index b5ce122..228b950 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -412,7 +412,9 @@
   // no dex files. So that we can distinguish the real failures...
   const ArtDexFileLoader dex_file_loader;
   std::vector<ClassLoaderInfo*> work_list;
-  CHECK(class_loader_chain_ != nullptr);
+  if (class_loader_chain_ == nullptr) {
+    return true;
+  }
   work_list.push_back(class_loader_chain_.get());
   size_t dex_file_index = 0;
   while (!work_list.empty()) {
@@ -1155,7 +1157,9 @@
     jobjectArray dex_elements) {
   ScopedTrace trace(__FUNCTION__);
 
-  CHECK(class_loader != nullptr);
+  if (class_loader == nullptr) {
+    return nullptr;
+  }
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<2> hs(soa.Self());
   Handle<mirror::ClassLoader> h_class_loader =
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 1c4adab..f8ad7f1 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -18,6 +18,7 @@
 
 #include <sstream>
 
+#include "android-base/file.h"
 #include "android-base/stringprintf.h"
 
 #include "base/casts.h"
@@ -541,22 +542,26 @@
       env->ThrowNew(iae.get(), message.c_str());
       return -1;
     }
+    std::vector<int> context_fds;
+    context->OpenDexFiles(android::base::Dirname(filename),
+                          context_fds,
+                          /*only_read_checksums*/ true);
   }
 
   // TODO: Verify the dex location is well formed, and throw an IOException if
   // not?
 
-  OatFileAssistant oat_file_assistant(filename, target_instruction_set, false);
+  OatFileAssistant oat_file_assistant(filename,
+                                      target_instruction_set,
+                                      context.get(),
+                                      /* load_executable= */ false);
 
   // Always treat elements of the bootclasspath as up-to-date.
   if (oat_file_assistant.IsInBootClassPath()) {
     return OatFileAssistant::kNoDexOptNeeded;
   }
 
-  std::vector<int> context_fds;
   return oat_file_assistant.GetDexOptNeeded(filter,
-                                            context.get(),
-                                            context_fds,
                                             profile_changed,
                                             downgrade);
 }
@@ -584,7 +589,9 @@
     return nullptr;
   }
 
-  OatFileAssistant oat_file_assistant(filename.c_str(), target_instruction_set,
+  OatFileAssistant oat_file_assistant(filename.c_str(),
+                                      target_instruction_set,
+                                      /* context= */ nullptr,
                                       /* load_executable= */ false);
   return env->NewStringUTF(oat_file_assistant.GetStatusDump().c_str());
 }
@@ -691,7 +698,10 @@
     return JNI_FALSE;
   }
 
-  OatFileAssistant oat_file_assistant(filename, kRuntimeISA, false);
+  OatFileAssistant oat_file_assistant(filename,
+                                      kRuntimeISA,
+                                      /* context= */ nullptr,
+                                      /* load_executable= */ false);
   return oat_file_assistant.IsUpToDate() ? JNI_FALSE : JNI_TRUE;
 }
 
@@ -828,10 +838,11 @@
     }
   }
 
-  // If did not find a boot classpath oat file, lookup the oat file for an app.
+  // If we did not find a boot classpath oat file, lookup the oat file for an app.
   if (oat_filename.empty()) {
     OatFileAssistant oat_file_assistant(filename.c_str(),
                                         target_instruction_set,
+                                        /* context= */ nullptr,
                                         /* load_executable= */ false);
 
     std::unique_ptr<OatFile> best_oat_file = oat_file_assistant.GetBestOatFile();
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 245ae36..0bccc82 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -21,6 +21,7 @@
 #include <sys/stat.h>
 #include "zlib.h"
 
+#include "android-base/file.h"
 #include "android-base/stringprintf.h"
 #include "android-base/strings.h"
 
@@ -67,8 +68,9 @@
     case OatFileAssistant::kOatUpToDate:
       stream << "kOatUpToDate";
       break;
-    default:
-      UNREACHABLE();
+    case OatFileAssistant::kOatContextOutOfDate:
+      stream << "kOaContextOutOfDate";
+      break;
   }
 
   return stream;
@@ -76,10 +78,12 @@
 
 OatFileAssistant::OatFileAssistant(const char* dex_location,
                                    const InstructionSet isa,
+                                   ClassLoaderContext* context,
                                    bool load_executable,
                                    bool only_load_system_executable)
     : OatFileAssistant(dex_location,
                        isa,
+                       context,
                        load_executable,
                        only_load_system_executable,
                        /*vdex_fd=*/ -1,
@@ -89,12 +93,14 @@
 
 OatFileAssistant::OatFileAssistant(const char* dex_location,
                                    const InstructionSet isa,
+                                   ClassLoaderContext* context,
                                    bool load_executable,
                                    bool only_load_system_executable,
                                    int vdex_fd,
                                    int oat_fd,
                                    int zip_fd)
-    : isa_(isa),
+    : context_(context),
+      isa_(isa),
       load_executable_(load_executable),
       only_load_system_executable_(only_load_system_executable),
       odex_(this, /*is_oat_location=*/ false),
@@ -103,6 +109,7 @@
       vdex_for_oat_(this, /*is_oat_location=*/ true),
       zip_fd_(zip_fd) {
   CHECK(dex_location != nullptr) << "OatFileAssistant: null dex location";
+  CHECK(!load_executable || context != nullptr) << "Loading executable without a context";
 
   if (zip_fd < 0) {
     CHECK_LE(oat_fd, 0) << "zip_fd must be provided with valid oat_fd. zip_fd=" << zip_fd
@@ -192,14 +199,10 @@
 }
 
 int OatFileAssistant::GetDexOptNeeded(CompilerFilter::Filter target,
-                                      ClassLoaderContext* class_loader_context,
-                                      const std::vector<int>& context_fds,
                                       bool profile_changed,
                                       bool downgrade) {
   OatFileInfo& info = GetBestInfo();
   DexOptNeeded dexopt_needed = info.GetDexOptNeeded(target,
-                                                    class_loader_context,
-                                                    context_fds,
                                                     profile_changed,
                                                     downgrade);
   if (info.IsOatLocation() || dexopt_needed == kDex2OatFromScratch) {
@@ -443,6 +446,10 @@
     return kOatDexOutOfDate;
   }
 
+  if (!ClassLoaderContextIsOkay(file)) {
+    return kOatContextOutOfDate;
+  }
+
   return kOatUpToDate;
 }
 
@@ -727,6 +734,7 @@
   switch (Status()) {
     case kOatCannotOpen:
     case kOatDexOutOfDate:
+    case kOatContextOutOfDate:
     case kOatBootImageOutOfDate: return false;
 
     case kOatUpToDate: return true;
@@ -752,29 +760,17 @@
 
 OatFileAssistant::DexOptNeeded OatFileAssistant::OatFileInfo::GetDexOptNeeded(
     CompilerFilter::Filter target,
-    ClassLoaderContext* context,
-    const std::vector<int>& context_fds,
     bool profile_changed,
     bool downgrade) {
 
-  bool filter_okay = CompilerFilterIsOkay(target, profile_changed, downgrade);
-  bool class_loader_context_okay = ClassLoaderContextIsOkay(context, context_fds);
+  if (IsUseable()) {
+    return CompilerFilterIsOkay(target, profile_changed, downgrade)
+        ? kNoDexOptNeeded
+        : kDex2OatForFilter;
+  }
 
-  // Only check the filter and relocation if the class loader context is ok.
-  // If it is not, we will return kDex2OatFromScratch as the compilation needs to be redone.
-  if (class_loader_context_okay) {
-    if (filter_okay && Status() == kOatUpToDate) {
-      // The oat file is in good shape as is.
-      return kNoDexOptNeeded;
-    }
-
-    if (IsUseable()) {
-      return kDex2OatForFilter;
-    }
-
-    if (Status() == kOatBootImageOutOfDate) {
-      return kDex2OatForBootImage;
-    }
+  if (Status() == kOatBootImageOutOfDate) {
+    return kDex2OatForBootImage;
   }
 
   if (oat_file_assistant_->HasDexFiles()) {
@@ -887,51 +883,36 @@
     CompilerFilter::IsAsGoodAs(current, target);
 }
 
-bool OatFileAssistant::OatFileInfo::ClassLoaderContextIsOkay(ClassLoaderContext* context,
-                                                             const std::vector<int>& context_fds) {
-  const OatFile* file = GetFile();
-  if (file == nullptr) {
-    // No oat file means we have nothing to verify.
-    return true;
-  }
-
-  if (file->IsBackedByVdexOnly()) {
+bool OatFileAssistant::ClassLoaderContextIsOkay(const OatFile& oat_file) const {
+  if (oat_file.IsBackedByVdexOnly()) {
     // Only a vdex file, we don't depend on the class loader context.
     return true;
   }
 
-  if (!CompilerFilter::IsVerificationEnabled(file->GetCompilerFilter())) {
+  if (!CompilerFilter::IsVerificationEnabled(oat_file.GetCompilerFilter())) {
     // If verification is not enabled we don't need to verify the class loader context and we
     // assume it's ok.
     return true;
   }
 
-
-  if (context == nullptr) {
-    // TODO(calin): stop using null for the unkown contexts.
-    // b/148494302 introduces runtime encoding for unknown context which will make this possible.
-    VLOG(oat) << "ClassLoaderContext check failed: uknown(null) context";
-    return false;
+  if (context_ == nullptr) {
+    // When no class loader context is provided (which happens for deprecated
+    // DexFile APIs), just assume it is OK.
+    return true;
   }
 
-  size_t dir_index = oat_file_assistant_->dex_location_.rfind('/');
-  std::string classpath_dir = (dir_index != std::string::npos)
-      ? oat_file_assistant_->dex_location_.substr(0, dir_index)
-      : "";
-
-  if (!context->OpenDexFiles(classpath_dir, context_fds, /*only_read_checksums*/ true)) {
-    VLOG(oat) << "ClassLoaderContext check failed: dex files from the context could not be opened";
-    return false;
-  }
-
-  const bool result = context->VerifyClassLoaderContextMatch(file->GetClassLoaderContext()) !=
-      ClassLoaderContext::VerificationResult::kMismatch;
-  if (!result) {
+  ClassLoaderContext::VerificationResult matches = context_->VerifyClassLoaderContextMatch(
+      oat_file.GetClassLoaderContext(),
+      /*verify_names=*/ true,
+      /*verify_checksums=*/ true);
+  if (matches == ClassLoaderContext::VerificationResult::kMismatch) {
     VLOG(oat) << "ClassLoaderContext check failed. Context was "
-              << file->GetClassLoaderContext()
-              << ". The expected context is " << context->EncodeContextForOatFile(classpath_dir);
+              << oat_file.GetClassLoaderContext()
+              << ". The expected context is "
+              << context_->EncodeContextForOatFile(android::base::Dirname(dex_location_));
+    return false;
   }
-  return result;
+  return true;
 }
 
 bool OatFileAssistant::OatFileInfo::IsExecutable() {
@@ -983,7 +964,10 @@
     std::string* out_compilation_reason) {
   // It may not be possible to load an oat file executable (e.g., selinux restrictions). Load
   // non-executable and check the status manually.
-  OatFileAssistant oat_file_assistant(filename.c_str(), isa, /*load_executable=*/ false);
+  OatFileAssistant oat_file_assistant(filename.c_str(),
+                                      isa,
+                                      /* context= */ nullptr,
+                                      /*load_executable=*/ false);
   std::string out_odex_location;  // unused
   std::string out_odex_status;  // unused
   oat_file_assistant.GetOptimizationStatus(
@@ -1038,6 +1022,11 @@
       *out_odex_status = "boot-image-more-recent";
       return;
 
+    case kOatContextOutOfDate:
+      *out_compilation_filter = "run-from-apk-fallback";
+      *out_odex_status = "context-mismatch";
+      return;
+
     case kOatDexOutOfDate:
       *out_compilation_filter = "run-from-apk-fallback";
       *out_odex_status = "apk-more-recent";
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index e771dcc..50b54af 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -80,6 +80,10 @@
     // dex file, but is out of date with respect to the boot image.
     kOatBootImageOutOfDate,
 
+    // kOatContextOutOfDate - The context in the oat file is out of date with
+    // respect to the class loader context.
+    kOatContextOutOfDate,
+
     // kOatUpToDate - The oat file is completely up to date with respect to
     // the dex file and boot image.
     kOatUpToDate,
@@ -107,6 +111,7 @@
   // only oat files from /system loaded executable.
   OatFileAssistant(const char* dex_location,
                    const InstructionSet isa,
+                   ClassLoaderContext* context,
                    bool load_executable,
                    bool only_load_system_executable = false);
 
@@ -115,6 +120,7 @@
   // Otherwise, dex_location will be used to construct necessary filenames.
   OatFileAssistant(const char* dex_location,
                    const InstructionSet isa,
+                   ClassLoaderContext* context,
                    bool load_executable,
                    bool only_load_system_executable,
                    int vdex_fd,
@@ -142,8 +148,6 @@
   // the oat location. Returns a negative status code if the status refers to
   // the oat file in the odex location.
   int GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter,
-                      ClassLoaderContext* context,
-                      const std::vector<int>& context_fds,
                       bool profile_changed = false,
                       bool downgrade = false);
 
@@ -227,6 +231,10 @@
   // Returns the status of the oat file for the dex location.
   OatStatus OatFileStatus();
 
+  OatStatus GetBestStatus() {
+    return GetBestInfo().Status();
+  }
+
   // Constructs the odex file name for the given dex location.
   // Returns true on success, in which case odex_filename is set to the odex
   // file name.
@@ -262,6 +270,8 @@
   // anonymous dex file(s) created by AnonymousDexVdexLocation.
   static bool IsAnonymousVdexBasename(const std::string& basename);
 
+  bool ClassLoaderContextIsOkay(const OatFile& oat_file) const;
+
  private:
   class OatFileInfo {
    public:
@@ -294,8 +304,6 @@
     // downgrade should be true if the purpose of dexopt is to downgrade the
     // compiler filter.
     DexOptNeeded GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter,
-                                 ClassLoaderContext* context,
-                                 const std::vector<int>& context_fds,
                                  bool profile_changed,
                                  bool downgrade);
 
@@ -338,8 +346,6 @@
     // compiler filter.
     bool CompilerFilterIsOkay(CompilerFilter::Filter target, bool profile_changed, bool downgrade);
 
-    bool ClassLoaderContextIsOkay(ClassLoaderContext* context, const std::vector<int>& context_fds);
-
     // Release the loaded oat file.
     // Returns null if the oat file hasn't been loaded.
     //
@@ -407,6 +413,8 @@
 
   std::string dex_location_;
 
+  ClassLoaderContext* context_;
+
   // Whether or not the parent directory of the dex file is writable.
   bool dex_parent_writable_ = false;
 
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 16d3ce0..5631e12 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -98,32 +98,24 @@
     }
   }
 
-  int GetDexOptNeeded(OatFileAssistant* assistant,
-                      CompilerFilter::Filter compiler_filter,
-                      bool profile_changed) {
-    std::vector<int> context_fds;
-    return GetDexOptNeeded(assistant,
-        compiler_filter,
-        ClassLoaderContext::Default(),
-        context_fds,
-        profile_changed,
-        /*downgrade=*/ false);
-  }
-
   int GetDexOptNeeded(
       OatFileAssistant* assistant,
       CompilerFilter::Filter compiler_filter,
-      const std::unique_ptr<ClassLoaderContext>& context = ClassLoaderContext::Default(),
-      const std::vector<int>& context_fds = std::vector<int>(),
       bool profile_changed = false,
       bool downgrade = false) {
     return assistant->GetDexOptNeeded(
         compiler_filter,
-        context.get(),
-        context_fds,
         profile_changed,
         downgrade);
   }
+
+  static std::unique_ptr<ClassLoaderContext> InitializeDefaultContext() {
+    auto context = ClassLoaderContext::Default();
+    context->OpenDexFiles();
+    return context;
+  }
+
+  std::unique_ptr<ClassLoaderContext> default_context_ = InitializeDefaultContext();
 };
 
 class ScopedNonWritable {
@@ -181,7 +173,10 @@
   ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
 
   // Verify we can load both dex files.
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      true);
 
   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
   ASSERT_TRUE(oat_file.get() != nullptr);
@@ -198,13 +193,13 @@
   Copy(GetDexSrc1(), dex_location);
   Copy(GetDexSrc2(), context_location);
 
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
-
   std::string context_str = "PCL[" + context_location + "]";
   std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(context_str);
   ASSERT_TRUE(context != nullptr);
   ASSERT_TRUE(context->OpenDexFiles());
 
+  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, context.get(), false);
+
   std::string error_msg;
   std::vector<std::string> args;
   args.push_back("--dex-file=" + dex_location);
@@ -213,7 +208,8 @@
   ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
 
   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
-  EXPECT_NE(nullptr, oat_file.get());
+  ASSERT_NE(nullptr, oat_file.get());
+  ASSERT_NE(nullptr, oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey));
   EXPECT_EQ(context->EncodeContextForOatFile(""),
             oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey));
 }
@@ -225,27 +221,27 @@
   Copy(GetDexSrc1(), dex_location);
   Copy(GetDexSrc2(), context_location);
 
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+  // A relative context simulates a dependent split context.
+  std::unique_ptr<ClassLoaderContext> relative_context =
+      ClassLoaderContext::Create("PCL[ContextDex.jar]");
+  ASSERT_TRUE(relative_context != nullptr);
+  std::vector<int> context_fds;
+  ASSERT_TRUE(relative_context->OpenDexFiles(GetScratchDir(), context_fds));
 
-  std::string context_str = "PCL[" + context_location + "]";
-  std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(context_str);
-  ASSERT_TRUE(context != nullptr);
-  ASSERT_TRUE(context->OpenDexFiles());
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      relative_context.get(),
+                                      false);
 
   std::string error_msg;
   std::vector<std::string> args;
   args.push_back("--dex-file=" + dex_location);
   args.push_back("--oat-file=" + odex_location);
-  args.push_back("--class-loader-context=" + context_str);
+  args.push_back("--class-loader-context=PCL[" + context_location + "]");
   ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
 
-  // A relative context simulates a dependent split context.
-  std::unique_ptr<ClassLoaderContext> relative_context =
-      ClassLoaderContext::Create("PCL[ContextDex.jar]");
   EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
-            GetDexOptNeeded(&oat_file_assistant,
-                CompilerFilter::kDefaultCompilerFilter,
-                relative_context));
+            GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kDefaultCompilerFilter));
 }
 
 // Case: We have a DEX file, but no OAT file for it.
@@ -254,7 +250,10 @@
   std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
   Copy(GetDexSrc1(), dex_location);
 
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      false);
 
   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
@@ -283,7 +282,10 @@
 TEST_F(OatFileAssistantTest, NoDexNoOat) {
   std::string dex_location = GetScratchDir() + "/NoDexNoOat.jar";
 
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      true);
 
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -304,7 +306,10 @@
 
   // Force the use of oat location by making the dex parent not writable.
   OatFileAssistant oat_file_assistant(
-      dex_location.c_str(), kRuntimeISA, /*load_executable=*/ false);
+      dex_location.c_str(),
+      kRuntimeISA,
+      default_context_.get(),
+      /*load_executable=*/ false);
 
   EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
             GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -341,7 +346,10 @@
 
   // Force the use of oat location by making the dex parent not writable.
   OatFileAssistant oat_file_assistant(
-      dex_location.c_str(), kRuntimeISA, /*load_executable=*/ false);
+      dex_location.c_str(),
+      kRuntimeISA,
+      default_context_.get(),
+      /*load_executable=*/ false);
 
   EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
             GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -381,7 +389,10 @@
   ASSERT_EQ(0, symlink(scratch_dir.c_str(), link.c_str()));
   dex_location = link + "/OdexUpToDate.jar";
 
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      false);
 
   EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -415,7 +426,10 @@
   ScopedNonWritable scoped_non_writable(dex_location);
   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
 
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      false);
 
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -458,6 +472,7 @@
 
   OatFileAssistant oat_file_assistant(dex_location.c_str(),
                                       kRuntimeISA,
+                                      default_context_.get(),
                                       false,
                                       false,
                                       vdex_fd.get(),
@@ -496,6 +511,7 @@
 
   OatFileAssistant oat_file_assistant(dex_location.c_str(),
                                       kRuntimeISA,
+                                      default_context_.get(),
                                       false,
                                       false,
                                       vdex_fd.get(),
@@ -531,6 +547,7 @@
 
   OatFileAssistant oat_file_assistant(dex_location.c_str(),
                                       kRuntimeISA,
+                                      default_context_.get(),
                                       false,
                                       false,
                                       /* vdex_fd= */ -1,
@@ -555,6 +572,7 @@
   android::base::unique_fd zip_fd(open(dex_location.c_str(), O_RDONLY | O_CLOEXEC));
   OatFileAssistant oat_file_assistant(dex_location.c_str(),
                                       kRuntimeISA,
+                                      default_context_.get(),
                                       false,
                                       false,
                                       /* vdex_fd= */ -1,
@@ -579,7 +597,10 @@
   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
   ASSERT_EQ(0, unlink(odex_location.c_str()));
 
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      false);
 
   EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kVerify));
@@ -608,7 +629,10 @@
   ScratchFile vdex_file(vdex_location.c_str());
   ScratchFile odex_file(odex_location.c_str());
 
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      false);
   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
 }
@@ -634,7 +658,10 @@
 
   ScopedNonWritable scoped_non_writable(dex_location);
   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      false);
 
   EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -657,7 +684,10 @@
   ScopedNonWritable scoped_non_writable(dex_location);
   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
 
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      false);
 
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeedProfile, false));
@@ -690,7 +720,10 @@
   ScopedNonWritable scoped_non_writable(dex_location);
   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
 
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      true);
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
   EXPECT_TRUE(oat_file_assistant.HasDexFiles());
@@ -726,7 +759,10 @@
   ScopedNonWritable scoped_non_writable(dex_location);
   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
 
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      true);
   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
   EXPECT_TRUE(oat_file_assistant.HasDexFiles());
@@ -752,7 +788,10 @@
   ScopedNonWritable scoped_non_writable(dex_location);
   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
 
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      false);
   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
@@ -782,7 +821,10 @@
   ASSERT_EQ(0, unlink(odex_location.c_str()));
   Copy(GetDexSrc2(), dex_location);
 
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      false);
 
   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -799,7 +841,10 @@
   ASSERT_EQ(0, unlink(odex_location.c_str()));
   Copy(GetMultiDexSrc2(), dex_location);
 
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      false);
 
   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -824,7 +869,10 @@
   ScopedNonWritable scoped_non_writable(dex_location);
   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
 
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      false);
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
@@ -866,7 +914,10 @@
   ScopedNonWritable scoped_non_writable(dex_location);
   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
 
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      false);
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
   EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
@@ -888,7 +939,10 @@
   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
 
   // Verify the status.
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      false);
 
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
@@ -913,7 +967,10 @@
   Copy(GetResourceOnlySrc1(), dex_location);
 
   // Verify the status.
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      true);
 
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -948,7 +1005,10 @@
   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
 
   // Verify things don't go bad.
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      true);
 
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
             GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -978,7 +1038,10 @@
   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kExtract);
 
   // Verify the status.
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      false);
 
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
@@ -1009,7 +1072,10 @@
   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
 
   // Load the oat using an oat file assistant.
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      true);
 
   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
   ASSERT_TRUE(oat_file.get() != nullptr);
@@ -1037,7 +1103,10 @@
   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
 
   // Load the oat using an oat file assistant.
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      true);
 
   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
   ASSERT_TRUE(oat_file.get() != nullptr);
@@ -1066,7 +1135,10 @@
   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
 
   // Load the oat using an oat file assistant.
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      false);
 
   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
   ASSERT_TRUE(oat_file.get() != nullptr);
@@ -1119,7 +1191,10 @@
   Copy(GetDexSrc1(), abs_dex_location);
 
   std::string dex_location = MakePathRelative(abs_dex_location);
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      true);
 
   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
@@ -1133,7 +1208,10 @@
 TEST_F(OatFileAssistantTest, ShortDexLocation) {
   std::string dex_location = "/xx";
 
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      true);
 
   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
@@ -1149,7 +1227,10 @@
   std::string dex_location = GetScratchDir() + "/LongDexExtension.jarx";
   Copy(GetDexSrc1(), dex_location);
 
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      false);
 
   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -1255,7 +1336,7 @@
 
 // Case: We have a DEX file and an ODEX file, and no OAT file,
 // Expect: We should load the odex file executable.
-TEST_F(DexoptTest, LoadDexOdexNoOat) {
+TEST_F(OatFileAssistantTest, LoadDexOdexNoOat) {
   std::string dex_location = GetScratchDir() + "/LoadDexOdexNoOat.jar";
   std::string odex_location = GetOdexDir() + "/LoadDexOdexNoOat.odex";
 
@@ -1264,7 +1345,10 @@
   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
 
   // Load the oat using an executable oat file assistant.
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      true);
 
   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
   ASSERT_TRUE(oat_file.get() != nullptr);
@@ -1276,7 +1360,7 @@
 
 // Case: We have a MultiDEX file and an ODEX file, and no OAT file.
 // Expect: We should load the odex file executable.
-TEST_F(DexoptTest, LoadMultiDexOdexNoOat) {
+TEST_F(OatFileAssistantTest, LoadMultiDexOdexNoOat) {
   std::string dex_location = GetScratchDir() + "/LoadMultiDexOdexNoOat.jar";
   std::string odex_location = GetOdexDir() + "/LoadMultiDexOdexNoOat.odex";
 
@@ -1285,7 +1369,10 @@
   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
 
   // Load the oat using an executable oat file assistant.
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      kRuntimeISA,
+                                      default_context_.get(),
+                                      true);
 
   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
   ASSERT_TRUE(oat_file.get() != nullptr);
@@ -1367,24 +1454,39 @@
   {
     std::unique_ptr<ClassLoaderContext> updated_context = ClassLoaderContext::Create(context_str);
     ASSERT_TRUE(updated_context != nullptr);
-    OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
-    // DexOptNeeded should advise compilation from scratch when the context changes.
-    EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
-              GetDexOptNeeded(&oat_file_assistant,
-                    CompilerFilter::kDefaultCompilerFilter,
-                    updated_context));
+    std::vector<int> context_fds;
+    ASSERT_TRUE(updated_context->OpenDexFiles("", context_fds,  /*only_read_checksums*/ true));
+    OatFileAssistant oat_file_assistant(
+        dex_location.c_str(), kRuntimeISA, updated_context.get(), false);
+    // DexOptNeeded should advise compilation for filter when the context changes.
+    EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
+              GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kDefaultCompilerFilter));
   }
   {
     std::unique_ptr<ClassLoaderContext> updated_context = ClassLoaderContext::Create(context_str);
     ASSERT_TRUE(updated_context != nullptr);
-    OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+    std::vector<int> context_fds;
+    ASSERT_TRUE(updated_context->OpenDexFiles("", context_fds,  /*only_read_checksums*/ true));
+    OatFileAssistant oat_file_assistant(
+        dex_location.c_str(), kRuntimeISA, updated_context.get(), false);
     // Now check that DexOptNeeded does not advise compilation if we only extracted the file.
     args.push_back("--compiler-filter=extract");
     ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
     EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
-              GetDexOptNeeded(&oat_file_assistant,
-                    CompilerFilter::kExtract,
-                    updated_context));
+              GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
+  }
+  {
+    std::unique_ptr<ClassLoaderContext> updated_context = ClassLoaderContext::Create(context_str);
+    ASSERT_TRUE(updated_context != nullptr);
+    std::vector<int> context_fds;
+    ASSERT_TRUE(updated_context->OpenDexFiles("", context_fds,  /*only_read_checksums*/ true));
+    OatFileAssistant oat_file_assistant(
+        dex_location.c_str(), kRuntimeISA, updated_context.get(), false);
+    // Now check that DexOptNeeded does not advise compilation if we only verify the file.
+    args.push_back("--compiler-filter=verify");
+    ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
+    EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
+              GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
   }
 }
 
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index e485413..438ed6c 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -177,40 +177,6 @@
   return oat_files;
 }
 
-static bool ClassLoaderContextMatches(
-    const OatFile* oat_file,
-    const ClassLoaderContext* context,
-    /*out*/ std::string* error_msg) {
-  DCHECK(oat_file != nullptr);
-  DCHECK(error_msg != nullptr);
-  DCHECK(context != nullptr);
-
-  if (oat_file->IsBackedByVdexOnly()) {
-    // Only a vdex file, we don't depend on the class loader context.
-    return true;
-  }
-
-  if (!CompilerFilter::IsVerificationEnabled(oat_file->GetCompilerFilter())) {
-    // 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
-  // the oat file without addition checks
-  ClassLoaderContext::VerificationResult result = context->VerifyClassLoaderContextMatch(
-      oat_file->GetClassLoaderContext(),
-      /*verify_names=*/ true,
-      /*verify_checksums=*/ true);
-  switch (result) {
-    case ClassLoaderContext::VerificationResult::kMismatch:
-      return false;
-    case ClassLoaderContext::VerificationResult::kVerifies:
-      return true;
-  }
-  LOG(FATAL) << "Unreachable";
-}
-
 bool OatFileManager::ShouldLoadAppImage(const OatFile* source_oat_file) const {
   Runtime* const runtime = Runtime::Current();
   return kEnableAppImage && (!runtime->IsJavaDebuggable() || source_oat_file->IsDebuggable());
@@ -233,18 +199,18 @@
   Runtime* const runtime = Runtime::Current();
 
   std::vector<std::unique_ptr<const DexFile>> dex_files;
+  std::unique_ptr<ClassLoaderContext> context(
+      ClassLoaderContext::CreateContextForClassLoader(class_loader, dex_elements));
 
   // 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?";
-  } else {
-    std::unique_ptr<ClassLoaderContext> context(
-        ClassLoaderContext::CreateContextForClassLoader(class_loader, dex_elements));
-
+  } else if (context != nullptr) {
     OatFileAssistant oat_file_assistant(dex_location,
                                         kRuntimeISA,
+                                        context.get(),
                                         runtime->GetOatFilesExecutable(),
                                         only_use_system_oat_files_);
 
@@ -280,22 +246,7 @@
         << "optimization-status-location=" << odex_location
         << " best_oat_file-location=" << oat_file->GetLocation();
 
-    const OatFile* source_oat_file = nullptr;
-    std::string error_msg;
-    bool class_loader_context_matches = false;
-    bool check_context = oat_file != nullptr && context != nullptr;
-    if (check_context) {
-        class_loader_context_matches =
-            ClassLoaderContextMatches(oat_file.get(),
-                                      context.get(),
-                                      /*out*/ &error_msg);
-    }
-    ScopedTrace context_results(StringPrintf(
-        "check_context=%s contex-ok=%s",
-        check_context ? "true" : "false",
-        class_loader_context_matches ? "true" : "false"));
-
-    if (class_loader_context_matches) {
+    if (oat_file != nullptr) {
       // Load the dex files from the oat file.
       bool added_image_space = false;
       if (oat_file->IsExecutable()) {
@@ -367,6 +318,7 @@
           // file as non-executable.
           OatFileAssistant nonexecutable_oat_file_assistant(dex_location,
                                                             kRuntimeISA,
+                                                            context.get(),
                                                             /*load_executable=*/false,
                                                             only_use_system_oat_files_);
           oat_file.reset(nonexecutable_oat_file_assistant.GetBestOatFile().release());
@@ -390,46 +342,44 @@
       }
 
       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;
-    }
+      *out_oat_file = RegisterOatFile(std::move(oat_file));
+    } else {
+      // oat_file == nullptr
+      // 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 (oat_file_assistant.GetBestStatus() == OatFileAssistant::kOatContextOutOfDate) {
+        std::set<const DexFile*> already_exists_in_classpath =
+            context->CheckForDuplicateDexFiles(MakeNonOwningPointerVector(dex_files));
+        if (!already_exists_in_classpath.empty()) {
+          ScopedTrace duplicate_dex_files("DuplicateDexFilesInContext");
+          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();
+          }
 
-    // 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()) {
-        ScopedTrace duplicate_dex_files("DuplicateDexFilesInContext");
-        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();
         }
-
-        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();
       }
     }
   }