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.

Bug: 30765660
Change-Id: Icd43746e681c62ce2e4e8745fb17bda65ca60372
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 5a52e9a..b7b9ffe 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -505,6 +505,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 57bf59f..fc9a3cf 100644
--- a/runtime/gc/space/image_space_fs.h
+++ b/runtime/gc/space/image_space_fs.h
@@ -114,8 +114,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))) {