Compare checksum in oat files adjacent to jar/apk to support oat in system image

Change-Id: I45554c9fa5c369a0f47830623b6dbe7f9c691a08
diff --git a/Android.mk b/Android.mk
index 9c422b9..14a7679 100644
--- a/Android.mk
+++ b/Android.mk
@@ -233,7 +233,11 @@
 
 # $(1): input jar or apk target location
 define declare-oat-target-target
+ifneq (,$(filter $(1),$(addprefix system/app/,$(addsuffix .apk,$(PRODUCT_DEX_PREOPT_PACKAGES_IN_DATA)))))
 OUT_OAT_FILE := $(call art-cache-out,$(1).oat)
+else
+OUT_OAT_FILE := $(PRODUCT_OUT)/$(1).oat
+endif
 
 ifeq ($(ONE_SHOT_MAKEFILE),)
 .PHONY: oat-target-$(1)
@@ -254,7 +258,7 @@
 
 $(foreach file,\
   $(filter-out\
-    $(TARGET_BOOT_DEX),\
+    $(addprefix $(TARGET_OUT_JAVA_LIBRARIES)/,$(addsuffix .jar,$(TARGET_BOOT_JARS))),\
     $(wildcard $(TARGET_OUT_APPS)/*.apk) $(wildcard $(TARGET_OUT_JAVA_LIBRARIES)/*.jar)),\
   $(eval $(call declare-oat-target-target,$(subst $(PRODUCT_OUT)/,,$(file)))))
 
diff --git a/src/class_linker.cc b/src/class_linker.cc
index f891913..b18b31f 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -741,6 +741,40 @@
   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);
+
+   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());
+
+   if (image_check && dex_check) {
+     RegisterOatFileLocked(*oat_file);
+     return oat_file->GetOatDexFile(dex_location)->OpenDexFile();
+   }
+
+   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;
+}
+
 const DexFile* ClassLinker::FindDexFileInOatFileFromDexLocation(const std::string& dex_location) {
   MutexLock mu(dex_lock_);
 
@@ -749,14 +783,26 @@
     return open_oat_file->GetOatDexFile(dex_location)->OpenDexFile();
   }
 
-  // Look for an existing file next to dex, assuming its up-to-date if found
+  // Look for an existing file next to dex. for example, for
+  // /foo/bar/baz.jar, look for /foo/bar/baz.jar.oat.
   std::string oat_filename(OatFile::DexFilenameToOatFilename(dex_location));
   const OatFile* oat_file = FindOatFileFromOatLocation(oat_filename);
   if (oat_file != NULL) {
-    const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location);
-    CHECK(oat_dex_file != NULL) << oat_filename << " " << dex_location;
-    RegisterOatFileLocked(*oat_file);
-    return oat_dex_file->OpenDexFile();
+    uint32_t dex_location_checksum;
+    if (!DexFile::GetChecksum(dex_location, dex_location_checksum)) {
+      // If no classes.dex found in dex_location, it has been stripped, assume oat is up-to-date.
+      // This is the common case in user builds for jar's and apk's in the /system directory.
+      const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location);
+      CHECK(oat_dex_file != NULL) << oat_filename << " " << dex_location;
+      RegisterOatFileLocked(*oat_file);
+      return oat_dex_file->OpenDexFile();
+    }
+    const DexFile* dex_file = VerifyOatFileChecksums(oat_file,
+                                                     dex_location,
+                                                     dex_location_checksum);
+    if (dex_file != NULL) {
+      return dex_file;
+    }
   }
   // Look for an existing file in the art-cache, validating the result if found
   // not found in /foo/bar/baz.oat? try /data/art-cache/foo@bar@baz.oat
@@ -768,33 +814,11 @@
       LOG(WARNING) << "Failed to compute checksum: " << dex_location;
       return NULL;
     }
-
-    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_filename << " " << dex_location;
-    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) {
-      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 << ")--- regenerating";
-    }
-    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 << ")--- regenerating";
+    const DexFile* dex_file = VerifyOatFileChecksums(oat_file,
+                                                     dex_location,
+                                                     dex_location_checksum);
+    if (dex_file != NULL) {
+      return dex_file;
     }
     if (TEMP_FAILURE_RETRY(unlink(oat_file->GetLocation().c_str())) != 0) {
       PLOG(FATAL) << "Failed to remove obsolete .oat file " << oat_file->GetLocation();
diff --git a/src/class_linker.h b/src/class_linker.h
index 293e3ab..01c1051 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -404,6 +404,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_);
 
   Method* CreateProxyConstructor(SirtRef<Class>& klass, Class* proxy_class);
   Method* CreateProxyMethod(SirtRef<Class>& klass, SirtRef<Method>& prototype);