Update DexFile_isDexOptNeeded to handle system.img oat files with classes.dex

Change-Id: I564bacec777b745a9c911a8fe8dd98437b1ddd2d
diff --git a/src/class_linker.cc b/src/class_linker.cc
index a904800..990fb62 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -742,38 +742,58 @@
   return oat_dex_file->OpenDexFile();
 }
 
-const DexFile* ClassLinker::VerifyOatFileChecksums(const OatFile* oat_file,
-                                                   const std::string& dex_location,
-                                                   uint32_t dex_location_checksum) {
-   Runtime* runtime = Runtime::Current();
-   const ImageHeader& image_header = runtime->GetHeap()->GetImageSpace()->GetImageHeader();
-   uint32_t image_checksum = image_header.GetOatChecksum();
-   bool image_check = (oat_file->GetOatHeader().GetImageFileLocationChecksum() == image_checksum);
+bool ClassLinker::VerifyOatFileChecksums(const OatFile* oat_file,
+                                         const std::string& dex_location,
+                                         uint32_t dex_location_checksum) {
+  Runtime* runtime = Runtime::Current();
+  const ImageHeader& image_header = runtime->GetHeap()->GetImageSpace()->GetImageHeader();
+  uint32_t image_checksum = image_header.GetOatChecksum();
+  bool image_check = (oat_file->GetOatHeader().GetImageFileLocationChecksum() == image_checksum);
 
-   const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location);
-   CHECK(oat_dex_file != NULL) << oat_file->GetLocation() << " " << dex_location;
-   bool dex_check = (dex_location_checksum == oat_dex_file->GetDexFileLocationChecksum());
+  const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location);
+  if (oat_dex_file == NULL) {
+    LOG(ERROR) << ".oat file " << oat_file->GetLocation()
+               << " does not contain contents for " << dex_location;
+    std::vector<const OatFile::OatDexFile*> oat_dex_files = oat_file->GetOatDexFiles();
+    for (size_t i = 0; i < oat_dex_files.size(); i++) {
+      const OatFile::OatDexFile* oat_dex_file = oat_dex_files[i];
+      LOG(ERROR) << ".oat file " << oat_file->GetLocation()
+                 << " contains contents for " << oat_dex_file->GetDexFileLocation();
+    }
+    return false;
+  }
+  bool dex_check = (dex_location_checksum == oat_dex_file->GetDexFileLocationChecksum());
 
-   if (image_check && dex_check) {
-     RegisterOatFileLocked(*oat_file);
-     return oat_file->GetOatDexFile(dex_location)->OpenDexFile();
-   }
+  if (image_check && dex_check) {
+    return true;
+  }
 
-   if (!image_check) {
-     std::string image_file(image_header.GetImageRoot(
-         ImageHeader::kOatLocation)->AsString()->ToModifiedUtf8());
-     LOG(WARNING) << ".oat file " << oat_file->GetLocation()
-                  << " checksum ( " << std::hex << oat_dex_file->GetDexFileLocationChecksum()
-                  << ") mismatch with " << image_file
-                  << " (" << std::hex << image_checksum << ")";
-   }
-   if (!dex_check) {
-     LOG(WARNING) << ".oat file " << oat_file->GetLocation()
-                  << " checksum ( " << std::hex << oat_dex_file->GetDexFileLocationChecksum()
-                  << ") mismatch with " << dex_location
-                  << " (" << std::hex << dex_location_checksum << ")";
-   }
-   return NULL;
+  if (!image_check) {
+    std::string image_file(image_header.GetImageRoot(
+        ImageHeader::kOatLocation)->AsString()->ToModifiedUtf8());
+    LOG(WARNING) << ".oat file " << oat_file->GetLocation()
+                 << " checksum ( " << std::hex << oat_dex_file->GetDexFileLocationChecksum()
+                 << ") mismatch with " << image_file
+                 << " (" << std::hex << image_checksum << ")";
+  }
+  if (!dex_check) {
+    LOG(WARNING) << ".oat file " << oat_file->GetLocation()
+                 << " checksum ( " << std::hex << oat_dex_file->GetDexFileLocationChecksum()
+                 << ") mismatch with " << dex_location
+                 << " (" << std::hex << dex_location_checksum << ")";
+  }
+  return false;
+}
+
+const DexFile* ClassLinker::VerifyAndOpenDexFileFromOatFile(const OatFile* oat_file,
+                                                            const std::string& dex_location,
+                                                            uint32_t dex_location_checksum) {
+  bool verified = VerifyOatFileChecksums(oat_file, dex_location, dex_location_checksum);
+  if (!verified) {
+    return NULL;
+  }
+  RegisterOatFileLocked(*oat_file);
+  return oat_file->GetOatDexFile(dex_location)->OpenDexFile();
 }
 
 const DexFile* ClassLinker::FindDexFileInOatFileFromDexLocation(const std::string& dex_location) {
@@ -798,9 +818,9 @@
       RegisterOatFileLocked(*oat_file);
       return oat_dex_file->OpenDexFile();
     }
-    const DexFile* dex_file = VerifyOatFileChecksums(oat_file,
-                                                     dex_location,
-                                                     dex_location_checksum);
+    const DexFile* dex_file = VerifyAndOpenDexFileFromOatFile(oat_file,
+                                                              dex_location,
+                                                              dex_location_checksum);
     if (dex_file != NULL) {
       return dex_file;
     }
