Add CanWriteToDalvikCache() check before writing a boot marker or image cache.

A new zygote process, the webview_zygote, will spawn isolated_app children,
but the process itself does not run as root and cannot write to the dalvik
cache. In order to not print SELinux avc errors, check for file-write
permission when testing to see if a boot marker or cache image or should be
written.

Test: m test-art
Test: angler boots

Bug: 21643067
Change-Id: I9f797fe7332a21ef4c6b83d2210b1673af09de1b
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index e41c532..fd47a33 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -363,15 +363,29 @@
   return true;
 }
 
-static bool ImageCreationAllowed(bool is_global_cache, std::string* error_msg) {
+static bool CanWriteToDalvikCache(const InstructionSet isa) {
+  const std::string dalvik_cache = GetDalvikCache(GetInstructionSetString(isa));
+  if (access(dalvik_cache.c_str(), O_RDWR) == 0) {
+    return true;
+  } else if (errno != EACCES) {
+    PLOG(WARNING) << "CanWriteToDalvikCache returned error other than EACCES";
+  }
+  return false;
+}
+
+static bool ImageCreationAllowed(bool is_global_cache,
+                                 const InstructionSet isa,
+                                 std::string* error_msg) {
   // Anyone can write into a "local" cache.
   if (!is_global_cache) {
     return true;
   }
 
-  // Only the zygote is allowed to create the global boot image.
+  // Only the zygote running as root is allowed to create the global boot image.
+  // If the zygote is running as non-root (and cannot write to the dalvik-cache),
+  // then image creation is not allowed..
   if (Runtime::Current()->IsZygote()) {
-    return true;
+    return CanWriteToDalvikCache(isa);
   }
 
   *error_msg = "Only the zygote can create the global boot image.";
@@ -1410,7 +1424,7 @@
 
   // Step 0.a: If we're the zygote, mark boot.
   const bool is_zygote = Runtime::Current()->IsZygote();
-  if (is_zygote && !secondary_image) {
+  if (is_zygote && !secondary_image && CanWriteToDalvikCache(image_isa)) {
     MarkZygoteStart(image_isa, Runtime::Current()->GetZygoteMaxFailedBoots());
   }
 
@@ -1525,7 +1539,7 @@
       local_error_msg = "Patching disabled.";
     } else if (secondary_image) {
       local_error_msg = "Cannot patch a secondary image.";
-    } else if (ImageCreationAllowed(is_global_cache, &local_error_msg)) {
+    } else if (ImageCreationAllowed(is_global_cache, image_isa, &local_error_msg)) {
       bool patch_success =
           RelocateImage(image_location, cache_filename.c_str(), image_isa, &local_error_msg);
       if (patch_success) {
@@ -1555,7 +1569,7 @@
       local_error_msg = "Image compilation disabled.";
     } else if (secondary_image) {
       local_error_msg = "Cannot compile a secondary image.";
-    } else if (ImageCreationAllowed(is_global_cache, &local_error_msg)) {
+    } else if (ImageCreationAllowed(is_global_cache, image_isa, &local_error_msg)) {
       bool compilation_success = GenerateImage(cache_filename, image_isa, &local_error_msg);
       if (compilation_success) {
         std::unique_ptr<ImageSpace> compiled_space =