Refactor OatFileAssistant to allow it to function without a runtime.

After this change, OatFileAssistant accepts an optional input
OatFileAssistant::RuntimeOptions, and when the input is provided,
OatFileAssistant can function without a runtime.

Also:
- Update tests to verify that OatFileAssistant works properly with and
  without a runtime.

Bug: 233383589
Test: atest art_standalone_runtime_tests:OatFileAssistantTest
Change-Id: Ie828a37f5f3c0843cf33cc40b07420eba0ee6dd0
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index c243cc3..6a6b3c0 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -19,11 +19,12 @@
 
 #include <cstdint>
 #include <memory>
+#include <optional>
 #include <sstream>
 #include <string>
 
-#include "base/compiler_filter.h"
 #include "arch/instruction_set.h"
+#include "base/compiler_filter.h"
 #include "base/os.h"
 #include "base/scoped_flock.h"
 #include "base/unix_file/fd_file.h"
@@ -89,6 +90,28 @@
     kOatUpToDate,
   };
 
+  // Options that a runtime would take if the OAT file were going to be loaded by the runtime.
+  // Note that the struct only keeps references, so the caller must keep the objects alive during
+  // the lifetime of OatFileAssistant.
+  struct RuntimeOptions {
+    // Required. See `-Ximage`.
+    const std::vector<std::string>& image_locations;
+    // Required. See `-Xbootclasspath`.
+    const std::vector<std::string>& boot_class_path;
+    // Required. See `-Xbootclasspath-locations`.
+    const std::vector<std::string>& boot_class_path_locations;
+    // Optional. See `-Xbootclasspathfds`.
+    const std::vector<int>* const boot_class_path_fds = nullptr;
+    // Optional. See `-Xforcejitzygote`.
+    const bool use_jit_zygote = false;
+    // Optional. See `-Xdeny-art-apex-data-files`.
+    const bool deny_art_apex_data_files = false;
+    // Required. A string that represents the apex versions of boot classpath jars. See
+    // `Runtime::apex_versions_` for the encoding format. Can be obtained from
+    // `Runtime::GetApexVersions(boot_class_path_locations)`.
+    const std::string& apex_versions;
+  };
+
   // Constructs an OatFileAssistant object to assist the oat file
   // corresponding to the given dex location with the target instruction set.
   //
@@ -110,11 +133,15 @@
   // only_load_trusted_executable should be true if the caller intends to have
   // only oat files from trusted locations loaded executable. See IsTrustedLocation() for
   // details on trusted locations.
+  //
+  // runtime_options should be provided with all the required fields filled if the caller intends to
+  // use OatFileAssistant without a runtime.
   OatFileAssistant(const char* dex_location,
                    const InstructionSet isa,
                    ClassLoaderContext* context,
                    bool load_executable,
-                   bool only_load_trusted_executable = false);
+                   bool only_load_trusted_executable = false,
+                   std::unique_ptr<RuntimeOptions> runtime_options = nullptr);
 
   // Similar to this(const char*, const InstructionSet, bool), however, if a valid zip_fd is
   // provided, vdex, oat, and zip files will be read from vdex_fd, oat_fd and zip_fd respectively.
@@ -124,6 +151,7 @@
                    ClassLoaderContext* context,
                    bool load_executable,
                    bool only_load_trusted_executable,
+                   std::unique_ptr<RuntimeOptions> runtime_options,
                    int vdex_fd,
                    int oat_fd,
                    int zip_fd);
@@ -189,7 +217,8 @@
   static void GetOptimizationStatus(const std::string& filename,
                                     InstructionSet isa,
                                     std::string* out_compilation_filter,
-                                    std::string* out_compilation_reason);
+                                    std::string* out_compilation_reason,
+                                    std::unique_ptr<RuntimeOptions> runtime_options = nullptr);
 
   // Open and returns an image space associated with the oat file.
   static std::unique_ptr<gc::space::ImageSpace> OpenImageSpace(const OatFile* oat_file);
@@ -253,15 +282,28 @@
   // Returns false on error, in which case error_msg describes the error and
   // oat_filename is not changed.
   // Neither oat_filename nor error_msg may be null.
+  //
+  // Calling this function requires an active runtime.
   static bool DexLocationToOatFilename(const std::string& location,
                                        InstructionSet isa,
                                        std::string* oat_filename,
                                        std::string* error_msg);
 
+  // Same as above, but also takes `deny_art_apex_data_files` from input.
+  //
+  // Calling this function does not require an active runtime.
+  static bool DexLocationToOatFilename(const std::string& location,
+                                       InstructionSet isa,
+                                       bool deny_art_apex_data_files,
+                                       std::string* oat_filename,
+                                       std::string* error_msg);
+
   // Computes the dex location and vdex filename. If the data directory of the process
   // is known, creates an absolute path in that directory and tries to infer path
   // of a corresponding vdex file. Otherwise only creates a basename dex_location
   // from the combined checksums. Returns true if all out-arguments have been set.
+  //
+  // Calling this function requires an active runtime.
   static bool AnonymousDexVdexLocation(const std::vector<const DexFile::Header*>& dex_headers,
                                        InstructionSet isa,
                                        /* out */ std::string* dex_location,
@@ -412,6 +454,9 @@
   // Validates the boot class path checksum of an OatFile.
   bool ValidateBootClassPathChecksums(const OatFile& oat_file);
 
+  // Returns whether there is at least one boot image usable.
+  bool IsPrimaryBootImageUsable();
+
   std::string dex_location_;
 
   ClassLoaderContext* context_;
@@ -432,6 +477,12 @@
   // Will be set during GetRequiredDexChecksums.
   bool zip_file_only_contains_uncompressed_dex_ = true;
 
+  // The runtime options taken from the active runtime or the input.
+  //
+  // All member functions should get runtime options from this variable rather than referencing the
+  // active runtime. This is to allow OatFileAssistant to function without an active runtime.
+  std::unique_ptr<RuntimeOptions> runtime_options_;
+
   // Cached value of the required dex checksums.
   // This should be accessed only by the GetRequiredDexChecksums() method.
   std::vector<uint32_t> cached_required_dex_checksums_;
@@ -461,6 +512,7 @@
 
   std::string cached_boot_class_path_;
   std::string cached_boot_class_path_checksums_;
+  std::optional<bool> cached_is_boot_image_usable_ = std::nullopt;
 
   friend class OatFileAssistantTest;