@@ -815,9 +835,9 @@
       LOG(WARNING) << "Failed to compute checksum: " << dex_location;
       return NULL;
     }
-    const DexFile* dex_file = VerifyOatFileChecksums(oat_file,
-                                                     dex_location,
-                                                     dex_location_checksum);
+    const DexFile* dex_file = VerifyAndOpenDexFileFromOatFile(oat_file,
+                                                              dex_location,
+                                                              dex_location_checksum);
     if (dex_file != NULL) {
       return dex_file;
     }
diff --git a/src/class_linker.h b/src/class_linker.h
index 26ce31e..8e474df 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -251,6 +251,11 @@
   const DexFile* FindDexFileInOatFileFromDexLocation(const std::string& location);
 
 
+  // Returns true if oat file contains the dex file with the given location and checksum
+  static bool VerifyOatFileChecksums(const OatFile* oat_file,
+                                     const std::string& dex_location,
+                                     uint32_t dex_location_checksum);
+
   // TODO: replace this with multiple methods that allocate the correct managed type.
   template <class T>
   ObjectArray<T>* AllocObjectArray(size_t length) {
@@ -402,10 +407,10 @@
   const OatFile* FindOpenedOatFileForDexFile(const DexFile& dex_file);
   const OatFile* FindOpenedOatFileFromDexLocation(const std::string& dex_location);
   const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location);
-  const DexFile* VerifyOatFileChecksums(const OatFile* oat_file,
-                                        const std::string& dex_location,
-                                        uint32_t dex_location_checksum)
-          EXCLUSIVE_LOCKS_REQUIRED(dex_lock_);
+  const DexFile* VerifyAndOpenDexFileFromOatFile(const OatFile* oat_file,
+                                                 const std::string& dex_location,
+                                                 uint32_t dex_location_checksum)
+      EXCLUSIVE_LOCKS_REQUIRED(dex_lock_);
 
   Method* CreateProxyConstructor(SirtRef<Class>& klass, Class* proxy_class);
   Method* CreateProxyMethod(SirtRef<Class>& klass, SirtRef<Method>& prototype);
diff --git a/src/native/dalvik_system_DexFile.cc b/src/native/dalvik_system_DexFile.cc
index 3bf0ea5..ef38f00 100644
--- a/src/native/dalvik_system_DexFile.cc
+++ b/src/native/dalvik_system_DexFile.cc
@@ -192,17 +192,26 @@
     }
   }
 
-  // If we have an oat file next to the dex file, assume up-to-date.
-  // A user build looks like this, and it will have no classes.dex in
-  // the input for checksum validation.
+  // Check if we have an oat file next to the dex file.
   std::string oat_filename(OatFile::DexFilenameToOatFilename(filename.c_str()));
   UniquePtr<const OatFile> oat_file(
       OatFile::Open(oat_filename, oat_filename, NULL, OatFile::kRelocNone));
   if (oat_file.get() != NULL && oat_file->GetOatDexFile(filename.c_str()) != NULL) {
-    if (debug_logging) {
-      LOG(INFO) << "DexFile_isDexOptNeeded ignoring precompiled file: " << filename.c_str();
+    uint32_t location_checksum;
+    // If we have no classes.dex checksum such as in a user build, assume up-to-date.
+    if (!DexFile::GetChecksum(filename.c_str(), location_checksum)) {
+      if (debug_logging) {
+        LOG(INFO) << "DexFile_isDexOptNeeded ignoring precompiled stripped file: " << filename.c_str();
+      }
+      return JNI_FALSE;
     }
-    return JNI_FALSE;
+    if (ClassLinker::VerifyOatFileChecksums(oat_file.get(), filename.c_str(), location_checksum)) {
+      if (debug_logging) {
+        LOG(INFO) << "DexFile_isDexOptNeeded precompiled file " << oat_filename
+                  << " is up-to-date checksum compared to " << filename.c_str();
+      }
+      return JNI_FALSE;
+    }
   }
 
   // Check if we have an oat file in the cache
@@ -223,26 +232,13 @@
     return JNI_TRUE;
   }
 
-  const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(filename.c_str());
-  if (oat_dex_file == NULL) {
-    LOG(ERROR) << "DexFile_isDexOptNeeded cache file " << cache_location
-               << " does not contain contents for " << filename.c_str();
-    std::vector<const OatFile::OatDexFile*> oat_dex_files = oat_file->GetOatDexFiles();
-    for (size_t i = 0; i < oat_dex_files.size(); i++) {
-      const OatFile::OatDexFile* oat_dex_file = oat_dex_files[i];
-      LOG(ERROR) << "DexFile_isDexOptNeeded cache file " << cache_location
-                 << " contains contents for " << oat_dex_file->GetDexFileLocation();
-    }
-    return JNI_TRUE;
-  }
-
   uint32_t location_checksum;
   if (!DexFile::GetChecksum(filename.c_str(), location_checksum)) {
     LOG(ERROR) << "DexFile_isDexOptNeeded failed to compute checksum of " << filename.c_str();
     return JNI_TRUE;
   }
 
-  if (location_checksum != oat_dex_file->GetDexFileLocationChecksum()) {
+  if (!ClassLinker::VerifyOatFileChecksums(oat_file.get(), filename.c_str(), location_checksum)) {
     LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
               << " has out-of-date checksum compared to " << filename.c_str();
     return JNI_TRUE;