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/compiler/dex/arena_allocator.cc b/compiler/dex/arena_allocator.cc
index 2da8064..95e44b3 100644
--- a/compiler/dex/arena_allocator.cc
+++ b/compiler/dex/arena_allocator.cc
@@ -50,7 +50,9 @@
       map_(nullptr),
       next_(nullptr) {
   if (kUseMemMap) {
-    map_ = MemMap::MapAnonymous("dalvik-arena", NULL, size, PROT_READ | PROT_WRITE);
+    std::string error_msg;
+    map_ = MemMap::MapAnonymous("dalvik-arena", NULL, size, PROT_READ | PROT_WRITE, &error_msg);
+    CHECK(map_ != nullptr) << error_msg;
     memory_ = map_->Begin();
     size_ = map_->Size();
   } else {
diff --git a/compiler/elf_fixup.cc b/compiler/elf_fixup.cc
index 359c493..c571288 100644
--- a/compiler/elf_fixup.cc
+++ b/compiler/elf_fixup.cc
@@ -27,8 +27,9 @@
 static const bool DEBUG_FIXUP = false;
 
 bool ElfFixup::Fixup(File* file, uintptr_t oat_data_begin) {
-  UniquePtr<ElfFile> elf_file(ElfFile::Open(file, true, false));
-  CHECK(elf_file.get() != NULL);
+  std::string error_msg;
+  UniquePtr<ElfFile> elf_file(ElfFile::Open(file, true, false, &error_msg));
+  CHECK(elf_file.get() != nullptr) << error_msg;
 
   // Lookup "oatdata" symbol address.
   ::llvm::ELF::Elf32_Addr oatdata_address = ElfWriter::GetOatDataAddress(elf_file.get());
diff --git a/compiler/elf_stripper.cc b/compiler/elf_stripper.cc
index 7fc662c..7ee8d3c 100644
--- a/compiler/elf_stripper.cc
+++ b/compiler/elf_stripper.cc
@@ -27,9 +27,11 @@
 
 namespace art {
 
-bool ElfStripper::Strip(File* file) {
-  UniquePtr<ElfFile> elf_file(ElfFile::Open(file, true, false));
-  CHECK(elf_file.get() != NULL);
+bool ElfStripper::Strip(File* file, std::string* error_msg) {
+  UniquePtr<ElfFile> elf_file(ElfFile::Open(file, true, false, error_msg));
+  if (elf_file.get() == nullptr) {
+    return false;
+  }
 
   // ELF files produced by MCLinker look roughly like this
   //
@@ -120,7 +122,8 @@
   elf_file->GetHeader().e_shoff = shoff;
   int result = ftruncate(file->Fd(), offset);
   if (result != 0) {
-    PLOG(ERROR) << "Failed to truncate while stripping ELF file: " << file->GetPath();
+    *error_msg = StringPrintf("Failed to truncate while stripping ELF file: '%s': %s",
+                              file->GetPath().c_str(), strerror(errno));
     return false;
   }
   return true;
diff --git a/compiler/elf_stripper.h b/compiler/elf_stripper.h
index 6015b30..f1a1d46 100644
--- a/compiler/elf_stripper.h
+++ b/compiler/elf_stripper.h
@@ -17,6 +17,8 @@
 #ifndef ART_COMPILER_ELF_STRIPPER_H_
 #define ART_COMPILER_ELF_STRIPPER_H_
 
+#include <string>
+
 #include "base/macros.h"
 #include "os.h"
 
@@ -26,7 +28,7 @@
  public:
   // Strip an ELF file of unneeded debugging information.
   // Returns true on success, false on failure.
-  static bool Strip(File* file);
+  static bool Strip(File* file, std::string* error_msg);
 
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(ElfStripper);
diff --git a/compiler/elf_writer.cc b/compiler/elf_writer.cc
index d3c13dd..0bfe4a4 100644
--- a/compiler/elf_writer.cc
+++ b/compiler/elf_writer.cc
@@ -47,8 +47,9 @@
 void ElfWriter::GetOatElfInformation(File* file,
                                      size_t& oat_loaded_size,
                                      size_t& oat_data_offset) {
-  UniquePtr<ElfFile> elf_file(ElfFile::Open(file, false, false));
-  CHECK(elf_file.get() != NULL);
+  std::string error_msg;
+  UniquePtr<ElfFile> elf_file(ElfFile::Open(file, false, false, &error_msg));
+  CHECK(elf_file.get() != NULL) << error_msg;
 
   oat_loaded_size = elf_file->GetLoadedSize();
   CHECK_NE(0U, oat_loaded_size);
diff --git a/compiler/elf_writer_test.cc b/compiler/elf_writer_test.cc
index ffe1f72..eca67a8 100644
--- a/compiler/elf_writer_test.cc
+++ b/compiler/elf_writer_test.cc
@@ -65,23 +65,26 @@
   UniquePtr<File> file(OS::OpenFileForReading(elf_filename.c_str()));
   ASSERT_TRUE(file.get() != NULL);
   {
-    UniquePtr<ElfFile> ef(ElfFile::Open(file.get(), false, false));
-    CHECK(ef.get() != NULL);
+    std::string error_msg;
+    UniquePtr<ElfFile> ef(ElfFile::Open(file.get(), false, false, &error_msg));
+    CHECK(ef.get() != nullptr) << error_msg;
     EXPECT_ELF_FILE_ADDRESS(ef, dl_oatdata, "oatdata", false);
     EXPECT_ELF_FILE_ADDRESS(ef, dl_oatexec, "oatexec", false);
     EXPECT_ELF_FILE_ADDRESS(ef, dl_oatlastword, "oatlastword", false);
   }
   {
-    UniquePtr<ElfFile> ef(ElfFile::Open(file.get(), false, false));
-    CHECK(ef.get() != NULL);
+    std::string error_msg;
+    UniquePtr<ElfFile> ef(ElfFile::Open(file.get(), false, false, &error_msg));
+    CHECK(ef.get() != nullptr) << error_msg;
     EXPECT_ELF_FILE_ADDRESS(ef, dl_oatdata, "oatdata", true);
     EXPECT_ELF_FILE_ADDRESS(ef, dl_oatexec, "oatexec", true);
     EXPECT_ELF_FILE_ADDRESS(ef, dl_oatlastword, "oatlastword", true);
   }
   {
-    UniquePtr<ElfFile> ef(ElfFile::Open(file.get(), false, true));
-    CHECK(ef.get() != NULL);
-    ef->Load(false);
+    std::string error_msg;
+    UniquePtr<ElfFile> ef(ElfFile::Open(file.get(), false, true, &error_msg));
+    CHECK(ef.get() != nullptr) << error_msg;
+    CHECK(ef->Load(false, &error_msg)) << error_msg;
     EXPECT_EQ(dl_oatdata, ef->FindDynamicSymbolAddress("oatdata"));
     EXPECT_EQ(dl_oatexec, ef->FindDynamicSymbolAddress("oatexec"));
     EXPECT_EQ(dl_oatlastword, ef->FindDynamicSymbolAddress("oatlastword"));
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index d4be7c0..a8b7c88 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -112,8 +112,11 @@
   runtime_.reset();
   java_lang_dex_file_ = NULL;
 
-  UniquePtr<const DexFile> dex(DexFile::Open(GetLibCoreDexFileName(), GetLibCoreDexFileName()));
-  ASSERT_TRUE(dex.get() != NULL);
+  std::string error_msg;
+  UniquePtr<const DexFile> dex(DexFile::Open(GetLibCoreDexFileName().c_str(),
+                                             GetLibCoreDexFileName().c_str(),
+                                             &error_msg));
+  ASSERT_TRUE(dex.get() != nullptr) << error_msg;
 
   // Remove the reservation of the memory for use to load the image.
   UnreserveImageSpace();
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index bcdc1c1..871cfd5 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -82,12 +82,14 @@
     LOG(ERROR) << "Failed to open oat file " << oat_filename << " for " << oat_location;
     return false;
   }
-  oat_file_ = OatFile::OpenWritable(oat_file.get(), oat_location);
-  if (oat_file_ == NULL) {
-    LOG(ERROR) << "Failed to open writable oat file " << oat_filename << " for " << oat_location;
+  std::string error_msg;
+  oat_file_ = OatFile::OpenWritable(oat_file.get(), oat_location, &error_msg);
+  if (oat_file_ == nullptr) {
+    LOG(ERROR) << "Failed to open writable oat file " << oat_filename << " for " << oat_location
+        << ": " << error_msg;
     return false;
   }
-  class_linker->RegisterOatFile(*oat_file_);
+  CHECK_EQ(class_linker->RegisterOatFile(oat_file_), oat_file_);
 
   interpreter_to_interpreter_bridge_offset_ =
       oat_file_->GetOatHeader().GetInterpreterToInterpreterBridgeOffset();
@@ -192,9 +194,10 @@
 
   int prot = PROT_READ | PROT_WRITE;
   size_t length = RoundUp(size, kPageSize);
-  image_.reset(MemMap::MapAnonymous("image writer image", NULL, length, prot));
-  if (image_.get() == NULL) {
-    LOG(ERROR) << "Failed to allocate memory for image file generation";
+  std::string error_msg;
+  image_.reset(MemMap::MapAnonymous("image writer image", NULL, length, prot, &error_msg));
+  if (UNLIKELY(image_.get() == nullptr)) {
+    LOG(ERROR) << "Failed to allocate memory for image file generation: " << error_msg;
     return false;
   }
   return true;
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 6ac5d6a..634a160 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -100,8 +100,10 @@
     base::TimingLogger timings("CommonTest::WriteRead", false, false);
     compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), timings);
   }
-  UniquePtr<OatFile> oat_file(OatFile::Open(tmp.GetFilename(), tmp.GetFilename(), NULL, false));
-  ASSERT_TRUE(oat_file.get() != NULL);
+  std::string error_msg;
+  UniquePtr<OatFile> oat_file(OatFile::Open(tmp.GetFilename(), tmp.GetFilename(), NULL, false,
+                                            &error_msg));
+  ASSERT_TRUE(oat_file.get() != nullptr) << error_msg;
   const OatHeader& oat_header = oat_file->GetOatHeader();
   ASSERT_TRUE(oat_header.IsValid());
   ASSERT_EQ(1U, oat_header.GetDexFileCount());  // core
@@ -111,8 +113,9 @@
 
   const DexFile* dex_file = java_lang_dex_file_;
   uint32_t dex_file_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_file_checksum);
+  ASSERT_TRUE(oat_dex_file != nullptr);
   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);
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index d5d1303..d8112ea 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -200,21 +200,24 @@
   }
 
   // Reads the class names (java.lang.Object) and returns a set of descriptors (Ljava/lang/Object;)
-  CompilerDriver::DescriptorSet* ReadImageClassesFromZip(const std::string& zip_filename,
-                                                         const char* image_classes_filename) {
-    UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(zip_filename));
+  CompilerDriver::DescriptorSet* ReadImageClassesFromZip(const char* zip_filename,
+                                                         const char* image_classes_filename,
+                                                         std::string* error_msg) {
+    UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(zip_filename, error_msg));
     if (zip_archive.get() == NULL) {
-      LOG(ERROR) << "Failed to open zip file " << zip_filename;
       return NULL;
     }
     UniquePtr<ZipEntry> zip_entry(zip_archive->Find(image_classes_filename));
     if (zip_entry.get() == NULL) {
-      LOG(ERROR) << "Failed to find " << image_classes_filename << " within " << zip_filename;
+      *error_msg = StringPrintf("Failed to find '%s' within '%s': %s", image_classes_filename,
+                                zip_filename, error_msg->c_str());
       return NULL;
     }
-    UniquePtr<MemMap> image_classes_file(zip_entry->ExtractToMemMap(image_classes_filename));
+    UniquePtr<MemMap> image_classes_file(zip_entry->ExtractToMemMap(image_classes_filename,
+                                                                    error_msg));
     if (image_classes_file.get() == NULL) {
-      LOG(ERROR) << "Failed to extract " << image_classes_filename << " from " << zip_filename;
+      *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", image_classes_filename,
+                                zip_filename, error_msg->c_str());
       return NULL;
     }
     const std::string image_classes_string(reinterpret_cast<char*>(image_classes_file->Begin()),
@@ -368,9 +371,10 @@
       if (DexFilesContains(dex_files, parsed[i])) {
         continue;
       }
-      const DexFile* dex_file = DexFile::Open(parsed[i], parsed[i]);
+      std::string error_msg;
+      const DexFile* dex_file = DexFile::Open(parsed[i].c_str(), parsed[i].c_str(), &error_msg);
       if (dex_file == NULL) {
-        LOG(WARNING) << "Failed to open dex file " << parsed[i];
+        LOG(WARNING) << "Failed to open dex file '" << parsed[i] << "': " << error_msg;
       } else {
         dex_files.push_back(dex_file);
       }
@@ -416,9 +420,10 @@
   for (size_t i = 0; i < dex_filenames.size(); i++) {
     const char* dex_filename = dex_filenames[i];
     const char* dex_location = dex_locations[i];
-    const DexFile* dex_file = DexFile::Open(dex_filename, dex_location);
+    std::string error_msg;
+    const DexFile* dex_file = DexFile::Open(dex_filename, dex_location, &error_msg);
     if (dex_file == NULL) {
-      LOG(WARNING) << "Failed to open .dex from file '" << dex_filename << "'\n";
+      LOG(WARNING) << "Failed to open .dex from file '" << dex_filename << "': " << error_msg;
       ++failure_count;
     } else {
       dex_files.push_back(dex_file);
@@ -887,14 +892,17 @@
   // If --image-classes was specified, calculate the full list of classes to include in the image
   UniquePtr<CompilerDriver::DescriptorSet> image_classes(NULL);
   if (image_classes_filename != NULL) {
+    std::string error_msg;
     if (image_classes_zip_filename != NULL) {
       image_classes.reset(dex2oat->ReadImageClassesFromZip(image_classes_zip_filename,
-                                                           image_classes_filename));
+                                                           image_classes_filename,
+                                                           &error_msg));
     } else {
       image_classes.reset(dex2oat->ReadImageClassesFromFile(image_classes_filename));
     }
     if (image_classes.get() == NULL) {
-      LOG(ERROR) << "Failed to create list of image classes from " << image_classes_filename;
+      LOG(ERROR) << "Failed to create list of image classes from '" << image_classes_filename <<
+          "': " << error_msg;
       return EXIT_FAILURE;
     }
   }
@@ -904,14 +912,18 @@
     dex_files = Runtime::Current()->GetClassLinker()->GetBootClassPath();
   } else {
     if (dex_filenames.empty()) {
-      UniquePtr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(zip_fd));
+      std::string error_msg;
+      UniquePtr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(zip_fd, zip_location.c_str(),
+                                                               &error_msg));
       if (zip_archive.get() == NULL) {
-        LOG(ERROR) << "Failed to open zip from file descriptor for " << zip_location;
+        LOG(ERROR) << "Failed to open zip from file descriptor for '" << zip_location << "': "
+            << error_msg;
         return EXIT_FAILURE;
       }
-      const DexFile* dex_file = DexFile::Open(*zip_archive.get(), zip_location);
+      const DexFile* dex_file = DexFile::Open(*zip_archive.get(), zip_location, &error_msg);
       if (dex_file == NULL) {
-        LOG(ERROR) << "Failed to open dex from file descriptor for zip file: " << zip_location;
+        LOG(ERROR) << "Failed to open dex from file descriptor for zip file '" << zip_location
+            << "': " << error_msg;
         return EXIT_FAILURE;
       }
       dex_files.push_back(dex_file);
@@ -1063,7 +1075,8 @@
   // Strip unneeded sections for target
   off_t seek_actual = lseek(oat_file->Fd(), 0, SEEK_SET);
   CHECK_EQ(0, seek_actual);
-  ElfStripper::Strip(oat_file.get());
+  std::string error_msg;
+  CHECK(ElfStripper::Strip(oat_file.get(), &error_msg)) << error_msg;
 
 
   // We wrote the oat file successfully, and want to keep it.
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 6db5813..ea06b02 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -173,9 +173,13 @@
     MethodHelper mh(m);
     for (size_t i = 0; i < oat_dex_files_.size(); i++) {
       const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
-      CHECK(oat_dex_file != NULL);
-      UniquePtr<const DexFile> dex_file(oat_dex_file->OpenDexFile());
-      if (dex_file.get() != NULL) {
+      CHECK(oat_dex_file != nullptr);
+      std::string error_msg;
+      UniquePtr<const DexFile> dex_file(oat_dex_file->OpenDexFile(&error_msg));
+      if (dex_file.get() == nullptr) {
+        LOG(WARNING) << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation()
+            << "': " << error_msg;
+      } else {
         const DexFile::ClassDef* class_def =
             dex_file->FindClassDef(mh.GetDeclaringClassDescriptor());
         if (class_def != NULL) {
@@ -199,8 +203,11 @@
     for (size_t i = 0; i < oat_dex_files_.size(); i++) {
       const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
       CHECK(oat_dex_file != NULL);
-      UniquePtr<const DexFile> dex_file(oat_dex_file->OpenDexFile());
-      if (dex_file.get() == NULL) {
+      std::string error_msg;
+      UniquePtr<const DexFile> dex_file(oat_dex_file->OpenDexFile(&error_msg));
+      if (dex_file.get() == nullptr) {
+        LOG(WARNING) << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation()
+            << "': " << error_msg;
         continue;
       }
       offsets_.insert(reinterpret_cast<uint32_t>(&dex_file->GetHeader()));
@@ -245,9 +252,10 @@
     os << "OAT DEX FILE:\n";
     os << StringPrintf("location: %s\n", oat_dex_file.GetDexFileLocation().c_str());
     os << StringPrintf("checksum: 0x%08x\n", oat_dex_file.GetDexFileLocationChecksum());
-    UniquePtr<const DexFile> dex_file(oat_dex_file.OpenDexFile());
+    std::string error_msg;
+    UniquePtr<const DexFile> dex_file(oat_dex_file.OpenDexFile(&error_msg));
     if (dex_file.get() == NULL) {
-      os << "NOT FOUND\n\n";
+      os << "NOT FOUND: " << error_msg << "\n\n";
       return;
     }
     for (size_t class_def_index = 0; class_def_index < dex_file->NumClassDefs(); class_def_index++) {
@@ -727,9 +735,10 @@
       os << " (" << oat_location << ")";
     }
     os << "\n";
-    const OatFile* oat_file = class_linker->FindOatFileFromOatLocation(oat_location);
+    std::string error_msg;
+    const OatFile* oat_file = class_linker->FindOatFileFromOatLocation(oat_location, &error_msg);
     if (oat_file == NULL) {
-      os << "NOT FOUND\n";
+      os << "NOT FOUND: " << error_msg << "\n";
       return;
     }
     os << "\n";
@@ -775,7 +784,7 @@
     os << "STATS:\n" << std::flush;
     UniquePtr<File> file(OS::OpenFileForReading(image_filename_.c_str()));
     if (file.get() == NULL) {
-      std::string cache_location(GetDalvikCacheFilenameOrDie(image_filename_));
+      std::string cache_location(GetDalvikCacheFilenameOrDie(image_filename_.c_str()));
       file.reset(OS::OpenFileForReading(cache_location.c_str()));
       if (file.get() == NULL) {
           LOG(WARNING) << "Failed to find image in " << image_filename_
@@ -1412,10 +1421,11 @@
   }
 
   if (oat_filename != NULL) {
+    std::string error_msg;
     OatFile* oat_file =
-        OatFile::Open(oat_filename, oat_filename, NULL, false);
+        OatFile::Open(oat_filename, oat_filename, NULL, false, &error_msg);
     if (oat_file == NULL) {
-      fprintf(stderr, "Failed to open oat file from %s\n", oat_filename);
+      fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
       return EXIT_FAILURE;
     }
     OatDumper oat_dumper(*host_prefix.get(), *oat_file);
diff --git a/runtime/base/macros.h b/runtime/base/macros.h
index 6531858..d00c64a 100644
--- a/runtime/base/macros.h
+++ b/runtime/base/macros.h
@@ -138,8 +138,10 @@
 
 #if defined (__APPLE__)
 #define HOT_ATTR
+#define COLD_ATTR
 #else
 #define HOT_ATTR __attribute__ ((hot))
+#define COLD_ATTR __attribute__ ((cold))
 #endif
 
 #define PURE __attribute__ ((__pure__))
diff --git a/runtime/base/unix_file/fd_file.cc b/runtime/base/unix_file/fd_file.cc
index 36f8ba7..f48c76d 100644
--- a/runtime/base/unix_file/fd_file.cc
+++ b/runtime/base/unix_file/fd_file.cc
@@ -102,10 +102,6 @@
   return fd_ >= 0;
 }
 
-std::string FdFile::GetPath() const {
-  return file_path_;
-}
-
 bool FdFile::ReadFully(void* buffer, int64_t byte_count) {
   char* ptr = static_cast<char*>(buffer);
   while (byte_count > 0) {
diff --git a/runtime/base/unix_file/fd_file.h b/runtime/base/unix_file/fd_file.h
index 79a0db9..19e3511 100644
--- a/runtime/base/unix_file/fd_file.h
+++ b/runtime/base/unix_file/fd_file.h
@@ -57,7 +57,9 @@
   // Bonus API.
   int Fd() const;
   bool IsOpened() const;
-  std::string GetPath() const;
+  const std::string& GetPath() const {
+    return file_path_;
+  }
   void DisableAutoClose();
   bool ReadFully(void* buffer, int64_t byte_count);
   bool WriteFully(const void* buffer, int64_t byte_count);
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.
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 11ba78b..0bc1b5f 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -215,7 +215,7 @@
       LOCKS_EXCLUDED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void RegisterOatFile(const OatFile& oat_file)
+  const OatFile* RegisterOatFile(const OatFile* oat_file)
       LOCKS_EXCLUDED(dex_lock_);
 
   const std::vector<const DexFile*>& GetBootClassPath() {
@@ -244,43 +244,37 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Generate an oat file from a dex file
-  bool GenerateOatFile(const std::string& dex_filename,
+  bool GenerateOatFile(const char* dex_filename,
                        int oat_fd,
-                       const std::string& oat_cache_filename);
+                       const char* oat_cache_filename);
+      LOCKS_EXCLUDED(Locks::mutator_lock_);
 
-  const OatFile* FindOatFileFromOatLocation(const std::string& location)
+  const OatFile* FindOatFileFromOatLocation(const std::string& location,
+                                            std::string* error_msg)
       LOCKS_EXCLUDED(dex_lock_);
 
-  const OatFile* FindOatFileFromOatLocationLocked(const std::string& location)
-      SHARED_LOCKS_REQUIRED(dex_lock_);
-
   // 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 DexFile* FindOrCreateOatFileForDexLocation(const char* dex_location,
                                                    uint32_t dex_location_checksum,
-                                                   const std::string& oat_location)
-      LOCKS_EXCLUDED(dex_lock_)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  const DexFile* FindOrCreateOatFileForDexLocationLocked(const std::string& dex_location,
-                                                         uint32_t dex_location_checksum,
-                                                         const std::string& oat_location)
-      EXCLUSIVE_LOCKS_REQUIRED(dex_lock_)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+                                                   const char* oat_location,
+                                                   std::string* error_msg)
+      LOCKS_EXCLUDED(dex_lock_, Locks::mutator_lock_);
   // 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,
-                                                     uint32_t location_checksum)
-      LOCKS_EXCLUDED(dex_lock_)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const DexFile* FindDexFileInOatFileFromDexLocation(const char* location,
+                                                     uint32_t location_checksum,
+                                                     std::string* error_msg)
+      LOCKS_EXCLUDED(dex_lock_, Locks::mutator_lock_);
 
 
   // 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)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+                                     const char* dex_location,
+                                     uint32_t dex_location_checksum,
+                                     std::string* error_msg);
 
   // TODO: replace this with multiple methods that allocate the correct managed type.
   template <class T>
@@ -430,8 +424,6 @@
       EXCLUSIVE_LOCKS_REQUIRED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool IsDexFileRegisteredLocked(const DexFile& dex_file) const SHARED_LOCKS_REQUIRED(dex_lock_);
-  void RegisterOatFileLocked(const OatFile& oat_file) EXCLUSIVE_LOCKS_REQUIRED(dex_lock_)
-      EXCLUSIVE_LOCKS_REQUIRED(dex_lock_);
 
   bool InitializeClass(mirror::Class* klass, bool can_run_clinit, bool can_init_parents)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -493,22 +485,22 @@
   const OatFile* FindOpenedOatFileForDexFile(const DexFile& dex_file)
       LOCKS_EXCLUDED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  const OatFile* FindOpenedOatFileFromDexLocation(const std::string& dex_location,
+  const OatFile* FindOpenedOatFileFromDexLocation(const char* dex_location,
                                                   uint32_t dex_location_checksum)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, dex_lock_);
+      LOCKS_EXCLUDED(dex_lock);
   const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location)
-      SHARED_LOCKS_REQUIRED(dex_lock_);
-  const DexFile* FindDexFileInOatLocation(const std::string& dex_location,
+      LOCKS_EXCLUDED(dex_lock_);
+  const DexFile* FindDexFileInOatLocation(const char* dex_location,
                                           uint32_t dex_location_checksum,
-                                          const std::string& oat_location)
-      EXCLUSIVE_LOCKS_REQUIRED(dex_lock_)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+                                          const char* oat_location,
+                                          std::string* error_msg)
+      LOCKS_EXCLUDED(dex_lock_);
 
-  const DexFile* VerifyAndOpenDexFileFromOatFile(const OatFile* oat_file,
-                                                 const std::string& dex_location,
-                                                 uint32_t dex_location_checksum)
-      EXCLUSIVE_LOCKS_REQUIRED(dex_lock_)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const DexFile* VerifyAndOpenDexFileFromOatFile(const std::string& oat_file_location,
+                                                 const char* dex_location,
+                                                 std::string* error_msg,
+                                                 bool* open_failed)
+      LOCKS_EXCLUDED(dex_lock_);
 
   mirror::ArtMethod* CreateProxyConstructor(Thread* self, SirtRef<mirror::Class>& klass,
                                             mirror::Class* proxy_class)
diff --git a/runtime/common_test.h b/runtime/common_test.h
index fe54d03..899eab1 100644
--- a/runtime/common_test.h
+++ b/runtime/common_test.h
@@ -282,9 +282,12 @@
     int mkdir_result = mkdir(dalvik_cache_.c_str(), 0700);
     ASSERT_EQ(mkdir_result, 0);
 
-    java_lang_dex_file_ = DexFile::Open(GetLibCoreDexFileName(), GetLibCoreDexFileName());
+    std::string error_msg;
+    java_lang_dex_file_ = DexFile::Open(GetLibCoreDexFileName().c_str(),
+                                        GetLibCoreDexFileName().c_str(), &error_msg);
     if (java_lang_dex_file_ == NULL) {
-      LOG(FATAL) << "Could not open .dex file '" << GetLibCoreDexFileName() << "'\n";
+      LOG(FATAL) << "Could not open .dex file '" << GetLibCoreDexFileName() << "': "
+          << error_msg << "\n";
     }
     boot_class_path_.push_back(java_lang_dex_file_);
 
@@ -423,8 +426,9 @@
     filename += "art-test-dex-";
     filename += name;
     filename += ".jar";
-    const DexFile* dex_file = DexFile::Open(filename, filename);
-    CHECK(dex_file != NULL) << "Failed to open " << filename;
+    std::string error_msg;
+    const DexFile* dex_file = DexFile::Open(filename.c_str(), filename.c_str(), &error_msg);
+    CHECK(dex_file != NULL) << "Failed to open '" << filename << "': " << error_msg;
     CHECK_EQ(PROT_READ, dex_file->GetPermissions());
     CHECK(dex_file->IsReadOnly());
     opened_dex_files_.push_back(dex_file);
@@ -498,10 +502,12 @@
   void ReserveImageSpace() {
     // Reserve where the image will be loaded up front so that other parts of test set up don't
     // accidentally end up colliding with the fixed memory address when we need to load the image.
+    std::string error_msg;
     image_reservation_.reset(MemMap::MapAnonymous("image reservation",
                                                   reinterpret_cast<byte*>(ART_BASE_ADDRESS),
                                                   (size_t)100 * 1024 * 1024,  // 100MB
-                                                  PROT_NONE));
+                                                  PROT_NONE, &error_msg));
+    CHECK(image_reservation_.get() != nullptr) << error_msg;
   }
 
   void UnreserveImageSpace() {
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc
index 189e3ed..0419dab 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -230,6 +230,15 @@
   va_end(args);
 }
 
+// IOException
+
+void ThrowIOException(const char* fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+  ThrowException(NULL, "Ljava/io/IOException;", NULL, fmt, &args);
+  va_end(args);
+}
+
 // LinkageError
 
 void ThrowLinkageError(const mirror::Class* referrer, const char* fmt, ...) {
diff --git a/runtime/common_throws.h b/runtime/common_throws.h
index 1d77e2d..3164f30 100644
--- a/runtime/common_throws.h
+++ b/runtime/common_throws.h
@@ -22,10 +22,10 @@
 
 namespace art {
 namespace mirror {
-class ArtField;
-class ArtMethod;
-class Class;
-class Object;
+  class ArtField;
+  class ArtMethod;
+  class Class;
+  class Object;
 }  // namespace mirror
 class Signature;
 class StringPiece;
@@ -34,102 +34,110 @@
 // AbstractMethodError
 
 void ThrowAbstractMethodError(const mirror::ArtMethod* method)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 // ArithmeticException
 
-void ThrowArithmeticExceptionDivideByZero() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+void ThrowArithmeticExceptionDivideByZero() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 // ArrayIndexOutOfBoundsException
 
 void ThrowArrayIndexOutOfBoundsException(int index, int length)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 // ArrayStoreException
 
 void ThrowArrayStoreException(const mirror::Class* element_class,
                               const mirror::Class* array_class)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 // ClassCircularityError
 
-void ThrowClassCircularityError(mirror::Class* c) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+void ThrowClassCircularityError(mirror::Class* c)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 // ClassCastException
 
 void ThrowClassCastException(const mirror::Class* dest_type, const mirror::Class* src_type)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 void ThrowClassCastException(const ThrowLocation* throw_location, const char* msg)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 // ClassFormatError
 
 void ThrowClassFormatError(const mirror::Class* referrer, const char* fmt, ...)
     __attribute__((__format__(__printf__, 2, 3)))
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 // IllegalAccessError
 
 void ThrowIllegalAccessErrorClass(mirror::Class* referrer, mirror::Class* accessed)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 void ThrowIllegalAccessErrorClassForMethodDispatch(mirror::Class* referrer, mirror::Class* accessed,
                                                    const mirror::ArtMethod* caller,
                                                    const mirror::ArtMethod* called,
                                                    InvokeType type)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 void ThrowIllegalAccessErrorMethod(mirror::Class* referrer, mirror::ArtMethod* accessed)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 void ThrowIllegalAccessErrorField(mirror::Class* referrer, mirror::ArtField* accessed)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 void ThrowIllegalAccessErrorFinalField(const mirror::ArtMethod* referrer,
                                        mirror::ArtField* accessed)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 void ThrowIllegalAccessError(mirror::Class* referrer, const char* fmt, ...)
     __attribute__((__format__(__printf__, 2, 3)))
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 // IllegalArgumentException
 
 void ThrowIllegalArgumentException(const ThrowLocation* throw_location, const char* msg)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 // IncompatibleClassChangeError
 
 void ThrowIncompatibleClassChangeError(InvokeType expected_type, InvokeType found_type,
                                        mirror::ArtMethod* method,
                                        const mirror::ArtMethod* referrer)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 void ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(const mirror::ArtMethod* interface_method,
                                                                 mirror::Object* this_object,
                                                                 const mirror::ArtMethod* referrer)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 void ThrowIncompatibleClassChangeErrorField(const mirror::ArtField* resolved_field, bool is_static,
                                             const mirror::ArtMethod* referrer)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 void ThrowIncompatibleClassChangeError(const mirror::Class* referrer, const char* fmt, ...)
     __attribute__((__format__(__printf__, 2, 3)))
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
+
+// IOException
+
+void ThrowIOException(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2)))
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 // LinkageError
 
 void ThrowLinkageError(const mirror::Class* referrer, const char* fmt, ...)
     __attribute__((__format__(__printf__, 2, 3)))
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 // NegativeArraySizeException
 
-void ThrowNegativeArraySizeException(int size) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+void ThrowNegativeArraySizeException(int size)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
-void ThrowNegativeArraySizeException(const char* msg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+void ThrowNegativeArraySizeException(const char* msg)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 
 // NoSuchFieldError
@@ -142,45 +150,45 @@
 
 void ThrowNoSuchMethodError(InvokeType type, mirror::Class* c, const StringPiece& name,
                             const Signature& signature)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 void ThrowNoSuchMethodError(uint32_t method_idx)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 // NullPointerException
 
 void ThrowNullPointerExceptionForFieldAccess(const ThrowLocation& throw_location,
                                              mirror::ArtField* field,
                                              bool is_read)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 void ThrowNullPointerExceptionForMethodAccess(const ThrowLocation& throw_location,
                                               uint32_t method_idx,
                                               InvokeType type)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 void ThrowNullPointerExceptionForMethodAccess(const ThrowLocation& throw_location,
                                               mirror::ArtMethod* method,
                                               InvokeType type)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 void ThrowNullPointerExceptionFromDexPC(const ThrowLocation& throw_location)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 void ThrowNullPointerException(const ThrowLocation* throw_location, const char* msg)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 // RuntimeException
 
 void ThrowRuntimeException(const char* fmt, ...)
     __attribute__((__format__(__printf__, 1, 2)))
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 // VerifyError
 
 void ThrowVerifyError(const mirror::Class* referrer, const char* fmt, ...)
     __attribute__((__format__(__printf__, 2, 3)))
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
 }  // namespace art
 
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index ac133a3..a0f5601 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -62,72 +62,77 @@
                         reinterpret_cast<const DexFile::ClassDef*>(NULL));
 }
 
-int OpenAndReadMagic(const std::string& filename, uint32_t* magic) {
+static int OpenAndReadMagic(const char* filename, uint32_t* magic, std::string* error_msg) {
   CHECK(magic != NULL);
-  int fd = open(filename.c_str(), O_RDONLY, 0);
+  int fd = open(filename, O_RDONLY, 0);
   if (fd == -1) {
-    PLOG(WARNING) << "Unable to open '" << filename << "'";
+    *error_msg = StringPrintf("Unable to open '%s' : %s", filename, strerror(errno));
     return -1;
   }
   int n = TEMP_FAILURE_RETRY(read(fd, magic, sizeof(*magic)));
   if (n != sizeof(*magic)) {
-    PLOG(ERROR) << "Failed to find magic in '" << filename << "'";
+    *error_msg = StringPrintf("Failed to find magic in '%s'", filename);
     return -1;
   }
   if (lseek(fd, 0, SEEK_SET) != 0) {
-    PLOG(ERROR) << "Failed to seek to beginning of file '" << filename << "'";
+    *error_msg = StringPrintf("Failed to seek to beginning of file '%s' : %s", filename,
+                              strerror(errno));
     return -1;
   }
   return fd;
 }
 
-bool DexFile::GetChecksum(const std::string& filename, uint32_t* checksum) {
+bool DexFile::GetChecksum(const char* filename, uint32_t* checksum, std::string* error_msg) {
   CHECK(checksum != NULL);
   uint32_t magic;
-  int fd = OpenAndReadMagic(filename, &magic);
+  int fd = OpenAndReadMagic(filename, &magic, error_msg);
   if (fd == -1) {
+    DCHECK(!error_msg->empty());
     return false;
   }
   if (IsZipMagic(magic)) {
-    UniquePtr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd));
+    UniquePtr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, filename, error_msg));
     if (zip_archive.get() == NULL) {
+      *error_msg = StringPrintf("Failed to open zip archive '%s'", filename);
       return false;
     }
     UniquePtr<ZipEntry> zip_entry(zip_archive->Find(kClassesDex));
     if (zip_entry.get() == NULL) {
-      LOG(ERROR) << "Zip archive '" << filename << "' doesn't contain " << kClassesDex;
+      *error_msg = StringPrintf("Zip archive '%s' doesn\'t contain %s", filename, kClassesDex);
       return false;
     }
     *checksum = zip_entry->GetCrc32();
     return true;
   }
   if (IsDexMagic(magic)) {
-    UniquePtr<const DexFile> dex_file(DexFile::OpenFile(fd, filename, false));
+    UniquePtr<const DexFile> dex_file(DexFile::OpenFile(fd, filename, false, error_msg));
     if (dex_file.get() == NULL) {
       return false;
     }
     *checksum = dex_file->GetHeader().checksum_;
     return true;
   }
-  LOG(ERROR) << "Expected valid zip or dex file: " << filename;
+  *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
   return false;
 }
 
-const DexFile* DexFile::Open(const std::string& filename,
-                             const std::string& location) {
+const DexFile* DexFile::Open(const char* filename,
+                             const char* location,
+                             std::string* error_msg) {
   uint32_t magic;
-  int fd = OpenAndReadMagic(filename, &magic);
+  int fd = OpenAndReadMagic(filename, &magic, error_msg);
   if (fd == -1) {
+    DCHECK(!error_msg->empty());
     return NULL;
   }
   if (IsZipMagic(magic)) {
-    return DexFile::OpenZip(fd, location);
+    return DexFile::OpenZip(fd, location, error_msg);
   }
   if (IsDexMagic(magic)) {
-    return DexFile::OpenFile(fd, location, true);
+    return DexFile::OpenFile(fd, location, true, error_msg);
   }
-  LOG(ERROR) << "Expected valid zip or dex file: " << filename;
-  return NULL;
+  *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
+  return nullptr;
 }
 
 int DexFile::GetPermissions() const {
@@ -160,46 +165,48 @@
   }
 }
 
-const DexFile* DexFile::OpenFile(int fd,
-                                 const std::string& location,
-                                 bool verify) {
-  CHECK(!location.empty());
+const DexFile* DexFile::OpenFile(int fd, const char* location, bool verify,
+                                 std::string* error_msg) {
+  CHECK(location != nullptr);
   struct stat sbuf;
   memset(&sbuf, 0, sizeof(sbuf));
   if (fstat(fd, &sbuf) == -1) {
-    PLOG(ERROR) << "fstat \"" << location << "\" failed";
+    *error_msg = StringPrintf("DexFile: fstat \'%s\' failed: %s", location, strerror(errno));
     close(fd);
-    return NULL;
+    return nullptr;
   }
   if (S_ISDIR(sbuf.st_mode)) {
-    LOG(ERROR) << "attempt to mmap directory \"" << location << "\"";
-    return NULL;
+    *error_msg = StringPrintf("Attempt to mmap directory '%s'", location);
+    return nullptr;
   }
   size_t length = sbuf.st_size;
-  UniquePtr<MemMap> map(MemMap::MapFile(length, PROT_READ, MAP_PRIVATE, fd, 0));
-  if (map.get() == NULL) {
-    LOG(ERROR) << "mmap \"" << location << "\" failed";
+  UniquePtr<MemMap> map(MemMap::MapFile(length, PROT_READ, MAP_PRIVATE, fd, 0, location,
+                                        error_msg));
+  if (map.get() == nullptr) {
+    DCHECK(!error_msg->empty());
     close(fd);
-    return NULL;
+    return nullptr;
   }
   close(fd);
 
   if (map->Size() < sizeof(DexFile::Header)) {
-    LOG(ERROR) << "Failed to open dex file '" << location << "' that is too short to have a header";
-    return NULL;
+    *error_msg = StringPrintf(
+        "DexFile: failed to open dex file \'%s\' that is too short to have a header", location);
+    return nullptr;
   }
 
   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";
-    return NULL;
+  const DexFile* dex_file = OpenMemory(location, dex_header->checksum_, map.release(), error_msg);
+  if (dex_file == nullptr) {
+    *error_msg = StringPrintf("Failed to open dex file '%s' from memory: %s", location,
+                              error_msg->c_str());
+    return nullptr;
   }
 
-  if (verify && !DexFileVerifier::Verify(dex_file, dex_file->Begin(), dex_file->Size())) {
-    LOG(ERROR) << "Failed to verify dex file '" << location << "'";
-    return NULL;
+  if (verify && !DexFileVerifier::Verify(dex_file, dex_file->Begin(), dex_file->Size(), location,
+                                         error_msg)) {
+    return nullptr;
   }
 
   return dex_file;
@@ -207,49 +214,55 @@
 
 const char* DexFile::kClassesDex = "classes.dex";
 
-const DexFile* DexFile::OpenZip(int fd, const std::string& location) {
-  UniquePtr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd));
-  if (zip_archive.get() == NULL) {
-    LOG(ERROR) << "Failed to open " << location << " when looking for classes.dex";
-    return NULL;
+const DexFile* DexFile::OpenZip(int fd, const std::string& location, std::string* error_msg) {
+  UniquePtr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, location.c_str(), error_msg));
+  if (zip_archive.get() == nullptr) {
+    DCHECK(!error_msg->empty());
+    return nullptr;
   }
-  return DexFile::Open(*zip_archive.get(), location);
+  return DexFile::Open(*zip_archive.get(), location, error_msg);
 }
 
 const DexFile* DexFile::OpenMemory(const std::string& location,
                                    uint32_t location_checksum,
-                                   MemMap* mem_map) {
+                                   MemMap* mem_map,
+                                   std::string* error_msg) {
   return OpenMemory(mem_map->Begin(),
                     mem_map->Size(),
                     location,
                     location_checksum,
-                    mem_map);
+                    mem_map,
+                    error_msg);
 }
 
-const DexFile* DexFile::Open(const ZipArchive& zip_archive, const std::string& location) {
+const DexFile* DexFile::Open(const ZipArchive& zip_archive, const std::string& location,
+                             std::string* error_msg) {
   CHECK(!location.empty());
   UniquePtr<ZipEntry> zip_entry(zip_archive.Find(kClassesDex));
   if (zip_entry.get() == NULL) {
-    LOG(ERROR) << "Failed to find classes.dex within '" << location << "'";
-    return NULL;
+    *error_msg = StringPrintf("Failed to find classes.dex within '%s'", location.c_str());
+    return nullptr;
   }
-  UniquePtr<MemMap> map(zip_entry->ExtractToMemMap(kClassesDex));
+  UniquePtr<MemMap> map(zip_entry->ExtractToMemMap(kClassesDex, error_msg));
   if (map.get() == NULL) {
-    LOG(ERROR) << "Failed to extract '" << kClassesDex << "' from '" << location << "'";
-    return NULL;
+    *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", kClassesDex, location.c_str(),
+                              error_msg->c_str());
+    return nullptr;
   }
-  UniquePtr<const DexFile> dex_file(OpenMemory(location, zip_entry->GetCrc32(), map.release()));
-  if (dex_file.get() == NULL) {
-    LOG(ERROR) << "Failed to open dex file '" << location << "' from memory";
-    return NULL;
+  UniquePtr<const DexFile> dex_file(OpenMemory(location, zip_entry->GetCrc32(), map.release(),
+                                               error_msg));
+  if (dex_file.get() == nullptr) {
+    *error_msg = StringPrintf("Failed to open dex file '%s' from memory: %s", location.c_str(),
+                              error_msg->c_str());
+    return nullptr;
   }
-  if (!DexFileVerifier::Verify(dex_file.get(), dex_file->Begin(), dex_file->Size())) {
-    LOG(ERROR) << "Failed to verify dex file '" << location << "'";
-    return NULL;
+  if (!DexFileVerifier::Verify(dex_file.get(), dex_file->Begin(), dex_file->Size(),
+                               location.c_str(), error_msg)) {
+    return nullptr;
   }
   if (!dex_file->DisableWrite()) {
-    LOG(ERROR) << "Failed to make dex file read only '" << location << "'";
-    return NULL;
+    *error_msg = StringPrintf("Failed to make dex file '%s' read only", location.c_str());
+    return nullptr;
   }
   CHECK(dex_file->IsReadOnly()) << location;
   return dex_file.release();
@@ -259,11 +272,11 @@
                                    size_t size,
                                    const std::string& location,
                                    uint32_t location_checksum,
-                                   MemMap* mem_map) {
+                                   MemMap* mem_map, std::string* error_msg) {
   CHECK_ALIGNED(base, 4);  // various dex file structures must be word aligned
   UniquePtr<DexFile> dex_file(new DexFile(base, size, location, location_checksum, mem_map));
-  if (!dex_file->Init()) {
-    return NULL;
+  if (!dex_file->Init(error_msg)) {
+    return nullptr;
   } else {
     return dex_file.release();
   }
@@ -276,9 +289,9 @@
   // the global reference table is otherwise empty!
 }
 
-bool DexFile::Init() {
+bool DexFile::Init(std::string* error_msg) {
   InitMembers();
-  if (!CheckMagicAndVersion()) {
+  if (!CheckMagicAndVersion(error_msg)) {
     return false;
   }
   return true;
@@ -296,22 +309,26 @@
   class_defs_ = reinterpret_cast<const ClassDef*>(b + h->class_defs_off_);
 }
 
-bool DexFile::CheckMagicAndVersion() const {
+bool DexFile::CheckMagicAndVersion(std::string* error_msg) const {
   CHECK(header_->magic_ != NULL) << GetLocation();
   if (!IsMagicValid(header_->magic_)) {
-    LOG(ERROR) << "Unrecognized magic number in "  << GetLocation() << ":"
+    std::ostringstream oss;
+    oss << "Unrecognized magic number in "  << GetLocation() << ":"
             << " " << header_->magic_[0]
             << " " << header_->magic_[1]
             << " " << header_->magic_[2]
             << " " << header_->magic_[3];
+    *error_msg = oss.str();
     return false;
   }
   if (!IsVersionValid(header_->magic_)) {
-    LOG(ERROR) << "Unrecognized version number in "  << GetLocation() << ":"
+    std::ostringstream oss;
+    oss << "Unrecognized version number in "  << GetLocation() << ":"
             << " " << header_->magic_[4]
             << " " << header_->magic_[5]
             << " " << header_->magic_[6]
             << " " << header_->magic_[7];
+    *error_msg = oss.str();
     return false;
   }
   return true;
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 12e8440..035a691 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -350,22 +350,22 @@
   // 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)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static bool GetChecksum(const char* filename, uint32_t* checksum, std::string* error_msg);
 
   // Opens .dex file, guessing the container format based on file extension
-  static const DexFile* Open(const std::string& filename,
-                             const std::string& location);
+  static const DexFile* Open(const char* filename, const char* location, std::string* error_msg);
 
   // Opens .dex file, backed by existing memory
   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);
+                             uint32_t location_checksum,
+                             std::string* error_msg) {
+    return OpenMemory(base, size, location, location_checksum, NULL, error_msg);
   }
 
   // Opens .dex file from the classes.dex in a zip archive
-  static const DexFile* Open(const ZipArchive& zip_archive, const std::string& location);
+  static const DexFile* Open(const ZipArchive& zip_archive, const std::string& location,
+                             std::string* error_msg);
 
   // Closes a .dex file.
   virtual ~DexFile();
@@ -820,24 +820,24 @@
 
  private:
   // Opens a .dex file
-  static const DexFile* OpenFile(int fd,
-                                 const std::string& location,
-                                 bool verify);
+  static const DexFile* OpenFile(int fd, const char* location, bool verify, std::string* error_msg);
 
   // Opens a dex file from within a .jar, .zip, or .apk file
-  static const DexFile* OpenZip(int fd, const std::string& location);
+  static const DexFile* OpenZip(int fd, const std::string& location, std::string* error_msg);
 
   // 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);
+                                   MemMap* mem_map,
+                                   std::string* error_msg);
 
   // Opens a .dex file at the given address, optionally backed by a MemMap
   static const DexFile* OpenMemory(const byte* dex_file,
                                    size_t size,
                                    const std::string& location,
                                    uint32_t location_checksum,
-                                   MemMap* mem_map);
+                                   MemMap* mem_map,
+                                   std::string* error_msg);
 
   DexFile(const byte* base, size_t size,
           const std::string& location,
@@ -861,13 +861,13 @@
   }
 
   // Top-level initializer that calls other Init methods.
-  bool Init();
+  bool Init(std::string* error_msg);
 
   // Caches pointers into to the various file sections.
   void InitMembers();
 
   // Returns true if the header magic and version numbers are of the expected values.
-  bool CheckMagicAndVersion() const;
+  bool CheckMagicAndVersion(std::string* error_msg) const;
 
   void DecodeDebugInfo0(const CodeItem* code_item, bool is_static, uint32_t method_idx,
       DexDebugNewPositionCb position_cb, DexDebugNewLocalCb local_cb,
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index 7575d4a..543a7b0 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -56,7 +56,7 @@
   "AAMgAAACAAAAiAIAAAQgAAADAAAAlAIAAAAgAAACAAAAqwIAAAAQAAABAAAAxAIAAA==";
 
 static const DexFile* OpenDexFileBase64(const char* base64,
-                                        const std::string& location) {
+                                        const char* location) {
   // decode base64
   CHECK(base64 != NULL);
   size_t length;
@@ -64,7 +64,7 @@
   CHECK(dex_bytes.get() != NULL);
 
   // write to provided file
-  UniquePtr<File> file(OS::CreateEmptyFile(location.c_str()));
+  UniquePtr<File> file(OS::CreateEmptyFile(location));
   CHECK(file.get() != NULL);
   if (!file->WriteFully(dex_bytes.get(), length)) {
     PLOG(FATAL) << "Failed to write base64 as dex file";
@@ -73,8 +73,9 @@
 
   // read dex file
   ScopedObjectAccess soa(Thread::Current());
-  const DexFile* dex_file = DexFile::Open(location, location);
-  CHECK(dex_file != NULL);
+  std::string error_msg;
+  const DexFile* dex_file = DexFile::Open(location, location, &error_msg);
+  CHECK(dex_file != nullptr) << error_msg;
   EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
   EXPECT_TRUE(dex_file->IsReadOnly());
   return dex_file;
@@ -82,7 +83,7 @@
 
 TEST_F(DexFileTest, Header) {
   ScratchFile tmp;
-  UniquePtr<const DexFile> raw(OpenDexFileBase64(kRawDex, tmp.GetFilename()));
+  UniquePtr<const DexFile> raw(OpenDexFileBase64(kRawDex, tmp.GetFilename().c_str()));
   ASSERT_TRUE(raw.get() != NULL);
 
   const DexFile::Header& header = raw->GetHeader();
@@ -120,7 +121,9 @@
 TEST_F(DexFileTest, GetChecksum) {
   uint32_t checksum;
   ScopedObjectAccess soa(Thread::Current());
-  EXPECT_TRUE(DexFile::GetChecksum(GetLibCoreDexFileName(), &checksum));
+  std::string error_msg;
+  EXPECT_TRUE(DexFile::GetChecksum(GetLibCoreDexFileName().c_str(), &checksum, &error_msg))
+      << error_msg;
   EXPECT_EQ(java_lang_dex_file_->GetLocationChecksum(), checksum);
 }
 
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index 7dc2b31..56bf21d 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -65,12 +65,22 @@
   return true;
 }
 
-static bool CheckShortyDescriptorMatch(char shorty_char, const char* descriptor,
-    bool is_return_type) {
+bool DexFileVerifier::Verify(const DexFile* dex_file, const byte* begin, size_t size,
+                             const char* location, std::string* error_msg) {
+  UniquePtr<DexFileVerifier> verifier(new DexFileVerifier(dex_file, begin, size, location));
+  if (!verifier->Verify()) {
+    *error_msg = verifier->FailureReason();
+    return false;
+  }
+  return true;
+}
+
+bool DexFileVerifier::CheckShortyDescriptorMatch(char shorty_char, const char* descriptor,
+                                                bool is_return_type) {
   switch (shorty_char) {
     case 'V':
-      if (!is_return_type) {
-        LOG(ERROR) << "Invalid use of void";
+      if (UNLIKELY(!is_return_type)) {
+        ErrorStringPrintf("Invalid use of void");
         return false;
       }
       // Intentional fallthrough.
@@ -82,62 +92,58 @@
     case 'J':
     case 'S':
     case 'Z':
-      if ((descriptor[0] != shorty_char) || (descriptor[1] != '\0')) {
-        LOG(ERROR) << StringPrintf("Shorty vs. primitive type mismatch: '%c', '%s'", shorty_char, descriptor);
+      if (UNLIKELY((descriptor[0] != shorty_char) || (descriptor[1] != '\0'))) {
+        ErrorStringPrintf("Shorty vs. primitive type mismatch: '%c', '%s'",
+                          shorty_char, descriptor);
         return false;
       }
       break;
     case 'L':
-      if ((descriptor[0] != 'L') && (descriptor[0] != '[')) {
-        LOG(ERROR) << StringPrintf("Shorty vs. type mismatch: '%c', '%s'", shorty_char, descriptor);
+      if (UNLIKELY((descriptor[0] != 'L') && (descriptor[0] != '['))) {
+        ErrorStringPrintf("Shorty vs. type mismatch: '%c', '%s'", shorty_char, descriptor);
         return false;
       }
       break;
     default:
-      LOG(ERROR) << "Bad shorty character: '" << shorty_char << "'";
+      ErrorStringPrintf("Bad shorty character: '%c'", shorty_char);
       return false;
   }
   return true;
 }
 
-bool DexFileVerifier::Verify(const DexFile* dex_file, const byte* begin, size_t size) {
-  UniquePtr<DexFileVerifier> verifier(new DexFileVerifier(dex_file, begin, size));
-  return verifier->Verify();
-}
-
-bool DexFileVerifier::CheckPointerRange(const void* start, const void* end, const char* label) const {
+bool DexFileVerifier::CheckPointerRange(const void* start, const void* end, const char* label) {
   uint32_t range_start = reinterpret_cast<uint32_t>(start);
   uint32_t range_end = reinterpret_cast<uint32_t>(end);
   uint32_t file_start = reinterpret_cast<uint32_t>(begin_);
   uint32_t file_end = file_start + size_;
-  if ((range_start < file_start) || (range_start > file_end) ||
-      (range_end < file_start) || (range_end > file_end)) {
-    LOG(ERROR) << StringPrintf("Bad range for %s: %x to %x", label,
-        range_start - file_start, range_end - file_start);
+  if (UNLIKELY((range_start < file_start) || (range_start > file_end) ||
+               (range_end < file_start) || (range_end > file_end))) {
+    ErrorStringPrintf("Bad range for %s: %x to %x", label,
+                      range_start - file_start, range_end - file_start);
     return false;
   }
   return true;
 }
 
 bool DexFileVerifier::CheckListSize(const void* start, uint32_t count,
-    uint32_t element_size, const char* label) const {
+                                    uint32_t element_size, const char* label) {
   const byte* list_start = reinterpret_cast<const byte*>(start);
   return CheckPointerRange(list_start, list_start + (count * element_size), label);
 }
 
-bool DexFileVerifier::CheckIndex(uint32_t field, uint32_t limit, const char* label) const {
-  if (field >= limit) {
-    LOG(ERROR) << StringPrintf("Bad index for %s: %x >= %x", label, field, limit);
+bool DexFileVerifier::CheckIndex(uint32_t field, uint32_t limit, const char* label) {
+  if (UNLIKELY(field >= limit)) {
+    ErrorStringPrintf("Bad index for %s: %x >= %x", label, field, limit);
     return false;
   }
   return true;
 }
 
-bool DexFileVerifier::CheckHeader() const {
+bool DexFileVerifier::CheckHeader() {
   // Check file size from the header.
   uint32_t expected_size = header_->file_size_;
   if (size_ != expected_size) {
-    LOG(ERROR) << "Bad file size (" << size_ << ", expected " << expected_size << ")";
+    ErrorStringPrintf("Bad file size (%zd, expected %ud)", size_, expected_size);
     return false;
   }
 
@@ -147,25 +153,25 @@
   const byte* non_sum_ptr = reinterpret_cast<const byte*>(header_) + non_sum;
   adler_checksum = adler32(adler_checksum, non_sum_ptr, expected_size - non_sum);
   if (adler_checksum != header_->checksum_) {
-    LOG(ERROR) << StringPrintf("Bad checksum (%08x, expected %08x)", adler_checksum, header_->checksum_);
+    ErrorStringPrintf("Bad checksum (%08x, expected %08x)", adler_checksum, header_->checksum_);
     return false;
   }
 
   // Check the contents of the header.
   if (header_->endian_tag_ != DexFile::kDexEndianConstant) {
-    LOG(ERROR) << StringPrintf("Unexpected endian_tag: %x", header_->endian_tag_);
+    ErrorStringPrintf("Unexpected endian_tag: %x", header_->endian_tag_);
     return false;
   }
 
   if (header_->header_size_ != sizeof(DexFile::Header)) {
-    LOG(ERROR) << "Bad header size: " << header_->header_size_;
+    ErrorStringPrintf("Bad header size: %ud", header_->header_size_);
     return false;
   }
 
   return true;
 }
 
-bool DexFileVerifier::CheckMap() const {
+bool DexFileVerifier::CheckMap() {
   const DexFile::MapList* map = reinterpret_cast<const DexFile::MapList*>(begin_ + header_->map_off_);
   const DexFile::MapItem* item = map->list_;
 
@@ -182,19 +188,20 @@
 
   // Check the items listed in the map.
   for (uint32_t i = 0; i < count; i++) {
-    if (last_offset >= item->offset_ && i != 0) {
-      LOG(ERROR) << StringPrintf("Out of order map item: %x then %x", last_offset, item->offset_);
+    if (UNLIKELY(last_offset >= item->offset_ && i != 0)) {
+      ErrorStringPrintf("Out of order map item: %x then %x", last_offset, item->offset_);
       return false;
     }
-    if (item->offset_ >= header_->file_size_) {
-      LOG(ERROR) << StringPrintf("Map item after end of file: %x, size %x", item->offset_, header_->file_size_);
+    if (UNLIKELY(item->offset_ >= header_->file_size_)) {
+      ErrorStringPrintf("Map item after end of file: %x, size %x",
+                        item->offset_, header_->file_size_);
       return false;
     }
 
     if (IsDataSectionType(item->type_)) {
       uint32_t icount = item->size_;
-      if (icount > data_items_left) {
-        LOG(ERROR) << "Too many items in data section: " << data_item_count + icount;
+      if (UNLIKELY(icount > data_items_left)) {
+        ErrorStringPrintf("Too many items in data section: %ud", data_item_count + icount);
         return false;
       }
       data_items_left -= icount;
@@ -203,13 +210,13 @@
 
     uint32_t bit = MapTypeToBitMask(item->type_);
 
-    if (bit == 0) {
-      LOG(ERROR) << StringPrintf("Unknown map section type %x", item->type_);
+    if (UNLIKELY(bit == 0)) {
+      ErrorStringPrintf("Unknown map section type %x", item->type_);
       return false;
     }
 
-    if ((used_bits & bit) != 0) {
-      LOG(ERROR) << StringPrintf("Duplicate map section of type %x", item->type_);
+    if (UNLIKELY((used_bits & bit) != 0)) {
+      ErrorStringPrintf("Duplicate map section of type %x", item->type_);
       return false;
     }
 
@@ -219,63 +226,59 @@
   }
 
   // Check for missing sections in the map.
-  if ((used_bits & MapTypeToBitMask(DexFile::kDexTypeHeaderItem)) == 0) {
-    LOG(ERROR) << "Map is missing header entry";
+  if (UNLIKELY((used_bits & MapTypeToBitMask(DexFile::kDexTypeHeaderItem)) == 0)) {
+    ErrorStringPrintf("Map is missing header entry");
     return false;
   }
-  if ((used_bits & MapTypeToBitMask(DexFile::kDexTypeMapList)) == 0) {
-    LOG(ERROR) << "Map is missing map_list entry";
+  if (UNLIKELY((used_bits & MapTypeToBitMask(DexFile::kDexTypeMapList)) == 0)) {
+    ErrorStringPrintf("Map is missing map_list entry");
     return false;
   }
-  if ((used_bits & MapTypeToBitMask(DexFile::kDexTypeStringIdItem)) == 0 &&
-      ((header_->string_ids_off_ != 0) || (header_->string_ids_size_ != 0))) {
-    LOG(ERROR) << "Map is missing string_ids entry";
+  if (UNLIKELY((used_bits & MapTypeToBitMask(DexFile::kDexTypeStringIdItem)) == 0 &&
+               ((header_->string_ids_off_ != 0) || (header_->string_ids_size_ != 0)))) {
+    ErrorStringPrintf("Map is missing string_ids entry");
     return false;
   }
-  if ((used_bits & MapTypeToBitMask(DexFile::kDexTypeTypeIdItem)) == 0 &&
-      ((header_->type_ids_off_ != 0) || (header_->type_ids_size_ != 0))) {
-    LOG(ERROR) << "Map is missing type_ids entry";
+  if (UNLIKELY((used_bits & MapTypeToBitMask(DexFile::kDexTypeTypeIdItem)) == 0 &&
+               ((header_->type_ids_off_ != 0) || (header_->type_ids_size_ != 0)))) {
+    ErrorStringPrintf("Map is missing type_ids entry");
     return false;
   }
-  if ((used_bits & MapTypeToBitMask(DexFile::kDexTypeProtoIdItem)) == 0 &&
-      ((header_->proto_ids_off_ != 0) || (header_->proto_ids_size_ != 0))) {
-    LOG(ERROR) << "Map is missing proto_ids entry";
+  if (UNLIKELY((used_bits & MapTypeToBitMask(DexFile::kDexTypeProtoIdItem)) == 0 &&
+               ((header_->proto_ids_off_ != 0) || (header_->proto_ids_size_ != 0)))) {
+    ErrorStringPrintf("Map is missing proto_ids entry");
     return false;
   }
-  if ((used_bits & MapTypeToBitMask(DexFile::kDexTypeFieldIdItem)) == 0 &&
-      ((header_->field_ids_off_ != 0) || (header_->field_ids_size_ != 0))) {
-    LOG(ERROR) << "Map is missing field_ids entry";
+  if (UNLIKELY((used_bits & MapTypeToBitMask(DexFile::kDexTypeFieldIdItem)) == 0 &&
+               ((header_->field_ids_off_ != 0) || (header_->field_ids_size_ != 0)))) {
+    ErrorStringPrintf("Map is missing field_ids entry");
     return false;
   }
-  if ((used_bits & MapTypeToBitMask(DexFile::kDexTypeMethodIdItem)) == 0 &&
-      ((header_->method_ids_off_ != 0) || (header_->method_ids_size_ != 0))) {
-    LOG(ERROR) << "Map is missing method_ids entry";
+  if (UNLIKELY((used_bits & MapTypeToBitMask(DexFile::kDexTypeMethodIdItem)) == 0 &&
+               ((header_->method_ids_off_ != 0) || (header_->method_ids_size_ != 0)))) {
+    ErrorStringPrintf("Map is missing method_ids entry");
     return false;
   }
-  if ((used_bits & MapTypeToBitMask(DexFile::kDexTypeClassDefItem)) == 0 &&
-      ((header_->class_defs_off_ != 0) || (header_->class_defs_size_ != 0))) {
-    LOG(ERROR) << "Map is missing class_defs entry";
+  if (UNLIKELY((used_bits & MapTypeToBitMask(DexFile::kDexTypeClassDefItem)) == 0 &&
+               ((header_->class_defs_off_ != 0) || (header_->class_defs_size_ != 0)))) {
+    ErrorStringPrintf("Map is missing class_defs entry");
     return false;
   }
-
   return true;
 }
 
 uint32_t DexFileVerifier::ReadUnsignedLittleEndian(uint32_t size) {
   uint32_t result = 0;
-  if (!CheckPointerRange(ptr_, ptr_ + size, "encoded_value")) {
-    return 0;
+  if (LIKELY(CheckPointerRange(ptr_, ptr_ + size, "encoded_value"))) {
+    for (uint32_t i = 0; i < size; i++) {
+      result |= ((uint32_t) *(ptr_++)) << (i * 8);
+    }
   }
-
-  for (uint32_t i = 0; i < size; i++) {
-    result |= ((uint32_t) *(ptr_++)) << (i * 8);
-  }
-
   return result;
 }
 
 bool DexFileVerifier::CheckAndGetHandlerOffsets(const DexFile::CodeItem* code_item,
-    uint32_t* handler_offsets, uint32_t handlers_size) {
+                                                uint32_t* handler_offsets, uint32_t handlers_size) {
   const byte* handlers_base = DexFile::GetCatchHandlerData(*code_item, 0);
 
   for (uint32_t i = 0; i < handlers_size; i++) {
@@ -283,8 +286,8 @@
     uint32_t offset = reinterpret_cast<uint32_t>(ptr_) - reinterpret_cast<uint32_t>(handlers_base);
     int32_t size = DecodeSignedLeb128(&ptr_);
 
-    if ((size < -65536) || (size > 65536)) {
-      LOG(ERROR) << "Invalid exception handler size: " << size;
+    if (UNLIKELY((size < -65536) || (size > 65536))) {
+      ErrorStringPrintf("Invalid exception handler size: %d", size);
       return false;
     }
 
@@ -304,16 +307,16 @@
       }
 
       uint32_t addr = DecodeUnsignedLeb128(&ptr_);
-      if (addr >= code_item->insns_size_in_code_units_) {
-        LOG(ERROR) << StringPrintf("Invalid handler addr: %x", addr);
+      if (UNLIKELY(addr >= code_item->insns_size_in_code_units_)) {
+        ErrorStringPrintf("Invalid handler addr: %x", addr);
         return false;
       }
     }
 
     if (catch_all) {
       uint32_t addr = DecodeUnsignedLeb128(&ptr_);
-      if (addr >= code_item->insns_size_in_code_units_) {
-        LOG(ERROR) << StringPrintf("Invalid handler catch_all_addr: %x", addr);
+      if (UNLIKELY(addr >= code_item->insns_size_in_code_units_)) {
+        ErrorStringPrintf("Invalid handler catch_all_addr: %x", addr);
         return false;
       }
     }
@@ -323,21 +326,21 @@
 }
 
 bool DexFileVerifier::CheckClassDataItemField(uint32_t idx, uint32_t access_flags,
-    bool expect_static) const {
+                                              bool expect_static) {
   if (!CheckIndex(idx, header_->field_ids_size_, "class_data_item field_idx")) {
     return false;
   }
 
   bool is_static = (access_flags & kAccStatic) != 0;
-  if (is_static != expect_static) {
-    LOG(ERROR) << "Static/instance field not in expected list";
+  if (UNLIKELY(is_static != expect_static)) {
+    ErrorStringPrintf("Static/instance field not in expected list");
     return false;
   }
 
   uint32_t access_field_mask = kAccPublic | kAccPrivate | kAccProtected | kAccStatic |
       kAccFinal | kAccVolatile | kAccTransient | kAccSynthetic | kAccEnum;
-  if ((access_flags & ~access_field_mask) != 0) {
-    LOG(ERROR) << StringPrintf("Bad class_data_item field access_flags %x", access_flags);
+  if (UNLIKELY((access_flags & ~access_field_mask) != 0)) {
+    ErrorStringPrintf("Bad class_data_item field access_flags %x", access_flags);
     return false;
   }
 
@@ -345,7 +348,7 @@
 }
 
 bool DexFileVerifier::CheckClassDataItemMethod(uint32_t idx, uint32_t access_flags,
-    uint32_t code_offset, bool expect_direct) const {
+                                               uint32_t code_offset, bool expect_direct) {
   if (!CheckIndex(idx, header_->method_ids_size_, "class_data_item method_idx")) {
     return false;
   }
@@ -355,26 +358,27 @@
   bool is_synchronized = (access_flags & kAccSynchronized) != 0;
   bool allow_synchronized = (access_flags & kAccNative) != 0;
 
-  if (is_direct != expect_direct) {
-    LOG(ERROR) << "Direct/virtual method not in expected list";
+  if (UNLIKELY(is_direct != expect_direct)) {
+    ErrorStringPrintf("Direct/virtual method not in expected list");
     return false;
   }
 
   uint32_t access_method_mask = kAccPublic | kAccPrivate | kAccProtected | kAccStatic |
       kAccFinal | kAccSynchronized | kAccBridge | kAccVarargs | kAccNative | kAccAbstract |
       kAccStrict | kAccSynthetic | kAccConstructor | kAccDeclaredSynchronized;
-  if (((access_flags & ~access_method_mask) != 0) || (is_synchronized && !allow_synchronized)) {
-    LOG(ERROR) << StringPrintf("Bad class_data_item method access_flags %x", access_flags);
+  if (UNLIKELY(((access_flags & ~access_method_mask) != 0) ||
+               (is_synchronized && !allow_synchronized))) {
+    ErrorStringPrintf("Bad class_data_item method access_flags %x", access_flags);
     return false;
   }
 
-  if (expect_code && code_offset == 0) {
-    LOG(ERROR)<< StringPrintf("Unexpected zero value for class_data_item method code_off"
-        " with access flags %x", access_flags);
+  if (UNLIKELY(expect_code && (code_offset == 0))) {
+    ErrorStringPrintf("Unexpected zero value for class_data_item method code_off with access "
+                      "flags %x", access_flags);
     return false;
-  } else if (!expect_code && code_offset != 0) {
-    LOG(ERROR) << StringPrintf("Unexpected non-zero value %x for class_data_item method code_off"
-        " with access flags %x", code_offset, access_flags);
+  } else if (UNLIKELY(!expect_code && (code_offset != 0))) {
+    ErrorStringPrintf("Unexpected non-zero value %x for class_data_item method code_off"
+                      " with access flags %x", code_offset, access_flags);
     return false;
   }
 
@@ -387,8 +391,8 @@
       return false;
     }
     while (offset < aligned_offset) {
-      if (*ptr_ != '\0') {
-        LOG(ERROR) << StringPrintf("Non-zero padding %x before section start at %x", *ptr_, offset);
+      if (UNLIKELY(*ptr_ != '\0')) {
+        ErrorStringPrintf("Non-zero padding %x before section start at %x", *ptr_, offset);
         return false;
       }
       ptr_++;
@@ -409,24 +413,24 @@
 
   switch (value_type) {
     case DexFile::kDexAnnotationByte:
-      if (value_arg != 0) {
-        LOG(ERROR) << StringPrintf("Bad encoded_value byte size %x", value_arg);
+      if (UNLIKELY(value_arg != 0)) {
+        ErrorStringPrintf("Bad encoded_value byte size %x", value_arg);
         return false;
       }
       ptr_++;
       break;
     case DexFile::kDexAnnotationShort:
     case DexFile::kDexAnnotationChar:
-      if (value_arg > 1) {
-        LOG(ERROR) << StringPrintf("Bad encoded_value char/short size %x", value_arg);
+      if (UNLIKELY(value_arg > 1)) {
+        ErrorStringPrintf("Bad encoded_value char/short size %x", value_arg);
         return false;
       }
       ptr_ += value_arg + 1;
       break;
     case DexFile::kDexAnnotationInt:
     case DexFile::kDexAnnotationFloat:
-      if (value_arg > 3) {
-        LOG(ERROR) << StringPrintf("Bad encoded_value int/float size %x", value_arg);
+      if (UNLIKELY(value_arg > 3)) {
+        ErrorStringPrintf("Bad encoded_value int/float size %x", value_arg);
         return false;
       }
       ptr_ += value_arg + 1;
@@ -436,8 +440,8 @@
       ptr_ += value_arg + 1;
       break;
     case DexFile::kDexAnnotationString: {
-      if (value_arg > 3) {
-        LOG(ERROR) << StringPrintf("Bad encoded_value string size %x", value_arg);
+      if (UNLIKELY(value_arg > 3)) {
+        ErrorStringPrintf("Bad encoded_value string size %x", value_arg);
         return false;
       }
       uint32_t idx = ReadUnsignedLittleEndian(value_arg + 1);
@@ -447,8 +451,8 @@
       break;
     }
     case DexFile::kDexAnnotationType: {
-      if (value_arg > 3) {
-        LOG(ERROR) << StringPrintf("Bad encoded_value type size %x", value_arg);
+      if (UNLIKELY(value_arg > 3)) {
+        ErrorStringPrintf("Bad encoded_value type size %x", value_arg);
         return false;
       }
       uint32_t idx = ReadUnsignedLittleEndian(value_arg + 1);
@@ -459,8 +463,8 @@
     }
     case DexFile::kDexAnnotationField:
     case DexFile::kDexAnnotationEnum: {
-      if (value_arg > 3) {
-        LOG(ERROR) << StringPrintf("Bad encoded_value field/enum size %x", value_arg);
+      if (UNLIKELY(value_arg > 3)) {
+        ErrorStringPrintf("Bad encoded_value field/enum size %x", value_arg);
         return false;
       }
       uint32_t idx = ReadUnsignedLittleEndian(value_arg + 1);
@@ -470,8 +474,8 @@
       break;
     }
     case DexFile::kDexAnnotationMethod: {
-      if (value_arg > 3) {
-        LOG(ERROR) << StringPrintf("Bad encoded_value method size %x", value_arg);
+      if (UNLIKELY(value_arg > 3)) {
+        ErrorStringPrintf("Bad encoded_value method size %x", value_arg);
         return false;
       }
       uint32_t idx = ReadUnsignedLittleEndian(value_arg + 1);
@@ -481,8 +485,8 @@
       break;
     }
     case DexFile::kDexAnnotationArray:
-      if (value_arg != 0) {
-        LOG(ERROR) << StringPrintf("Bad encoded_value array value_arg %x", value_arg);
+      if (UNLIKELY(value_arg != 0)) {
+        ErrorStringPrintf("Bad encoded_value array value_arg %x", value_arg);
         return false;
       }
       if (!CheckEncodedArray()) {
@@ -490,8 +494,8 @@
       }
       break;
     case DexFile::kDexAnnotationAnnotation:
-      if (value_arg != 0) {
-        LOG(ERROR) << StringPrintf("Bad encoded_value annotation value_arg %x", value_arg);
+      if (UNLIKELY(value_arg != 0)) {
+        ErrorStringPrintf("Bad encoded_value annotation value_arg %x", value_arg);
         return false;
       }
       if (!CheckEncodedAnnotation()) {
@@ -499,19 +503,19 @@
       }
       break;
     case DexFile::kDexAnnotationNull:
-      if (value_arg != 0) {
-        LOG(ERROR) << StringPrintf("Bad encoded_value null value_arg %x", value_arg);
+      if (UNLIKELY(value_arg != 0)) {
+        ErrorStringPrintf("Bad encoded_value null value_arg %x", value_arg);
         return false;
       }
       break;
     case DexFile::kDexAnnotationBoolean:
-      if (value_arg > 1) {
-        LOG(ERROR) << StringPrintf("Bad encoded_value boolean size %x", value_arg);
+      if (UNLIKELY(value_arg > 1)) {
+        ErrorStringPrintf("Bad encoded_value boolean size %x", value_arg);
         return false;
       }
       break;
     default:
-      LOG(ERROR) << StringPrintf("Bogus encoded_value value_type %x", value_type);
+      ErrorStringPrintf("Bogus encoded_value value_type %x", value_type);
       return false;
   }
 
@@ -523,7 +527,7 @@
 
   while (size--) {
     if (!CheckEncodedValue()) {
-      LOG(ERROR) << "Bad encoded_array value";
+      failure_reason_ = StringPrintf("Bad encoded_array value: %s", failure_reason_.c_str());
       return false;
     }
   }
@@ -545,9 +549,9 @@
       return false;
     }
 
-    if (last_idx >= idx && i != 0) {
-      LOG(ERROR) << StringPrintf("Out-of-order annotation_element name_idx: %x then %x",
-          last_idx, idx);
+    if (UNLIKELY(last_idx >= idx && i != 0)) {
+      ErrorStringPrintf("Out-of-order annotation_element name_idx: %x then %x",
+                        last_idx, idx);
       return false;
     }
 
@@ -596,21 +600,22 @@
     return false;
   }
 
-  if (code_item->ins_size_ > code_item->registers_size_) {
-    LOG(ERROR) << "ins_size (" << code_item->ins_size_ << ") > registers_size ("
-               << code_item->registers_size_ << ")";
+  if (UNLIKELY(code_item->ins_size_ > code_item->registers_size_)) {
+    ErrorStringPrintf("ins_size (%ud) > registers_size (%ud)",
+                      code_item->ins_size_, code_item->registers_size_);
     return false;
   }
 
-  if ((code_item->outs_size_ > 5) && (code_item->outs_size_ > code_item->registers_size_)) {
+  if (UNLIKELY((code_item->outs_size_ > 5) &&
+               (code_item->outs_size_ > code_item->registers_size_))) {
     /*
      * outs_size can be up to 5, even if registers_size is smaller, since the
      * short forms of method invocation allow repetitions of a register multiple
      * times within a single parameter list. However, longer parameter lists
      * need to be represented in-order in the register file.
      */
-    LOG(ERROR) << "outs_size (" << code_item->outs_size_ << ") > registers_size ("
-               << code_item->registers_size_ << ")";
+    ErrorStringPrintf("outs_size (%ud) > registers_size (%ud)",
+                      code_item->outs_size_, code_item->registers_size_);
     return false;
   }
 
@@ -629,7 +634,7 @@
 
   // try_items are 4-byte aligned. Verify the spacer is 0.
   if ((((uint32_t) &insns[insns_size] & 3) != 0) && (insns[insns_size] != 0)) {
-    LOG(ERROR) << StringPrintf("Non-zero padding: %x", insns[insns_size]);
+    ErrorStringPrintf("Non-zero padding: %x", insns[insns_size]);
     return false;
   }
 
@@ -641,8 +646,8 @@
     return false;
   }
 
-  if ((handlers_size == 0) || (handlers_size >= 65536)) {
-    LOG(ERROR) << "Invalid handlers_size: " << handlers_size;
+  if (UNLIKELY((handlers_size == 0) || (handlers_size >= 65536))) {
+    ErrorStringPrintf("Invalid handlers_size: %ud", handlers_size);
     return false;
   }
 
@@ -653,14 +658,13 @@
 
   uint32_t last_addr = 0;
   while (try_items_size--) {
-    if (try_items->start_addr_ < last_addr) {
-      LOG(ERROR) << StringPrintf("Out-of_order try_item with start_addr: %x",
-          try_items->start_addr_);
+    if (UNLIKELY(try_items->start_addr_ < last_addr)) {
+      ErrorStringPrintf("Out-of_order try_item with start_addr: %x", try_items->start_addr_);
       return false;
     }
 
-    if (try_items->start_addr_ >= insns_size) {
-      LOG(ERROR) << StringPrintf("Invalid try_item start_addr: %x", try_items->start_addr_);
+    if (UNLIKELY(try_items->start_addr_ >= insns_size)) {
+      ErrorStringPrintf("Invalid try_item start_addr: %x", try_items->start_addr_);
       return false;
     }
 
@@ -671,14 +675,14 @@
       }
     }
 
-    if (i == handlers_size) {
-      LOG(ERROR) << StringPrintf("Bogus handler offset: %x", try_items->handler_off_);
+    if (UNLIKELY(i == handlers_size)) {
+      ErrorStringPrintf("Bogus handler offset: %x", try_items->handler_off_);
       return false;
     }
 
     last_addr = try_items->start_addr_ + try_items->insn_count_;
-    if (last_addr > insns_size) {
-      LOG(ERROR) << StringPrintf("Invalid try_item insn_count: %x", try_items->insn_count_);
+    if (UNLIKELY(last_addr > insns_size)) {
+      ErrorStringPrintf("Invalid try_item insn_count: %x", try_items->insn_count_);
       return false;
     }
 
@@ -693,8 +697,8 @@
   const byte* file_end = begin_ + size_;
 
   for (uint32_t i = 0; i < size; i++) {
-    if (ptr_ >= file_end) {
-      LOG(ERROR) << "String data would go beyond end-of-file";
+    if (UNLIKELY(ptr_ >= file_end)) {
+      ErrorStringPrintf("String data would go beyond end-of-file");
       return false;
     }
 
@@ -704,8 +708,8 @@
     switch (byte >> 4) {
       case 0x00:
         // Special case of bit pattern 0xxx.
-        if (byte == 0) {
-          LOG(ERROR) << StringPrintf("String data shorter than indicated utf16_size %x", size);
+        if (UNLIKELY(byte == 0)) {
+          ErrorStringPrintf("String data shorter than indicated utf16_size %x", size);
           return false;
         }
         break;
@@ -725,19 +729,19 @@
       case 0x0f:
         // Illegal bit patterns 10xx or 1111.
         // Note: 1111 is valid for normal UTF-8, but not here.
-        LOG(ERROR) << StringPrintf("Illegal start byte %x in string data", byte);
+        ErrorStringPrintf("Illegal start byte %x in string data", byte);
         return false;
       case 0x0c:
       case 0x0d: {
         // Bit pattern 110x has an additional byte.
         uint8_t byte2 = *(ptr_++);
-        if ((byte2 & 0xc0) != 0x80) {
-          LOG(ERROR) << StringPrintf("Illegal continuation byte %x in string data", byte2);
+        if (UNLIKELY((byte2 & 0xc0) != 0x80)) {
+          ErrorStringPrintf("Illegal continuation byte %x in string data", byte2);
           return false;
         }
         uint16_t value = ((byte & 0x1f) << 6) | (byte2 & 0x3f);
-        if ((value != 0) && (value < 0x80)) {
-          LOG(ERROR) << StringPrintf("Illegal representation for value %x in string data", value);
+        if (UNLIKELY((value != 0) && (value < 0x80))) {
+          ErrorStringPrintf("Illegal representation for value %x in string data", value);
           return false;
         }
         break;
@@ -745,18 +749,18 @@
       case 0x0e: {
         // Bit pattern 1110 has 2 additional bytes.
         uint8_t byte2 = *(ptr_++);
-        if ((byte2 & 0xc0) != 0x80) {
-          LOG(ERROR) << StringPrintf("Illegal continuation byte %x in string data", byte2);
+        if (UNLIKELY((byte2 & 0xc0) != 0x80)) {
+          ErrorStringPrintf("Illegal continuation byte %x in string data", byte2);
           return false;
         }
         uint8_t byte3 = *(ptr_++);
-        if ((byte3 & 0xc0) != 0x80) {
-          LOG(ERROR) << StringPrintf("Illegal continuation byte %x in string data", byte3);
+        if (UNLIKELY((byte3 & 0xc0) != 0x80)) {
+          ErrorStringPrintf("Illegal continuation byte %x in string data", byte3);
           return false;
         }
         uint16_t value = ((byte & 0x0f) << 12) | ((byte2 & 0x3f) << 6) | (byte3 & 0x3f);
-        if (value < 0x800) {
-          LOG(ERROR) << StringPrintf("Illegal representation for value %x in string data", value);
+        if (UNLIKELY(value < 0x800)) {
+          ErrorStringPrintf("Illegal representation for value %x in string data", value);
           return false;
         }
         break;
@@ -764,8 +768,8 @@
     }
   }
 
-  if (*(ptr_++) != '\0') {
-    LOG(ERROR) << StringPrintf("String longer than indicated size %x", size);
+  if (UNLIKELY(*(ptr_++) != '\0')) {
+    ErrorStringPrintf("String longer than indicated size %x", size);
     return false;
   }
 
@@ -775,8 +779,8 @@
 bool DexFileVerifier::CheckIntraDebugInfoItem() {
   DecodeUnsignedLeb128(&ptr_);
   uint32_t parameters_size = DecodeUnsignedLeb128(&ptr_);
-  if (parameters_size > 65536) {
-    LOG(ERROR) << StringPrintf("Invalid parameters_size: %x", parameters_size);
+  if (UNLIKELY(parameters_size > 65536)) {
+    ErrorStringPrintf("Invalid parameters_size: %x", parameters_size);
     return false;
   }
 
@@ -806,8 +810,8 @@
       }
       case DexFile::DBG_START_LOCAL: {
         uint32_t reg_num = DecodeUnsignedLeb128(&ptr_);
-        if (reg_num >= 65536) {
-          LOG(ERROR) << StringPrintf("Bad reg_num for opcode %x", opcode);
+        if (UNLIKELY(reg_num >= 65536)) {
+          ErrorStringPrintf("Bad reg_num for opcode %x", opcode);
           return false;
         }
         uint32_t name_idx = DecodeUnsignedLeb128(&ptr_);
@@ -829,16 +833,16 @@
       case DexFile::DBG_END_LOCAL:
       case DexFile::DBG_RESTART_LOCAL: {
         uint32_t reg_num = DecodeUnsignedLeb128(&ptr_);
-        if (reg_num >= 65536) {
-          LOG(ERROR) << StringPrintf("Bad reg_num for opcode %x", opcode);
+        if (UNLIKELY(reg_num >= 65536)) {
+          ErrorStringPrintf("Bad reg_num for opcode %x", opcode);
           return false;
         }
         break;
       }
       case DexFile::DBG_START_LOCAL_EXTENDED: {
         uint32_t reg_num = DecodeUnsignedLeb128(&ptr_);
-        if (reg_num >= 65536) {
-          LOG(ERROR) << StringPrintf("Bad reg_num for opcode %x", opcode);
+        if (UNLIKELY(reg_num >= 65536)) {
+          ErrorStringPrintf("Bad reg_num for opcode %x", opcode);
           return false;
         }
         uint32_t name_idx = DecodeUnsignedLeb128(&ptr_);
@@ -890,7 +894,7 @@
     case DexFile::kDexVisibilitySystem:
       break;
     default:
-      LOG(ERROR) << StringPrintf("Bad annotation visibility: %x", *ptr_);
+      ErrorStringPrintf("Bad annotation visibility: %x", *ptr_);
       return false;
   }
 
@@ -918,8 +922,8 @@
 
   uint32_t last_idx = 0;
   for (uint32_t i = 0; i < field_count; i++) {
-    if (last_idx >= field_item->field_idx_ && i != 0) {
-      LOG(ERROR) << StringPrintf("Out-of-order field_idx for annotation: %x then %x", last_idx, field_item->field_idx_);
+    if (UNLIKELY(last_idx >= field_item->field_idx_ && i != 0)) {
+      ErrorStringPrintf("Out-of-order field_idx for annotation: %x then %x", last_idx, field_item->field_idx_);
       return false;
     }
     last_idx = field_item->field_idx_;
@@ -936,9 +940,9 @@
 
   last_idx = 0;
   for (uint32_t i = 0; i < method_count; i++) {
-    if (last_idx >= method_item->method_idx_ && i != 0) {
-      LOG(ERROR) << StringPrintf("Out-of-order method_idx for annotation: %x then %x",
-          last_idx, method_item->method_idx_);
+    if (UNLIKELY(last_idx >= method_item->method_idx_ && i != 0)) {
+      ErrorStringPrintf("Out-of-order method_idx for annotation: %x then %x",
+                       last_idx, method_item->method_idx_);
       return false;
     }
     last_idx = method_item->method_idx_;
@@ -950,15 +954,15 @@
       reinterpret_cast<const DexFile::ParameterAnnotationsItem*>(method_item);
   uint32_t parameter_count = item->parameters_size_;
   if (!CheckListSize(parameter_item, parameter_count, sizeof(DexFile::ParameterAnnotationsItem),
-      "parameter_annotations list")) {
+                     "parameter_annotations list")) {
     return false;
   }
 
   last_idx = 0;
   for (uint32_t i = 0; i < parameter_count; i++) {
-    if (last_idx >= parameter_item->method_idx_ && i != 0) {
-      LOG(ERROR) << StringPrintf("Out-of-order method_idx for annotation: %x then %x",
-          last_idx, parameter_item->method_idx_);
+    if (UNLIKELY(last_idx >= parameter_item->method_idx_ && i != 0)) {
+      ErrorStringPrintf("Out-of-order method_idx for annotation: %x then %x",
+                        last_idx, parameter_item->method_idx_);
       return false;
     }
     last_idx = parameter_item->method_idx_;
@@ -1059,7 +1063,7 @@
 
         if (!CheckPointerRange(list, list + 1, "annotation_set_ref_list") ||
             !CheckListSize(item, count, sizeof(DexFile::AnnotationSetRefItem),
-                "annotation_set_ref_list size")) {
+                           "annotation_set_ref_list size")) {
           return false;
         }
         ptr_ = reinterpret_cast<const byte*>(item + count);
@@ -1121,7 +1125,7 @@
         break;
       }
       default:
-        LOG(ERROR) << StringPrintf("Unknown map item type %x", type);
+        ErrorStringPrintf("Unknown map item type %x", type);
         return false;
     }
 
@@ -1130,8 +1134,8 @@
     }
 
     aligned_offset = reinterpret_cast<uint32_t>(ptr_) - reinterpret_cast<uint32_t>(begin_);
-    if (aligned_offset > size_) {
-      LOG(ERROR) << StringPrintf("Item %d at ends out of bounds", i);
+    if (UNLIKELY(aligned_offset > size_)) {
+      ErrorStringPrintf("Item %d at ends out of bounds", i);
       return false;
     }
 
@@ -1172,17 +1176,17 @@
       expected_size = header_->class_defs_size_;
       break;
     default:
-      LOG(ERROR) << StringPrintf("Bad type for id section: %x", type);
+      ErrorStringPrintf("Bad type for id section: %x", type);
       return false;
   }
 
   // Check that the offset and size are what were expected from the header.
-  if (offset != expected_offset) {
-    LOG(ERROR) << StringPrintf("Bad offset for section: got %x, expected %x", offset, expected_offset);
+  if (UNLIKELY(offset != expected_offset)) {
+    ErrorStringPrintf("Bad offset for section: got %x, expected %x", offset, expected_offset);
     return false;
   }
-  if (count != expected_size) {
-    LOG(ERROR) << StringPrintf("Bad size for section: got %x, expected %x", count, expected_size);
+  if (UNLIKELY(count != expected_size)) {
+    ErrorStringPrintf("Bad size for section: got %x, expected %x", count, expected_size);
     return false;
   }
 
@@ -1194,8 +1198,8 @@
   uint32_t data_end = data_start + header_->data_size_;
 
   // Sanity check the offset of the section.
-  if ((offset < data_start) || (offset > data_end)) {
-    LOG(ERROR) << StringPrintf("Bad offset for data subsection: %x", offset);
+  if (UNLIKELY((offset < data_start) || (offset > data_end))) {
+    ErrorStringPrintf("Bad offset for data subsection: %x", offset);
     return false;
   }
 
@@ -1205,7 +1209,7 @@
 
   uint32_t next_offset = reinterpret_cast<uint32_t>(ptr_) - reinterpret_cast<uint32_t>(begin_);
   if (next_offset > data_end) {
-    LOG(ERROR) << StringPrintf("Out-of-bounds end of data subsection: %x", next_offset);
+    ErrorStringPrintf("Out-of-bounds end of data subsection: %x", next_offset);
     return false;
   }
 
@@ -1229,20 +1233,20 @@
     // Check for padding and overlap between items.
     if (!CheckPadding(offset, section_offset)) {
       return false;
-    } else if (offset > section_offset) {
-      LOG(ERROR) << StringPrintf("Section overlap or out-of-order map: %x, %x", offset, section_offset);
+    } else if (UNLIKELY(offset > section_offset)) {
+      ErrorStringPrintf("Section overlap or out-of-order map: %x, %x", offset, section_offset);
       return false;
     }
 
     // Check each item based on its type.
     switch (type) {
       case DexFile::kDexTypeHeaderItem:
-        if (section_count != 1) {
-          LOG(ERROR) << "Multiple header items";
+        if (UNLIKELY(section_count != 1)) {
+          ErrorStringPrintf("Multiple header items");
           return false;
         }
-        if (section_offset != 0) {
-          LOG(ERROR) << StringPrintf("Header at %x, not at start of file", section_offset);
+        if (UNLIKELY(section_offset != 0)) {
+          ErrorStringPrintf("Header at %x, not at start of file", section_offset);
           return false;
         }
         ptr_ = begin_ + header_->header_size_;
@@ -1260,13 +1264,13 @@
         offset = reinterpret_cast<uint32_t>(ptr_) - reinterpret_cast<uint32_t>(begin_);
         break;
       case DexFile::kDexTypeMapList:
-        if (section_count != 1) {
-          LOG(ERROR) << "Multiple map list items";
+        if (UNLIKELY(section_count != 1)) {
+          ErrorStringPrintf("Multiple map list items");
           return false;
         }
-        if (section_offset != header_->map_off_) {
-          LOG(ERROR) << StringPrintf("Map not at header-defined offset: %x, expected %x",
-              section_offset, header_->map_off_);
+        if (UNLIKELY(section_offset != header_->map_off_)) {
+          ErrorStringPrintf("Map not at header-defined offset: %x, expected %x",
+                            section_offset, header_->map_off_);
           return false;
         }
         ptr_ += sizeof(uint32_t) + (map->size_ * sizeof(DexFile::MapItem));
@@ -1288,7 +1292,7 @@
         offset = reinterpret_cast<uint32_t>(ptr_) - reinterpret_cast<uint32_t>(begin_);
         break;
       default:
-        LOG(ERROR) << StringPrintf("Unknown map item type %x", type);
+        ErrorStringPrintf("Unknown map item type %x", type);
         return false;
     }
 
@@ -1300,13 +1304,13 @@
 
 bool DexFileVerifier::CheckOffsetToTypeMap(uint32_t offset, uint16_t type) {
   auto it = offset_to_type_map_.find(offset);
-  if (it == offset_to_type_map_.end()) {
-    LOG(ERROR) << StringPrintf("No data map entry found @ %x; expected %x", offset, type);
+  if (UNLIKELY(it == offset_to_type_map_.end())) {
+    ErrorStringPrintf("No data map entry found @ %x; expected %x", offset, type);
     return false;
   }
-  if (it->second != type) {
-    LOG(ERROR) << StringPrintf("Unexpected data map entry @ %x; expected %x, found %x",
-        offset, type, it->second);
+  if (UNLIKELY(it->second != type)) {
+    ErrorStringPrintf("Unexpected data map entry @ %x; expected %x, found %x",
+                      offset, type, it->second);
     return false;
   }
   return true;
@@ -1365,8 +1369,8 @@
     const DexFile::StringId* prev_item = reinterpret_cast<const DexFile::StringId*>(previous_item_);
     const char* prev_str = dex_file_->GetStringData(*prev_item);
     const char* str = dex_file_->GetStringData(*item);
-    if (CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(prev_str, str) >= 0) {
-      LOG(ERROR) << StringPrintf("Out-of-order string_ids: '%s' then '%s'", prev_str, str);
+    if (UNLIKELY(CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(prev_str, str) >= 0)) {
+      ErrorStringPrintf("Out-of-order string_ids: '%s' then '%s'", prev_str, str);
       return false;
     }
   }
@@ -1380,17 +1384,17 @@
   const char* descriptor = dex_file_->StringDataByIdx(item->descriptor_idx_);
 
   // Check that the descriptor is a valid type.
-  if (!IsValidDescriptor(descriptor)) {
-    LOG(ERROR) << StringPrintf("Invalid type descriptor: '%s'", descriptor);
+  if (UNLIKELY(!IsValidDescriptor(descriptor))) {
+    ErrorStringPrintf("Invalid type descriptor: '%s'", descriptor);
     return false;
   }
 
   // Check ordering between items.
   if (previous_item_ != NULL) {
     const DexFile::TypeId* prev_item = reinterpret_cast<const DexFile::TypeId*>(previous_item_);
-    if (prev_item->descriptor_idx_ >= item->descriptor_idx_) {
-      LOG(ERROR) << StringPrintf("Out-of-order type_ids: %x then %x",
-          prev_item->descriptor_idx_, item->descriptor_idx_);
+    if (UNLIKELY(prev_item->descriptor_idx_ >= item->descriptor_idx_)) {
+      ErrorStringPrintf("Out-of-order type_ids: %x then %x",
+                        prev_item->descriptor_idx_, item->descriptor_idx_);
       return false;
     }
   }
@@ -1422,16 +1426,16 @@
     it.Next();
     shorty++;
   }
-  if (it.HasNext() || *shorty != '\0') {
-    LOG(ERROR) << "Mismatched length for parameters and shorty";
+  if (UNLIKELY(it.HasNext() || *shorty != '\0')) {
+    ErrorStringPrintf("Mismatched length for parameters and shorty");
     return false;
   }
 
   // Check ordering between items. This relies on type_ids being in order.
   if (previous_item_ != NULL) {
     const DexFile::ProtoId* prev = reinterpret_cast<const DexFile::ProtoId*>(previous_item_);
-    if (prev->return_type_idx_ > item->return_type_idx_) {
-      LOG(ERROR) << "Out-of-order proto_id return types";
+    if (UNLIKELY(prev->return_type_idx_ > item->return_type_idx_)) {
+      ErrorStringPrintf("Out-of-order proto_id return types");
       return false;
     } else if (prev->return_type_idx_ == item->return_type_idx_) {
       DexFileParameterIterator curr_it(*dex_file_, *item);
@@ -1443,15 +1447,15 @@
         if (prev_idx == DexFile::kDexNoIndex16) {
           break;
         }
-        if (curr_idx == DexFile::kDexNoIndex16) {
-          LOG(ERROR) << "Out-of-order proto_id arguments";
+        if (UNLIKELY(curr_idx == DexFile::kDexNoIndex16)) {
+          ErrorStringPrintf("Out-of-order proto_id arguments");
           return false;
         }
 
         if (prev_idx < curr_idx) {
           break;
-        } else if (prev_idx > curr_idx) {
-          LOG(ERROR) << "Out-of-order proto_id arguments";
+        } else if (UNLIKELY(prev_idx > curr_idx)) {
+          ErrorStringPrintf("Out-of-order proto_id arguments");
           return false;
         }
 
@@ -1470,38 +1474,38 @@
 
   // Check that the class descriptor is valid.
   const char* descriptor = dex_file_->StringByTypeIdx(item->class_idx_);
-  if (!IsValidDescriptor(descriptor) || descriptor[0] != 'L') {
-    LOG(ERROR) << "Invalid descriptor for class_idx: '" << descriptor << '"';
+  if (UNLIKELY(!IsValidDescriptor(descriptor) || descriptor[0] != 'L')) {
+    ErrorStringPrintf("Invalid descriptor for class_idx: '%s'", descriptor);
     return false;
   }
 
   // Check that the type descriptor is a valid field name.
   descriptor = dex_file_->StringByTypeIdx(item->type_idx_);
-  if (!IsValidDescriptor(descriptor) || descriptor[0] == 'V') {
-    LOG(ERROR) << "Invalid descriptor for type_idx: '" << descriptor << '"';
+  if (UNLIKELY(!IsValidDescriptor(descriptor) || descriptor[0] == 'V')) {
+    ErrorStringPrintf("Invalid descriptor for type_idx: '%s'", descriptor);
     return false;
   }
 
   // Check that the name is valid.
   descriptor = dex_file_->StringDataByIdx(item->name_idx_);
-  if (!IsValidMemberName(descriptor)) {
-    LOG(ERROR) << "Invalid field name: '" << descriptor << '"';
+  if (UNLIKELY(!IsValidMemberName(descriptor))) {
+    ErrorStringPrintf("Invalid field name: '%s'", descriptor);
     return false;
   }
 
   // Check ordering between items. This relies on the other sections being in order.
   if (previous_item_ != NULL) {
     const DexFile::FieldId* prev_item = reinterpret_cast<const DexFile::FieldId*>(previous_item_);
-    if (prev_item->class_idx_ > item->class_idx_) {
-      LOG(ERROR) << "Out-of-order field_ids";
+    if (UNLIKELY(prev_item->class_idx_ > item->class_idx_)) {
+      ErrorStringPrintf("Out-of-order field_ids");
       return false;
     } else if (prev_item->class_idx_ == item->class_idx_) {
-      if (prev_item->name_idx_ > item->name_idx_) {
-        LOG(ERROR) << "Out-of-order field_ids";
+      if (UNLIKELY(prev_item->name_idx_ > item->name_idx_)) {
+        ErrorStringPrintf("Out-of-order field_ids");
         return false;
       } else if (prev_item->name_idx_ == item->name_idx_) {
-        if (prev_item->type_idx_ >= item->type_idx_) {
-          LOG(ERROR) << "Out-of-order field_ids";
+        if (UNLIKELY(prev_item->type_idx_ >= item->type_idx_)) {
+          ErrorStringPrintf("Out-of-order field_ids");
           return false;
         }
       }
@@ -1517,31 +1521,31 @@
 
   // Check that the class descriptor is a valid reference name.
   const char* descriptor = dex_file_->StringByTypeIdx(item->class_idx_);
-  if (!IsValidDescriptor(descriptor) || (descriptor[0] != 'L' && descriptor[0] != '[')) {
-    LOG(ERROR) << "Invalid descriptor for class_idx: '" << descriptor << '"';
+  if (UNLIKELY(!IsValidDescriptor(descriptor) || (descriptor[0] != 'L' && descriptor[0] != '['))) {
+    ErrorStringPrintf("Invalid descriptor for class_idx: '%s'", descriptor);
     return false;
   }
 
   // Check that the name is valid.
   descriptor = dex_file_->StringDataByIdx(item->name_idx_);
-  if (!IsValidMemberName(descriptor)) {
-    LOG(ERROR) << "Invalid method name: '" << descriptor << '"';
+  if (UNLIKELY(!IsValidMemberName(descriptor))) {
+    ErrorStringPrintf("Invalid method name: '%s'", descriptor);
     return false;
   }
 
   // Check ordering between items. This relies on the other sections being in order.
   if (previous_item_ != NULL) {
     const DexFile::MethodId* prev_item = reinterpret_cast<const DexFile::MethodId*>(previous_item_);
-    if (prev_item->class_idx_ > item->class_idx_) {
-      LOG(ERROR) << "Out-of-order method_ids";
+    if (UNLIKELY(prev_item->class_idx_ > item->class_idx_)) {
+      ErrorStringPrintf("Out-of-order method_ids");
       return false;
     } else if (prev_item->class_idx_ == item->class_idx_) {
-      if (prev_item->name_idx_ > item->name_idx_) {
-        LOG(ERROR) << "Out-of-order method_ids";
+      if (UNLIKELY(prev_item->name_idx_ > item->name_idx_)) {
+        ErrorStringPrintf("Out-of-order method_ids");
         return false;
       } else if (prev_item->name_idx_ == item->name_idx_) {
-        if (prev_item->proto_idx_ >= item->proto_idx_) {
-          LOG(ERROR) << "Out-of-order method_ids";
+        if (UNLIKELY(prev_item->proto_idx_ >= item->proto_idx_)) {
+          ErrorStringPrintf("Out-of-order method_ids");
           return false;
         }
       }
@@ -1557,8 +1561,8 @@
   uint32_t class_idx = item->class_idx_;
   const char* descriptor = dex_file_->StringByTypeIdx(class_idx);
 
-  if (!IsValidDescriptor(descriptor) || descriptor[0] != 'L') {
-    LOG(ERROR) << "Invalid class descriptor: '" << descriptor << "'";
+  if (UNLIKELY(!IsValidDescriptor(descriptor) || descriptor[0] != 'L')) {
+    ErrorStringPrintf("Invalid class descriptor: '%s'", descriptor);
     return false;
   }
 
@@ -1581,8 +1585,8 @@
 
   if (item->superclass_idx_ != DexFile::kDexNoIndex16) {
     descriptor = dex_file_->StringByTypeIdx(item->superclass_idx_);
-    if (!IsValidDescriptor(descriptor) || descriptor[0] != 'L') {
-      LOG(ERROR) << "Invalid superclass: '" << descriptor << "'";
+    if (UNLIKELY(!IsValidDescriptor(descriptor) || descriptor[0] != 'L')) {
+      ErrorStringPrintf("Invalid superclass: '%s'", descriptor);
       return false;
     }
   }
@@ -1594,8 +1598,8 @@
     // Ensure that all interfaces refer to classes (not arrays or primitives).
     for (uint32_t i = 0; i < size; i++) {
       descriptor = dex_file_->StringByTypeIdx(interfaces->GetTypeItem(i).type_idx_);
-      if (!IsValidDescriptor(descriptor) || descriptor[0] != 'L') {
-        LOG(ERROR) << "Invalid interface: '" << descriptor << "'";
+      if (UNLIKELY(!IsValidDescriptor(descriptor) || descriptor[0] != 'L')) {
+        ErrorStringPrintf("Invalid interface: '%s'", descriptor);
         return false;
       }
     }
@@ -1608,8 +1612,8 @@
       uint32_t idx1 = interfaces->GetTypeItem(i).type_idx_;
       for (uint32_t j =0; j < i; j++) {
         uint32_t idx2 = interfaces->GetTypeItem(j).type_idx_;
-        if (idx1 == idx2) {
-          LOG(ERROR) << "Duplicate interface: '" << dex_file_->StringByTypeIdx(idx1) << "'";
+        if (UNLIKELY(idx1 == idx2)) {
+          ErrorStringPrintf("Duplicate interface: '%s'", dex_file_->StringByTypeIdx(idx1));
           return false;
         }
       }
@@ -1620,8 +1624,8 @@
   if (item->class_data_off_ != 0) {
     const byte* data = begin_ + item->class_data_off_;
     uint16_t data_definer = FindFirstClassDataDefiner(data);
-    if ((data_definer != item->class_idx_) && (data_definer != DexFile::kDexNoIndex16)) {
-      LOG(ERROR) << "Invalid class_data_item";
+    if (UNLIKELY((data_definer != item->class_idx_) && (data_definer != DexFile::kDexNoIndex16))) {
+      ErrorStringPrintf("Invalid class_data_item");
       return false;
     }
   }
@@ -1630,8 +1634,9 @@
   if (item->annotations_off_ != 0) {
     const byte* data = begin_ + item->annotations_off_;
     uint16_t annotations_definer = FindFirstAnnotationsDirectoryDefiner(data);
-    if ((annotations_definer != item->class_idx_) && (annotations_definer != DexFile::kDexNoIndex16)) {
-      LOG(ERROR) << "Invalid annotations_directory_item";
+    if (UNLIKELY((annotations_definer != item->class_idx_) &&
+                 (annotations_definer != DexFile::kDexNoIndex16))) {
+      ErrorStringPrintf("Invalid annotations_directory_item");
       return false;
     }
   }
@@ -1675,8 +1680,8 @@
     const uint8_t* data = annotation->annotation_;
     uint32_t idx = DecodeUnsignedLeb128(&data);
 
-    if (last_idx >= idx && i != 0) {
-      LOG(ERROR) << StringPrintf("Out-of-order entry types: %x then %x", last_idx, idx);
+    if (UNLIKELY(last_idx >= idx && i != 0)) {
+      ErrorStringPrintf("Out-of-order entry types: %x then %x", last_idx, idx);
       return false;
     }
 
@@ -1694,8 +1699,8 @@
 
   for (; it.HasNextStaticField() || it.HasNextInstanceField(); it.Next()) {
     const DexFile::FieldId& field = dex_file_->GetFieldId(it.GetMemberIndex());
-    if (field.class_idx_ != defining_class) {
-      LOG(ERROR) << "Mismatched defining class for class_data_item field";
+    if (UNLIKELY(field.class_idx_ != defining_class)) {
+      ErrorStringPrintf("Mismatched defining class for class_data_item field");
       return false;
     }
   }
@@ -1705,8 +1710,8 @@
       return false;
     }
     const DexFile::MethodId& method = dex_file_->GetMethodId(it.GetMemberIndex());
-    if (method.class_idx_ != defining_class) {
-      LOG(ERROR) << "Mismatched defining class for class_data_item method";
+    if (UNLIKELY(method.class_idx_ != defining_class)) {
+      ErrorStringPrintf("Mismatched defining class for class_data_item method");
       return false;
     }
   }
@@ -1731,8 +1736,8 @@
   uint32_t field_count = item->fields_size_;
   for (uint32_t i = 0; i < field_count; i++) {
     const DexFile::FieldId& field = dex_file_->GetFieldId(field_item->field_idx_);
-    if (field.class_idx_ != defining_class) {
-      LOG(ERROR) << "Mismatched defining class for field_annotation";
+    if (UNLIKELY(field.class_idx_ != defining_class)) {
+      ErrorStringPrintf("Mismatched defining class for field_annotation");
       return false;
     }
     if (!CheckOffsetToTypeMap(field_item->annotations_off_, DexFile::kDexTypeAnnotationSetItem)) {
@@ -1747,8 +1752,8 @@
   uint32_t method_count = item->methods_size_;
   for (uint32_t i = 0; i < method_count; i++) {
     const DexFile::MethodId& method = dex_file_->GetMethodId(method_item->method_idx_);
-    if (method.class_idx_ != defining_class) {
-      LOG(ERROR) << "Mismatched defining class for method_annotation";
+    if (UNLIKELY(method.class_idx_ != defining_class)) {
+      ErrorStringPrintf("Mismatched defining class for method_annotation");
       return false;
     }
     if (!CheckOffsetToTypeMap(method_item->annotations_off_, DexFile::kDexTypeAnnotationSetItem)) {
@@ -1763,8 +1768,8 @@
   uint32_t parameter_count = item->parameters_size_;
   for (uint32_t i = 0; i < parameter_count; i++) {
     const DexFile::MethodId& parameter_method = dex_file_->GetMethodId(parameter_item->method_idx_);
-    if (parameter_method.class_idx_ != defining_class) {
-      LOG(ERROR) << "Mismatched defining class for parameter_annotation";
+    if (UNLIKELY(parameter_method.class_idx_ != defining_class)) {
+      ErrorStringPrintf("Mismatched defining class for parameter_annotation");
       return false;
     }
     if (!CheckOffsetToTypeMap(parameter_item->annotations_off_,
@@ -1860,7 +1865,7 @@
         break;
       }
       default:
-        LOG(ERROR) << StringPrintf("Unknown map item type %x", type);
+        ErrorStringPrintf("Unknown map item type %x", type);
         return false;
     }
 
@@ -1908,7 +1913,7 @@
         break;
       }
       default:
-        LOG(ERROR) << StringPrintf("Unknown map item type %x", type);
+        ErrorStringPrintf("Unknown map item type %x", type);
         return false;
     }
 
@@ -1942,4 +1947,13 @@
   return true;
 }
 
+void DexFileVerifier::ErrorStringPrintf(const char* fmt, ...) {
+  va_list ap;
+  va_start(ap, fmt);
+  DCHECK(failure_reason_.empty()) << failure_reason_;
+  failure_reason_ = StringPrintf("Failure to verify dex file '%s': ", location_);
+  StringAppendV(&failure_reason_, fmt, ap);
+  va_end(ap);
+}
+
 }  // namespace art
diff --git a/runtime/dex_file_verifier.h b/runtime/dex_file_verifier.h
index 3797dc7..4b8b80a 100644
--- a/runtime/dex_file_verifier.h
+++ b/runtime/dex_file_verifier.h
@@ -24,29 +24,35 @@
 
 class DexFileVerifier {
  public:
-  static bool Verify(const DexFile* dex_file, const byte* begin, size_t size);
+  static bool Verify(const DexFile* dex_file, const byte* begin, size_t size,
+                     const char* location, std::string* error_msg);
+
+  const std::string& FailureReason() const {
+    return failure_reason_;
+  }
 
  private:
-  DexFileVerifier(const DexFile* dex_file, const byte* begin, size_t size)
-      : dex_file_(dex_file), begin_(begin), size_(size),
+  DexFileVerifier(const DexFile* dex_file, const byte* begin, size_t size, const char* location)
+      : dex_file_(dex_file), begin_(begin), size_(size), location_(location),
         header_(&dex_file->GetHeader()), ptr_(NULL), previous_item_(NULL)  {
   }
 
   bool Verify();
 
-  bool CheckPointerRange(const void* start, const void* end, const char* label) const;
-  bool CheckListSize(const void* start, uint32_t count, uint32_t element_size, const char* label) const;
-  bool CheckIndex(uint32_t field, uint32_t limit, const char* label) const;
+  bool CheckShortyDescriptorMatch(char shorty_char, const char* descriptor, bool is_return_type);
+  bool CheckPointerRange(const void* start, const void* end, const char* label);
+  bool CheckListSize(const void* start, uint32_t count, uint32_t element_size, const char* label);
+  bool CheckIndex(uint32_t field, uint32_t limit, const char* label);
 
-  bool CheckHeader() const;
-  bool CheckMap() const;
+  bool CheckHeader();
+  bool CheckMap();
 
   uint32_t ReadUnsignedLittleEndian(uint32_t size);
   bool CheckAndGetHandlerOffsets(const DexFile::CodeItem* code_item,
-      uint32_t* handler_offsets, uint32_t handlers_size);
-  bool CheckClassDataItemField(uint32_t idx, uint32_t access_flags, bool expect_static) const;
+                                 uint32_t* handler_offsets, uint32_t handlers_size);
+  bool CheckClassDataItemField(uint32_t idx, uint32_t access_flags, bool expect_static);
   bool CheckClassDataItemMethod(uint32_t idx, uint32_t access_flags, uint32_t code_offset,
-      bool expect_direct) const;
+                                bool expect_direct);
   bool CheckPadding(uint32_t offset, uint32_t aligned_offset);
   bool CheckEncodedValue();
   bool CheckEncodedArray();
@@ -82,14 +88,20 @@
   bool CheckInterSectionIterate(uint32_t offset, uint32_t count, uint16_t type);
   bool CheckInterSection();
 
-  const DexFile* dex_file_;
-  const byte* begin_;
-  size_t size_;
-  const DexFile::Header* header_;
+  void ErrorStringPrintf(const char* fmt, ...)
+      __attribute__((__format__(__printf__, 2, 3))) COLD_ATTR;
+
+  const DexFile* const dex_file_;
+  const byte* const begin_;
+  const size_t size_;
+  const char* const location_;
+  const DexFile::Header* const header_;
 
   SafeMap<uint32_t, uint16_t> offset_to_type_map_;
   const byte* ptr_;
   const void* previous_item_;
+
+  std::string failure_reason_;
 };
 
 }  // namespace art
diff --git a/runtime/dex_method_iterator_test.cc b/runtime/dex_method_iterator_test.cc
index 64c645e..9961df9 100644
--- a/runtime/dex_method_iterator_test.cc
+++ b/runtime/dex_method_iterator_test.cc
@@ -20,16 +20,27 @@
 
 namespace art {
 
-class DexMethodIteratorTest : public CommonTest {};
+class DexMethodIteratorTest : public CommonTest {
+ public:
+  const DexFile* OpenDexFile(const std::string& partial_filename) {
+    std::string dfn = GetDexFileName(partial_filename);
+    std::string error_msg;
+    const DexFile* dexfile = DexFile::Open(dfn.c_str(), dfn.c_str(), &error_msg);
+    if (dexfile == nullptr) {
+      LG << "Failed to open '" << dfn << "': " << error_msg;
+    }
+    return dexfile;
+  }
+};
 
 TEST_F(DexMethodIteratorTest, Basic) {
   ScopedObjectAccess soa(Thread::Current());
   std::vector<const DexFile*> dex_files;
-  dex_files.push_back(DexFile::Open(GetDexFileName("core"), GetDexFileName("core")));
-  dex_files.push_back(DexFile::Open(GetDexFileName("conscrypt"), GetDexFileName("conscrypt")));
-  dex_files.push_back(DexFile::Open(GetDexFileName("okhttp"), GetDexFileName("okhttp")));
-  dex_files.push_back(DexFile::Open(GetDexFileName("core-junit"), GetDexFileName("core-junit")));
-  dex_files.push_back(DexFile::Open(GetDexFileName("bouncycastle"), GetDexFileName("bouncycastle")));
+  dex_files.push_back(OpenDexFile("core"));
+  dex_files.push_back(OpenDexFile("conscrypt"));
+  dex_files.push_back(OpenDexFile("okhttp"));
+  dex_files.push_back(OpenDexFile("core-junit"));
+  dex_files.push_back(OpenDexFile("bouncycastle"));
   DexMethodIterator it(dex_files);
   while (it.HasNext()) {
     const DexFile& dex_file = it.GetDexFile();
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index dfb6819..15c95f2 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -40,15 +40,16 @@
     symtab_symbol_table_(NULL),
     dynsym_symbol_table_(NULL) {}
 
-ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only) {
+ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only,
+                       std::string* error_msg) {
   UniquePtr<ElfFile> elf_file(new ElfFile());
-  if (!elf_file->Setup(file, writable, program_header_only)) {
-    return NULL;
+  if (!elf_file->Setup(file, writable, program_header_only, error_msg)) {
+    return nullptr;
   }
   return elf_file.release();
 }
 
-bool ElfFile::Setup(File* file, bool writable, bool program_header_only) {
+bool ElfFile::Setup(File* file, bool writable, bool program_header_only, std::string* error_msg) {
   CHECK(file != NULL);
   file_ = file;
   writable_ = writable;
@@ -66,40 +67,42 @@
   int64_t file_length = file_->GetLength();
   if (file_length < 0) {
     errno = -file_length;
-    PLOG(WARNING) << "Failed to get length of file: " << file_->GetPath() << " fd=" << file_->Fd();
+    *error_msg = StringPrintf("Failed to get length of file: '%s' fd=%d: %s",
+                              file_->GetPath().c_str(), file_->Fd(), strerror(errno));
     return false;
   }
   if (file_length < sizeof(llvm::ELF::Elf32_Ehdr)) {
-    if (writable) {
-      LOG(WARNING) << "File size of " << file_length
-                   << " bytes not large enough to contain ELF header of "
-                   << sizeof(llvm::ELF::Elf32_Ehdr) << " bytes: " << file_->GetPath();
-    }
+    *error_msg = StringPrintf("File size of %lld bytes not large enough to contain ELF header of "
+                              "%zd bytes: '%s'", file_length, sizeof(llvm::ELF::Elf32_Ehdr),
+                              file_->GetPath().c_str());
     return false;
   }
 
   if (program_header_only) {
     // first just map ELF header to get program header size information
     size_t elf_header_size = sizeof(llvm::ELF::Elf32_Ehdr);
-    if (!SetMap(MemMap::MapFile(elf_header_size, prot, flags, file_->Fd(), 0))) {
+    if (!SetMap(MemMap::MapFile(elf_header_size, prot, flags, file_->Fd(), 0,
+                                file_->GetPath().c_str(), error_msg))) {
       return false;
     }
     // then remap to cover program header
     size_t program_header_size = header_->e_phoff + (header_->e_phentsize * header_->e_phnum);
     if (file_length < program_header_size) {
-      LOG(WARNING) << "File size of " << file_length
-                   << " bytes not large enough to contain ELF program header of "
-                   << program_header_size << " bytes: " << file_->GetPath();
+      *error_msg = StringPrintf("File size of %lld bytes not large enough to contain ELF program "
+                                "header of %zd bytes: '%s'", file_length,
+                                sizeof(llvm::ELF::Elf32_Ehdr), file_->GetPath().c_str());
       return false;
     }
-    if (!SetMap(MemMap::MapFile(program_header_size, prot, flags, file_->Fd(), 0))) {
-      LOG(WARNING) << "Failed to map ELF program headers: " << file_->GetPath();
+    if (!SetMap(MemMap::MapFile(program_header_size, prot, flags, file_->Fd(), 0,
+                                file_->GetPath().c_str(), error_msg))) {
+      *error_msg = StringPrintf("Failed to map ELF program headers: %s", error_msg->c_str());
       return false;
     }
   } else {
     // otherwise map entire file
-    if (!SetMap(MemMap::MapFile(file_->GetLength(), prot, flags, file_->Fd(), 0))) {
-      LOG(WARNING) << "Failed to map ELF file: " << file_->GetPath();
+    if (!SetMap(MemMap::MapFile(file_->GetLength(), prot, flags, file_->Fd(), 0,
+                                file_->GetPath().c_str(), error_msg))) {
+      *error_msg = StringPrintf("Failed to map ELF file: %s", error_msg->c_str());
       return false;
     }
   }
@@ -114,7 +117,8 @@
     // Find .dynamic section info from program header
     dynamic_program_header_ = FindProgamHeaderByType(llvm::ELF::PT_DYNAMIC);
     if (dynamic_program_header_ == NULL) {
-      LOG(WARNING) << "Failed to find PT_DYNAMIC program header in ELF file: " << file_->GetPath();
+      *error_msg = StringPrintf("Failed to find PT_DYNAMIC program header in ELF file: '%s'",
+                                file_->GetPath().c_str());
       return false;
     }
 
@@ -596,7 +600,7 @@
   return loaded_size;
 }
 
-bool ElfFile::Load(bool executable) {
+bool ElfFile::Load(bool executable, std::string* error_msg) {
   // TODO: actually return false error
   CHECK(program_header_only_) << file_->GetPath();
   for (llvm::ELF::Elf32_Word i = 0; i < GetProgramHeaderNum(); i++) {
@@ -628,9 +632,10 @@
     if (program_header.p_vaddr == 0) {
       std::string reservation_name("ElfFile reservation for ");
       reservation_name += file_->GetPath();
+      std::string error_msg;
       UniquePtr<MemMap> reserve(MemMap::MapAnonymous(reservation_name.c_str(),
-                                                     NULL, GetLoadedSize(), PROT_NONE));
-      CHECK(reserve.get() != NULL) << file_->GetPath();
+                                                     NULL, GetLoadedSize(), PROT_NONE, &error_msg));
+      CHECK(reserve.get() != NULL) << file_->GetPath() << ": " << error_msg;
       base_address_ = reserve->Begin();
       segments_.push_back(reserve.release());
     }
@@ -657,18 +662,20 @@
       flags |= MAP_PRIVATE;
     }
     if (file_length < (program_header.p_offset + program_header.p_memsz)) {
-      LOG(WARNING) << "File size of " << file_length
-                   << " bytes not large enough to contain ELF segment " << i
-                   << " of " << (program_header.p_offset + program_header.p_memsz)
-                   << " bytes: " << file_->GetPath();
+      *error_msg = StringPrintf("File size of %lld bytes not large enough to contain ELF segment "
+                                "%d of %d bytes: '%s'", file_length, i,
+                                program_header.p_offset + program_header.p_memsz,
+                                file_->GetPath().c_str());
       return false;
     }
     UniquePtr<MemMap> segment(MemMap::MapFileAtAddress(p_vaddr,
                                                        program_header.p_memsz,
                                                        prot, flags, file_->Fd(),
                                                        program_header.p_offset,
-                                                       true));
-    CHECK(segment.get() != NULL) << file_->GetPath();
+                                                       true,
+                                                       file_->GetPath().c_str(),
+                                                       error_msg));
+    CHECK(segment.get() != nullptr) << *error_msg;
     CHECK_EQ(segment->Begin(), p_vaddr) << file_->GetPath();
     segments_.push_back(segment.release());
   }
diff --git a/runtime/elf_file.h b/runtime/elf_file.h
index 33b5fc3..b025137 100644
--- a/runtime/elf_file.h
+++ b/runtime/elf_file.h
@@ -35,7 +35,7 @@
 // ELFObjectFile.
 class ElfFile {
  public:
-  static ElfFile* Open(File* file, bool writable, bool program_header_only);
+  static ElfFile* Open(File* file, bool writable, bool program_header_only, std::string* error_msg);
   ~ElfFile();
 
   // Load segments into memory based on PT_LOAD program headers
@@ -115,12 +115,12 @@
 
   // Load segments into memory based on PT_LOAD program headers.
   // executable is true at run time, false at compile time.
-  bool Load(bool executable);
+  bool Load(bool executable, std::string* error_msg);
 
  private:
   ElfFile();
 
-  bool Setup(File* file, bool writable, bool program_header_only);
+  bool Setup(File* file, bool writable, bool program_header_only, std::string* error_msg);
 
   bool SetMap(MemMap* map);
 
diff --git a/runtime/gc/accounting/atomic_stack.h b/runtime/gc/accounting/atomic_stack.h
index 997d725..8fa5b86 100644
--- a/runtime/gc/accounting/atomic_stack.h
+++ b/runtime/gc/accounting/atomic_stack.h
@@ -163,8 +163,10 @@
 
   // Size in number of elements.
   void Init() {
-    mem_map_.reset(MemMap::MapAnonymous(name_.c_str(), NULL, capacity_ * sizeof(T), PROT_READ | PROT_WRITE));
-    CHECK(mem_map_.get() != NULL) << "couldn't allocate mark stack";
+    std::string error_msg;
+    mem_map_.reset(MemMap::MapAnonymous(name_.c_str(), NULL, capacity_ * sizeof(T),
+                                        PROT_READ | PROT_WRITE, &error_msg));
+    CHECK(mem_map_.get() != NULL) << "couldn't allocate mark stack.\n" << error_msg;
     byte* addr = mem_map_->Begin();
     CHECK(addr != NULL);
     debug_is_sorted_ = true;
diff --git a/runtime/gc/accounting/card_table.cc b/runtime/gc/accounting/card_table.cc
index 85034a0..7818bc8 100644
--- a/runtime/gc/accounting/card_table.cc
+++ b/runtime/gc/accounting/card_table.cc
@@ -54,9 +54,11 @@
   /* Set up the card table */
   size_t capacity = heap_capacity / kCardSize;
   /* Allocate an extra 256 bytes to allow fixed low-byte of base */
+  std::string error_msg;
   UniquePtr<MemMap> mem_map(MemMap::MapAnonymous("card table", NULL,
-                                                 capacity + 256, PROT_READ | PROT_WRITE));
-  CHECK(mem_map.get() != NULL) << "couldn't allocate card table";
+                                                 capacity + 256, PROT_READ | PROT_WRITE,
+                                                 &error_msg));
+  CHECK(mem_map.get() != NULL) << "couldn't allocate card table: " << error_msg;
   // All zeros is the correct initial value; all clean. Anonymous mmaps are initialized to zero, we
   // don't clear the card table to avoid unnecessary pages being allocated
   COMPILE_ASSERT(kCardClean == 0, card_clean_must_be_0);
diff --git a/runtime/gc/accounting/gc_allocator.cc b/runtime/gc/accounting/gc_allocator.cc
index 11d0e67..49d84fa 100644
--- a/runtime/gc/accounting/gc_allocator.cc
+++ b/runtime/gc/accounting/gc_allocator.cc
@@ -22,15 +22,17 @@
 namespace art {
 namespace gc {
 namespace accounting {
-  void* RegisterGCAllocation(size_t bytes) {
-    Runtime::Current()->GetHeap()->RegisterGCAllocation(bytes);
-    return malloc(bytes);
-  }
 
-  void RegisterGCDeAllocation(void* p, size_t bytes) {
-    Runtime::Current()->GetHeap()->RegisterGCDeAllocation(bytes);
-    free(p);
-  }
+void* RegisterGcAllocation(size_t bytes) {
+  Runtime::Current()->GetHeap()->RegisterGCAllocation(bytes);
+  return malloc(bytes);
+}
+
+void RegisterGcDeallocation(void* p, size_t bytes) {
+  Runtime::Current()->GetHeap()->RegisterGCDeAllocation(bytes);
+  free(p);
+}
+
 }  // namespace accounting
 }  // namespace gc
 }  // namespace art
diff --git a/runtime/gc/accounting/gc_allocator.h b/runtime/gc/accounting/gc_allocator.h
index 1fba858..4fe9367 100644
--- a/runtime/gc/accounting/gc_allocator.h
+++ b/runtime/gc/accounting/gc_allocator.h
@@ -26,55 +26,56 @@
 namespace art {
 namespace gc {
 namespace accounting {
-  void* RegisterGCAllocation(size_t bytes);
-  void RegisterGCDeAllocation(void* p, size_t bytes);
 
-  static const bool kMeasureGCMemoryOverhead = false;
+void* RegisterGcAllocation(size_t bytes);
+void RegisterGcDeallocation(void* p, size_t bytes);
 
-  template <typename T>
-  class GCAllocatorImpl : public std::allocator<T> {
-  public:
-    typedef typename std::allocator<T>::value_type value_type;
-    typedef typename std::allocator<T>::size_type size_type;
-    typedef typename std::allocator<T>::difference_type difference_type;
-    typedef typename std::allocator<T>::pointer pointer;
-    typedef typename std::allocator<T>::const_pointer const_pointer;
-    typedef typename std::allocator<T>::reference reference;
-    typedef typename std::allocator<T>::const_reference const_reference;
+static const bool kMeasureGcMemoryOverhead = false;
 
-    // Used internally by STL data structures.
-    template <class U>
-    GCAllocatorImpl(const GCAllocatorImpl<U>& alloc) throw() {
-    }
+template <typename T>
+class GcAllocatorImpl : public std::allocator<T> {
+ public:
+  typedef typename std::allocator<T>::value_type value_type;
+  typedef typename std::allocator<T>::size_type size_type;
+  typedef typename std::allocator<T>::difference_type difference_type;
+  typedef typename std::allocator<T>::pointer pointer;
+  typedef typename std::allocator<T>::const_pointer const_pointer;
+  typedef typename std::allocator<T>::reference reference;
+  typedef typename std::allocator<T>::const_reference const_reference;
 
-    // Used internally by STL data structures.
-    GCAllocatorImpl() throw() {
-    }
+  // Used internally by STL data structures.
+  template <class U>
+  GcAllocatorImpl(const GcAllocatorImpl<U>& alloc) throw() {
+  }
 
-    // Enables an allocator for objects of one type to allocate storage for objects of another type.
-    // Used internally by STL data structures.
-    template <class U>
-    struct rebind {
-        typedef GCAllocatorImpl<U> other;
-    };
+  // Used internally by STL data structures.
+  GcAllocatorImpl() throw() {
+  }
 
-    pointer allocate(size_type n, const_pointer hint = 0) {
-      return reinterpret_cast<pointer>(RegisterGCAllocation(n * sizeof(T)));
-    }
-
-    template <typename PT>
-    void deallocate(PT p, size_type n) {
-      RegisterGCDeAllocation(p, n * sizeof(T));
-    }
+  // Enables an allocator for objects of one type to allocate storage for objects of another type.
+  // Used internally by STL data structures.
+  template <class U>
+  struct rebind {
+    typedef GcAllocatorImpl<U> other;
   };
 
-  // C++ doesn't allow template typedefs. This is a workaround template typedef which is
-  // GCAllocatorImpl<T> if kMeasureGCMemoryOverhead is true, std::allocator<T> otherwise.
-  template <typename T>
-  class GCAllocator : public TypeStaticIf<kMeasureGCMemoryOverhead,
-                                          GCAllocatorImpl<T>,
-                                          std::allocator<T> >::value {
-  };
+  pointer allocate(size_type n, const_pointer hint = 0) {
+    return reinterpret_cast<pointer>(RegisterGcAllocation(n * sizeof(T)));
+  }
+
+  template <typename PT>
+  void deallocate(PT p, size_type n) {
+    RegisterGcDeallocation(p, n * sizeof(T));
+  }
+};
+
+// C++ doesn't allow template typedefs. This is a workaround template typedef which is
+// GCAllocatorImpl<T> if kMeasureGCMemoryOverhead is true, std::allocator<T> otherwise.
+template <typename T>
+class GcAllocator : public TypeStaticIf<kMeasureGcMemoryOverhead, GcAllocatorImpl<T>,
+                                        std::allocator<T> >::value {
+};
+
 }  // namespace accounting
 }  // namespace gc
 }  // namespace art
diff --git a/runtime/gc/accounting/heap_bitmap.h b/runtime/gc/accounting/heap_bitmap.h
index 2ca8c4a..24ebbaa 100644
--- a/runtime/gc/accounting/heap_bitmap.h
+++ b/runtime/gc/accounting/heap_bitmap.h
@@ -31,8 +31,8 @@
 
 class HeapBitmap {
  public:
-  typedef std::vector<SpaceBitmap*, GCAllocator<SpaceBitmap*> > SpaceBitmapVector;
-  typedef std::vector<SpaceSetMap*, GCAllocator<SpaceSetMap*> > SpaceSetMapVector;
+  typedef std::vector<SpaceBitmap*, GcAllocator<SpaceBitmap*> > SpaceBitmapVector;
+  typedef std::vector<SpaceSetMap*, GcAllocator<SpaceSetMap*> > SpaceSetMapVector;
 
   bool Test(const mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
     SpaceBitmap* bitmap = GetContinuousSpaceBitmap(obj);
diff --git a/runtime/gc/accounting/mod_union_table.h b/runtime/gc/accounting/mod_union_table.h
index d874c60..5a99f1b 100644
--- a/runtime/gc/accounting/mod_union_table.h
+++ b/runtime/gc/accounting/mod_union_table.h
@@ -51,7 +51,7 @@
 // cleared between GC phases, reducing the number of dirty cards that need to be scanned.
 class ModUnionTable {
  public:
-  typedef std::set<byte*, std::less<byte*>, GCAllocator<byte*> > CardSet;
+  typedef std::set<byte*, std::less<byte*>, GcAllocator<byte*> > CardSet;
 
   explicit ModUnionTable(const std::string& name, Heap* heap, space::ContinuousSpace* space)
       : name_(name),
@@ -125,7 +125,7 @@
 
   // Maps from dirty cards to their corresponding alloc space references.
   SafeMap<const byte*, std::vector<mirror::Object**>, std::less<const byte*>,
-    GCAllocator<std::pair<const byte*, std::vector<mirror::Object**> > > > references_;
+    GcAllocator<std::pair<const byte*, std::vector<mirror::Object**> > > > references_;
 };
 
 // Card caching implementation. Keeps track of which cards we cleared and only this information.
diff --git a/runtime/gc/accounting/space_bitmap.cc b/runtime/gc/accounting/space_bitmap.cc
index 63b24ff..52c02f7 100644
--- a/runtime/gc/accounting/space_bitmap.cc
+++ b/runtime/gc/accounting/space_bitmap.cc
@@ -62,9 +62,11 @@
   CHECK(heap_begin != NULL);
   // Round up since heap_capacity is not necessarily a multiple of kAlignment * kBitsPerWord.
   size_t bitmap_size = OffsetToIndex(RoundUp(heap_capacity, kAlignment * kBitsPerWord)) * kWordSize;
-  UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(name.c_str(), NULL, bitmap_size, PROT_READ | PROT_WRITE));
-  if (mem_map.get() == NULL) {
-    LOG(ERROR) << "Failed to allocate bitmap " << name;
+  std::string error_msg;
+  UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(name.c_str(), NULL, bitmap_size,
+                                                 PROT_READ | PROT_WRITE, &error_msg));
+  if (UNLIKELY(mem_map.get() == nullptr)) {
+    LOG(ERROR) << "Failed to allocate bitmap " << name << ": " << error_msg;
     return NULL;
   }
   return CreateFromMemMap(name, mem_map.release(), heap_begin, heap_capacity);
diff --git a/runtime/gc/accounting/space_bitmap.h b/runtime/gc/accounting/space_bitmap.h
index 4cf8872..21709ad 100644
--- a/runtime/gc/accounting/space_bitmap.h
+++ b/runtime/gc/accounting/space_bitmap.h
@@ -212,7 +212,7 @@
  public:
   typedef std::set<
       const mirror::Object*, std::less<const mirror::Object*>,
-      GCAllocator<const mirror::Object*> > Objects;
+      GcAllocator<const mirror::Object*> > Objects;
 
   bool IsEmpty() const {
     return contained_.empty();
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index d26e28c..804c669 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -66,7 +66,7 @@
 static constexpr size_t kMinConcurrentRemainingBytes = 128 * KB;
 
 Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max_free,
-           double target_utilization, size_t capacity, const std::string& original_image_file_name,
+           double target_utilization, size_t capacity, const std::string& image_file_name,
            bool concurrent_gc, size_t parallel_gc_threads, size_t conc_gc_threads,
            bool low_memory_mode, size_t long_pause_log_threshold, size_t long_gc_log_threshold,
            bool ignore_max_footprint)
@@ -144,9 +144,8 @@
 
   // Requested begin for the alloc space, to follow the mapped image and oat files
   byte* requested_alloc_space_begin = NULL;
-  std::string image_file_name(original_image_file_name);
   if (!image_file_name.empty()) {
-    space::ImageSpace* image_space = space::ImageSpace::Create(image_file_name);
+    space::ImageSpace* image_space = space::ImageSpace::Create(image_file_name.c_str());
     CHECK(image_space != NULL) << "Failed to create space for " << image_file_name;
     AddContinuousSpace(image_space);
     // Oat files referenced by image files immediately follow them in memory, ensure alloc space
diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc
index 468d1d2..8c13d79 100644
--- a/runtime/gc/space/dlmalloc_space.cc
+++ b/runtime/gc/space/dlmalloc_space.cc
@@ -183,11 +183,12 @@
   growth_limit = RoundUp(growth_limit, kPageSize);
   capacity = RoundUp(capacity, kPageSize);
 
+  std::string error_msg;
   UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(name.c_str(), requested_begin, capacity,
-                                                 PROT_READ | PROT_WRITE));
+                                                 PROT_READ | PROT_WRITE, &error_msg));
   if (mem_map.get() == NULL) {
     LOG(ERROR) << "Failed to allocate pages for alloc space (" << name << ") of size "
-        << PrettySize(capacity);
+        << PrettySize(capacity) << ": " << error_msg;
     return NULL;
   }
 
@@ -307,7 +308,10 @@
   VLOG(heap) << "Size " << GetMemMap()->Size();
   VLOG(heap) << "GrowthLimit " << PrettySize(growth_limit);
   VLOG(heap) << "Capacity " << PrettySize(capacity);
-  UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(alloc_space_name, End(), capacity, PROT_READ | PROT_WRITE));
+  std::string error_msg;
+  UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(alloc_space_name, End(), capacity,
+                                                 PROT_READ | PROT_WRITE, &error_msg));
+  CHECK(mem_map.get() != nullptr) << error_msg;
   void* mspace = CreateMallocSpace(end_, starting_size, initial_size);
   // Protect memory beyond the initial size.
   byte* end = mem_map->Begin() + starting_size;
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 1cd33ee..fa28642 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -44,12 +44,13 @@
   live_bitmap_.reset(live_bitmap);
 }
 
-static bool GenerateImage(const std::string& image_file_name) {
+static bool GenerateImage(const std::string& image_file_name, std::string* error_msg) {
   const std::string boot_class_path_string(Runtime::Current()->GetBootClassPathString());
   std::vector<std::string> boot_class_path;
   Split(boot_class_path_string, ':', boot_class_path);
   if (boot_class_path.empty()) {
-    LOG(FATAL) << "Failed to generate image because no boot class path specified";
+    *error_msg = "Failed to generate image because no boot class path specified";
+    return false;
   }
 
   std::vector<std::string> arg_vector;
@@ -112,41 +113,57 @@
     return false;
   } else {
     if (pid == -1) {
-      PLOG(ERROR) << "fork failed";
+      *error_msg = StringPrintf("Failed to generate image '%s' because fork failed: %s",
+                                image_file_name.c_str(), strerror(errno));
+      return false;
     }
 
     // wait for dex2oat to finish
     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;
+      *error_msg = StringPrintf("Failed to generate image '%s' because waitpid failed: "
+                                "wanted %d, got %d: %s",
+                                image_file_name.c_str(), pid, got_pid, strerror(errno));
       return false;
     }
     if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
-      LOG(ERROR) << dex2oat << " failed: " << command_line;
+      *error_msg = StringPrintf("Failed to generate image '%s' because dex2oat failed: %s",
+                                image_file_name.c_str(), command_line.c_str());
       return false;
     }
   }
   return true;
 }
 
-ImageSpace* ImageSpace::Create(const std::string& original_image_file_name) {
-  if (OS::FileExists(original_image_file_name.c_str())) {
+ImageSpace* ImageSpace::Create(const char* original_image_file_name) {
+  if (OS::FileExists(original_image_file_name)) {
     // If the /system file exists, it should be up-to-date, don't try to generate
-    return space::ImageSpace::Init(original_image_file_name, false);
+    std::string error_msg;
+    ImageSpace* space = ImageSpace::Init(original_image_file_name, false, &error_msg);
+    if (space == nullptr) {
+      LOG(FATAL) << "Failed to load image '" << original_image_file_name << "': " << error_msg;
+    }
+    return space;
   }
   // If the /system file didn't exist, we need to use one from the dalvik-cache.
   // If the cache file exists, try to open, but if it fails, regenerate.
   // If it does not exist, generate.
   std::string image_file_name(GetDalvikCacheFilenameOrDie(original_image_file_name));
+  std::string error_msg;
   if (OS::FileExists(image_file_name.c_str())) {
-    space::ImageSpace* image_space = space::ImageSpace::Init(image_file_name, true);
-    if (image_space != NULL) {
+    space::ImageSpace* image_space = ImageSpace::Init(image_file_name.c_str(), true, &error_msg);
+    if (image_space != nullptr) {
       return image_space;
     }
   }
-  CHECK(GenerateImage(image_file_name)) << "Failed to generate image: " << image_file_name;
-  return space::ImageSpace::Init(image_file_name, true);
+  CHECK(GenerateImage(image_file_name, &error_msg))
+      << "Failed to generate image '" << image_file_name << "': " << error_msg;
+  ImageSpace* space = ImageSpace::Init(image_file_name.c_str(), true, &error_msg);
+  if (space == nullptr) {
+    LOG(FATAL) << "Failed to load image '" << original_image_file_name << "': " << error_msg;
+  }
+  return space;
 }
 
 void ImageSpace::VerifyImageAllocations() {
@@ -160,8 +177,9 @@
   }
 }
 
-ImageSpace* ImageSpace::Init(const std::string& image_file_name, bool validate_oat_file) {
-  CHECK(!image_file_name.empty());
+ImageSpace* ImageSpace::Init(const char* image_file_name, bool validate_oat_file,
+                             std::string* error_msg) {
+  CHECK(image_file_name != nullptr);
 
   uint64_t start_time = 0;
   if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
@@ -169,16 +187,16 @@
     LOG(INFO) << "ImageSpace::Init entering image_file_name=" << image_file_name;
   }
 
-  UniquePtr<File> file(OS::OpenFileForReading(image_file_name.c_str()));
+  UniquePtr<File> file(OS::OpenFileForReading(image_file_name));
   if (file.get() == NULL) {
-    LOG(ERROR) << "Failed to open " << image_file_name;
-    return NULL;
+    *error_msg = StringPrintf("Failed to open '%s'", image_file_name);
+    return nullptr;
   }
   ImageHeader image_header;
   bool success = file->ReadFully(&image_header, sizeof(image_header));
   if (!success || !image_header.IsValid()) {
-    LOG(ERROR) << "Invalid image header " << image_file_name;
-    return NULL;
+    *error_msg = StringPrintf("Invalid image header in '%s'", image_file_name);
+    return nullptr;
   }
 
   // Note: The image header is part of the image due to mmap page alignment required of offset.
@@ -188,10 +206,12 @@
                                                  MAP_PRIVATE | MAP_FIXED,
                                                  file->Fd(),
                                                  0,
-                                                 false));
+                                                 false,
+                                                 image_file_name,
+                                                 error_msg));
   if (map.get() == NULL) {
-    LOG(ERROR) << "Failed to map " << image_file_name;
-    return NULL;
+    DCHECK(!error_msg->empty());
+    return nullptr;
   }
   CHECK_EQ(image_header.GetImageBegin(), map->Begin());
   DCHECK_EQ(0, memcmp(&image_header, map->Begin(), sizeof(ImageHeader)));
@@ -199,16 +219,24 @@
   UniquePtr<MemMap> image_map(MemMap::MapFileAtAddress(nullptr, image_header.GetImageBitmapSize(),
                                                        PROT_READ, MAP_PRIVATE,
                                                        file->Fd(), image_header.GetBitmapOffset(),
-                                                       false));
-  CHECK(image_map.get() != nullptr) << "failed to map image bitmap";
+                                                       false,
+                                                       image_file_name,
+                                                       error_msg));
+  if (image_map.get() == nullptr) {
+    *error_msg = StringPrintf("Failed to map image bitmap: %s", error_msg->c_str());
+    return nullptr;
+  }
   size_t bitmap_index = bitmap_index_.fetch_add(1);
-  std::string bitmap_name(StringPrintf("imagespace %s live-bitmap %u", image_file_name.c_str(),
+  std::string bitmap_name(StringPrintf("imagespace %s live-bitmap %u", image_file_name,
                                        bitmap_index));
   UniquePtr<accounting::SpaceBitmap> bitmap(
       accounting::SpaceBitmap::CreateFromMemMap(bitmap_name, image_map.release(),
                                                 reinterpret_cast<byte*>(map->Begin()),
                                                 map->Size()));
-  CHECK(bitmap.get() != nullptr) << "could not create " << bitmap_name;
+  if (bitmap.get() == nullptr) {
+    *error_msg = StringPrintf("Could not create bitmap '%s'", bitmap_name.c_str());
+    return nullptr;
+  }
 
   Runtime* runtime = Runtime::Current();
   mirror::Object* resolution_method = image_header.GetImageRoot(ImageHeader::kResolutionMethod);
@@ -226,15 +254,15 @@
     space->VerifyImageAllocations();
   }
 
-  space->oat_file_.reset(space->OpenOatFile());
-  if (space->oat_file_.get() == NULL) {
-    LOG(ERROR) << "Failed to open oat file for image: " << image_file_name;
-    return NULL;
+  space->oat_file_.reset(space->OpenOatFile(error_msg));
+  if (space->oat_file_.get() == nullptr) {
+    DCHECK(!error_msg->empty());
+    return nullptr;
   }
 
-  if (validate_oat_file && !space->ValidateOatFile()) {
-    LOG(WARNING) << "Failed to validate oat file for image: " << image_file_name;
-    return NULL;
+  if (validate_oat_file && !space->ValidateOatFile(error_msg)) {
+    DCHECK(!error_msg->empty());
+    return nullptr;
   }
 
   if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
@@ -244,7 +272,7 @@
   return space.release();
 }
 
-OatFile* ImageSpace::OpenOatFile() const {
+OatFile* ImageSpace::OpenOatFile(std::string* error_msg) const {
   const Runtime* runtime = Runtime::Current();
   const ImageHeader& image_header = GetImageHeader();
   // Grab location but don't use Object::AsString as we haven't yet initialized the roots to
@@ -255,45 +283,47 @@
   oat_filename += runtime->GetHostPrefix();
   oat_filename += oat_location->ToModifiedUtf8();
   OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, image_header.GetOatDataBegin(),
-                                    !Runtime::Current()->IsCompiler());
+                                    !Runtime::Current()->IsCompiler(), error_msg);
   if (oat_file == NULL) {
-    LOG(ERROR) << "Failed to open oat file " << oat_filename << " referenced from image.";
-    return NULL;
+    *error_msg = StringPrintf("Failed to open oat file '%s' referenced from image %s: %s",
+                              oat_filename.c_str(), GetName(), error_msg->c_str());
+    return nullptr;
   }
   uint32_t oat_checksum = oat_file->GetOatHeader().GetChecksum();
   uint32_t image_oat_checksum = image_header.GetOatChecksum();
   if (oat_checksum != image_oat_checksum) {
-    LOG(ERROR) << "Failed to match oat file checksum " << std::hex << oat_checksum
-               << " to expected oat checksum " << std::hex << image_oat_checksum
-               << " in image";
-    return NULL;
+    *error_msg = StringPrintf("Failed to match oat file checksum 0x%x to expected oat checksum 0x%x"
+                              " in image %s", oat_checksum, image_oat_checksum, GetName());
+    return nullptr;
   }
   return oat_file;
 }
 
-bool ImageSpace::ValidateOatFile() const {
+bool ImageSpace::ValidateOatFile(std::string* error_msg) const {
   CHECK(oat_file_.get() != NULL);
   for (const OatFile::OatDexFile* oat_dex_file : oat_file_->GetOatDexFiles()) {
     const std::string& dex_file_location = oat_dex_file->GetDexFileLocation();
     uint32_t dex_file_location_checksum;
-    if (!DexFile::GetChecksum(dex_file_location.c_str(), &dex_file_location_checksum)) {
-      LOG(WARNING) << "ValidateOatFile could not find checksum for " << dex_file_location;
+    if (!DexFile::GetChecksum(dex_file_location.c_str(), &dex_file_location_checksum, error_msg)) {
+      *error_msg = StringPrintf("Failed to get checksum of dex file '%s' referenced by image %s: "
+                                "%s", dex_file_location.c_str(), GetName(), error_msg->c_str());
       return false;
     }
     if (dex_file_location_checksum != oat_dex_file->GetDexFileLocationChecksum()) {
-      LOG(WARNING) << "ValidateOatFile found checksum mismatch between oat file "
-                   << oat_file_->GetLocation() << " and dex file " << dex_file_location
-                   << " (" << oat_dex_file->GetDexFileLocationChecksum() << " != "
-                   << dex_file_location_checksum << ")";
+      *error_msg = StringPrintf("ValidateOatFile found checksum mismatch between oat file '%s' and "
+                                "dex file '%s' (0x%x != 0x%x)",
+                                oat_file_->GetLocation().c_str(), dex_file_location.c_str(),
+                                oat_dex_file->GetDexFileLocationChecksum(),
+                                dex_file_location_checksum);
       return false;
     }
   }
   return true;
 }
 
-OatFile& ImageSpace::ReleaseOatFile() {
+OatFile* ImageSpace::ReleaseOatFile() {
   CHECK(oat_file_.get() != NULL);
-  return *oat_file_.release();
+  return oat_file_.release();
 }
 
 void ImageSpace::Dump(std::ostream& os) const {
diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h
index 381a98e..78a83c9 100644
--- a/runtime/gc/space/image_space.h
+++ b/runtime/gc/space/image_space.h
@@ -45,12 +45,11 @@
   // creation of the alloc space. The ReleaseOatFile will later be
   // used to transfer ownership of the OatFile to the ClassLinker when
   // it is initialized.
-  static ImageSpace* Create(const std::string& image)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static ImageSpace* Create(const char* image) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Releases the OatFile from the ImageSpace so it can be transfer to
   // the caller, presumably the ClassLinker.
-  OatFile& ReleaseOatFile()
+  OatFile* ReleaseOatFile()
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void VerifyImageAllocations()
@@ -84,13 +83,13 @@
   // image's OatFile is up-to-date relative to its DexFile
   // inputs. Otherwise (for /data), validate the inputs and generate
   // the OatFile in /data/dalvik-cache if necessary.
-  static ImageSpace* Init(const std::string& image, bool validate_oat_file)
+  static ImageSpace* Init(const char* image, bool validate_oat_file, std::string* error_msg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  OatFile* OpenOatFile() const
+  OatFile* OpenOatFile(std::string* error_msg) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool ValidateOatFile() const
+  bool ValidateOatFile(std::string* error_msg) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   friend class Space;
diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc
index c6d028e..1321b19 100644
--- a/runtime/gc/space/large_object_space.cc
+++ b/runtime/gc/space/large_object_space.cc
@@ -56,10 +56,13 @@
   return new LargeObjectMapSpace(name);
 }
 
-mirror::Object* LargeObjectMapSpace::Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated) {
+mirror::Object* LargeObjectMapSpace::Alloc(Thread* self, size_t num_bytes,
+                                           size_t* bytes_allocated) {
+  std::string error_msg;
   MemMap* mem_map = MemMap::MapAnonymous("large object space allocation", NULL, num_bytes,
-                                         PROT_READ | PROT_WRITE);
-  if (mem_map == NULL) {
+                                         PROT_READ | PROT_WRITE, &error_msg);
+  if (UNLIKELY(mem_map == NULL)) {
+    LOG(WARNING) << "Large object allocation failed: " << error_msg;
     return NULL;
   }
   MutexLock mu(self, lock_);
@@ -129,9 +132,10 @@
 
 FreeListSpace* FreeListSpace::Create(const std::string& name, byte* requested_begin, size_t size) {
   CHECK_EQ(size % kAlignment, 0U);
+  std::string error_msg;
   MemMap* mem_map = MemMap::MapAnonymous(name.c_str(), requested_begin, size,
-                                         PROT_READ | PROT_WRITE);
-  CHECK(mem_map != NULL) << "Failed to allocate large object space mem map";
+                                         PROT_READ | PROT_WRITE, &error_msg);
+  CHECK(mem_map != NULL) << "Failed to allocate large object space mem map: " << error_msg;
   return new FreeListSpace(name, mem_map, mem_map->Begin(), mem_map->End());
 }
 
diff --git a/runtime/gc/space/large_object_space.h b/runtime/gc/space/large_object_space.h
index 3f2e848..ef889d4 100644
--- a/runtime/gc/space/large_object_space.h
+++ b/runtime/gc/space/large_object_space.h
@@ -96,9 +96,9 @@
   // Used to ensure mutual exclusion when the allocation spaces data structures are being modified.
   mutable Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   std::vector<mirror::Object*,
-      accounting::GCAllocator<mirror::Object*> > large_objects_ GUARDED_BY(lock_);
+      accounting::GcAllocator<mirror::Object*> > large_objects_ GUARDED_BY(lock_);
   typedef SafeMap<mirror::Object*, MemMap*, std::less<mirror::Object*>,
-      accounting::GCAllocator<std::pair<const mirror::Object*, MemMap*> > > MemMaps;
+      accounting::GcAllocator<std::pair<const mirror::Object*, MemMap*> > > MemMaps;
   MemMaps mem_maps_ GUARDED_BY(lock_);
 };
 
@@ -217,7 +217,7 @@
   AllocationHeader* GetAllocationHeader(const mirror::Object* obj);
 
   typedef std::set<AllocationHeader*, AllocationHeader::SortByPrevFree,
-                   accounting::GCAllocator<AllocationHeader*> > FreeBlocks;
+                   accounting::GcAllocator<AllocationHeader*> > FreeBlocks;
 
   byte* const begin_;
   byte* const end_;
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index 6451d5c..00316f7 100644
--- a/runtime/mem_map.cc
+++ b/runtime/mem_map.cc
@@ -67,7 +67,8 @@
 static void CheckMapRequest(byte*, size_t) { }
 #endif
 
-MemMap* MemMap::MapAnonymous(const char* name, byte* addr, size_t byte_count, int prot) {
+MemMap* MemMap::MapAnonymous(const char* name, byte* addr, size_t byte_count, int prot,
+                             std::string* error_msg) {
   if (byte_count == 0) {
     return new MemMap(name, NULL, 0, NULL, 0, prot);
   }
@@ -82,8 +83,8 @@
   ScopedFd fd(ashmem_create_region(debug_friendly_name.c_str(), page_aligned_byte_count));
   int flags = MAP_PRIVATE;
   if (fd.get() == -1) {
-    PLOG(ERROR) << "ashmem_create_region failed (" << name << ")";
-    return NULL;
+    *error_msg = StringPrintf("ashmem_create_region failed for '%s': %s", name, strerror(errno));
+    return nullptr;
   }
 #else
   ScopedFd fd(-1);
@@ -94,16 +95,17 @@
   if (actual == MAP_FAILED) {
     std::string maps;
     ReadFileToString("/proc/self/maps", &maps);
-    PLOG(ERROR) << "mmap(" << reinterpret_cast<void*>(addr) << ", " << page_aligned_byte_count
-                << ", " << prot << ", " << flags << ", " << fd.get() << ", 0) failed for " << name
-                << "\n" << maps;
-    return NULL;
+    *error_msg = StringPrintf("anonymous mmap(%p, %zd, %x, %x, %d, 0) failed\n%s",
+                              addr, page_aligned_byte_count, prot, flags, fd.get(),
+                              maps.c_str());
+    return nullptr;
   }
   return new MemMap(name, actual, byte_count, actual, page_aligned_byte_count, prot);
 }
 
-MemMap* MemMap::MapFileAtAddress(byte* addr, size_t byte_count,
-                                 int prot, int flags, int fd, off_t start, bool reuse) {
+MemMap* MemMap::MapFileAtAddress(byte* addr, size_t byte_count, int prot, int flags, int fd,
+                                 off_t start, bool reuse, const char* filename,
+                                 std::string* error_msg) {
   CHECK_NE(0, prot);
   CHECK_NE(0, flags & (MAP_SHARED | MAP_PRIVATE));
   if (byte_count == 0) {
@@ -133,10 +135,10 @@
   if (actual == MAP_FAILED) {
     std::string maps;
     ReadFileToString("/proc/self/maps", &maps);
-    PLOG(ERROR) << "mmap(" << reinterpret_cast<void*>(page_aligned_addr)
-                << ", " << page_aligned_byte_count
-                << ", " << prot << ", " << flags << ", " << fd << ", " << page_aligned_offset
-                << ") failed\n" << maps;
+    *error_msg = StringPrintf("mmap(%p, %zd, %x, %x, %d, %lld) of file '%s' failed\n%s",
+                              page_aligned_addr, page_aligned_byte_count, prot, flags, fd,
+                              static_cast<int64_t>(page_aligned_offset),
+                              filename, maps.c_str());
     return NULL;
   }
   return new MemMap("file", actual + page_offset, byte_count, actual, page_aligned_byte_count,
diff --git a/runtime/mem_map.h b/runtime/mem_map.h
index e294824..919463c 100644
--- a/runtime/mem_map.h
+++ b/runtime/mem_map.h
@@ -38,14 +38,16 @@
   // a name.
   //
   // On success, returns returns a MemMap instance.  On failure, returns a NULL;
-  static MemMap* MapAnonymous(const char* ashmem_name, byte* addr, size_t byte_count, int prot);
+  static MemMap* MapAnonymous(const char* ashmem_name, byte* addr, size_t byte_count, int prot,
+                              std::string* error_msg);
 
   // Map part of a file, taking care of non-page aligned offsets.  The
   // "start" offset is absolute, not relative.
   //
   // On success, returns returns a MemMap instance.  On failure, returns a NULL;
-  static MemMap* MapFile(size_t byte_count, int prot, int flags, int fd, off_t start) {
-    return MapFileAtAddress(NULL, byte_count, prot, flags, fd, start, false);
+  static MemMap* MapFile(size_t byte_count, int prot, int flags, int fd, off_t start,
+                         const char* filename, std::string* error_msg) {
+    return MapFileAtAddress(NULL, byte_count, prot, flags, fd, start, false, filename, error_msg);
   }
 
   // Map part of a file, taking care of non-page aligned offsets.  The
@@ -53,8 +55,9 @@
   // requesting a specific address for the base of the mapping.
   //
   // On success, returns returns a MemMap instance.  On failure, returns a NULL;
-  static MemMap* MapFileAtAddress(
-      byte* addr, size_t byte_count, int prot, int flags, int fd, off_t start, bool reuse);
+  static MemMap* MapFileAtAddress(byte* addr, size_t byte_count, int prot, int flags, int fd,
+                                  off_t start, bool reuse, const char* filename,
+                                  std::string* error_msg);
 
   // Releases the memory mapping
   ~MemMap();
diff --git a/runtime/mem_map_test.cc b/runtime/mem_map_test.cc
index dade01b..09de320 100644
--- a/runtime/mem_map_test.cc
+++ b/runtime/mem_map_test.cc
@@ -24,11 +24,14 @@
 class MemMapTest : public testing::Test {};
 
 TEST_F(MemMapTest, MapAnonymousEmpty) {
+  std::string error_msg;
   UniquePtr<MemMap> map(MemMap::MapAnonymous("MapAnonymousEmpty",
                                              NULL,
                                              0,
-                                             PROT_READ));
-  ASSERT_TRUE(map.get() != NULL);
+                                             PROT_READ,
+                                             &error_msg));
+  ASSERT_TRUE(map.get() != NULL) << error_msg;
+  ASSERT_TRUE(error_msg.empty());
 }
 
 }  // namespace art
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 4e17b79..af09a1c 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -89,34 +89,32 @@
   if (sourceName.c_str() == NULL) {
     return 0;
   }
-  std::string dex_location(sourceName.c_str());
   NullableScopedUtfChars outputName(env, javaOutputName);
   if (env->ExceptionCheck()) {
     return 0;
   }
-  ScopedObjectAccess soa(env);
+
   uint32_t dex_location_checksum;
-  if (!DexFile::GetChecksum(dex_location, &dex_location_checksum)) {
-    LOG(WARNING) << "Failed to compute checksum: " << dex_location;
-    ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
-    soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/io/IOException;",
-                                   "Unable to get checksum of dex file: %s", dex_location.c_str());
+  std::string error_msg;
+  if (!DexFile::GetChecksum(sourceName.c_str(), &dex_location_checksum, &error_msg)) {
+    ScopedObjectAccess soa(env);
+    DCHECK(!error_msg.empty());
+    ThrowIOException("%s", error_msg.c_str());
     return 0;
   }
 
   ClassLinker* linker = Runtime::Current()->GetClassLinker();
   const DexFile* dex_file;
-  if (outputName.c_str() == NULL) {
-    dex_file = linker->FindDexFileInOatFileFromDexLocation(dex_location, dex_location_checksum);
+  if (outputName.c_str() == nullptr) {
+    dex_file = linker->FindDexFileInOatFileFromDexLocation(sourceName.c_str(),
+                                                           dex_location_checksum, &error_msg);
   } else {
-    std::string oat_location(outputName.c_str());
-    dex_file = linker->FindOrCreateOatFileForDexLocation(dex_location, dex_location_checksum, oat_location);
+    dex_file = linker->FindOrCreateOatFileForDexLocation(sourceName.c_str(), dex_location_checksum,
+                                                         outputName.c_str(), &error_msg);
   }
-  if (dex_file == NULL) {
-    LOG(WARNING) << "Failed to open dex file: " << dex_location;
-    ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
-    soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/io/IOException;",
-                                   "Unable to open dex file: %s", dex_location.c_str());
+  if (dex_file == nullptr) {
+    ScopedObjectAccess soa(env);
+    ThrowIOException("%s", error_msg.c_str());
     return 0;
   }
   return static_cast<jint>(reinterpret_cast<uintptr_t>(dex_file));
@@ -188,21 +186,17 @@
 }
 
 static jboolean DexFile_isDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename) {
-  bool debug_logging = false;
+  const bool kVerboseLogging = false;  // Spammy logging.
+  const bool kDebugLogging = true;  // Logging useful for debugging.
 
   ScopedUtfChars filename(env, javaFilename);
-  if (filename.c_str() == NULL) {
-    LOG(ERROR) << "DexFile_isDexOptNeeded null filename";
-    return JNI_TRUE;
-  }
 
-  if (!OS::FileExists(filename.c_str())) {
+  if ((filename.c_str() == nullptr) || !OS::FileExists(filename.c_str())) {
     LOG(ERROR) << "DexFile_isDexOptNeeded file '" << filename.c_str() << "' does not exist";
-    ScopedObjectAccess soa(env);
-    ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
-    soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/io/FileNotFoundException;",
-                                   "%s", filename.c_str());
-    return JNI_TRUE;
+    ScopedLocalRef<jclass> fnfe(env, env->FindClass("java/io/FileNotFoundException"));
+    const char* message = (filename.c_str() == nullptr) ? "<empty file name>" : filename.c_str();
+    env->ThrowNew(fnfe.get(), message);
+    return JNI_FALSE;
   }
 
   // Always treat elements of the bootclasspath as up-to-date.  The
@@ -212,7 +206,7 @@
   const std::vector<const DexFile*>& boot_class_path = class_linker->GetBootClassPath();
   for (size_t i = 0; i < boot_class_path.size(); i++) {
     if (boot_class_path[i]->GetLocation() == filename.c_str()) {
-      if (debug_logging) {
+      if (kVerboseLogging) {
         LOG(INFO) << "DexFile_isDexOptNeeded ignoring boot class path file: " << filename.c_str();
       }
       return JNI_FALSE;
@@ -221,26 +215,32 @@
 
   // Check if we have an odex file next to the dex file.
   std::string odex_filename(OatFile::DexFilenameToOdexFilename(filename.c_str()));
-  UniquePtr<const OatFile> oat_file(OatFile::Open(odex_filename, odex_filename, NULL, false));
-  if (oat_file.get() != NULL) {
-    ScopedObjectAccess soa(env);
-    const art::OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(filename.c_str(), NULL);
-    if (oat_dex_file == NULL) {
-      if (debug_logging) {
-        LOG(INFO) << "DexFile_isDexOptNeeded GetOatDexFile failed";
-      }
-    } else {
+  std::string error_msg;
+  UniquePtr<const OatFile> oat_file(OatFile::Open(odex_filename, odex_filename, NULL, false,
+                                                  &error_msg));
+  if (oat_file.get() == nullptr) {
+    if (kVerboseLogging) {
+      LOG(INFO) << "DexFile_isDexOptNeeded failed to open oat file '" << filename.c_str()
+          << "': " << error_msg;
+    }
+    error_msg.clear();
+  } else {
+    const art::OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(filename.c_str(), NULL,
+                                                                           kDebugLogging);
+    if (oat_dex_file != nullptr) {
       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) {
+      // If its not possible to read the classes.dex assume up-to-date as we won't be able to
+      // compile it anyway.
+      if (!DexFile::GetChecksum(filename.c_str(), &location_checksum, &error_msg)) {
+        if (kVerboseLogging) {
           LOG(INFO) << "DexFile_isDexOptNeeded ignoring precompiled stripped file: "
-              << filename.c_str();
+              << filename.c_str() << ": " << error_msg;
         }
         return JNI_FALSE;
       }
-      if (ClassLinker::VerifyOatFileChecksums(oat_file.get(), filename.c_str(), location_checksum)) {
-        if (debug_logging) {
+      if (ClassLinker::VerifyOatFileChecksums(oat_file.get(), filename.c_str(), location_checksum,
+                                              &error_msg)) {
+        if (kVerboseLogging) {
           LOG(INFO) << "DexFile_isDexOptNeeded precompiled file " << odex_filename
               << " is up-to-date checksum compared to " << filename.c_str();
         }
@@ -251,10 +251,12 @@
 
   // Check if we have an oat file in the cache
   std::string cache_location(GetDalvikCacheFilenameOrDie(filename.c_str()));
-  oat_file.reset(OatFile::Open(cache_location, filename.c_str(), NULL, false));
-  if (oat_file.get() == NULL) {
-    LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
-              << " does not exist for " << filename.c_str();
+  oat_file.reset(OatFile::Open(cache_location, filename.c_str(), NULL, false, &error_msg));
+  if (oat_file.get() == nullptr) {
+    if (kDebugLogging) {
+      LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
+          << " does not exist for " << filename.c_str() << ": " << error_msg;
+    }
     return JNI_TRUE;
   }
 
@@ -262,41 +264,53 @@
     if (space->IsImageSpace()) {
       // TODO: Ensure this works with multiple image spaces.
       const ImageHeader& image_header = space->AsImageSpace()->GetImageHeader();
-      if (oat_file->GetOatHeader().GetImageFileLocationOatChecksum() != image_header.GetOatChecksum()) {
-        ScopedObjectAccess soa(env);
-        LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
-                  << " has out-of-date oat checksum compared to "
-                  << image_header.GetImageRoot(ImageHeader::kOatLocation)->AsString()->ToModifiedUtf8();
+      if (oat_file->GetOatHeader().GetImageFileLocationOatChecksum() !=
+          image_header.GetOatChecksum()) {
+        if (kDebugLogging) {
+          ScopedObjectAccess soa(env);
+          LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
+              << " has out-of-date oat checksum compared to "
+              << image_header.GetImageRoot(ImageHeader::kOatLocation)->AsString()->ToModifiedUtf8();
+        }
         return JNI_TRUE;
       }
       if (oat_file->GetOatHeader().GetImageFileLocationOatDataBegin()
           != reinterpret_cast<uint32_t>(image_header.GetOatDataBegin())) {
-        ScopedObjectAccess soa(env);
-        LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
-                  << " has out-of-date oat begin compared to "
-                  << image_header.GetImageRoot(ImageHeader::kOatLocation)->AsString()->ToModifiedUtf8();
+        if (kDebugLogging) {
+          ScopedObjectAccess soa(env);
+          LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
+              << " has out-of-date oat begin compared to "
+              << image_header.GetImageRoot(ImageHeader::kOatLocation)->AsString()->ToModifiedUtf8();
+        }
         return JNI_TRUE;
       }
     }
   }
 
-  ScopedObjectAccess soa(env);
   uint32_t location_checksum;
-  if (!DexFile::GetChecksum(filename.c_str(), &location_checksum)) {
-    LOG(ERROR) << "DexFile_isDexOptNeeded failed to compute checksum of " << filename.c_str();
+  if (!DexFile::GetChecksum(filename.c_str(), &location_checksum, &error_msg)) {
+    if (kDebugLogging) {
+      LOG(ERROR) << "DexFile_isDexOptNeeded failed to compute checksum of " << filename.c_str()
+            << " (error " << error_msg << ")";
+    }
     return JNI_TRUE;
   }
 
-  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();
+  if (!ClassLinker::VerifyOatFileChecksums(oat_file.get(), filename.c_str(), location_checksum,
+                                           &error_msg)) {
+    if (kDebugLogging) {
+      LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
+          << " has out-of-date checksum compared to " << filename.c_str()
+          << " (error " << error_msg << ")";
+    }
     return JNI_TRUE;
   }
 
-  if (debug_logging) {
+  if (kVerboseLogging) {
     LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
               << " is up-to-date for " << filename.c_str();
   }
+  CHECK(error_msg.empty()) << error_msg;
   return JNI_FALSE;
 }
 
diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc
index c23b08c..af1b548 100644
--- a/runtime/native/java_lang_VMClassLoader.cc
+++ b/runtime/native/java_lang_VMClassLoader.cc
@@ -72,8 +72,10 @@
   }
   const DexFile* dex_file = path[index];
   const std::string& location(dex_file->GetLocation());
-  UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(location));
-  if (zip_archive.get() == NULL) {
+  std::string error_msg;
+  UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(location.c_str(), &error_msg));
+  if (zip_archive.get() == nullptr) {
+    LOG(WARNING) << "Failed to open zip archive '" << location << "': " << error_msg;
     return NULL;
   }
   UniquePtr<ZipEntry> zip_entry(zip_archive->Find(name.c_str()));
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 7ecaf01..7553dcc 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -48,19 +48,21 @@
 }
 
 OatFile* OatFile::OpenMemory(std::vector<uint8_t>& oat_contents,
-                             const std::string& location) {
+                             const std::string& location,
+                             std::string* error_msg) {
   CHECK(!oat_contents.empty()) << location;
   CheckLocation(location);
   UniquePtr<OatFile> oat_file(new OatFile(location));
   oat_file->begin_ = &oat_contents[0];
   oat_file->end_ = &oat_contents[oat_contents.size()];
-  return oat_file->Setup() ? oat_file.release() : NULL;
+  return oat_file->Setup(error_msg) ? oat_file.release() : nullptr;
 }
 
 OatFile* OatFile::Open(const std::string& filename,
                        const std::string& location,
                        byte* requested_base,
-                       bool executable) {
+                       bool executable,
+                       std::string* error_msg) {
   CHECK(!filename.empty()) << location;
   CheckLocation(filename);
 #ifdef ART_USE_PORTABLE_COMPILER
@@ -70,7 +72,7 @@
   // open a generated dex file by name, remove the file, then open
   // another generated dex file with the same name. http://b/10614658
   if (executable) {
-    return OpenDlopen(filename, location, requested_base);
+    return OpenDlopen(filename, location, requested_base, error_msg);
   }
 #endif
   // If we aren't trying to execute, we just use our own ElfFile loader for a couple reasons:
@@ -83,21 +85,22 @@
   if (file.get() == NULL) {
     return NULL;
   }
-  return OpenElfFile(file.get(), location, requested_base, false, executable);
+  return OpenElfFile(file.get(), location, requested_base, false, executable, error_msg);
 }
 
-OatFile* OatFile::OpenWritable(File* file, const std::string& location) {
+OatFile* OatFile::OpenWritable(File* file, const std::string& location, std::string* error_msg) {
   CheckLocation(location);
-  return OpenElfFile(file, location, NULL, true, false);
+  return OpenElfFile(file, location, NULL, true, false, error_msg);
 }
 
 OatFile* OatFile::OpenDlopen(const std::string& elf_filename,
                              const std::string& location,
-                             byte* requested_base) {
+                             byte* requested_base,
+                             std::string* error_msg) {
   UniquePtr<OatFile> oat_file(new OatFile(location));
-  bool success = oat_file->Dlopen(elf_filename, requested_base);
+  bool success = oat_file->Dlopen(elf_filename, requested_base, error_msg);
   if (!success) {
-    return NULL;
+    return nullptr;
   }
   return oat_file.release();
 }
@@ -106,11 +109,13 @@
                               const std::string& location,
                               byte* requested_base,
                               bool writable,
-                              bool executable) {
+                              bool executable,
+                              std::string* error_msg) {
   UniquePtr<OatFile> oat_file(new OatFile(location));
-  bool success = oat_file->ElfFileOpen(file, requested_base, writable, executable);
+  bool success = oat_file->ElfFileOpen(file, requested_base, writable, executable, error_msg);
   if (!success) {
-    return NULL;
+    CHECK(!error_msg->empty());
+    return nullptr;
   }
   return oat_file.release();
 }
@@ -127,120 +132,117 @@
   }
 }
 
-bool OatFile::Dlopen(const std::string& elf_filename, byte* requested_base) {
+bool OatFile::Dlopen(const std::string& elf_filename, byte* requested_base,
+                     std::string* error_msg) {
   char* absolute_path = realpath(elf_filename.c_str(), NULL);
   if (absolute_path == NULL) {
-    VLOG(class_linker) << "Failed to find absolute path for " << elf_filename;
+    *error_msg = StringPrintf("Failed to find absolute path for '%s'", elf_filename.c_str());
     return false;
   }
   dlopen_handle_ = dlopen(absolute_path, RTLD_NOW);
   free(absolute_path);
   if (dlopen_handle_ == NULL) {
-    VLOG(class_linker) << "Failed to dlopen " << elf_filename << ": " << dlerror();
+    *error_msg = StringPrintf("Failed to dlopen '%s': %s", elf_filename.c_str(), dlerror());
     return false;
   }
   begin_ = reinterpret_cast<byte*>(dlsym(dlopen_handle_, "oatdata"));
   if (begin_ == NULL) {
-    LOG(WARNING) << "Failed to find oatdata symbol in " << elf_filename << ": " << dlerror();
+    *error_msg = StringPrintf("Failed to find oatdata symbol in '%s': %s", elf_filename.c_str(),
+                              dlerror());
     return false;
   }
   if (requested_base != NULL && begin_ != requested_base) {
-    std::string maps;
-    ReadFileToString("/proc/self/maps", &maps);
-    LOG(WARNING) << "Failed to find oatdata symbol at expected address: oatdata="
-                 << reinterpret_cast<const void*>(begin_) << " != expected="
-                 << reinterpret_cast<const void*>(requested_base)
-                 << " /proc/self/maps:\n" << maps;
+    *error_msg = StringPrintf("Failed to find oatdata symbol at expected address: "
+                              "oatdata=%p != expected=%p /proc/self/maps:\n",
+                              begin_, requested_base);
+    ReadFileToString("/proc/self/maps", error_msg);
     return false;
   }
   end_ = reinterpret_cast<byte*>(dlsym(dlopen_handle_, "oatlastword"));
   if (end_ == NULL) {
-    LOG(WARNING) << "Failed to find oatlastword symbol in " << elf_filename << ": " << dlerror();
+    *error_msg = StringPrintf("Failed to find oatlastword symbol in '%s': %s", elf_filename.c_str(),
+                              dlerror());
     return false;
   }
   // Readjust to be non-inclusive upper bound.
   end_ += sizeof(uint32_t);
-  return Setup();
+  return Setup(error_msg);
 }
 
-bool OatFile::ElfFileOpen(File* file, byte* requested_base, bool writable, bool executable) {
-  elf_file_.reset(ElfFile::Open(file, writable, true));
-  if (elf_file_.get() == NULL) {
-    if (writable) {
-      PLOG(WARNING) << "Failed to open ELF file for " << file->GetPath();
-    }
+bool OatFile::ElfFileOpen(File* file, byte* requested_base, bool writable, bool executable,
+                          std::string* error_msg) {
+  elf_file_.reset(ElfFile::Open(file, writable, true, error_msg));
+  if (elf_file_.get() == nullptr) {
+    DCHECK(!error_msg->empty());
     return false;
   }
-  bool loaded = elf_file_->Load(executable);
+  bool loaded = elf_file_->Load(executable, error_msg);
   if (!loaded) {
-    LOG(WARNING) << "Failed to load ELF file " << file->GetPath();
+    DCHECK(!error_msg->empty());
     return false;
   }
   begin_ = elf_file_->FindDynamicSymbolAddress("oatdata");
   if (begin_ == NULL) {
-    LOG(WARNING) << "Failed to find oatdata symbol in " << file->GetPath();
+    *error_msg = StringPrintf("Failed to find oatdata symbol in '%s'", file->GetPath().c_str());
     return false;
   }
   if (requested_base != NULL && begin_ != requested_base) {
-    std::string maps;
-    ReadFileToString("/proc/self/maps", &maps);
-    LOG(WARNING) << "Failed to find oatdata symbol at expected address: oatdata="
-                 << reinterpret_cast<const void*>(begin_) << " != expected="
-                 << reinterpret_cast<const void*>(requested_base)
-                 << " /proc/self/maps:\n" << maps;
+    *error_msg = StringPrintf("Failed to find oatdata symbol at expected address: "
+                              "oatdata=%p != expected=%p /proc/self/maps:\n",
+                              begin_, requested_base);
+    ReadFileToString("/proc/self/maps", error_msg);
     return false;
   }
   end_ = elf_file_->FindDynamicSymbolAddress("oatlastword");
   if (end_ == NULL) {
-    LOG(WARNING) << "Failed to find oatlastword symbol in " << file->GetPath();
+    *error_msg = StringPrintf("Failed to find oatlastword symbol in '%s'", file->GetPath().c_str());
     return false;
   }
   // Readjust to be non-inclusive upper bound.
   end_ += sizeof(uint32_t);
-  return Setup();
+  return Setup(error_msg);
 }
 
-bool OatFile::Setup() {
+bool OatFile::Setup(std::string* error_msg) {
   if (!GetOatHeader().IsValid()) {
-    LOG(WARNING) << "Invalid oat magic for " << GetLocation();
+    *error_msg = StringPrintf("Invalid oat magic for '%s'", GetLocation().c_str());
     return false;
   }
   const byte* oat = Begin();
   oat += sizeof(OatHeader);
   if (oat > End()) {
-    LOG(ERROR) << "In oat file " << GetLocation() << " found truncated OatHeader";
+    *error_msg = StringPrintf("In oat file '%s' found truncated OatHeader", GetLocation().c_str());
     return false;
   }
 
   oat += GetOatHeader().GetImageFileLocationSize();
   if (oat > End()) {
-    LOG(ERROR) << "In oat file " << GetLocation() << " found truncated image file location: "
-               << reinterpret_cast<const void*>(Begin())
-               << "+" << sizeof(OatHeader)
-               << "+" << GetOatHeader().GetImageFileLocationSize()
-               << "<=" << reinterpret_cast<const void*>(End());
+    *error_msg = StringPrintf("In oat file '%s' found truncated image file location: "
+                              "%p + %zd + %ud <= %p", GetLocation().c_str(),
+                              Begin(), sizeof(OatHeader), GetOatHeader().GetImageFileLocationSize(),
+                              End());
     return false;
   }
 
   for (size_t i = 0; i < GetOatHeader().GetDexFileCount(); i++) {
     size_t dex_file_location_size = *reinterpret_cast<const uint32_t*>(oat);
-    if (dex_file_location_size == 0U) {
-      LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i
-                 << " with empty location name";
+    if (UNLIKELY(dex_file_location_size == 0U)) {
+      *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd with empty location name",
+                                GetLocation().c_str(), i);
       return false;
     }
     oat += sizeof(dex_file_location_size);
-    if (oat > End()) {
-      LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i
-                 << " truncated after dex file location size";
+    if (UNLIKELY(oat > End())) {
+      *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd truncated after dex file "
+                                "location size", GetLocation().c_str(), i);
       return false;
     }
 
     const char* dex_file_location_data = reinterpret_cast<const char*>(oat);
     oat += dex_file_location_size;
-    if (oat > End()) {
-      LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i
-                 << " with truncated dex file location";
+    if (UNLIKELY(oat > End())) {
+      *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd with truncated dex file "
+                                "location", GetLocation().c_str(), i);
       return false;
     }
 
@@ -248,55 +250,54 @@
 
     uint32_t dex_file_checksum = *reinterpret_cast<const uint32_t*>(oat);
     oat += sizeof(dex_file_checksum);
-    if (oat > End()) {
-      LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i
-                 << " for "<< dex_file_location
-                 << " truncated after dex file checksum";
+    if (UNLIKELY(oat > End())) {
+      *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' truncated after "
+                                "dex file checksum", GetLocation().c_str(), i,
+                                dex_file_location.c_str());
       return false;
     }
 
     uint32_t dex_file_offset = *reinterpret_cast<const uint32_t*>(oat);
-    if (dex_file_offset == 0U) {
-      LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i
-                 << " for "<< dex_file_location
-                 << " with zero dex file offset";
+    if (UNLIKELY(dex_file_offset == 0U)) {
+      *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with zero dex "
+                                "file offset", GetLocation().c_str(), i, dex_file_location.c_str());
       return false;
     }
-    if (dex_file_offset > Size()) {
-      LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i
-                 << " for "<< dex_file_location
-                 << " with dex file offset" << dex_file_offset << " > " << Size();
+    if (UNLIKELY(dex_file_offset > Size())) {
+      *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with dex file "
+                                "offset %ud > %zd", GetLocation().c_str(), i,
+                                dex_file_location.c_str(), dex_file_offset, Size());
       return false;
     }
     oat += sizeof(dex_file_offset);
-    if (oat > End()) {
-      LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i
-                 << " for "<< dex_file_location
-                 << " truncated after dex file offset";
+    if (UNLIKELY(oat > End())) {
+      *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' truncated "
+                                " after dex file offsets", GetLocation().c_str(), i,
+                                dex_file_location.c_str());
       return false;
     }
 
     const uint8_t* dex_file_pointer = Begin() + dex_file_offset;
-    if (!DexFile::IsMagicValid(dex_file_pointer)) {
-      LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i
-                 << " for "<< dex_file_location
-                 << " with invalid dex file magic: " << dex_file_pointer;
+    if (UNLIKELY(!DexFile::IsMagicValid(dex_file_pointer))) {
+      *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with invalid "
+                                " dex file magic '%s'", GetLocation().c_str(), i,
+                                dex_file_location.c_str(), dex_file_pointer);
       return false;
     }
-    if (!DexFile::IsVersionValid(dex_file_pointer)) {
-      LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i
-                 << " for "<< dex_file_location
-                 << " with invalid dex file version: " << dex_file_pointer;
+    if (UNLIKELY(!DexFile::IsVersionValid(dex_file_pointer))) {
+      *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with invalid "
+                                " dex file version '%s'", GetLocation().c_str(), i,
+                                dex_file_location.c_str(), dex_file_pointer);
       return false;
     }
     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_);
-    if (oat > End()) {
-      LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i
-                 << " for "<< dex_file_location
-                 << " with truncated method offsets";
+    if (UNLIKELY(oat > End())) {
+      *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with truncated "
+                                " method offsets", GetLocation().c_str(), i,
+                                dex_file_location.c_str());
       return false;
     }
 
@@ -323,8 +324,8 @@
   return end_;
 }
 
-const OatFile::OatDexFile* OatFile::GetOatDexFile(const std::string& dex_location,
-                                                  const uint32_t* const dex_location_checksum,
+const OatFile::OatDexFile* OatFile::GetOatDexFile(const char* dex_location,
+                                                  const uint32_t* dex_location_checksum,
                                                   bool warn_if_not_found) const {
   Table::const_iterator it = oat_dex_files_.find(dex_location);
   if (it != oat_dex_files_.end()) {
@@ -373,9 +374,9 @@
   return reinterpret_cast<const DexFile::Header*>(dex_file_pointer_)->file_size_;
 }
 
-const DexFile* OatFile::OatDexFile::OpenDexFile() const {
+const DexFile* OatFile::OatDexFile::OpenDexFile(std::string* error_msg) const {
   return DexFile::Open(dex_file_pointer_, FileSize(), dex_file_location_,
-                       dex_file_location_checksum_);
+                       dex_file_location_checksum_, error_msg);
 }
 
 const OatFile::OatClass* OatFile::OatDexFile::GetOatClass(uint16_t class_def_index) const {
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 270976f..af14760 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -45,18 +45,20 @@
   static OatFile* Open(const std::string& filename,
                        const std::string& location,
                        byte* requested_base,
-                       bool executable);
+                       bool executable,
+                       std::string* error_msg);
 
   // Open an oat file from an already opened File.
   // Does not use dlopen underneath so cannot be used for runtime use
   // where relocations may be required. Currently used from
   // ImageWriter which wants to open a writable version from an existing
   // file descriptor for patching.
-  static OatFile* OpenWritable(File* file, const std::string& location);
+  static OatFile* OpenWritable(File* file, const std::string& location, std::string* error_msg);
 
   // Open an oat file backed by a std::vector with the given location.
   static OatFile* OpenMemory(std::vector<uint8_t>& oat_contents,
-                             const std::string& location);
+                             const std::string& location,
+                             std::string* error_msg);
 
   ~OatFile();
 
@@ -167,7 +169,7 @@
   class OatDexFile {
    public:
     // Opens the DexFile referred to by this OatDexFile from within the containing OatFile.
-    const DexFile* OpenDexFile() const;
+    const DexFile* OpenDexFile(std::string* error_msg) const;
 
     // Returns the size of the DexFile refered to by this OatDexFile.
     size_t FileSize() const;
@@ -204,10 +206,10 @@
     DISALLOW_COPY_AND_ASSIGN(OatDexFile);
   };
 
-  const OatDexFile* GetOatDexFile(const std::string& dex_location,
+  const OatDexFile* GetOatDexFile(const char* dex_location,
                                   const uint32_t* const dex_location_checksum,
-                                  bool exception_if_not_found = true) const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+                                  bool exception_if_not_found = true) const;
+
   std::vector<const OatDexFile*> GetOatDexFiles() const;
 
   size_t Size() const {
@@ -219,18 +221,21 @@
 
   static OatFile* OpenDlopen(const std::string& elf_filename,
                              const std::string& location,
-                             byte* requested_base);
+                             byte* requested_base,
+                             std::string* error_msg);
 
   static OatFile* OpenElfFile(File* file,
                               const std::string& location,
                               byte* requested_base,
                               bool writable,
-                              bool executable);
+                              bool executable,
+                              std::string* error_msg);
 
   explicit OatFile(const std::string& filename);
-  bool Dlopen(const std::string& elf_filename, byte* requested_base);
-  bool ElfFileOpen(File* file, byte* requested_base, bool writable, bool executable);
-  bool Setup();
+  bool Dlopen(const std::string& elf_filename, byte* requested_base, std::string* error_msg);
+  bool ElfFileOpen(File* file, byte* requested_base, bool writable, bool executable,
+                   std::string* error_msg);
+  bool Setup(std::string* error_msg);
 
   const byte* Begin() const;
   const byte* End() const;
diff --git a/runtime/utils.cc b/runtime/utils.cc
index e2852a6..f9e4ebe 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -718,9 +718,9 @@
  * this function returns false, then the given pointer may only have
  * been partially advanced.
  */
-bool IsValidPartOfMemberNameUtf8(const char** pUtf8Ptr) {
+static bool IsValidPartOfMemberNameUtf8(const char** pUtf8Ptr) {
   uint8_t c = (uint8_t) **pUtf8Ptr;
-  if (c <= 0x7f) {
+  if (LIKELY(c <= 0x7f)) {
     // It's low-ascii, so check the table.
     uint32_t wordIdx = c >> 5;
     uint32_t bitIdx = c & 0x1f;
@@ -761,7 +761,7 @@
 }
 
 enum ClassNameType { kName, kDescriptor };
-bool IsValidClassName(const char* s, ClassNameType type, char separator) {
+static bool IsValidClassName(const char* s, ClassNameType type, char separator) {
   int arrayCount = 0;
   while (*s == '[') {
     arrayCount++;
@@ -1194,12 +1194,12 @@
   return dalvik_cache;
 }
 
-std::string GetDalvikCacheFilenameOrDie(const std::string& location) {
+std::string GetDalvikCacheFilenameOrDie(const char* location) {
   std::string dalvik_cache(GetDalvikCacheOrDie(GetAndroidData()));
   if (location[0] != '/') {
     LOG(FATAL) << "Expected path in location to be absolute: "<< location;
   }
-  std::string cache_file(location, 1);  // skip leading slash
+  std::string cache_file(&location[1]);  // skip leading slash
   if (!EndsWith(location, ".dex") && !EndsWith(location, ".art")) {
     cache_file += "/";
     cache_file += DexFile::kClassesDex;
diff --git a/runtime/utils.h b/runtime/utils.h
index 975f08b..0174b37 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -351,7 +351,7 @@
 std::string GetDalvikCacheOrDie(const char* android_data);
 
 // Returns the dalvik-cache location for a DexFile or OatFile, or dies trying.
-std::string GetDalvikCacheFilenameOrDie(const std::string& location);
+std::string GetDalvikCacheFilenameOrDie(const char* location);
 
 // Check whether the given magic matches a known file type.
 bool IsZipMagic(uint32_t magic);
diff --git a/runtime/zip_archive.cc b/runtime/zip_archive.cc
index 8e09e78..db273ec 100644
--- a/runtime/zip_archive.cc
+++ b/runtime/zip_archive.cc
@@ -19,10 +19,12 @@
 #include <vector>
 
 #include <fcntl.h>
+#include <stdio.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
 
+#include "base/stringprintf.h"
 #include "base/unix_file/fd_file.h"
 #include "UniquePtr.h"
 
@@ -247,35 +249,38 @@
   return true;
 }
 
-bool ZipEntry::ExtractToFile(File& file) {
+bool ZipEntry::ExtractToFile(File& file, std::string* error_msg) {
   uint32_t length = GetUncompressedLength();
   int result = TEMP_FAILURE_RETRY(ftruncate(file.Fd(), length));
   if (result == -1) {
-    PLOG(WARNING) << "Zip: failed to ftruncate " << file.GetPath() << " to length " << length;
+    *error_msg = StringPrintf("Zip: failed to ftruncate '%s' to length %ud", file.GetPath().c_str(),
+                              length);
     return false;
   }
 
-  UniquePtr<MemMap> map(MemMap::MapFile(length, PROT_READ | PROT_WRITE, MAP_SHARED, file.Fd(), 0));
+  UniquePtr<MemMap> map(MemMap::MapFile(length, PROT_READ | PROT_WRITE, MAP_SHARED, file.Fd(), 0,
+                                        file.GetPath().c_str(), error_msg));
   if (map.get() == NULL) {
-    LOG(WARNING) << "Zip: failed to mmap space for " << file.GetPath();
+    *error_msg = StringPrintf("Zip: failed to mmap space for '%s': %s", file.GetPath().c_str(),
+                              error_msg->c_str());
     return false;
   }
 
-  return ExtractToMemory(map->Begin(), map->Size());
+  return ExtractToMemory(map->Begin(), map->Size(), error_msg);
 }
 
-bool ZipEntry::ExtractToMemory(uint8_t* begin, size_t size) {
+bool ZipEntry::ExtractToMemory(uint8_t* begin, size_t size, std::string* error_msg) {
   // If size is zero, data offset will be meaningless, so bail out early.
   if (size == 0) {
     return true;
   }
   off64_t data_offset = GetDataOffset();
   if (data_offset == -1) {
-    LOG(WARNING) << "Zip: data_offset=" << data_offset;
+    *error_msg = StringPrintf("Zip: data_offset=%lld", data_offset);
     return false;
   }
   if (lseek64(zip_archive_->fd_, data_offset, SEEK_SET) != data_offset) {
-    PLOG(WARNING) << "Zip: lseek to data at " << data_offset << " failed";
+    *error_msg = StringPrintf("Zip: lseek to data at %lld failed", data_offset);
     return false;
   }
 
@@ -288,25 +293,25 @@
       return InflateToMemory(begin, size, zip_archive_->fd_,
                              GetUncompressedLength(), GetCompressedLength());
     default:
-      LOG(WARNING) << "Zip: unknown compression method " << std::hex << GetCompressionMethod();
+      *error_msg = StringPrintf("Zip: unknown compression method 0x%x", GetCompressionMethod());
       return false;
   }
 }
 
-MemMap* ZipEntry::ExtractToMemMap(const char* entry_filename) {
+MemMap* ZipEntry::ExtractToMemMap(const char* entry_filename, std::string* error_msg) {
   std::string name(entry_filename);
   name += " extracted in memory from ";
   name += entry_filename;
   UniquePtr<MemMap> map(MemMap::MapAnonymous(name.c_str(),
                                              NULL,
                                              GetUncompressedLength(),
-                                             PROT_READ | PROT_WRITE));
-  if (map.get() == NULL) {
-    LOG(ERROR) << "Zip: mmap for '" << entry_filename << "' failed";
+                                             PROT_READ | PROT_WRITE, error_msg));
+  if (map.get() == nullptr) {
+    DCHECK(!error_msg->empty());
     return NULL;
   }
 
-  bool success = ExtractToMemory(map->Begin(), map->Size());
+  bool success = ExtractToMemory(map->Begin(), map->Size(), error_msg);
   if (!success) {
     LOG(ERROR) << "Zip: Failed to extract '" << entry_filename << "' to memory";
     return NULL;
@@ -329,27 +334,25 @@
   }
 }
 
-ZipArchive* ZipArchive::Open(const std::string& filename) {
-  DCHECK(!filename.empty());
-  int fd = open(filename.c_str(), O_RDONLY, 0);
+ZipArchive* ZipArchive::Open(const char* filename, std::string* error_msg) {
+  DCHECK(filename != nullptr);
+  int fd = open(filename, O_RDONLY, 0);
   if (fd == -1) {
-    PLOG(WARNING) << "Unable to open '" << filename << "'";
+    *error_msg = StringPrintf("Zip: unable to open '%s': %s", filename, strerror(errno));
     return NULL;
   }
-  return OpenFromFd(fd);
+  return OpenFromFd(fd, filename, error_msg);
 }
 
-ZipArchive* ZipArchive::OpenFromFd(int fd) {
+ZipArchive* ZipArchive::OpenFromFd(int fd, const char* filename, std::string* error_msg) {
   SetCloseOnExec(fd);
-  UniquePtr<ZipArchive> zip_archive(new ZipArchive(fd));
-  if (zip_archive.get() == NULL) {
-      return NULL;
-  }
-  if (!zip_archive->MapCentralDirectory()) {
+  UniquePtr<ZipArchive> zip_archive(new ZipArchive(fd, filename));
+  CHECK(zip_archive.get() != nullptr);
+  if (!zip_archive->MapCentralDirectory(error_msg)) {
       zip_archive->Close();
       return NULL;
   }
-  if (!zip_archive->Parse()) {
+  if (!zip_archive->Parse(error_msg)) {
       zip_archive->Close();
       return NULL;
   }
@@ -374,19 +377,28 @@
   dir_offset_ = 0;
 }
 
+std::string ZipArchive::ErrorStringPrintf(const char* fmt, ...) {
+  va_list ap;
+  va_start(ap, fmt);
+  std::string result(StringPrintf("Zip '%s' : ", filename_.c_str()));
+  StringAppendV(&result, fmt, ap);
+  va_end(ap);
+  return result;
+}
+
 // Find the zip Central Directory and memory-map it.
 //
 // On success, returns true after populating fields from the EOCD area:
 //   num_entries_
 //   dir_offset_
 //   dir_map_
-bool ZipArchive::MapCentralDirectory() {
+bool ZipArchive::MapCentralDirectory(std::string* error_msg) {
   /*
    * Get and test file length.
    */
   off64_t file_length = lseek64(fd_, 0, SEEK_END);
   if (file_length < kEOCDLen) {
-    LOG(WARNING) << "Zip: length " << file_length << " is too small to be zip";
+    *error_msg = ErrorStringPrintf("length %lld is too small to be zip", file_length);
     return false;
   }
 
@@ -396,27 +408,26 @@
   }
 
   UniquePtr<uint8_t[]> scan_buf(new uint8_t[read_amount]);
-  if (scan_buf.get() == NULL) {
-    return false;
-  }
+  CHECK(scan_buf.get() != nullptr);
 
   /*
    * Make sure this is a Zip archive.
    */
   if (lseek64(fd_, 0, SEEK_SET) != 0) {
-    PLOG(WARNING) << "seek to start failed: ";
+    *error_msg = ErrorStringPrintf("seek to start failed: %s", strerror(errno));
     return false;
   }
 
   ssize_t actual = TEMP_FAILURE_RETRY(read(fd_, scan_buf.get(), sizeof(int32_t)));
   if (actual != static_cast<ssize_t>(sizeof(int32_t))) {
-    PLOG(INFO) << "couldn't read first signature from zip archive: ";
+    *error_msg = ErrorStringPrintf("couldn\'t read first signature from zip archive: %s",
+                                   strerror(errno));
     return false;
   }
 
   unsigned int header = Le32ToHost(scan_buf.get());
   if (header != kLFHSignature) {
-    LOG(VERBOSE) << "Not a Zip archive (found " << std::hex << header << ")";
+    *error_msg = ErrorStringPrintf("not a zip archive (found 0x%x)", header);
     return false;
   }
 
@@ -433,12 +444,13 @@
   off64_t search_start = file_length - read_amount;
 
   if (lseek64(fd_, search_start, SEEK_SET) != search_start) {
-    PLOG(WARNING) << "Zip: seek " << search_start << " failed";
+    *error_msg = ErrorStringPrintf("seek %lld failed: %s", search_start, strerror(errno));
     return false;
   }
   actual = TEMP_FAILURE_RETRY(read(fd_, scan_buf.get(), read_amount));
   if (actual != static_cast<ssize_t>(read_amount)) {
-    PLOG(WARNING) << "Zip: read " << actual << ", expected " << read_amount << ". failed";
+    *error_msg = ErrorStringPrintf("read %lld, expected %zd. %s", search_start, read_amount,
+                                   strerror(errno));
     return false;
   }
 
@@ -454,14 +466,14 @@
     }
   }
   if (i < 0) {
-    LOG(WARNING) << "Zip: EOCD not found, not a zip file";
+    *error_msg = ErrorStringPrintf("EOCD not found, not a zip file");
     return false;
   }
 
   off64_t eocd_offset = search_start + i;
   const byte* eocd_ptr = scan_buf.get() + i;
 
-  DCHECK(eocd_offset < file_length);
+  CHECK(eocd_offset < file_length);
 
   // Grab the CD offset and size, and the number of entries in the
   // archive.  Verify that they look reasonable.
@@ -474,29 +486,28 @@
   uint16_t comment_size = Le16ToHost(eocd_ptr + kEOCDCommentSize);
 
   if ((uint64_t) dir_offset + (uint64_t) dir_size > (uint64_t) eocd_offset) {
-    LOG(WARNING) << "Zip: bad offsets ("
-                 << "dir=" << dir_offset << ", "
-                 << "size=" << dir_size  << ", "
-                 << "eocd=" << eocd_offset << ")";
+    *error_msg = ErrorStringPrintf("bad offsets (dir=%ud, size=%ud, eocd=%lld)",
+                                   dir_offset, dir_size, eocd_offset);
     return false;
   }
   if (num_entries == 0) {
-    LOG(WARNING) << "Zip: empty archive?";
+    *error_msg = ErrorStringPrintf("empty archive?");
     return false;
   } else if (num_entries != total_num_entries || disk_number != 0 || disk_with_central_dir != 0) {
-    LOG(WARNING) << "spanned archives not supported";
+    *error_msg = ErrorStringPrintf("spanned archives not supported");
     return false;
   }
 
   // Check to see if comment is a sane size
   if ((comment_size > (file_length - kEOCDLen))
       || (eocd_offset > (file_length - kEOCDLen) - comment_size)) {
-    LOG(WARNING) << "comment size runs off end of file";
+    *error_msg = ErrorStringPrintf("comment size runs off end of file");
     return false;
   }
 
   // It all looks good.  Create a mapping for the CD.
-  dir_map_.reset(MemMap::MapFile(dir_size, PROT_READ, MAP_SHARED, fd_, dir_offset));
+  dir_map_.reset(MemMap::MapFile(dir_size, PROT_READ, MAP_SHARED, fd_, dir_offset,
+                                 filename_.c_str(), error_msg));
   if (dir_map_.get() == NULL) {
     return false;
   }
@@ -506,7 +517,7 @@
   return true;
 }
 
-bool ZipArchive::Parse() {
+bool ZipArchive::Parse(std::string* error_msg) {
   const byte* cd_ptr = dir_map_->Begin();
   size_t cd_length = dir_map_->Size();
 
@@ -515,23 +526,23 @@
   const byte* ptr = cd_ptr;
   for (int i = 0; i < num_entries_; i++) {
     if (Le32ToHost(ptr) != kCDESignature) {
-      LOG(WARNING) << "Zip: missed a central dir sig (at " << i << ")";
+      *error_msg = ErrorStringPrintf("missed a central dir sig (at %d)", i);
       return false;
     }
     if (ptr + kCDELen > cd_ptr + cd_length) {
-      LOG(WARNING) << "Zip: ran off the end (at " << i << ")";
+      *error_msg = ErrorStringPrintf("ran off the end (at %d)", i);
       return false;
     }
 
     int64_t local_hdr_offset = Le32ToHost(ptr + kCDELocalOffset);
     if (local_hdr_offset >= dir_offset_) {
-      LOG(WARNING) << "Zip: bad LFH offset " << local_hdr_offset << " at entry " << i;
+      *error_msg = ErrorStringPrintf("bad LFH offset %lld at entry %d", local_hdr_offset, i);
       return false;
     }
 
     uint16_t gpbf = Le16ToHost(ptr + kCDEGPBFlags);
     if ((gpbf & kGPFUnsupportedMask) != 0) {
-      LOG(WARNING) << "Invalid General Purpose Bit Flag: " << gpbf;
+      *error_msg = ErrorStringPrintf("invalid general purpose bit flag %x", gpbf);
       return false;
     }
 
@@ -544,16 +555,15 @@
 
     // Check name for NULL characters
     if (memchr(name, 0, name_len) != NULL) {
-      LOG(WARNING) << "Filename contains NUL byte";
+      *error_msg = ErrorStringPrintf("filename contains NUL byte");
       return false;
     }
 
     dir_entries_.Put(StringPiece(name, name_len), ptr);
     ptr += kCDELen + name_len + extra_len + comment_len;
     if (ptr > cd_ptr + cd_length) {
-      LOG(WARNING) << "Zip: bad CD advance "
-                   << "(" << ptr << " vs " << (cd_ptr + cd_length) << ") "
-                   << "at entry " << i;
+      *error_msg = ErrorStringPrintf("bad CD advance (%p vs %p) at entry %d",
+                                     ptr, cd_ptr + cd_length, i);
       return false;
     }
   }
diff --git a/runtime/zip_archive.h b/runtime/zip_archive.h
index d9ccba2..8ff952b 100644
--- a/runtime/zip_archive.h
+++ b/runtime/zip_archive.h
@@ -19,6 +19,7 @@
 
 #include <stdint.h>
 #include <zlib.h>
+#include <string>
 
 #include "base/logging.h"
 #include "base/stringpiece.h"
@@ -36,9 +37,9 @@
 
 class ZipEntry {
  public:
-  bool ExtractToFile(File& file);
-  bool ExtractToMemory(uint8_t* begin, size_t size);
-  MemMap* ExtractToMemMap(const char* entry_filename);
+  bool ExtractToFile(File& file, std::string* error_msg);
+  bool ExtractToMemory(uint8_t* begin, size_t size, std::string* error_msg);
+  MemMap* ExtractToMemMap(const char* entry_filename, std::string* error_msg);
 
   uint32_t GetUncompressedLength();
   uint32_t GetCrc32();
@@ -109,8 +110,8 @@
   static const int32_t kGPFUnsupportedMask = (kGPFEncryptedFlag);
 
   // return new ZipArchive instance on success, NULL on error.
-  static ZipArchive* Open(const std::string& filename);
-  static ZipArchive* OpenFromFd(int fd);
+  static ZipArchive* Open(const char* filename, std::string* error_msg);
+  static ZipArchive* OpenFromFd(int fd, const char* filename, std::string* error_msg);
 
   ZipEntry* Find(const char* name) const;
 
@@ -119,11 +120,14 @@
   }
 
  private:
-  explicit ZipArchive(int fd) : fd_(fd), num_entries_(0), dir_offset_(0) {}
+  explicit ZipArchive(int fd, const char* filename)
+      : fd_(fd), num_entries_(0), dir_offset_(0), filename_(filename) {}
 
-  bool MapCentralDirectory();
-  bool Parse();
+  bool MapCentralDirectory(std::string* error_msg);
+  bool Parse(std::string* error_msg);
   void Close();
+  std::string ErrorStringPrintf(const char* fmt, ...)
+          __attribute__((__format__(__printf__, 2, 3))) COLD_ATTR;
 
   int fd_;
   uint16_t num_entries_;
@@ -131,6 +135,8 @@
   UniquePtr<MemMap> dir_map_;
   typedef SafeMap<StringPiece, const byte*> DirEntries;
   DirEntries dir_entries_;
+  // Containing file for error reporting.
+  const std::string filename_;
 
   friend class ZipEntry;
 
diff --git a/runtime/zip_archive_test.cc b/runtime/zip_archive_test.cc
index 9bdc24b..622dc89 100644
--- a/runtime/zip_archive_test.cc
+++ b/runtime/zip_archive_test.cc
@@ -29,8 +29,10 @@
 class ZipArchiveTest : public CommonTest {};
 
 TEST_F(ZipArchiveTest, FindAndExtract) {
-  UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(GetLibCoreDexFileName()));
-  ASSERT_TRUE(zip_archive.get() != false);
+  std::string error_msg;
+  UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(GetLibCoreDexFileName().c_str(), &error_msg));
+  ASSERT_TRUE(zip_archive.get() != false) << error_msg;
+  ASSERT_TRUE(error_msg.empty());
   UniquePtr<ZipEntry> zip_entry(zip_archive->Find("classes.dex"));
   ASSERT_TRUE(zip_entry.get() != false);
 
@@ -38,8 +40,9 @@
   ASSERT_NE(-1, tmp.GetFd());
   UniquePtr<File> file(new File(tmp.GetFd(), tmp.GetFilename()));
   ASSERT_TRUE(file.get() != NULL);
-  bool success = zip_entry->ExtractToFile(*file);
-  ASSERT_TRUE(success);
+  bool success = zip_entry->ExtractToFile(*file, &error_msg);
+  ASSERT_TRUE(success) << error_msg;
+  ASSERT_TRUE(error_msg.empty());
   file.reset(NULL);
 
   uint32_t computed_crc = crc32(0L, Z_NULL, 0);