Fix checksum verification when opening DexFiles from OatFiles

Change-Id: Ic3d13f3d591c34f159bf0739536a1751c3e7dc75
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 87976a3..f414c4b 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -40,6 +40,7 @@
 #include "oat_file.h"
 #include "object.h"
 #include "object_utils.h"
+#include "os.h"
 #include "runtime.h"
 #include "runtime_support.h"
 #include "ScopedLocalRef.h"
@@ -678,10 +679,18 @@
 }
 
 const OatFile* ClassLinker::FindOpenedOatFileForDexFile(const DexFile& dex_file) {
+  return FindOpenedOatFileFromDexLocation(dex_file.GetLocation(),
+                                          dex_file.GetLocationChecksum());
+}
+
+const OatFile* ClassLinker::FindOpenedOatFileFromDexLocation(const std::string& dex_location,
+                                                             uint32_t dex_location_checksum) {
   for (size_t i = 0; i < oat_files_.size(); i++) {
     const OatFile* oat_file = oat_files_[i];
     DCHECK(oat_file != NULL);
-    if (oat_file->GetOatDexFile(dex_file.GetLocation(), false)) {
+    const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location, false);
+    if (oat_dex_file != NULL
+        && oat_dex_file->GetDexFileLocationChecksum() == dex_location_checksum) {
       return oat_file;
     }
   }
@@ -734,77 +743,103 @@
   int fd_;
 };
 
