Open only necessary files for BCP checksums test.

Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Test: aosp_taimen-userdebug boots.
Bug: 128479972
Change-Id: I13040acb5603d9207c2aaaa51ffd2fc7d3de1d82
diff --git a/runtime/dexopt_test.cc b/runtime/dexopt_test.cc
index 0624525..33f8c7f 100644
--- a/runtime/dexopt_test.cc
+++ b/runtime/dexopt_test.cc
@@ -120,7 +120,7 @@
   EXPECT_EQ(filter, odex_file->GetCompilerFilter());
 
   std::string boot_image_checksums = gc::space::ImageSpace::GetBootClassPathChecksums(
-      Runtime::Current()->GetBootClassPath(),
+      ArrayRef<const std::string>(Runtime::Current()->GetBootClassPath()),
       image_location,
       kRuntimeISA,
       gc::space::ImageSpaceLoadingOrder::kSystemFirst,
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 5ebd4b3..b10c9801 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -2181,7 +2181,7 @@
   return true;
 }
 
-std::string ImageSpace::GetBootClassPathChecksums(const std::vector<std::string>& boot_class_path,
+std::string ImageSpace::GetBootClassPathChecksums(ArrayRef<const std::string> boot_class_path,
                                                   const std::string& image_location,
                                                   InstructionSet image_isa,
                                                   ImageSpaceLoadingOrder order,
diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h
index a3a9557..e27810d 100644
--- a/runtime/gc/space/image_space.h
+++ b/runtime/gc/space/image_space.h
@@ -135,7 +135,7 @@
   // Returns the checksums for the boot image and extra boot class path dex files,
   // based on the boot class path, image location and ISA (may differ from the ISA of an
   // initialized Runtime). The boot image and dex files do not need to be loaded in memory.
-  static std::string GetBootClassPathChecksums(const std::vector<std::string>& boot_class_path,
+  static std::string GetBootClassPathChecksums(ArrayRef<const std::string> boot_class_path,
                                                const std::string& image_location,
                                                InstructionSet image_isa,
                                                ImageSpaceLoadingOrder order,
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 5529434..f122e57 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -28,6 +28,7 @@
 #include "base/macros.h"
 #include "base/os.h"
 #include "base/stl_util.h"
+#include "base/string_view_cpp20.h"
 #include "base/utils.h"
 #include "class_linker.h"
 #include "compiler_filter.h"
@@ -405,23 +406,7 @@
 
   // Verify the image checksum
   if (CompilerFilter::DependsOnImageChecksum(current_compiler_filter)) {
-    const ImageInfo* image_info = GetImageInfo();
-    if (image_info == nullptr) {
-      VLOG(oat) << "No image for oat image checksum to match against.";
-
-      if (HasOriginalDexFiles()) {
-        return kOatBootImageOutOfDate;
-      }
-
-      // 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.";
-    } else if (!image_info->ValidateBootClassPathChecksums(file)) {
+    if (!ValidateBootClassPathChecksums(file)) {
       VLOG(oat) << "Oat image checksum does not match image checksum.";
       return kOatBootImageOutOfDate;
     }
@@ -562,51 +547,79 @@
   return required_dex_checksums_found_ ? &cached_required_dex_checksums_ : nullptr;
 }
 
-bool OatFileAssistant::ImageInfo::ValidateBootClassPathChecksums(const OatFile& oat_file) const {
+bool OatFileAssistant::ValidateBootClassPathChecksums(const OatFile& oat_file) {
+  // Get the BCP from the oat file.
+  const char* oat_boot_class_path =
+      oat_file.GetOatHeader().GetStoreValueByKey(OatHeader::kBootClassPathKey);
+  if (oat_boot_class_path == nullptr) {
+    return false;
+  }
+
+  // Check that the oat BCP is a prefix of current BCP locations and count components.
+  Runtime* runtime = Runtime::Current();
+  size_t component_count = 0u;
+  std::string_view remaining_bcp(oat_boot_class_path);
+  bool bcp_ok = false;
+  for (const std::string& location : runtime->GetBootClassPathLocations()) {
+    if (!StartsWith(remaining_bcp, location)) {
+      break;
+    }
+    remaining_bcp.remove_prefix(location.size());
+    ++component_count;
+    if (remaining_bcp.empty()) {
+      bcp_ok = true;
+      break;
+    }
+    if (!StartsWith(remaining_bcp, ":")) {
+      break;
+    }
+    remaining_bcp.remove_prefix(1u);
+  }
+  if (!bcp_ok) {
+    return false;
+  }
+
+  // Get the checksums.
   const char* oat_boot_class_path_checksums =
       oat_file.GetOatHeader().GetStoreValueByKey(OatHeader::kBootClassPathChecksumsKey);
   if (oat_boot_class_path_checksums == nullptr) {
     return false;
   }
-  // The checksums can be either the same or a prefix of the expected checksums,
-  // ending before the ':' delimiter.
-  size_t length = strlen(oat_boot_class_path_checksums);
-  if (length > boot_class_path_checksums.length() ||
-      (length < boot_class_path_checksums.length() && boot_class_path_checksums[length] != ':')) {
-    return false;
-  }
-  return boot_class_path_checksums.compare(0u, length, oat_boot_class_path_checksums) == 0;
-}
 
-std::unique_ptr<OatFileAssistant::ImageInfo>
-OatFileAssistant::ImageInfo::GetRuntimeImageInfo(InstructionSet isa, std::string* error_msg) {
-  CHECK(error_msg != nullptr);
-
-  Runtime* runtime = Runtime::Current();
-  std::unique_ptr<ImageInfo> info(new ImageInfo());
-  info->location = runtime->GetImageLocation();
-  info->boot_class_path_checksums = gc::space::ImageSpace::GetBootClassPathChecksums(
-      runtime->GetBootClassPath(),
-      info->location,
-      isa,
-      runtime->GetImageSpaceLoadingOrder(),
-      error_msg);
-  if (info->boot_class_path_checksums.empty()) {
-    return nullptr;
-  }
-  return info;
-}
-
-const OatFileAssistant::ImageInfo* OatFileAssistant::GetImageInfo() {
-  if (!image_info_load_attempted_) {
-    image_info_load_attempted_ = true;
+  // Retrieve checksums for this portion of the BCP if we do not have them cached.
+  if (cached_boot_class_path_checksum_component_count_ != component_count) {
+    ArrayRef<const std::string> boot_class_path(runtime->GetBootClassPath());
     std::string error_msg;
-    cached_image_info_ = ImageInfo::GetRuntimeImageInfo(isa_, &error_msg);
-    if (cached_image_info_ == nullptr) {
-      LOG(WARNING) << "Unable to get runtime image info: " << error_msg;
+    std::string boot_class_path_checksums = gc::space::ImageSpace::GetBootClassPathChecksums(
+        boot_class_path.SubArray(/* pos= */ 0u, component_count),
+        runtime->GetImageLocation(),
+        isa_,
+        runtime->GetImageSpaceLoadingOrder(),
+        &error_msg);
+    if (boot_class_path_checksums.empty()) {
+      VLOG(oat) << "No image for oat image checksum to match against.";
+
+      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;
     }
+    cached_boot_class_path_checksum_component_count_ = component_count;
+    cached_boot_class_path_checksums_ = boot_class_path_checksums;
   }
-  return cached_image_info_.get();
+
+  // Compare the checksums.
+  return cached_boot_class_path_checksums_ == oat_boot_class_path_checksums;
 }
 
 OatFileAssistant::OatFileInfo& OatFileAssistant::GetBestInfo() {
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index 85e5917..83ae3cb 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -246,16 +246,6 @@
                                        std::string* error_msg);
 
  private:
-  struct ImageInfo {
-    bool ValidateBootClassPathChecksums(const OatFile& oat_file) const;
-
-    std::string location;
-    std::string boot_class_path_checksums;
-
-    static std::unique_ptr<ImageInfo> GetRuntimeImageInfo(InstructionSet isa,
-                                                          std::string* error_msg);
-  };
-
   class OatFileInfo {
    public:
     // Initially the info is for no file in particular. It will treat the
@@ -395,11 +385,8 @@
   // dex_location_ dex file.
   const std::vector<uint32_t>* GetRequiredDexChecksums();
 
-  // Returns the loaded image info.
-  // Loads the image info if needed. Returns null if the image info failed
-  // to load.
-  // The caller shouldn't clean up or free the returned pointer.
-  const ImageInfo* GetImageInfo();
+  // Validates the boot class path checksum of an OatFile.
+  bool ValidateBootClassPathChecksums(const OatFile& oat_file);
 
   // To implement Lock(), we lock a dummy file where the oat file would go
   // (adding ".flock" to the target file name) and retain the lock for the
@@ -437,12 +424,8 @@
   // File descriptor corresponding to apk, dex file, or zip.
   int zip_fd_;
 
-  // Cached value of the image info.
-  // Use the GetImageInfo method rather than accessing these directly.
-  // TODO: The image info should probably be moved out of the oat file
-  // assistant to an image file manager.
-  bool image_info_load_attempted_ = false;
-  std::unique_ptr<ImageInfo> cached_image_info_;
+  size_t cached_boot_class_path_checksum_component_count_ = 0u;
+  std::string cached_boot_class_path_checksums_;
 
   friend class OatFileAssistantTest;