Continue image space initialization if the primary boot image is valid.

`BootImageLoader::LoadFromSystem` checks the return value of
`BootImageLayout::LoadFromSystem` and continues only if the return value
is true. Therefore, `BootImageLayout::LoadFromSystem` shouldn't return
false to abort image space initialization even if it fails to load a
boot image extension. However, before this change, when
`allow_in_memory_compilation` is false, `BootImageLayout::LoadFromSystem`
returns false when a boot image extension is unusable. This isn't
expected. It wasn't a problem before because
`allow_in_memory_compilation` was always true, but
`allow_in_memory_compilation` can be false starting from aosp/2219944,
so we need to fix this issue.

Bug: 247055146
Test: ArtGtestsTargetChroot
Change-Id: I866e8acd38df270896b4acb362876cd9addf02a1
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 41bb62f..00b4f47 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -2016,17 +2016,17 @@
     std::string base_filename;
     if (!filename_fn(base_location, &base_filename, &local_error_msg) ||
         !ReadHeader(base_location, base_filename, bcp_index, &local_error_msg)) {
-      if (!allow_in_memory_compilation) {
-        // The boot image is unusable and we can't continue by generating a boot image in memory.
-        // All we can do is to return.
-        *error_msg = std::move(local_error_msg);
-        return false;
-      }
       LOG(ERROR) << "Error reading named image component header for " << base_location
                  << ", error: " << local_error_msg;
       // If the primary boot image is invalid, we generate a single full image. This is faster than
       // generating the primary boot image and the extension separately.
       if (bcp_index == 0) {
+        if (!allow_in_memory_compilation) {
+          // The boot image is unusable and we can't continue by generating a boot image in memory.
+          // All we can do is to return.
+          *error_msg = std::move(local_error_msg);
+          return false;
+        }
         // We must at least have profiles for the core libraries.
         if (profile_filenames.empty()) {
           *error_msg = "Full boot image cannot be compiled because no profile is provided.";
@@ -2050,14 +2050,15 @@
         // No extensions are needed.
         return true;
       }
-      if (profile_filenames.empty() ||
+      bool should_compile_extension = allow_in_memory_compilation && !profile_filenames.empty();
+      if (!should_compile_extension ||
           !CompileBootclasspathElements(base_location,
                                         base_filename,
                                         bcp_index,
                                         profile_filenames,
                                         components.SubArray(/*pos=*/ 0, /*length=*/ 1),
                                         &local_error_msg)) {
-        if (!profile_filenames.empty()) {
+        if (should_compile_extension) {
           LOG(ERROR) << "Error compiling boot image extension for " << boot_class_path_[bcp_index]
                      << ", error: " << local_error_msg;
         }
diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h
index bf9cda2..472ae40 100644
--- a/runtime/gc/space/image_space.h
+++ b/runtime/gc/space/image_space.h
@@ -444,6 +444,7 @@
                                       ArrayRef<const std::string> dependencies,
                                       /*out*/ std::string* error_msg);
 
+    // Returns true if a least one chuck has been loaded.
     template <typename FilenameFn>
     bool Load(FilenameFn&& filename_fn,
               bool allow_in_memory_compilation,
diff --git a/runtime/oat_file_assistant_context.cc b/runtime/oat_file_assistant_context.cc
index becc329..4bd83b7 100644
--- a/runtime/oat_file_assistant_context.cc
+++ b/runtime/oat_file_assistant_context.cc
@@ -131,9 +131,11 @@
 
   std::string error_msg;
   if (!layout.LoadFromSystem(isa, /*allow_in_memory_compilation=*/false, &error_msg)) {
-    // At this point, `layout` contains a subset of boot images that can be loaded.
+    // At this point, `layout` contains nothing.
     VLOG(oat) << "Some error occurred when loading boot images for oat file validation: "
               << error_msg;
+    // Create an empty entry so that we don't have to retry when the function is called again.
+    return boot_image_info_list_by_isa_[isa];
   }
 
   std::vector<BootImageInfo>& boot_image_info_list = boot_image_info_list_by_isa_[isa];