-const OatFile* ClassLinker::FindOatFileForDexFile(const DexFile& dex_file) {
+static const DexFile* FindDexFileInOatLocation(const std::string& dex_location,
+                                               uint32_t dex_location_checksum,
+                                               const std::string& oat_location) {
+  UniquePtr<OatFile> oat_file(OatFile::Open(oat_location, "", NULL));
+  if (oat_file.get() == NULL) {
+    return NULL;
+  }
+  const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location);
+  if (oat_dex_file == NULL) {
+    return NULL;
+  }
+  if (oat_dex_file->GetDexFileLocationChecksum() != dex_location_checksum) {
+    return NULL;
+  }
+  Runtime::Current()->GetClassLinker()->RegisterOatFile(*oat_file.release());
+  return oat_dex_file->OpenDexFile();
+}
+
+const DexFile* ClassLinker::FindOrCreateOatFileForDexLocation(const std::string& dex_location,
+                                                              const std::string& oat_location) {
+  uint32_t dex_location_checksum;
+  if (!DexFile::GetChecksum(dex_location, dex_location_checksum)) {
+    LOG(ERROR) << "Failed to compute checksum '" << dex_location << "'";
+    return NULL;
+  }
+
+  // Check if we already have an up-to-date output file
+  const DexFile* dex_file = FindDexFileInOatLocation(dex_location,
+                                                     dex_location_checksum,
+                                                     oat_location);
+  if (dex_file != NULL) {
+    return dex_file;
+  }
+
+  // Generate the output oat file for the dex file
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  UniquePtr<File> file(OS::OpenFile(oat_location.c_str(), true));
+  if (file.get() == NULL) {
+    LOG(ERROR) << "Failed to create oat file: " << oat_location;
+    return NULL;
+  }
+  if (!class_linker->GenerateOatFile(dex_location, file->Fd(), oat_location)) {
+    LOG(ERROR) << "Failed to generate oat file: " << oat_location;
+    return NULL;
+  }
+  // Open the oat from file descriptor we passed to GenerateOatFile
+  if (lseek(file->Fd(), 0, SEEK_SET) != 0) {
+    LOG(ERROR) << "Failed to seek to start of generated oat file: " << oat_location;
+    return NULL;
+  }
+  const OatFile* oat_file = OatFile::Open(*file.get(), oat_location, NULL);
+  if (oat_file == NULL) {
+    LOG(ERROR) << "Failed to open generated oat file: " << oat_location;
+    return NULL;
+  }
+  class_linker->RegisterOatFile(*oat_file);
+  const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location);
+  if (oat_dex_file == NULL) {
+    LOG(ERROR) << "Failed to find dex file in generated oat file: " << oat_location;
+    return NULL;
+  }
+  return oat_dex_file->OpenDexFile();
+}
+
+const DexFile* ClassLinker::FindDexFileInOatFileFromDexLocation(const std::string& dex_location) {
   MutexLock mu(dex_lock_);
-  const OatFile* open_oat_file = FindOpenedOatFileForDexFile(dex_file);
+
+  uint32_t dex_location_checksum;
+  if (!DexFile::GetChecksum(dex_location, dex_location_checksum)) {
+    LOG(WARNING) << "Failed to compute checksum: " << dex_location;
+    return NULL;
+  }
+
+  const OatFile* open_oat_file = FindOpenedOatFileFromDexLocation(dex_location, dex_location_checksum);
   if (open_oat_file != NULL) {
-    return open_oat_file;
+    return open_oat_file->GetOatDexFile(dex_location)->OpenDexFile();
   }
 
-  std::string oat_filename(OatFile::DexFilenameToOatFilename(dex_file.GetLocation()));
-  open_oat_file = FindOpenedOatFileFromOatLocation(oat_filename);
-  if (open_oat_file != NULL) {
-    return open_oat_file;
-  }
-
-  while (true) {
-    UniquePtr<const OatFile> oat_file(FindOatFileFromOatLocation(oat_filename));
-    if (oat_file.get() != NULL) {
-      const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
-      if (dex_file.GetHeader().checksum_ == oat_dex_file->GetDexFileChecksum()) {
-        return oat_file.release();
-      }
-      LOG(WARNING) << ".oat file " << oat_file->GetLocation()
-                   << " checksum mismatch with " << dex_file.GetLocation() << " --- regenerating";
-      if (TEMP_FAILURE_RETRY(unlink(oat_file->GetLocation().c_str())) != 0) {
-        PLOG(FATAL) << "Couldn't remove obsolete .oat file " << oat_file->GetLocation();
-      }
-      // Fall through...
+  // Look for an existing file first next to dex and in art-cache
+  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);
+    if (dex_location_checksum == oat_dex_file->GetDexFileLocationChecksum()) {
+      return oat_file->GetOatDexFile(dex_location)->OpenDexFile();
     }
-    // Try to generate oat file if it wasn't found or was obsolete.
-    // Note we can be racing with another runtime to do this.
-    std::string oat_cache_filename(GetArtCacheFilenameOrDie(oat_filename));
-    UniquePtr<LockedFd> locked_fd(LockedFd::CreateAndLock(oat_cache_filename, 0644));
-    if (locked_fd.get() == NULL) {
-      LOG(ERROR) << "Failed to create and lock oat file " << oat_cache_filename;
-      return NULL;
-    }
-    // Check to see if the fd we opened and locked matches the file in
-    // the filesystem.  If they don't, then somebody else unlinked ours
-    // and created a new file, and we need to use that one instead.  (If
-    // we caught them between the unlink and the create, we'll get an
-    // ENOENT from the file stat.)
-    struct stat fd_stat;
-    int fd_stat_result = fstat(locked_fd->GetFd(), &fd_stat);
-    if (fd_stat_result != 0) {
-      PLOG(ERROR) << "Failed to fstat file descriptor of oat file " << oat_cache_filename;
-      return NULL;
-    }
-    struct stat file_stat;
-    int file_stat_result = stat(oat_cache_filename.c_str(), &file_stat);
-    if (file_stat_result != 0
-        || fd_stat.st_dev != file_stat.st_dev
-        || fd_stat.st_ino != file_stat.st_ino) {
-      LOG(INFO) << "Opened oat file " << oat_cache_filename << " is stale; sleeping and retrying";
-      usleep(250 * 1000);  // if something is hosed, don't peg machine
-      continue;
-    }
-
-    // We have the correct file open and locked.  If the file size is
-    // zero, then it was just created by us and we can generate its
-    // contents. If not, someone else created it. Either way, we'll
-    // loop to retry opening the file.
-    if (fd_stat.st_size == 0) {
-      bool success = GenerateOatFile(dex_file.GetLocation(),
-                                     locked_fd->GetFd(),
-                                     oat_cache_filename);
-      if (!success) {
-        LOG(ERROR) << "Failed to generate oat file " << oat_cache_filename;
-        return NULL;
-      }
+    LOG(WARNING) << ".oat file " << oat_file->GetLocation()
+                 << " checksum ( " << std::hex << oat_dex_file->GetDexFileLocationChecksum()
+                 << ") mismatch with " << dex_location
+                 << " (" << std::hex << dex_location_checksum << ")--- regenerating";
+    if (TEMP_FAILURE_RETRY(unlink(oat_file->GetLocation().c_str())) != 0) {
+      PLOG(FATAL) << "Couldn't remove obsolete .oat file " << oat_file->GetLocation();
     }
   }
-  // Not reached
+  // Try to generate oat file if it wasn't found or was obsolete.
+  std::string oat_cache_filename(GetArtCacheFilenameOrDie(oat_filename));
+  return FindOrCreateOatFileForDexLocation(dex_location, oat_cache_filename);
 }
 
 const OatFile* ClassLinker::FindOpenedOatFileFromOatLocation(const std::string& oat_location) {
@@ -850,26 +885,6 @@
   return oat_file;
 }
 
-const DexFile* ClassLinker::FindDexFileFromDexLocation(const std::string& location) {
-  std::string oat_location(OatFile::DexFilenameToOatFilename(location));
-  const OatFile* oat_file = FindOatFileFromOatLocation(oat_location);
-  if (oat_file == NULL) {
-    return NULL;
-  }
-  const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(location);
-  if (oat_dex_file == NULL) {
-    return NULL;
-  }
-  const DexFile* dex_file = oat_dex_file->OpenDexFile();
-  if (dex_file == NULL) {
-    return NULL;
-  }
-  if (oat_dex_file->GetDexFileChecksum() != dex_file->GetHeader().checksum_) {
-    return NULL;
-  }
-  return dex_file;
-}
-
 void ClassLinker::InitFromImage() {
   VLOG(startup) << "ClassLinker::InitFromImage entering";
   CHECK(!init_done_);
@@ -903,7 +918,7 @@
                      << " from within oat file " << oat_file->GetLocation();
         }
 
-        CHECK_EQ(dex_file->GetHeader().checksum_, oat_dex_file->GetDexFileChecksum());
+        CHECK_EQ(dex_file->GetLocationChecksum(), oat_dex_file->GetDexFileLocationChecksum());
 
         AppendToBootClassPath(*dex_file, dex_cache);
       }
