ART: Check for more low-space situations in zygote

Even if a boot image exists and can be loaded, the rest of the
platform may not be able to boot. We previously only checked
after full image generation and missed this case.

Also prune the cache if there wasn't even space to put the boot
marker.

(cherry picked from commit f242f66cf7137ef681e44a494758976e11579260)

Bug: 30765660
Test: m test-art-host
Change-Id: Icd43746e681c62ce2e4e8745fb17bda65ca60372
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index c2e2a1e..8d406b3 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -529,6 +529,17 @@
                                error_msg);
     }
     if (space != nullptr) {
+      // Check whether there is enough space left over in the data partition. Even if we can load
+      // the image, we need to be conservative, as some parts of the platform are not very tolerant
+      // of space constraints.
+      // ImageSpace doesn't know about the data partition per se, it relies on the FindImageFilename
+      // helper (which relies on GetDalvikCache). So for now, if we load an image out of /system,
+      // ignore the check (as it would test for free space in /system instead).
+      if (!is_system && !CheckSpace(*image_filename, error_msg)) {
+        // No. Delete the generated image and try to run out of the dex files.
+        PruneDalvikCache(image_isa);
+        return nullptr;
+      }
       return space;
     }
 
diff --git a/runtime/gc/space/image_space_fs.h b/runtime/gc/space/image_space_fs.h
index eac52f7..4d539d2 100644
--- a/runtime/gc/space/image_space_fs.h
+++ b/runtime/gc/space/image_space_fs.h
@@ -223,8 +223,21 @@
     file.reset(OS::CreateEmptyFile(file_name));
 
     if (file.get() == nullptr) {
+      int saved_errno = errno;
       PLOG(WARNING) << "Failed to create boot marker.";
-      return;
+      if (saved_errno != ENOSPC) {
+        return;
+      }
+
+      LOG(WARNING) << "Pruning dalvik cache because of low-memory situation.";
+      impl::DeleteDirectoryContents(isa_subdir, false);
+
+      // Try once more.
+      file.reset(OS::OpenFileReadWrite(file_name));
+      if (file == nullptr) {
+        PLOG(WARNING) << "Failed to create boot marker.";
+        return;
+      }
     }
   } else {
     if (!file->ReadFully(&num_failed_boots, sizeof(num_failed_boots))) {