Call patchoat --verify from art runtime to verify art files

patchoat --verify is used to determine if art files under
/data/dalvik-cache have been tampered with. When tampering is detected,
all files in the dalvik cache are deleted.

Bug: 66697305
Test: Boot with empty /data/dalvik-cache
Test: Boot when /data/dalvik-cache is properly populated
Test: Ensure /data/dalvik-cache/<ISA> is deleted and repopulated when
any of the files in the directory have been tampered with.

Change-Id: If64bee11bede2761d3b931c7aea9d0f60c5c37e9
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index ca5a3ee..2b06e83 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -277,6 +277,36 @@
   return Exec(argv, error_msg);
 }
 
+static bool VerifyImage(const char* image_location,
+                        const char* dest_filename,
+                        InstructionSet isa,
+                        std::string* error_msg) {
+  std::string patchoat(Runtime::Current()->GetPatchoatExecutable());
+
+  std::string input_image_location_arg("--input-image-location=");
+  input_image_location_arg += image_location;
+
+  std::string output_image_filename_arg("--output-image-file=");
+  output_image_filename_arg += dest_filename;
+
+  std::string instruction_set_arg("--instruction-set=");
+  instruction_set_arg += GetInstructionSetString(isa);
+
+  std::vector<std::string> argv;
+  argv.push_back(patchoat);
+
+  argv.push_back(input_image_location_arg);
+  argv.push_back(output_image_filename_arg);
+
+  argv.push_back(instruction_set_arg);
+
+  argv.push_back("--verify");
+
+  std::string command_line(android::base::Join(argv, ' '));
+  LOG(INFO) << "VerifyImage: " << command_line;
+  return Exec(argv, error_msg);
+}
+
 static ImageHeader* ReadSpecificImageHeader(const char* filename, std::string* error_msg) {
   std::unique_ptr<ImageHeader> hdr(new ImageHeader);
   if (!ReadSpecificImageHeader(filename, hdr.get())) {
@@ -1504,7 +1534,12 @@
   if (is_zygote && dalvik_cache_exists) {
     DCHECK(!dalvik_cache.empty());
     std::string local_error_msg;
-    if (!CheckSpace(dalvik_cache, &local_error_msg)) {
+    // All secondary images are verified when the primary image is verified.
+    bool verified = secondary_image || VerifyImage(image_location,
+                                                   cache_filename.c_str(),
+                                                   image_isa,
+                                                   &local_error_msg);
+    if (!(verified && CheckSpace(dalvik_cache, &local_error_msg))) {
       LOG(WARNING) << local_error_msg << " Preemptively pruning the dalvik cache.";
       PruneDalvikCache(image_isa);