@@ -1402,17 +1417,15 @@
 
   UniquePtr<const OatFile::OatClass> oat_class;
   if (Runtime::Current()->IsStarted() && !ClassLoader::UseCompileTimeClassPath()) {
-    const OatFile* oat_file = FindOatFileForDexFile(dex_file);
-    if (oat_file != NULL) {
-      const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
-      if (oat_dex_file != NULL) {
-        uint32_t class_def_index;
-        bool found = dex_file.FindClassDefIndex(descriptor, class_def_index);
-        CHECK(found) << descriptor;
-        oat_class.reset(oat_dex_file->GetOatClass(class_def_index));
-        CHECK(oat_class.get() != NULL) << descriptor;
-      }
-    }
+    const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file);
+    CHECK(oat_file != NULL) << dex_file.GetLocation() << " " << descriptor;
+    const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
+    CHECK(oat_dex_file != NULL) << dex_file.GetLocation() << " " << descriptor;
+    uint32_t class_def_index;
+    bool found = dex_file.FindClassDefIndex(descriptor, class_def_index);
+    CHECK(found) << dex_file.GetLocation() << " " << descriptor;
+    oat_class.reset(oat_dex_file->GetOatClass(class_def_index));
+    CHECK(oat_class.get() != NULL) << dex_file.GetLocation() << " " << descriptor;
   }
   // Load methods.
   if (it.NumDirectMethods() != 0) {
@@ -1956,18 +1969,17 @@
   if (ClassLoader::UseCompileTimeClassPath()) {
     return false;
   }
-  const OatFile* oat_file = FindOatFileForDexFile(dex_file);
-  if (oat_file == NULL) {
-    return false;
-  }
+  const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file);
+  CHECK(oat_file != NULL) << dex_file.GetLocation() << " " << PrettyClass(klass);
   const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
-  CHECK(oat_dex_file != NULL) << PrettyClass(klass);
+  CHECK(oat_dex_file != NULL) << dex_file.GetLocation() << " " << PrettyClass(klass);
   const char* descriptor = ClassHelper(klass).GetDescriptor();
   uint32_t class_def_index;
   bool found = dex_file.FindClassDefIndex(descriptor, class_def_index);
-  CHECK(found) << descriptor;
+  CHECK(found) << dex_file.GetLocation() << " " << PrettyClass(klass) << " " << descriptor;
   UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file->GetOatClass(class_def_index));
-  CHECK(oat_class.get() != NULL) << descriptor;
+  CHECK(oat_class.get() != NULL)
+          << dex_file.GetLocation() << " " << PrettyClass(klass) << " " << descriptor;
   Class::Status status = oat_class->GetStatus();
   if (status == Class::kStatusVerified || status == Class::kStatusInitialized) {
     return true;
@@ -1999,7 +2011,9 @@
     // isn't a problem and this case shouldn't occur
     return false;
   }
-  LOG(FATAL) << "Unexpected class status: " << status;
+  LOG(FATAL) << "Unexpected class status: " << status
+             << " " << dex_file.GetLocation() << " " << PrettyClass(klass) << " " << descriptor;
+
   return false;
 }
 
diff --git a/src/class_linker.h b/src/class_linker.h
index f2b44a3..c49c03f 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -247,12 +247,18 @@
                        int oat_fd,
                        const std::string& oat_cache_filename);
 
-  // Find, possibily opening, an OatFile corresponding to a DexFile
-  const OatFile* FindOatFileForDexFile(const DexFile& dex_file);
   const OatFile* FindOatFileFromOatLocation(const std::string& location);
 
-  // Find a DexFile within an OatFile given a DexFile location
-  const DexFile* FindDexFileFromDexLocation(const std::string& location);
+  // Finds the oat file for a dex location, generating the oat file if
+  // it is missing or out of date. Returns the DexFile from within the
+  // created oat file.
+  const DexFile* FindOrCreateOatFileForDexLocation(const std::string& dex_location,
+                                                   const std::string& oat_location);
+  // Find a DexFile within an OatFile given a DexFile location. Note
+  // that this returns null if the location checksum of the DexFile
+  // does not match the OatFile.
+  const DexFile* FindDexFileInOatFileFromDexLocation(const std::string& location);
+
 
   // TODO: replace this with multiple methods that allocate the correct managed type.
   template <class T>
@@ -388,6 +394,8 @@
   }
 
   const OatFile* FindOpenedOatFileForDexFile(const DexFile& dex_file);
+  const OatFile* FindOpenedOatFileFromDexLocation(const std::string& dex_location,
+                                                  uint32_t dex_location_checksum);
   const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location);
 
   Method* CreateProxyConstructor(SirtRef<Class>& klass, Class* proxy_class);
diff --git a/src/dalvik_system_DexFile.cc b/src/dalvik_system_DexFile.cc
index 67cb49b..a255141 100644
--- a/src/dalvik_system_DexFile.cc
+++ b/src/dalvik_system_DexFile.cc
@@ -84,60 +84,22 @@
   if (sourceName.c_str() == NULL) {
     return 0;
   }
