ART: Restrict ImageSpace space check to first image

The "secondary image inconsistent" path is sensitive to running
the space check twice.

Also disable patching/compilation under low-space condition to
not fill up the space again.

Bug: 73667005
Test: m
Test: manual
Change-Id: Ic93c28c272e6485b06fdb887a3d873a381db94af
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 9ae1f45..366eb53 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -1531,15 +1531,20 @@
                                            &has_cache,
                                            &cache_filename);
 
-  if (is_zygote && dalvik_cache_exists) {
+  bool dex2oat_enabled = Runtime::Current()->IsImageDex2OatEnabled();
+
+  if (is_zygote && dalvik_cache_exists && !secondary_image) {
+    // Extra checks for the zygote. These only apply when loading the first image, explained below.
     DCHECK(!dalvik_cache.empty());
     std::string local_error_msg;
     // All secondary images are verified when the primary image is verified.
-    bool verified = secondary_image || VerifyImage(image_location,
-                                                   dalvik_cache.c_str(),
-                                                   image_isa,
-                                                   &local_error_msg);
-    if (!(verified && CheckSpace(dalvik_cache, &local_error_msg))) {
+    bool verified = VerifyImage(image_location, dalvik_cache.c_str(), image_isa, &local_error_msg);
+    // If we prune for space at a secondary image, we may end up in a crash loop with the _exit
+    // path.
+    bool check_space = CheckSpace(dalvik_cache, &local_error_msg);
+    if (!verified || !check_space) {
+      // Note: it is important to only prune for space on the primary image, or we will hit the
+      //       restart path.
       LOG(WARNING) << local_error_msg << " Preemptively pruning the dalvik cache.";
       PruneDalvikCache(image_isa);
 
@@ -1554,6 +1559,10 @@
                                           &has_cache,
                                           &cache_filename);
     }
+    if (!check_space) {
+      // Disable compilation/patching - we do not want to fill up the space again.
+      dex2oat_enabled = false;
+    }
   }
 
   // Collect all the errors.
@@ -1620,7 +1629,7 @@
   //           secondary image.
   if (found_image && has_system && relocate) {
     std::string local_error_msg;
-    if (!Runtime::Current()->IsImageDex2OatEnabled()) {
+    if (!dex2oat_enabled) {
       local_error_msg = "Patching disabled.";
     } else if (secondary_image) {
       // We really want a working image. Prune and restart.
@@ -1652,7 +1661,7 @@
   //         cache. This step fails if this is a secondary image.
   if (!has_system) {
     std::string local_error_msg;
-    if (!Runtime::Current()->IsImageDex2OatEnabled()) {
+    if (!dex2oat_enabled) {
       local_error_msg = "Image compilation disabled.";
     } else if (secondary_image) {
       local_error_msg = "Cannot compile a secondary image.";