Allow OatFileAssistant::Create to take std::nullopt for the context.

Partially cherry picked from
commit 12f45c41158de6f6737efb102161f86f462d9290.

Bug: 249984283
Test: m test-art-host-gtest-art_runtime_tests
Change-Id: I7ebe2aa745d0da31242034a27f92b24dbdb08740
Merged-In: I7ebe2aa745d0da31242034a27f92b24dbdb08740
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index c04ff5a..a9f380d 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -616,6 +616,8 @@
     return nullptr;
   }
 
+  // The API doesn't support passing a class loader context, so skip the class loader context check
+  // and assume that it's OK.
   OatFileAssistant oat_file_assistant(filename.c_str(),
                                       target_instruction_set,
                                       /* context= */ nullptr,
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 389479c..9e0c173 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -226,7 +226,7 @@
 std::unique_ptr<OatFileAssistant> OatFileAssistant::Create(
     const std::string& filename,
     const std::string& isa_str,
-    const std::string& context_str,
+    const std::optional<std::string>& context_str,
     bool load_executable,
     bool only_load_trusted_executable,
     OatFileAssistantContext* ofa_context,
@@ -238,20 +238,23 @@
     return nullptr;
   }
 
-  std::unique_ptr<ClassLoaderContext> tmp_context = ClassLoaderContext::Create(context_str.c_str());
-  if (tmp_context == nullptr) {
-    *error_msg = StringPrintf("Class loader context '%s' is invalid", context_str.c_str());
-    return nullptr;
-  }
+  std::unique_ptr<ClassLoaderContext> tmp_context = nullptr;
+  if (context_str.has_value()) {
+    tmp_context = ClassLoaderContext::Create(context_str->c_str());
+    if (tmp_context == nullptr) {
+      *error_msg = StringPrintf("Class loader context '%s' is invalid", context_str->c_str());
+      return nullptr;
+    }
 
-  if (!tmp_context->OpenDexFiles(android::base::Dirname(filename.c_str()),
-                                 /*context_fds=*/{},
-                                 /*only_read_checksums=*/true)) {
-    *error_msg =
-        StringPrintf("Failed to load class loader context files for '%s' with context '%s'",
-                     filename.c_str(),
-                     context_str.c_str());
-    return nullptr;
+    if (!tmp_context->OpenDexFiles(android::base::Dirname(filename.c_str()),
+                                   /*context_fds=*/{},
+                                   /*only_read_checksums=*/true)) {
+      *error_msg =
+          StringPrintf("Failed to load class loader context files for '%s' with context '%s'",
+                       filename.c_str(),
+                       context_str->c_str());
+      return nullptr;
+    }
   }
 
   auto assistant = std::make_unique<OatFileAssistant>(filename.c_str(),
@@ -1182,6 +1185,11 @@
 }
 
 bool OatFileAssistant::ClassLoaderContextIsOkay(const OatFile& oat_file) const {
+  if (context_ == nullptr) {
+    // The caller requests to skip the check.
+    return true;
+  }
+
   if (oat_file.IsBackedByVdexOnly()) {
     // Only a vdex file, we don't depend on the class loader context.
     return true;
@@ -1193,12 +1201,6 @@
     return true;
   }
 
-  if (context_ == nullptr) {
-    // When no class loader context is provided (which happens for deprecated
-    // DexFile APIs), just assume it is OK.
-    return true;
-  }
-
   ClassLoaderContext::VerificationResult matches = context_->VerifyClassLoaderContextMatch(
       oat_file.GetClassLoaderContext(),
       /*verify_names=*/ true,
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index ce069d2..2d0a150 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -146,6 +146,8 @@
   // device. For example, on an arm device, use arm or arm64. An oat file can
   // be loaded executable only if the ISA matches the current runtime.
   //
+  // context should be the class loader context to check against, or null to skip the check.
+  //
   // load_executable should be true if the caller intends to try and load
   // executable code for this dex location.
   //
@@ -182,7 +184,7 @@
   static std::unique_ptr<OatFileAssistant> Create(
       const std::string& filename,
       const std::string& isa_str,
-      const std::string& context_str,
+      const std::optional<std::string>& context_str,
       bool load_executable,
       bool only_load_trusted_executable,
       OatFileAssistantContext* ofa_context,
@@ -523,6 +525,8 @@
 
   std::string dex_location_;
 
+  // The class loader context to check against, or null representing that the check should be
+  // skipped.
   ClassLoaderContext* context_;
 
   // Whether or not the parent directory of the dex file is writable.
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 2904ecb..090532c 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -23,6 +23,7 @@
 #include <functional>
 #include <iterator>
 #include <memory>
+#include <optional>
 #include <string>
 #include <type_traits>
 #include <vector>
@@ -78,33 +79,40 @@
     // Verify the static method (called from PM for dumpsys).
     // This variant does not check class loader context.
     if (!check_context) {
-      std::string compilation_filter1;
-      std::string compilation_reason1;
+      std::string compilation_filter;
+      std::string compilation_reason;
 
       OatFileAssistant::GetOptimizationStatus(file,
                                               kRuntimeISA,
-                                              &compilation_filter1,
-                                              &compilation_reason1,
+                                              &compilation_filter,
+                                              &compilation_reason,
                                               MaybeGetOatFileAssistantContext());
 
-      ASSERT_EQ(expected_filter_name, compilation_filter1);
-      ASSERT_EQ(expected_reason, compilation_reason1);
+      ASSERT_EQ(expected_filter_name, compilation_filter);
+      ASSERT_EQ(expected_reason, compilation_reason);
     }
 
     // Verify the instance methods (called at runtime and from artd).
     OatFileAssistant assistant = CreateOatFileAssistant(file.c_str(), context);
+    VerifyOptimizationStatusWithInstance(
+        &assistant, expected_filter_name, expected_reason, expected_odex_status);
+  }
 
-    std::string odex_location3;  // ignored
-    std::string compilation_filter3;
-    std::string compilation_reason3;
-    std::string odex_status3;
+  void VerifyOptimizationStatusWithInstance(OatFileAssistant* assistant,
+                                            const std::string& expected_filter,
+                                            const std::string& expected_reason,
+                                            const std::string& expected_odex_status) {
+    std::string odex_location;  // ignored
+    std::string compilation_filter;
+    std::string compilation_reason;
+    std::string odex_status;
 
-    assistant.GetOptimizationStatus(
-        &odex_location3, &compilation_filter3, &compilation_reason3, &odex_status3);
+    assistant->GetOptimizationStatus(
+        &odex_location, &compilation_filter, &compilation_reason, &odex_status);
 
-    ASSERT_EQ(expected_filter_name, compilation_filter3);
-    ASSERT_EQ(expected_reason, compilation_reason3);
-    ASSERT_EQ(expected_odex_status, odex_status3);
+    ASSERT_EQ(expected_filter, compilation_filter);
+    ASSERT_EQ(expected_reason, compilation_reason);
+    ASSERT_EQ(expected_odex_status, odex_status);
   }
 
   bool InsertNewBootClasspathEntry(const std::string& src, std::string* error_msg) {
@@ -2377,7 +2385,33 @@
   ASSERT_NE(oat_file_assistant, nullptr);
 
   // Verify that the created instance is usable.
-  VerifyOptimizationStatus(dex_location, default_context_.get(), "speed", "install", "up-to-date");
+  VerifyOptimizationStatusWithInstance(oat_file_assistant.get(), "speed", "install", "up-to-date");
+}
+
+TEST_P(OatFileAssistantTest, CreateWithNullContext) {
+  std::string dex_location = GetScratchDir() + "/OdexUpToDate.jar";
+  std::string odex_location = GetOdexDir() + "/OdexUpToDate.odex";
+  Copy(GetDexSrc1(), dex_location);
+  GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, "install");
+
+  auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
+
+  std::unique_ptr<ClassLoaderContext> context;
+  std::string error_msg;
+  std::unique_ptr<OatFileAssistant> oat_file_assistant =
+      OatFileAssistant::Create(dex_location,
+                               GetInstructionSetString(kRuntimeISA),
+                               /*context_str=*/std::nullopt,
+                               /*load_executable=*/false,
+                               /*only_load_trusted_executable=*/true,
+                               MaybeGetOatFileAssistantContext(),
+                               &context,
+                               &error_msg);
+  ASSERT_NE(oat_file_assistant, nullptr);
+  ASSERT_EQ(context, nullptr);
+
+  // Verify that the created instance is usable.
+  VerifyOptimizationStatusWithInstance(oat_file_assistant.get(), "speed", "install", "up-to-date");
 }
 
 TEST_P(OatFileAssistantTest, ErrorOnInvalidIsaString) {