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/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_;