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

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

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

Change-Id: I80058652e11e7ea63457cc01a0cb48afe1c15543
diff --git a/runtime/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;