Snap for 8101734 from 653cf4144e2a43ade887648f05958af84715d63c to mainline-media-swcodec-release

Change-Id: I846a4b9770f4979224fdaa5da312b8a81a2dd3eb
diff --git a/libartbase/base/file_magic.cc b/libartbase/base/file_magic.cc
index 1471c59..21b762f 100644
--- a/libartbase/base/file_magic.cc
+++ b/libartbase/base/file_magic.cc
@@ -44,6 +44,10 @@
 }
 
 bool ReadMagicAndReset(int fd, uint32_t* magic, std::string* error_msg) {
+  if (lseek(fd, 0, SEEK_SET) != 0) {
+    *error_msg = StringPrintf("Failed to seek to beginning of file : %s", strerror(errno));
+    return false;
+  }
   int n = TEMP_FAILURE_RETRY(read(fd, magic, sizeof(*magic)));
   if (n != sizeof(*magic)) {
     *error_msg = StringPrintf("Failed to find magic");
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 4eb7f25..3a92965 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -25,7 +25,6 @@
 #include "android-base/stringprintf.h"
 #include "android-base/strings.h"
 #include "android-base/unique_fd.h"
-
 #include "arch/instruction_set.h"
 #include "art_field-inl.h"
 #include "art_method-inl.h"
@@ -1503,6 +1502,12 @@
                       const char* file_description,
                       /*out*/std::string* error_msg);
 
+  bool ValidateOatFile(const std::string& base_location,
+                       const std::string& base_filename,
+                       size_t bcp_index,
+                       size_t component_count,
+                       /*out*/std::string* error_msg);
+
   bool ReadHeader(const std::string& base_location,
                   const std::string& base_filename,
                   size_t bcp_index,
@@ -1811,6 +1816,61 @@
   return true;
 }
 
+bool ImageSpace::BootImageLayout::ValidateOatFile(
+    const std::string& base_location,
+    const std::string& base_filename,
+    size_t bcp_index,
+    size_t component_count,
+    /*out*/std::string* error_msg) {
+  std::string art_filename = ExpandLocation(base_filename, bcp_index);
+  std::string art_location = ExpandLocation(base_location, bcp_index);
+  std::string oat_filename = ImageHeader::GetOatLocationFromImageLocation(art_filename);
+  std::string oat_location = ImageHeader::GetOatLocationFromImageLocation(art_location);
+  int oat_fd = -1;
+  int vdex_fd = -1;
+  auto dex_filenames =
+      ArrayRef<const std::string>(boot_class_path_).SubArray(bcp_index, component_count);
+  auto dex_fds = ArrayRef<const int>();
+  // We open the oat file here only for validating that it's up-to-date. We don't open it as
+  // executable or mmap it to a reserved space. This `OatFile` object will be dropped after
+  // validation, and will not go into the `ImageSpace`.
+  std::unique_ptr<OatFile> oat_file;
+  DCHECK_EQ(oat_fd >= 0, vdex_fd >= 0);
+  if (oat_fd >= 0) {
+    oat_file.reset(OatFile::Open(
+        /*zip_fd=*/ -1,
+        vdex_fd,
+        oat_fd,
+        oat_location,
+        /*executable=*/ false,
+        /*low_4gb=*/ false,
+        dex_filenames,
+        /*reservation=*/ nullptr,
+        error_msg));
+  } else {
+    oat_file.reset(OatFile::Open(
+        /*zip_fd=*/ -1,
+        oat_filename,
+        oat_location,
+        /*executable=*/ false,
+        /*low_4gb=*/ false,
+        dex_filenames,
+        /*reservation=*/ nullptr,
+        error_msg));
+  }
+  if (oat_file == nullptr) {
+    *error_msg = StringPrintf("Failed to open oat file '%s' when validating it for image '%s': %s",
+                              oat_filename.c_str(),
+                              art_location.c_str(),
+                              error_msg->c_str());
+    return false;
+  }
+  if (!ImageSpace::ValidateOatFile(*oat_file, error_msg, dex_filenames, dex_fds)) {
+    return false;
+  }
+  return true;
+}
+
 bool ImageSpace::BootImageLayout::ReadHeader(const std::string& base_location,
                                              const std::string& base_filename,
                                              size_t bcp_index,
@@ -1828,6 +1888,15 @@
     return false;
   }
 
+  // Validate oat files. We do it here so that the boot image will be re-compiled in memory if it's
+  // outdated.
+  size_t component_count = (header.GetImageSpaceCount() == 1u) ? header.GetComponentCount() : 1u;
+  for (size_t i = 0; i < header.GetImageSpaceCount(); i++) {
+    if (!ValidateOatFile(base_location, base_filename, bcp_index + i, component_count, error_msg)) {
+      return false;
+    }
+  }
+
   if (chunks_.empty()) {
     base_address_ = reinterpret_cast32<uint32_t>(header.GetImageBegin());
   }
@@ -3120,6 +3189,8 @@
     return false;
   }
 