+  std::string source(sourceName.c_str());
   NullableScopedUtfChars outputName(env, javaOutputName);
   if (env->ExceptionCheck()) {
     return 0;
   }
   const DexFile* dex_file;
   if (outputName.c_str() == NULL) {
-    dex_file = Runtime::Current()->GetClassLinker()->FindDexFileFromDexLocation(sourceName.c_str());
-    if (dex_file == NULL) {
-      dex_file = DexFile::Open(sourceName.c_str(), "");
-    }
+    dex_file = Runtime::Current()->GetClassLinker()->FindDexFileInOatFileFromDexLocation(source);
   } else {
-    // Sanity check the arguments.
-    if (!IsValidZipFilename(sourceName.c_str()) || !IsValidDexFilename(outputName.c_str())) {
-      LOG(ERROR) << "Bad filenames extracting dex '" << outputName.c_str()
-                 << "' from zip '" << sourceName.c_str() << "'";
-      return 0;
-    }
-    // Generate the output oat file for the source dex file
-    ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-    UniquePtr<File> file(OS::OpenFile(outputName.c_str(), true));
-    if (file.get() == NULL) {
-      LOG(WARNING) << "unable to create oat file: " << outputName.c_str();
-      jniThrowExceptionFmt(env, "java/io/IOException", "unable to create oat file: %s",
-                           outputName.c_str());
-      return 0;
-    }
-    if (!class_linker->GenerateOatFile(sourceName.c_str(), file->Fd(), outputName.c_str())) {
-      LOG(WARNING) << "unable to generate oat file: " << outputName.c_str();
-      jniThrowExceptionFmt(env, "java/io/IOException", "unable to generate oat file: %s",
-                           outputName.c_str());
-      return 0;
-    }
-    UniquePtr<OatFile> oat_file(OatFile::Open(outputName.c_str(), "", NULL));
-    if (oat_file.get() == NULL) {
-      LOG(WARNING) << "unable to open oat file: " << outputName.c_str();
-      jniThrowExceptionFmt(env, "java/io/IOException", "unable to open oat file: %s",
-                           outputName.c_str());
-      return 0;
-    }
-    const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(sourceName.c_str());
-    if (oat_dex_file == NULL) {
-      LOG(WARNING) << "unable to find dex file in oat file: " << outputName.c_str();
-      jniThrowExceptionFmt(env, "java/io/IOException", "unable to find dex file in oat file: %s",
-                           outputName.c_str());
-      return 0;
-    }
-    Runtime::Current()->GetClassLinker()->RegisterOatFile(*oat_file.release());
-    dex_file = oat_dex_file->OpenDexFile();
+    std::string output(outputName.c_str());
+    dex_file = Runtime::Current()->GetClassLinker()->FindOrCreateOatFileForDexLocation(source, output);
   }
-
   if (dex_file == NULL) {
-    LOG(WARNING) << "unable to open dex file: " << sourceName.c_str();
+    LOG(WARNING) << "Failed to open dex file: " << source;
     jniThrowExceptionFmt(env, "java/io/IOException", "unable to open dex file: %s",
-                         sourceName.c_str());
+                         source.c_str());
     return 0;
   }
   return static_cast<jint>(reinterpret_cast<uintptr_t>(dex_file));
@@ -236,10 +198,26 @@
     }
   }
 
-  const DexFile* dex_file = class_linker->FindDexFileFromDexLocation(filename.c_str());
-  if (dex_file == NULL) {
+  uint32_t location_checksum;
+  if (!DexFile::GetChecksum(filename.c_str(), location_checksum)) {
     return JNI_TRUE;
   }
+
+  std::string oat_filename(OatFile::DexFilenameToOatFilename(filename.c_str()));
+  const OatFile* oat_file(class_linker->FindOatFileFromOatLocation(oat_filename));
+  if (oat_file == NULL) {
+    return JNI_TRUE;
+  }
+
+  const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(filename.c_str());
+  if (oat_dex_file == NULL) {
+    return JNI_TRUE;
+  }
+
+  if (location_checksum != oat_dex_file->GetDexFileLocationChecksum()) {
+    return JNI_TRUE;
+  }
+
   return JNI_FALSE;
 }
 
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index c4ca894..25c1d82 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -379,6 +379,21 @@
   return true;
 }
 
+void OpenDexFiles(const std::vector<const char*>& dex_filenames,
+                  std::vector<const DexFile*>& dex_files,
+                  const std::string& strip_location_prefix) {
+  for (size_t i = 0; i < dex_filenames.size(); i++) {
+    const char* dex_filename = dex_filenames[i];
+    const DexFile* dex_file = DexFile::Open(dex_filename, strip_location_prefix);
+    if (dex_file == NULL) {
+      fprintf(stderr, "could not open .dex from file %s\n", dex_filename);
+      exit(EXIT_FAILURE);
+    }
+    dex_files.push_back(dex_file);
+  }
+}
+
+
 int dex2oat(int argc, char** argv) {
   // Skip over argv[0].
   argv++;
@@ -609,7 +624,7 @@
       }
       dex_files.push_back(dex_file);
     } else {
-      DexFile::OpenDexFiles(dex_filenames, dex_files, host_prefix);
+      OpenDexFiles(dex_filenames, dex_files, host_prefix);
     }
   }
 
diff --git a/src/dex_file.cc b/src/dex_file.cc
index cb90e15..16fd407 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -60,18 +60,28 @@
                         reinterpret_cast<const DexFile::ClassDef*>(NULL));
 }
 
