Throw IOException at source of failing to open a dex file.

Before is:
java.lang.ClassNotFoundException: Didn't find class "GCBench" on path: DexPathList[[zip file "/disk2/dalvik-dev/out/host/linux-x86/framework/GCBench.jar"],nativeLibraryDirectories=[/disk2/dalvik-dev/out/host/linux-x86/lib]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
        Suppressed: java.lang.ClassNotFoundException: GCBench
                at java.lang.Class.classForName(Native Method)
                at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
                at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
                at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
                ... 1 more
        Caused by: java.lang.NoClassDefFoundError: Class "LGCBench;" not found
                ... 5 more
And after is:
java.lang.ClassNotFoundException: Didn't find class "GCBench" on path: DexPathList[[zip file "/disk2/dalvik-dev/out/host/linux-x86/framework/GCBench.jar"],nativeLibraryDirectories=[/disk2/dalvik-dev/out/host/linux-x86/lib]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
        Suppressed: java.io.IOException: Zip archive '/disk2/dalvik-dev/out/host/linux-x86/framework/GCBench.jar' doesn't contain classes.dex
                at dalvik.system.DexFile.openDexFile(Native Method)
                at dalvik.system.DexFile.<init>(DexFile.java:80)
                at dalvik.system.DexFile.<init>(DexFile.java:59)
                at dalvik.system.DexPathList.loadDexFile(DexPathList.java:268)
                at dalvik.system.DexPathList.makeDexElements(DexPathList.java:235)
                at dalvik.system.DexPathList.<init>(DexPathList.java:113)
                at dalvik.system.BaseDexClassLoader.<init>(BaseDexClassLoader.java:48)
                at dalvik.system.PathClassLoader.<init>(PathClassLoader.java:38)
                at java.lang.ClassLoader.createSystemClassLoader(ClassLoader.java:128)
                at java.lang.ClassLoader.access$000(ClassLoader.java:65)
                at java.lang.ClassLoader$SystemClassLoader.<clinit>(ClassLoader.java:81)
                at java.lang.ClassLoader.getSystemClassLoader(ClassLoader.java:137)
        Suppressed: java.lang.ClassNotFoundException: GCBench
                at java.lang.Class.classForName(Native Method)
                at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
                at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
                at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
                ... 1 more
        Caused by: java.lang.NoClassDefFoundError: Class "LGCBench;" not found
                ... 5 more

Also, move dex file verifier messages out of logs.
In the process the ClassLinker::dex_lock_ needed tidying to cover a smaller
scope. Bug 11301553.

Change-Id: I80058652e11e7ea63457cc01a0cb48afe1c15543
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index aa5f2bf..eb42e0a 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -540,9 +540,10 @@
   }
 }
 
-bool ClassLinker::GenerateOatFile(const std::string& dex_filename,
+bool ClassLinker::GenerateOatFile(const char* dex_filename,
                                   int oat_fd,
-                                  const std::string& oat_cache_filename) {
+                                  const char* oat_cache_filename) {
+  Locks::mutator_lock_->AssertNotHeld(Thread::Current());  // Avoid starving GC.
   std::string dex2oat_string(GetAndroidRoot());
   dex2oat_string += (kIsDebugBuild ? "/bin/dex2oatd" : "/bin/dex2oat");
   const char* dex2oat = dex2oat_string.c_str();
@@ -567,7 +568,8 @@
   const char* oat_location_option = oat_location_option_string.c_str();
 
   std::string oat_compiler_filter_string("-compiler-filter:");
-  switch (Runtime::Current()->GetCompilerFilter()) {
+  Runtime::CompilerFilter filter = Runtime::Current()->GetCompilerFilter();
+  switch (filter) {
     case Runtime::kInterpretOnly:
       oat_compiler_filter_string += "interpret-only";
       break;
@@ -584,7 +586,7 @@
       oat_compiler_filter_string += "everything";
       break;
     default:
-      LOG(FATAL) << "Unexpected case.";
+      LOG(FATAL) << "Unexpected case: " << filter;
   }
   const char* oat_compiler_filter_option = oat_compiler_filter_string.c_str();
 
@@ -633,49 +635,55 @@
     int status;
     pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
     if (got_pid != pid) {
-      PLOG(ERROR) << "waitpid failed: wanted " << pid << ", got " << got_pid;
+      ScopedObjectAccess soa(Thread::Current());
+      ThrowIOException("Failed to create oat file. Waitpid failed: wanted %d, got %d", pid,
+                       got_pid);
       return false;
     }
     if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
-      LOG(ERROR) << dex2oat << " failed with dex-file=" << dex_filename;
+      ScopedObjectAccess soa(Thread::Current());
+      ThrowIOException("Failed to create oat file. %s failed with dex-file '%s'", dex2oat,
+                       dex_filename);
       return false;
     }
   }
   return true;
 }
 