+  // Load the image. We don't validate oat files in this stage because they have been validated
+  // before.
   if (!LoadImage(layout,
                  /*validate_oat_file=*/ false,
                  extra_reservation_size,
@@ -3268,20 +3339,32 @@
 }
 
 bool ImageSpace::ValidateOatFile(const OatFile& oat_file, std::string* error_msg) {
-  const ArtDexFileLoader dex_file_loader;
-  for (const OatDexFile* oat_dex_file : oat_file.GetOatDexFiles()) {
-    const std::string& dex_file_location = oat_dex_file->GetDexFileLocation();
+  return ValidateOatFile(oat_file, error_msg, ArrayRef<const std::string>(), ArrayRef<const int>());
+}
 
+bool ImageSpace::ValidateOatFile(const OatFile& oat_file,
+                                 std::string* error_msg,
+                                 ArrayRef<const std::string> dex_filenames,
+                                 ArrayRef<const int> dex_fds) {
+  const ArtDexFileLoader dex_file_loader;
+  size_t dex_file_index = 0;
+  for (const OatDexFile* oat_dex_file : oat_file.GetOatDexFiles()) {
     // Skip multidex locations - These will be checked when we visit their
     // corresponding primary non-multidex location.
-    if (DexFileLoader::IsMultiDexLocation(dex_file_location.c_str())) {
+    if (DexFileLoader::IsMultiDexLocation(oat_dex_file->GetDexFileLocation().c_str())) {
       continue;
     }
 
+    DCHECK(dex_filenames.empty() || dex_file_index < dex_filenames.size());
+    const std::string& dex_file_location =
+        dex_filenames.empty() ? oat_dex_file->GetDexFileLocation() : dex_filenames[dex_file_index];
+    int dex_fd = dex_file_index < dex_fds.size() ? dex_fds[dex_file_index] : -1;
+    dex_file_index++;
+
     std::vector<uint32_t> checksums;
     std::vector<std::string> dex_locations_ignored;
     if (!dex_file_loader.GetMultiDexChecksums(
-        dex_file_location.c_str(), &checksums, &dex_locations_ignored, error_msg)) {
+            dex_file_location.c_str(), &checksums, &dex_locations_ignored, error_msg, dex_fd)) {
       *error_msg = StringPrintf("ValidateOatFile failed to get checksums of dex file '%s' "
                                 "referenced by oat file %s: %s",
                                 dex_file_location.c_str(),
diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h
index 545f659..350b988 100644
--- a/runtime/gc/space/image_space.h
+++ b/runtime/gc/space/image_space.h
@@ -266,6 +266,16 @@
   // This function is exposed for testing purposes.
   static bool ValidateOatFile(const OatFile& oat_file, std::string* error_msg);
 
+  // Same as above, but allows to use `dex_filenames` and `dex_fds` to find the dex files instead of
+  // using the dex filenames in the header of the oat file. This overload is useful when the actual
+  // dex filenames are different from what's in the header (e.g., when we run dex2oat on host), or
+  // when the runtime can only access files through FDs (e.g., when we run dex2oat on target in a
+  // restricted SELinux domain).
+  static bool ValidateOatFile(const OatFile& oat_file,
+                              std::string* error_msg,
+                              ArrayRef<const std::string> dex_filenames,
+                              ArrayRef<const int> dex_fds);
+
   // Return the end of the image which includes non-heap objects such as ArtMethods and ArtFields.
   uint8_t* GetImageEnd() const {
     return Begin() + GetImageHeader().GetImageSize();