-void DexFile::OpenDexFiles(const std::vector<const char*>& dex_filenames,
-                           std::vector<const DexFile*>& dex_files,
-                           const std::string& strip_location_prefix) {
-  for (size_t i = 0; i < dex_filenames.size(); i++) {
-    const char* dex_filename = dex_filenames[i];
-    const DexFile* dex_file = Open(dex_filename, strip_location_prefix);
-    if (dex_file == NULL) {
-      fprintf(stderr, "could not open .dex from file %s\n", dex_filename);
-      exit(EXIT_FAILURE);
+bool DexFile::GetChecksum(const std::string& filename, uint32_t& checksum) {
+  if (IsValidZipFilename(filename)) {
+    UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(filename));
+    if (zip_archive.get() == NULL) {
+      return false;
     }
-    dex_files.push_back(dex_file);
+    UniquePtr<ZipEntry> zip_entry(zip_archive->Find(kClassesDex));
+    if (zip_entry.get() == NULL) {
+      return false;
+    }
+    checksum = zip_entry->GetCrc32();
+    return true;
   }
+  if (IsValidDexFilename(filename)) {
+    UniquePtr<const DexFile> dex_file(DexFile::OpenFile(filename, "", false));
+    if (dex_file.get() == NULL) {
+      return false;
+    }
+    checksum = dex_file->GetHeader().checksum_;
+    return true;
+  }
+  return false;
 }
 
 const DexFile* DexFile::Open(const std::string& filename,
@@ -82,7 +92,7 @@
   if (!IsValidDexFilename(filename)) {
     LOG(WARNING) << "Attempting to open dex file with unknown extension '" << filename << "'";
   }
-  return DexFile::OpenFile(filename, filename, strip_location_prefix);
+  return DexFile::OpenFile(filename, strip_location_prefix, true);
 }
 
 void DexFile::ChangePermissions(int prot) const {
@@ -103,9 +113,9 @@
 }
 
 const DexFile* DexFile::OpenFile(const std::string& filename,
-                                 const std::string& original_location,
-                                 const std::string& strip_location_prefix) {
-  std::string location(StripLocationPrefix(original_location, strip_location_prefix));
+                                 const std::string& strip_location_prefix,
+                                 bool verify) {
+  std::string location(StripLocationPrefix(filename, strip_location_prefix));
   if (location.empty()) {
     return NULL;
   }
@@ -134,14 +144,22 @@
     return NULL;
   }
   close(fd);
-  const DexFile* dex_file = OpenMemory(location, map.release());
+
+  if (map->Size() < sizeof(DexFile::Header)) {
+    LOG(ERROR) << "Failed to open dex file '" << filename << "' that is too short to have a header";
+    return NULL;
+  }
+
+  const Header* dex_header = reinterpret_cast<const Header*>(map->Begin());
+
+  const DexFile* dex_file = OpenMemory(location, dex_header->checksum_, map.release());
   if (dex_file == NULL) {
-    LOG(ERROR) << "Failed to open dex file '" << location << "' from memory";
+    LOG(ERROR) << "Failed to open dex file '" << filename << "' from memory";
     return NULL;
   }
 
   if (!DexFileVerifier::Verify(dex_file, dex_file->Begin(), dex_file->Size())) {
-    LOG(ERROR) << "Failed to verify dex file '" << location << "'";
+    LOG(ERROR) << "Failed to verify dex file '" << filename << "'";
     return NULL;
   }
 
@@ -189,7 +207,7 @@
     return NULL;
   }
 
-  const DexFile* dex_file = OpenMemory(location, map.release());
+  const DexFile* dex_file = OpenMemory(location, zip_entry->GetCrc32(), map.release());
   if (dex_file == NULL) {
     LOG(ERROR) << "Failed to open dex file '" << location << "' from memory";
     return NULL;
@@ -206,9 +224,10 @@
 const DexFile* DexFile::OpenMemory(const byte* base,
                                    size_t size,
                                    const std::string& location,
+                                   uint32_t location_checksum,
                                    MemMap* mem_map) {
   CHECK_ALIGNED(base, 4); // various dex file structures must be word aligned
-  UniquePtr<DexFile> dex_file(new DexFile(base, size, location, mem_map));
+  UniquePtr<DexFile> dex_file(new DexFile(base, size, location, location_checksum, mem_map));
   if (!dex_file->Init()) {
     return NULL;
   } else {
diff --git a/src/dex_file.h b/src/dex_file.h
index d883f98..5d63408 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -54,7 +54,7 @@
   // Raw header_item.
   struct Header {
     uint8_t magic_[8];
-    uint32_t checksum_;
+    uint32_t checksum_; // See also location_checksum_
     uint8_t signature_[kSha1DigestSize];
     uint32_t file_size_;  // size of entire file
     uint32_t header_size_;  // offset to start of next section
@@ -314,18 +314,20 @@
   static ClassPathEntry FindInClassPath(const StringPiece& descriptor,
                                         const ClassPath& class_path);
 
-  // Opens a collection of .dex files
-  static void OpenDexFiles(const std::vector<const char*>& dex_filenames,
-                           std::vector<const DexFile*>& dex_files,
-                           const std::string& strip_location_prefix);
+  // Returns the checksum of a file for comparison with GetLocationChecksum().
+  // For .dex files, this is the header checksum.
+  // For zip files, this is the classes.dex zip entry CRC32 checksum.
+  // Return true if the checksum could be found, false otherwise.
+  static bool GetChecksum(const std::string& filename, uint32_t& checksum);
 
   // Opens .dex file, guessing the container format based on file extension
   static const DexFile* Open(const std::string& filename,
                              const std::string& strip_location_prefix);
 
   // Opens .dex file, backed by existing memory
-  static const DexFile* Open(const uint8_t* base, size_t size, const std::string& location) {
-    return OpenMemory(base, size, location, NULL);
+  static const DexFile* Open(const uint8_t* base, size_t size,
+                             const std::string& location, uint32_t location_checksum) {
+    return OpenMemory(base, size, location, location_checksum, NULL);
   }
 
   // Opens .dex file from the classes.dex in a zip archive
@@ -338,6 +340,12 @@
     return location_;
   }
 
+  // For DexFiles directly from .dex files, this is the checksum from the DexFile::Header.
+  // For DexFiles opened from a zip files, this will be the ZipEntry CRC32 of classes.dex.
+  uint32_t GetLocationChecksum() const {
+    return location_checksum_;
+  }
+
   // Returns a com.android.dex.Dex object corresponding to the mapped-in dex file.
   // Used by managed code to implement annotations.
   jobject GetDexObject(JNIEnv* env) const;
@@ -765,8 +773,8 @@
 
   // Opens a .dex file
   static const DexFile* OpenFile(const std::string& filename,
-                                 const std::string& original_location,
-                                 const std::string& strip_location_prefix);
+                                 const std::string& strip_location_prefix,
+                                 bool verify);
 
   // Opens a dex file from within a .jar, .zip, or .apk file
   static const DexFile* OpenZip(const std::string& filename,
@@ -774,10 +782,12 @@
 
   // Opens a .dex file at the given address backed by a MemMap
   static const DexFile* OpenMemory(const std::string& location,
+                                   uint32_t location_checksum,
                                    MemMap* mem_map) {
     return OpenMemory(mem_map->Begin(),
                       mem_map->Size(),
                       location,
+                      location_checksum,
                       mem_map);
   }
 
@@ -785,12 +795,16 @@
   static const DexFile* OpenMemory(const byte* dex_file,
                                    size_t size,
                                    const std::string& location,
+                                   uint32_t location_checksum,
                                    MemMap* mem_map);
 
-  DexFile(const byte* base, size_t size, const std::string& location, MemMap* mem_map)
+  DexFile(const byte* base, size_t size,
+          const std::string& location, uint32_t location_checksum,
+          MemMap* mem_map)
       : begin_(base),
         size_(size),
         location_(location),
+        location_checksum_(location_checksum),
         mem_map_(mem_map),
         dex_object_lock_("a dex_object_lock_"),
         dex_object_(NULL),
@@ -845,6 +859,8 @@
   // path to DexCache::GetLocation when loading from an image.
   const std::string location_;
 
+  const uint32_t location_checksum_;
+
   // Manages the underlying memory allocation.
   UniquePtr<MemMap> mem_map_;
 
diff --git a/src/dex_file_test.cc b/src/dex_file_test.cc
index 1e876ba..f075fea 100644
--- a/src/dex_file_test.cc
+++ b/src/dex_file_test.cc
@@ -81,6 +81,19 @@
   EXPECT_EQ(256U, header.class_defs_off_);
   EXPECT_EQ(584U, header.data_size_);
   EXPECT_EQ(320U, header.data_off_);
+
+  EXPECT_EQ(header.checksum_, raw->GetLocationChecksum());
+}
+
+TEST_F(DexFileTest, GetLocationChecksum) {
+  const DexFile* raw(OpenTestDexFile("Main"));
+  EXPECT_NE(raw->GetHeader().checksum_, raw->GetLocationChecksum());
+}
+
+TEST_F(DexFileTest, GetChecksum) {
+  uint32_t checksum;
+  EXPECT_TRUE(DexFile::GetChecksum(GetLibCoreDexFileName(), checksum));
+  EXPECT_EQ(java_lang_dex_file_->GetLocationChecksum(), checksum);
 }
 
 TEST_F(DexFileTest, ClassDefs) {
diff --git a/src/oat_file.cc b/src/oat_file.cc
index 4bcd967..cf8bafe 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -34,15 +34,24 @@
 OatFile* OatFile::Open(const std::string& filename,
                        const std::string& strip_location_prefix,
                        byte* requested_base) {
-  StringPiece location = filename;
+  StringPiece location(filename);
   if (!location.starts_with(strip_location_prefix)) {
     LOG(ERROR) << filename << " does not start with " << strip_location_prefix;
     return NULL;
   }
   location.remove_prefix(strip_location_prefix.size());
+  UniquePtr<File> file(OS::OpenFile(filename.c_str(), false));
+  if (file.get() == NULL) {
+    return false;
+  }
+  return Open(*file.get(), location.ToString(), requested_base);
+}
 
-  UniquePtr<OatFile> oat_file(new OatFile(location.ToString()));
-  bool success = oat_file->Read(filename, requested_base);
+OatFile* OatFile::Open(File& file,
+                       const std::string& location,
+                       byte* requested_base) {
+  UniquePtr<OatFile> oat_file(new OatFile(location));
+  bool success = oat_file->Read(file, requested_base);
   if (!success) {
     return NULL;
   }
@@ -55,81 +64,77 @@
   STLDeleteValues(&oat_dex_files_);
 }
 
-bool OatFile::Read(const std::string& filename, byte* requested_base) {
-  UniquePtr<File> file(OS::OpenFile(filename.c_str(), false));
-  if (file.get() == NULL) {
-    return false;
-  }
+bool OatFile::Read(File& file, byte* requested_base) {
 
   OatHeader oat_header;
-  bool success = file->ReadFully(&oat_header, sizeof(oat_header));
+  bool success = file.ReadFully(&oat_header, sizeof(oat_header));
   if (!success || !oat_header.IsValid()) {
-    LOG(WARNING) << "Invalid oat header " << filename;
+    LOG(WARNING) << "Invalid oat header " << GetLocation();
     return false;
   }
 
   int flags = MAP_PRIVATE | ((requested_base != NULL) ? MAP_FIXED : 0);
   UniquePtr<MemMap> map(MemMap::MapFileAtAddress(requested_base,
-                                                 file->Length(),
+                                                 file.Length(),
                                                  PROT_READ,
                                                  flags,
-                                                 file->Fd(),
+                                                 file.Fd(),
                                                  0));
   if (map.get() == NULL) {
-    LOG(WARNING) << "Failed to map oat file " << filename;
+    LOG(WARNING) << "Failed to map oat file " << GetLocation();
     return false;
   }
   CHECK(requested_base == 0 || requested_base == map->Begin())
-          << filename << " " << reinterpret_cast<void*>(map->Begin());
-  DCHECK_EQ(0, memcmp(&oat_header, map->Begin(), sizeof(OatHeader))) << filename;
+          << GetLocation() << " " << reinterpret_cast<void*>(map->Begin());
+  DCHECK_EQ(0, memcmp(&oat_header, map->Begin(), sizeof(OatHeader))) << GetLocation();
 
   off_t code_offset = oat_header.GetExecutableOffset();
-  if (code_offset < file->Length()) {
+  if (code_offset < file.Length()) {
     byte* code_address = map->Begin() + code_offset;
-    size_t code_length = file->Length() - code_offset;
+    size_t code_length = file.Length() - code_offset;
     if (mprotect(code_address, code_length, PROT_READ | PROT_EXEC) != 0) {
-      PLOG(ERROR) << "Failed to make oat code executable in " << filename;
+      PLOG(ERROR) << "Failed to make oat code executable in " << GetLocation();
       return false;
     }
   } else {
     // its possible to have no code if all the methods were abstract, native, etc
-    DCHECK_EQ(code_offset, RoundUp(file->Length(), kPageSize)) << filename;
+    DCHECK_EQ(code_offset, RoundUp(file.Length(), kPageSize)) << GetLocation();
   }
 
   const byte* oat = map->Begin();
 
   oat += sizeof(OatHeader);
-  CHECK_LE(oat, map->End()) << filename;
+  CHECK_LE(oat, map->End()) << GetLocation();
   for (size_t i = 0; i < oat_header.GetDexFileCount(); i++) {
     size_t dex_file_location_size = *reinterpret_cast<const uint32_t*>(oat);
-    CHECK_GT(dex_file_location_size, 0U) << filename;
+    CHECK_GT(dex_file_location_size, 0U) << GetLocation();
     oat += sizeof(dex_file_location_size);
-    CHECK_LT(oat, map->End()) << filename;
+    CHECK_LT(oat, map->End()) << GetLocation();
 
     const char* dex_file_location_data = reinterpret_cast<const char*>(oat);
     oat += dex_file_location_size;
-    CHECK_LT(oat, map->End()) << filename;
+    CHECK_LT(oat, map->End()) << GetLocation();
 
     std::string dex_file_location(dex_file_location_data, dex_file_location_size);
 
     uint32_t dex_file_checksum = *reinterpret_cast<const uint32_t*>(oat);
     oat += sizeof(dex_file_checksum);
-    CHECK_LT(oat, map->End()) << filename;
+    CHECK_LT(oat, map->End()) << GetLocation();
 
     uint32_t dex_file_offset = *reinterpret_cast<const uint32_t*>(oat);
-    CHECK_GT(dex_file_offset, 0U) << filename;
-    CHECK_LT(dex_file_offset, static_cast<uint32_t>(file->Length())) << filename;
+    CHECK_GT(dex_file_offset, 0U) << GetLocation();
+    CHECK_LT(dex_file_offset, static_cast<uint32_t>(file.Length())) << GetLocation();
     oat += sizeof(dex_file_offset);
-    CHECK_LT(oat, map->End()) << filename;
+    CHECK_LT(oat, map->End()) << GetLocation();
 
     uint8_t* dex_file_pointer = map->Begin() + dex_file_offset;
-    CHECK(DexFile::IsMagicValid(dex_file_pointer)) << filename << " " << dex_file_pointer;
-    CHECK(DexFile::IsVersionValid(dex_file_pointer)) << filename << " "  << dex_file_pointer;
+    CHECK(DexFile::IsMagicValid(dex_file_pointer)) << GetLocation() << " " << dex_file_pointer;
+    CHECK(DexFile::IsVersionValid(dex_file_pointer)) << GetLocation() << " "  << dex_file_pointer;
     const DexFile::Header* header = reinterpret_cast<const DexFile::Header*>(dex_file_pointer);
     const uint32_t* methods_offsets_pointer = reinterpret_cast<const uint32_t*>(oat);
 
     oat += (sizeof(*methods_offsets_pointer) * header->class_defs_size_);
-    CHECK_LE(oat, map->End()) << filename;
+    CHECK_LE(oat, map->End()) << GetLocation();
 
     oat_dex_files_[dex_file_location] = new OatDexFile(this,
                                                        dex_file_location,
@@ -178,12 +183,12 @@
 
 OatFile::OatDexFile::OatDexFile(const OatFile* oat_file,
                                 const std::string& dex_file_location,
-                                uint32_t dex_file_checksum,
+                                uint32_t dex_file_location_checksum,
                                 byte* dex_file_pointer,
                                 const uint32_t* oat_class_offsets_pointer)
     : oat_file_(oat_file),
       dex_file_location_(dex_file_location),
-      dex_file_checksum_(dex_file_checksum),
+      dex_file_location_checksum_(dex_file_location_checksum),
       dex_file_pointer_(dex_file_pointer),
       oat_class_offsets_pointer_(oat_class_offsets_pointer) {}
 
@@ -191,7 +196,7 @@
 
 const DexFile* OatFile::OatDexFile::OpenDexFile() const {
   size_t length = reinterpret_cast<const DexFile::Header*>(dex_file_pointer_)->file_size_;
-  return DexFile::Open(dex_file_pointer_, length, dex_file_location_);
+  return DexFile::Open(dex_file_pointer_, length, dex_file_location_, dex_file_location_checksum_);
 }
 
 const OatFile::OatClass* OatFile::OatDexFile::GetOatClass(uint32_t class_def_index) const {
diff --git a/src/oat_file.h b/src/oat_file.h
index 4740ae7..2895d74 100644
--- a/src/oat_file.h
+++ b/src/oat_file.h
@@ -39,6 +39,11 @@
                        const std::string& strip_location_prefix,
                        byte* requested_base);
 
+  // Open an oat file from an already opened File with the given location.
+  static OatFile* Open(File& file,
+                       const std::string& location,
+                       byte* requested_base);
+
   ~OatFile();
 
   const std::string& GetLocation() const {
@@ -166,8 +171,8 @@
       return dex_file_location_;
     }
 
-    uint32_t GetDexFileChecksum() const {
-      return dex_file_checksum_;
+    uint32_t GetDexFileLocationChecksum() const {
+      return dex_file_location_checksum_;
     }
 
     ~OatDexFile();
@@ -180,7 +185,7 @@
 
     const OatFile* oat_file_;
     std::string dex_file_location_;
-    uint32_t dex_file_checksum_;
+    uint32_t dex_file_location_checksum_;
     const byte* dex_file_pointer_;
     const uint32_t* oat_class_offsets_pointer_;
 
@@ -198,7 +203,7 @@
 
  private:
   explicit OatFile(const std::string& filename);
-  bool Read(const std::string& filename, byte* requested_base);
+  bool Read(File& file, byte* requested_base);
 
   const byte* Begin() const;
   const byte* End() const;
diff --git a/src/oat_test.cc b/src/oat_test.cc
index d64f810..0fd64ff 100644
--- a/src/oat_test.cc
+++ b/src/oat_test.cc
@@ -47,6 +47,7 @@
 
   const DexFile& dex_file = *java_lang_dex_file_.get();
   const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
+  CHECK_EQ(dex_file.GetLocationChecksum(), oat_dex_file->GetDexFileLocationChecksum());
   for (size_t i = 0; i < dex_file.NumClassDefs(); i++) {
     const DexFile::ClassDef& class_def = dex_file.GetClassDef(i);
     const byte* class_data = dex_file.GetClassData(class_def);
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index 94281c9..e4c8135 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -680,7 +680,7 @@
   const std::string& location(dex_file.GetLocation());
   dex_file_location_size_ = location.size();
   dex_file_location_data_ = reinterpret_cast<const uint8_t*>(location.data());
-  dex_file_checksum_ = dex_file.GetHeader().checksum_;
+  dex_file_location_checksum_ = dex_file.GetLocationChecksum();
   dex_file_offset_ = 0;
   methods_offsets_.resize(dex_file.NumClassDefs());
 }
@@ -688,7 +688,7 @@
 size_t OatWriter::OatDexFile::SizeOf() const {
   return sizeof(dex_file_location_size_)
           + dex_file_location_size_
-          + sizeof(dex_file_checksum_)
+          + sizeof(dex_file_location_checksum_)
           + sizeof(dex_file_offset_)
           + (sizeof(methods_offsets_[0]) * methods_offsets_.size());
 }
@@ -696,7 +696,7 @@
 void OatWriter::OatDexFile::UpdateChecksum(OatHeader& oat_header) const {
   oat_header.UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_));
   oat_header.UpdateChecksum(dex_file_location_data_, dex_file_location_size_);
-  oat_header.UpdateChecksum(&dex_file_checksum_, sizeof(dex_file_checksum_));
+  oat_header.UpdateChecksum(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_));
   oat_header.UpdateChecksum(&dex_file_offset_, sizeof(dex_file_offset_));
   oat_header.UpdateChecksum(&methods_offsets_[0],
                             sizeof(methods_offsets_[0]) * methods_offsets_.size());
@@ -711,8 +711,8 @@
     PLOG(ERROR) << "Failed to write dex file location data to " << file->name();
     return false;
   }
-  if (!file->WriteFully(&dex_file_checksum_, sizeof(dex_file_checksum_))) {
-    PLOG(ERROR) << "Failed to write dex file checksum to " << file->name();
+  if (!file->WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
+    PLOG(ERROR) << "Failed to write dex file location checksum to " << file->name();
     return false;
   }
   if (!file->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
diff --git a/src/oat_writer.h b/src/oat_writer.h
index 93e4209..abb1f2e 100644
--- a/src/oat_writer.h
+++ b/src/oat_writer.h
@@ -115,7 +115,7 @@
     // data to write
     uint32_t dex_file_location_size_;
     const uint8_t* dex_file_location_data_;
-    uint32_t dex_file_checksum_;
+    uint32_t dex_file_location_checksum_;
     uint32_t dex_file_offset_;
     std::vector<uint32_t> methods_offsets_;
 
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 60b1a3b..4ea2af1 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -127,7 +127,7 @@
       os << " (" << dex_file_location << ")";
     }
     os << "\n";
-    os << StringPrintf("checksum: %08x\n", oat_dex_file.GetDexFileChecksum());
+    os << StringPrintf("checksum: %08x\n", oat_dex_file.GetDexFileLocationChecksum());
     const DexFile* dex_file = DexFile::Open(dex_file_location, "");
     if (dex_file == NULL) {
       os << "NOT FOUND\n\n";