-void ClassLinker::RegisterOatFile(const OatFile& oat_file) {
+const OatFile* ClassLinker::RegisterOatFile(const OatFile* oat_file) {
   WriterMutexLock mu(Thread::Current(), dex_lock_);
-  RegisterOatFileLocked(oat_file);
-}
-
-void ClassLinker::RegisterOatFileLocked(const OatFile& oat_file) {
-  dex_lock_.AssertExclusiveHeld(Thread::Current());
-  if (kIsDebugBuild) {
-    for (size_t i = 0; i < oat_files_.size(); ++i) {
-      CHECK_NE(&oat_file, oat_files_[i]) << oat_file.GetLocation();
+  for (size_t i = 0; i < oat_files_.size(); ++i) {
+    if (UNLIKELY(oat_file->GetLocation() == oat_files_[i]->GetLocation())) {
+      VLOG(class_linker) << "Attempt to register oat file that's already registered: "
+          << oat_file->GetLocation();
+      for (size_t j = i; j < oat_files_.size(); ++j) {
+        CHECK_NE(oat_file, oat_files_[j]) << "Attempt to re-register dex file.";
+      }
+      delete oat_file;
+      return oat_files_[i];
     }
   }
-  VLOG(class_linker) << "Registering " << oat_file.GetLocation();
-  oat_files_.push_back(&oat_file);
+  VLOG(class_linker) << "Registering " << oat_file->GetLocation();
+  oat_files_.push_back(oat_file);
+  return oat_file;
 }
 
 OatFile& ClassLinker::GetImageOatFile(gc::space::ImageSpace* space) {
   VLOG(startup) << "ClassLinker::GetImageOatFile entering";
-  OatFile& oat_file = space->ReleaseOatFile();
-  WriterMutexLock mu(Thread::Current(), dex_lock_);
-  RegisterOatFileLocked(oat_file);
+  OatFile* oat_file = space->ReleaseOatFile();
+  CHECK_EQ(RegisterOatFile(oat_file), oat_file);
   VLOG(startup) << "ClassLinker::GetImageOatFile exiting";
-  return oat_file;
+  return *oat_file;
 }
 
 const OatFile* ClassLinker::FindOpenedOatFileForDexFile(const DexFile& dex_file) {
-  ReaderMutexLock mu(Thread::Current(), dex_lock_);
-  return FindOpenedOatFileFromDexLocation(dex_file.GetLocation(), dex_file.GetLocationChecksum());
+  return FindOpenedOatFileFromDexLocation(dex_file.GetLocation().c_str(),
+                                          dex_file.GetLocationChecksum());
 }
 
-const OatFile* ClassLinker::FindOpenedOatFileFromDexLocation(const std::string& dex_location,
+const OatFile* ClassLinker::FindOpenedOatFileFromDexLocation(const char* dex_location,
                                                              uint32_t dex_location_checksum) {
+  ReaderMutexLock mu(Thread::Current(), dex_lock_);
   for (size_t i = 0; i < oat_files_.size(); i++) {
     const OatFile* oat_file = oat_files_[i];
     DCHECK(oat_file != NULL);
@@ -689,82 +697,83 @@
   return NULL;
 }
 
-const DexFile* ClassLinker::FindDexFileInOatLocation(const std::string& dex_location,
+const DexFile* ClassLinker::FindDexFileInOatLocation(const char* dex_location,
                                                      uint32_t dex_location_checksum,
-                                                     const std::string& oat_location) {
+                                                     const char* oat_location,
+                                                     std::string* error_msg) {
   UniquePtr<OatFile> oat_file(OatFile::Open(oat_location, oat_location, NULL,
-                                            !Runtime::Current()->IsCompiler()));
-  if (oat_file.get() == NULL) {
-    VLOG(class_linker) << "Failed to find existing oat file at " << oat_location;
-    return NULL;
+                                            !Runtime::Current()->IsCompiler(),
+                                            error_msg));
+  if (oat_file.get() == nullptr) {
+    *error_msg = StringPrintf("Failed to find existing oat file at %s: %s", oat_location,
+                              error_msg->c_str());
+    return nullptr;
   }
   Runtime* runtime = Runtime::Current();
   const ImageHeader& image_header = runtime->GetHeap()->GetImageSpace()->GetImageHeader();
   uint32_t expected_image_oat_checksum = image_header.GetOatChecksum();
   uint32_t actual_image_oat_checksum = oat_file->GetOatHeader().GetImageFileLocationOatChecksum();
   if (expected_image_oat_checksum != actual_image_oat_checksum) {
-    VLOG(class_linker) << "Failed to find oat file at " << oat_location
-                       << " with expected image oat checksum of " << expected_image_oat_checksum
-                       << ", found " << actual_image_oat_checksum;
-    return NULL;
+    *error_msg = StringPrintf("Failed to find oat file at '%s' with expected image oat checksum of "
+                              "0x%x, found 0x%x", oat_location, expected_image_oat_checksum,
+                              actual_image_oat_checksum);
+    return nullptr;
   }
 
   uint32_t expected_image_oat_offset = reinterpret_cast<uint32_t>(image_header.GetOatDataBegin());
   uint32_t actual_image_oat_offset = oat_file->GetOatHeader().GetImageFileLocationOatDataBegin();
   if (expected_image_oat_offset != actual_image_oat_offset) {
-    VLOG(class_linker) << "Failed to find oat file at " << oat_location
-                       << " with expected image oat offset " << expected_image_oat_offset
-                       << ", found " << actual_image_oat_offset;
-    return NULL;
+    *error_msg = StringPrintf("Failed to find oat file at '%s' with expected image oat offset %ud, "
+                              "found %ud", oat_location, expected_image_oat_offset,
+                              actual_image_oat_offset);
+    return nullptr;
   }
-  const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location, &dex_location_checksum);
-  if (oat_dex_file == NULL) {
-    VLOG(class_linker) << "Failed to find oat file at " << oat_location << " containing " << dex_location;
-    return NULL;
+  // TODO: this registers the oat file now as we may use the oat_dex_file later and we want the
+  //       intern behavior of RegisterOatFile. However, if we take an early return we could remove
+  //       the oat file.
+  const OatFile* opened_oat_file = RegisterOatFile(oat_file.release());
+  const OatFile::OatDexFile* oat_dex_file = opened_oat_file->GetOatDexFile(dex_location,
+                                                                           &dex_location_checksum);
+  if (oat_dex_file == nullptr) {
+    *error_msg = StringPrintf("Failed to find oat file at '%s' containing '%s'", oat_location,
+                              dex_location);
+    return nullptr;
   }
   uint32_t expected_dex_checksum = dex_location_checksum;
   uint32_t actual_dex_checksum = oat_dex_file->GetDexFileLocationChecksum();
   if (expected_dex_checksum != actual_dex_checksum) {
-    VLOG(class_linker) << "Failed to find oat file at " << oat_location
-                       << " with expected dex checksum of " << expected_dex_checksum
-                       << ", found " << actual_dex_checksum;
-    return NULL;
+    *error_msg = StringPrintf("Failed to find oat file at '%s' with expected dex checksum of 0x%x, "
+                              "found 0x%x", oat_location, expected_dex_checksum,
+                              actual_dex_checksum);
+    return nullptr;
   }
-  RegisterOatFileLocked(*oat_file.release());
-  return oat_dex_file->OpenDexFile();
-}
-
-const DexFile* ClassLinker::FindOrCreateOatFileForDexLocation(const std::string& dex_location,
-                                                              uint32_t dex_location_checksum,
-                                                              const std::string& oat_location) {
-  WriterMutexLock mu(Thread::Current(), dex_lock_);
-  return FindOrCreateOatFileForDexLocationLocked(dex_location, dex_location_checksum, oat_location);
+  return oat_dex_file->OpenDexFile(error_msg);
 }
 
 class ScopedFlock {
  public:
   ScopedFlock() {}
 
-  bool Init(const std::string& filename) {
+  bool Init(const char* filename, std::string* error_msg) {
     while (true) {
-      file_.reset(OS::OpenFileWithFlags(filename.c_str(), O_CREAT | O_RDWR));
+      file_.reset(OS::OpenFileWithFlags(filename, O_CREAT | O_RDWR));
       if (file_.get() == NULL) {
-        LOG(ERROR) << "Failed to open file: " << filename;
+        *error_msg = StringPrintf("Failed to open file '%s'", filename);
         return false;
       }
       int flock_result = TEMP_FAILURE_RETRY(flock(file_->Fd(), LOCK_EX));
       if (flock_result != 0) {
-        PLOG(ERROR) << "Failed to lock file: " << filename;
+        *error_msg = StringPrintf("Failed to lock file '%s': %s", filename, strerror(errno));
         return false;
       }
       struct stat fstat_stat;
       int fstat_result = TEMP_FAILURE_RETRY(fstat(file_->Fd(), &fstat_stat));
       if (fstat_result != 0) {
-        PLOG(ERROR) << "Failed to fstat: " << filename;
+        *error_msg = StringPrintf("Failed to fstat file '%s': %s", filename, strerror(errno));
         return false;
       }
       struct stat stat_stat;
-      int stat_result = TEMP_FAILURE_RETRY(stat(filename.c_str(), &stat_stat));
+      int stat_result = TEMP_FAILURE_RETRY(stat(filename, &stat_stat));
       if (stat_result != 0) {
         PLOG(WARNING) << "Failed to stat, will retry: " << filename;
         // ENOENT can happen if someone racing with us unlinks the file we created so just retry.
@@ -795,49 +804,54 @@
   DISALLOW_COPY_AND_ASSIGN(ScopedFlock);
 };
 
-const DexFile* ClassLinker::FindOrCreateOatFileForDexLocationLocked(const std::string& dex_location,
-                                                                    uint32_t dex_location_checksum,
-                                                                    const std::string& oat_location) {
+const DexFile* ClassLinker::FindOrCreateOatFileForDexLocation(const char* dex_location,
+                                                              uint32_t dex_location_checksum,
+                                                              const char* oat_location,
+                                                              std::string* error_msg) {
   // We play a locking game here so that if two different processes
   // race to generate (or worse, one tries to open a partial generated
   // file) we will be okay. This is actually common with apps that use
   // DexClassLoader to work around the dex method reference limit and
   // that have a background service running in a separate process.
   ScopedFlock scoped_flock;
-  if (!scoped_flock.Init(oat_location)) {
-    LOG(ERROR) << "Failed to open locked oat file: " << oat_location;
-    return NULL;
+  if (!scoped_flock.Init(oat_location, error_msg)) {
+    return nullptr;
   }
 
   // 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) {
+  const DexFile* dex_file = FindDexFileInOatLocation(dex_location, dex_location_checksum,
+                                                     oat_location, error_msg);
+  if (dex_file != nullptr) {
     return dex_file;
   }
+  VLOG(class_linker) << "Failed to find dex file '" << dex_location << "' in oat location '"
+      << oat_location << "': " << *error_msg;
+  error_msg->clear();
 
   // Generate the output oat file for the dex file
   VLOG(class_linker) << "Generating oat file " << oat_location << " for " << dex_location;
   if (!GenerateOatFile(dex_location, scoped_flock.GetFile().Fd(), oat_location)) {
-    LOG(ERROR) << "Failed to generate oat file: " << oat_location;
-    return NULL;
+    CHECK(Thread::Current()->IsExceptionPending());
+    return nullptr;
   }
   const OatFile* oat_file = OatFile::Open(oat_location, oat_location, NULL,
-                                          !Runtime::Current()->IsCompiler());
-  if (oat_file == NULL) {
-    LOG(ERROR) << "Failed to open generated oat file: " << oat_location;
-    return NULL;
+                                          !Runtime::Current()->IsCompiler(),
+                                          error_msg);
+  if (oat_file == nullptr) {
+    *error_msg = StringPrintf("Failed to open generated oat file '%s': %s",
+                              oat_location, error_msg->c_str());
+    return nullptr;
   }
-  RegisterOatFileLocked(*oat_file);
-  const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location, &dex_location_checksum);
-  if (oat_dex_file == NULL) {
-    LOG(ERROR) << "Failed to find dex file " << dex_location
-               << " (checksum " << dex_location_checksum
-               << ") in generated oat file: " << oat_location;
-    return NULL;
+  oat_file = RegisterOatFile(oat_file);
+  const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location,
+                                                                    &dex_location_checksum);
+  if (oat_dex_file == nullptr) {
+    *error_msg = StringPrintf("Failed to find dex file '%s' (checksum 0x%x) in generated out file "
+                              "'%s'", dex_location, dex_location_checksum, oat_location);
+    return nullptr;
   }
-  const DexFile* result = oat_dex_file->OpenDexFile();
+  const DexFile* result = oat_dex_file->OpenDexFile(error_msg);
+  CHECK(result != nullptr) << *error_msg;
   CHECK_EQ(dex_location_checksum, result->GetLocationChecksum())
           << "dex_location=" << dex_location << " oat_location=" << oat_location << std::hex
           << " dex_location_checksum=" << dex_location_checksum
@@ -846,8 +860,9 @@
 }
 
 bool ClassLinker::VerifyOatFileChecksums(const OatFile* oat_file,
-                                         const std::string& dex_location,
-                                         uint32_t dex_location_checksum) {
+                                         const char* dex_location,
+                                         uint32_t dex_location_checksum,
+                                         std::string* error_msg) {
   Runtime* runtime = Runtime::Current();
   const ImageHeader& image_header = runtime->GetHeap()->GetImageSpace()->GetImageHeader();
   uint32_t image_oat_checksum = image_header.GetOatChecksum();
@@ -857,14 +872,14 @@
 
   const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location, &dex_location_checksum);
   if (oat_dex_file == NULL) {
-    LOG(ERROR) << "oat file " << oat_file->GetLocation()
-               << " does not contain contents for " << dex_location
-               << " with checksum " << dex_location_checksum;
+    *error_msg = StringPrintf("oat file '%s' does not contain contents for '%s' with checksum 0x%x",
+                              oat_file->GetLocation().c_str(), dex_location, dex_location_checksum);
     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();
+      *error_msg  += StringPrintf("\noat file '%s' contains contents for '%s'",
+                                  oat_file->GetLocation().c_str(),
+                                  oat_dex_file->GetDexFileLocation().c_str());
     }
     return false;
   }
@@ -875,116 +890,123 @@
   }
 
   if (!image_check) {
-    std::string image_file(image_header.GetImageRoot(
-        ImageHeader::kOatLocation)->AsString()->ToModifiedUtf8());
-    LOG(WARNING) << "oat file " << oat_file->GetLocation()
-                 << " mismatch (" << std::hex << oat_file->GetOatHeader().GetImageFileLocationOatChecksum()
-                 << ", " << oat_file->GetOatHeader().GetImageFileLocationOatDataBegin()
-                 << ") with " << image_file
-                 << " (" << image_oat_checksum << ", " << std::hex << image_oat_data_begin << ")";
+    ScopedObjectAccess soa(Thread::Current());
+    mirror::String* oat_location = image_header.GetImageRoot(ImageHeader::kOatLocation)->AsString();
+    std::string image_file(oat_location->ToModifiedUtf8());
+    *error_msg = StringPrintf("oat file '%s' mismatch (0x%x, %d) with '%s' (0x%x, %d)",
+                              oat_file->GetLocation().c_str(),
+                              oat_file->GetOatHeader().GetImageFileLocationOatChecksum(),
+                              oat_file->GetOatHeader().GetImageFileLocationOatDataBegin(),
+                              image_file.c_str(), image_oat_checksum, image_oat_data_begin);
   }
   if (!dex_check) {
-    LOG(WARNING) << "oat file " << oat_file->GetLocation()
-                 << " mismatch (" << std::hex << oat_dex_file->GetDexFileLocationChecksum()
-                 << ") with " << dex_location
-                 << " (" << std::hex << dex_location_checksum << ")";
+    *error_msg = StringPrintf("oat file '%s' mismatch (0x%x) with '%s' (0x%x)",
+                              oat_file->GetLocation().c_str(),
+                              oat_dex_file->GetDexFileLocationChecksum(),
+                              dex_location, 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) {
-    delete oat_file;
-    return NULL;
+const DexFile* ClassLinker::VerifyAndOpenDexFileFromOatFile(const std::string& oat_file_location,
+                                                            const char* dex_location,
+                                                            std::string* error_msg,
+                                                            bool* open_failed) {
+  UniquePtr<const OatFile> oat_file(FindOatFileFromOatLocation(oat_file_location, error_msg));
+  if (oat_file.get() == nullptr) {
+    *open_failed = true;
+    return nullptr;
   }
-  RegisterOatFileLocked(*oat_file);
-  return oat_file->GetOatDexFile(dex_location, &dex_location_checksum)->OpenDexFile();
+  *open_failed = false;
+  uint32_t dex_location_checksum;
+  if (!DexFile::GetChecksum(dex_location, &dex_location_checksum, error_msg)) {
+    // If no classes.dex found in dex_location, it has been stripped or is corrupt, 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* opened_oat_file = oat_file.release();
+    opened_oat_file = RegisterOatFile(opened_oat_file);
+    const OatFile::OatDexFile* oat_dex_file = opened_oat_file->GetOatDexFile(dex_location, NULL);
+    if (oat_dex_file == nullptr) {
+      *error_msg = StringPrintf("Dex checksum mismatch for location '%s' and failed to find oat "
+                                "dex file '%s': %s", oat_file_location.c_str(), dex_location,
+                                error_msg->c_str());
+      return nullptr;
+    }
+    return oat_dex_file->OpenDexFile(error_msg);
+  }
+
+  bool verified = VerifyOatFileChecksums(oat_file.get(), dex_location, dex_location_checksum,
+                                         error_msg);
+  if (!verified) {
+    return nullptr;
+  }
+  const OatFile* opened_oat_file = oat_file.release();
+  opened_oat_file = RegisterOatFile(opened_oat_file);
+  return opened_oat_file->GetOatDexFile(dex_location,
+                                        &dex_location_checksum)->OpenDexFile(error_msg);
 }
 
-const DexFile* ClassLinker::FindDexFileInOatFileFromDexLocation(const std::string& dex_location,
-                                                                uint32_t dex_location_checksum) {
-  WriterMutexLock mu(Thread::Current(), dex_lock_);
-
+const DexFile* ClassLinker::FindDexFileInOatFileFromDexLocation(const char* dex_location,
+                                                                uint32_t dex_location_checksum,
+                                                                std::string* error_msg) {
   const OatFile* open_oat_file = FindOpenedOatFileFromDexLocation(dex_location,
                                                                   dex_location_checksum);
-  if (open_oat_file != NULL) {
-    return open_oat_file->GetOatDexFile(dex_location, &dex_location_checksum)->OpenDexFile();
+  if (open_oat_file != nullptr) {
+    const OatFile::OatDexFile* oat_dex_file = open_oat_file->GetOatDexFile(dex_location,
+                                                                           &dex_location_checksum);
+    return oat_dex_file->OpenDexFile(error_msg);
   }
 
   // Look for an existing file next to dex. for example, for
   // /foo/bar/baz.jar, look for /foo/bar/baz.odex.
   std::string odex_filename(OatFile::DexFilenameToOdexFilename(dex_location));
-  UniquePtr<const OatFile> oat_file(FindOatFileFromOatLocationLocked(odex_filename));
-  if (oat_file.get() != NULL) {
-    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, NULL);
-      CHECK(oat_dex_file != NULL) << odex_filename << " " << dex_location;
-      RegisterOatFileLocked(*oat_file);
-      return oat_dex_file->OpenDexFile();
-    }
-    const DexFile* dex_file = VerifyAndOpenDexFileFromOatFile(oat_file.release(),
-                                                              dex_location,
-                                                              dex_location_checksum);
-    if (dex_file != NULL) {
-      return dex_file;
-    }
+  bool open_failed;
+  const DexFile* dex_file = VerifyAndOpenDexFileFromOatFile(odex_filename, dex_location,
+                                                            error_msg, &open_failed);
+  if (dex_file != nullptr) {
+    return dex_file;
   }
-  // Look for an existing file in the dalvik-cache, validating the result if found
-  // not found in /foo/bar/baz.odex? try /data/dalvik-cache/foo@bar@baz.jar@classes.dex
+  std::string cache_error_msg;
   std::string cache_location(GetDalvikCacheFilenameOrDie(dex_location));
-  oat_file.reset(FindOatFileFromOatLocationLocked(cache_location));
-  if (oat_file.get() != NULL) {
-    uint32_t dex_location_checksum;
-    if (!DexFile::GetChecksum(dex_location, &dex_location_checksum)) {
-      LOG(WARNING) << "Failed to compute checksum: " << dex_location;
-      return NULL;
-    }
-    const DexFile* dex_file = VerifyAndOpenDexFileFromOatFile(oat_file.release(),
-                                                              dex_location,
-                                                              dex_location_checksum);
-    if (dex_file != NULL) {
-      return dex_file;
-    }
-    if (TEMP_FAILURE_RETRY(unlink(cache_location.c_str())) != 0) {
-      PLOG(FATAL) << "Failed to remove obsolete oat file from " << cache_location;
-    }
+  dex_file = VerifyAndOpenDexFileFromOatFile(cache_location, dex_location, &cache_error_msg,
+                                             &open_failed);
+  if (dex_file != nullptr) {
+    return dex_file;
   }
-  LOG(INFO) << "Failed to open oat file from " << odex_filename << " or " << cache_location << ".";
+  if (!open_failed && TEMP_FAILURE_RETRY(unlink(cache_location.c_str())) != 0) {
+    PLOG(FATAL) << "Failed to remove obsolete oat file from " << cache_location;
+  }
+  VLOG(class_linker) << "Failed to open oat file from " << odex_filename
+      << " (error '" << *error_msg << "') or " << cache_location
+      << " (error '" << cache_error_msg << "').";
 
   // Try to generate oat file if it wasn't found or was obsolete.
-  std::string oat_cache_filename(GetDalvikCacheFilenameOrDie(dex_location));
-  return FindOrCreateOatFileForDexLocationLocked(dex_location, dex_location_checksum, oat_cache_filename);
+  error_msg->clear();
+  return FindOrCreateOatFileForDexLocation(dex_location, dex_location_checksum,
+                                           cache_location.c_str(), error_msg);
 }
 
 const OatFile* ClassLinker::FindOpenedOatFileFromOatLocation(const std::string& oat_location) {
+  ReaderMutexLock mu(Thread::Current(), dex_lock_);
   for (size_t i = 0; i < oat_files_.size(); i++) {
     const OatFile* oat_file = oat_files_[i];
-    DCHECK(oat_file != NULL);
+    DCHECK(oat_file != nullptr);
     if (oat_file->GetLocation() == oat_location) {
       return oat_file;
     }
   }
-  return NULL;
+  return nullptr;
 }
 
-const OatFile* ClassLinker::FindOatFileFromOatLocation(const std::string& oat_location) {
-  ReaderMutexLock mu(Thread::Current(), dex_lock_);
-  return FindOatFileFromOatLocationLocked(oat_location);
-}
-
-const OatFile* ClassLinker::FindOatFileFromOatLocationLocked(const std::string& oat_location) {
+const OatFile* ClassLinker::FindOatFileFromOatLocation(const std::string& oat_location,
+                                                       std::string* error_msg) {
   const OatFile* oat_file = FindOpenedOatFileFromOatLocation(oat_location);
-  if (oat_file != NULL) {
+  if (oat_file != nullptr) {
     return oat_file;
   }
 
-  oat_file = OatFile::Open(oat_location, oat_location, NULL, !Runtime::Current()->IsCompiler());
+  oat_file = OatFile::Open(oat_location, oat_location, NULL, !Runtime::Current()->IsCompiler(),
+                           error_msg);
   if (oat_file == NULL) {
     return NULL;
   }
@@ -1041,12 +1063,15 @@
   for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
     SirtRef<mirror::DexCache> dex_cache(self, dex_caches->Get(i));
     const std::string& dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8());
-    const OatFile::OatDexFile* oat_dex_file = oat_file.GetOatDexFile(dex_file_location, NULL);
+    const OatFile::OatDexFile* oat_dex_file = oat_file.GetOatDexFile(dex_file_location.c_str(),
+                                                                     nullptr);
     CHECK(oat_dex_file != NULL) << oat_file.GetLocation() << " " << dex_file_location;
-    const DexFile* dex_file = oat_dex_file->OpenDexFile();
+    std::string error_msg;
+    const DexFile* dex_file = oat_dex_file->OpenDexFile(&error_msg);
     if (dex_file == NULL) {
       LOG(FATAL) << "Failed to open dex file " << dex_file_location
-                 << " from within oat file " << oat_file.GetLocation();
+                 << " from within oat file " << oat_file.GetLocation()
+                 << " error '" << error_msg << "'";
     }
 
     CHECK_EQ(dex_file->GetLocationChecksum(), oat_dex_file->GetDexFileLocationChecksum());
@@ -1510,7 +1535,7 @@
   const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file);
   CHECK(oat_file != NULL) << dex_file.GetLocation();
   uint dex_location_checksum = dex_file.GetLocationChecksum();
-  const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation(),
+  const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation().c_str(),
                                                                     &dex_location_checksum);
   CHECK(oat_dex_file != NULL) << dex_file.GetLocation();
   const OatFile::OatClass* oat_class = oat_dex_file->GetOatClass(class_def_idx);
@@ -2559,7 +2584,7 @@
 
   CHECK(oat_file != NULL) << dex_file.GetLocation() << " " << PrettyClass(klass);
   uint dex_location_checksum = dex_file.GetLocationChecksum();
-  const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation(),
+  const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation().c_str(),
                                                                     &dex_location_checksum);
   CHECK(oat_dex_file != NULL) << dex_file.GetLocation() << " " << PrettyClass(klass);
   uint16_t class_def_index = klass->GetDexClassDefIndex();
@@ -4025,7 +4050,7 @@
   DCHECK(dex_cache != NULL);
   // Check for hit in the dex cache.
   mirror::ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx);
-  if (resolved != NULL) {
+  if (resolved != NULL && !resolved->IsRuntimeMethod()) {
     return resolved;
   }
   // Fail, get the declaring class.