Support booting without functioning boot.oat/art patchoat.

Bug: 17000769

Change-Id: I89c26a905af12ea288742368c2c038afd57a879a
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 3fc6ad5..d05d031 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -46,6 +46,7 @@
 #include "atomic.h"
 #include "class_linker.h"
 #include "debugger.h"
+#include "elf_file.h"
 #include "fault_handler.h"
 #include "gc/accounting/card_table-inl.h"
 #include "gc/heap.h"
@@ -66,6 +67,7 @@
 #include "native_bridge_art_interface.h"
 #include "parsed_options.h"
 #include "oat_file.h"
+#include "os.h"
 #include "quick/quick_method_frame_info.h"
 #include "reflection.h"
 #include "ScopedLocalRef.h"
@@ -547,9 +549,74 @@
   VLOG(startup) << "Runtime::StartDaemonThreads exiting";
 }
 
+static bool OpenDexFilesFromImage(const std::vector<std::string>& dex_filenames,
+                                  const std::string& image_location,
+                                  std::vector<const DexFile*>& dex_files,
+                                  size_t* failures) {
+  std::string system_filename;
+  bool has_system = false;
+  std::string cache_filename_unused;
+  bool dalvik_cache_exists_unused;
+  bool has_cache_unused;
+  bool found_image = gc::space::ImageSpace::FindImageFilename(image_location.c_str(),
+                                                              kRuntimeISA,
+                                                              &system_filename,
+                                                              &has_system,
+                                                              &cache_filename_unused,
+                                                              &dalvik_cache_exists_unused,
+                                                              &has_cache_unused);
+  *failures = 0;
+  if (!found_image || !has_system) {
+    return false;
+  }
+  std::string error_msg;
+  // We are falling back to non-executable use of the oat file because patching failed, presumably
+  // due to lack of space.
+  std::string oat_filename = ImageHeader::GetOatLocationFromImageLocation(system_filename.c_str());
+  std::string oat_location = ImageHeader::GetOatLocationFromImageLocation(image_location.c_str());
+  std::unique_ptr<File> file(OS::OpenFileForReading(oat_filename.c_str()));
+  if (file.get() == nullptr) {
+    return false;
+  }
+  std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file.release(), false, false, &error_msg));
+  if (elf_file.get() == nullptr) {
+    return false;
+  }
+  std::unique_ptr<OatFile> oat_file(OatFile::OpenWithElfFile(elf_file.release(), oat_location,
+                                                             &error_msg));
+  if (oat_file.get() == nullptr) {
+    LOG(INFO) << "Unable to use '" << oat_filename << "' because " << error_msg;
+    return false;
+  }
+
+  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];
+    if (oat_dex_file == nullptr) {
+      *failures += 1;
+      continue;
+    }
+    const DexFile* dex_file = oat_dex_file->OpenDexFile(&error_msg);
+    if (dex_file == nullptr) {
+      *failures += 1;
+    } else {
+      dex_files.push_back(dex_file);
+    }
+  }
+  Runtime::Current()->GetClassLinker()->RegisterOatFile(oat_file.release());
+  return true;
+}
+
+
 static size_t OpenDexFiles(const std::vector<std::string>& dex_filenames,
+                           const std::string& image_location,
                            std::vector<const DexFile*>& dex_files) {
   size_t failure_count = 0;
+  if (!image_location.empty() && OpenDexFilesFromImage(dex_filenames, image_location, dex_files,
+                                                       &failure_count)) {
+    return failure_count;
+  }
+  failure_count = 0;
   for (size_t i = 0; i < dex_filenames.size(); i++) {
     const char* dex_filename = dex_filenames[i].c_str();
     std::string error_msg;
@@ -713,7 +780,7 @@
     std::vector<std::string> dex_filenames;
     Split(boot_class_path_string_, ':', dex_filenames);
     std::vector<const DexFile*> boot_class_path;
-    OpenDexFiles(dex_filenames, boot_class_path);
+    OpenDexFiles(dex_filenames, options->image_, boot_class_path);
     class_linker_->InitWithoutImage(boot_class_path);
     // TODO: Should we move the following to InitWithoutImage?
     SetInstructionSet(kRuntimeISA);