Make apps able to run with a failing patchoat

Bug: 17000769

Change-Id: I0a1a4dc7f5d4bb268530840302ecfb1555231e05
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index f31e273..7aef8fa 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -851,7 +851,8 @@
       // We opened the oat file, so we must register it.
       RegisterOatFile(oat_file);
     }
-    return true;
+    // If the file isn't executable we failed patchoat but did manage to get the dex files.
+    return oat_file->IsExecutable();
   } else {
     if (needs_registering) {
       // We opened it, delete it.
@@ -1136,11 +1137,18 @@
     error_msgs->push_back(StringPrintf("Failed to open oat file from dex location '%s'",
                                        dex_location));
     return nullptr;
-  } else if (!VerifyOatWithDexFile(oat_file.get(), dex_location, &error_msg)) {
+  } else if (oat_file->IsExecutable() &&
+             !VerifyOatWithDexFile(oat_file.get(), dex_location, &error_msg)) {
     error_msgs->push_back(StringPrintf("Failed to verify oat file '%s' found for dex location "
                                        "'%s': %s", oat_file->GetLocation().c_str(), dex_location,
                                        error_msg.c_str()));
     return nullptr;
+  } else if (!oat_file->IsExecutable() &&
+             !VerifyOatImageChecksum(oat_file.get(), isa)) {
+    error_msgs->push_back(StringPrintf("Failed to verify non-executable oat file '%s' found for "
+                                       "dex location '%s'. Image checksum incorrect.",
+                                       oat_file->GetLocation().c_str(), dex_location));
+    return nullptr;
   } else {
     return oat_file.release();
   }
@@ -1310,11 +1318,35 @@
   return ret;
 }
 
+const OatFile* ClassLinker::GetInterpretedOnlyOat(const std::string& oat_path,
+                                                  InstructionSet isa,
+                                                  std::string* error_msg) {
+  // We open it non-executable
+  std::unique_ptr<OatFile> output(OatFile::Open(oat_path, oat_path, NULL, false, error_msg));
+  if (output.get() == nullptr) {
+    return nullptr;
+  }
+  if (VerifyOatImageChecksum(output.get(), isa)) {
+    return output.release();
+  } else {
+    *error_msg = StringPrintf("Could not use oat file '%s', image checksum failed to verify.",
+                              oat_path.c_str());
+    return nullptr;
+  }
+}
+
 const OatFile* ClassLinker::PatchAndRetrieveOat(const std::string& input_oat,
                                                 const std::string& output_oat,
                                                 const std::string& image_location,
                                                 InstructionSet isa,
                                                 std::string* error_msg) {
+  if (!Runtime::Current()->IsDex2OatEnabled()) {
+    // We don't have dex2oat so we can assume we don't have patchoat either. We should just use the
+    // input_oat but make sure we only do interpretation on it's dex files.
+    LOG(WARNING) << "Patching of oat file '" << input_oat << "' not attempted due to dex2oat being "
+                 << "disabled. Attempting to use oat file for interpretation";
+    return GetInterpretedOnlyOat(input_oat, isa, error_msg);
+  }
   Locks::mutator_lock_->AssertNotHeld(Thread::Current());  // Avoid starving GC.
   std::string patchoat(Runtime::Current()->GetPatchoatExecutable());
 
@@ -1352,6 +1384,12 @@
                                 "but was unable to open output file '%s': %s",
                                 input_oat.c_str(), output_oat.c_str(), error_msg->c_str());
     }
+  } else if (!Runtime::Current()->IsCompiler()) {
+    // patchoat failed which means we probably don't have enough room to place the output oat file,
+    // instead of failing we should just run the interpreter from the dex files in the input oat.
+    LOG(WARNING) << "Patching of oat file '" << input_oat << "' failed. Attempting to use oat file "
+                 << "for interpretation. patchoat failure was: " << *error_msg;
+    return GetInterpretedOnlyOat(input_oat, isa, error_msg);
   } else {
     *error_msg = StringPrintf("Patching of oat file '%s to '%s' "
                               "failed: %s", input_oat.c_str(), output_oat.c_str(),
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 9ae3862..5694149 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -573,6 +573,10 @@
                                             std::vector<std::string>* error_msg)
       LOCKS_EXCLUDED(dex_lock_, Locks::mutator_lock_);
 
+  const OatFile* GetInterpretedOnlyOat(const std::string& oat_path,
+                                       InstructionSet isa,
+                                       std::string* error_msg);
+
   const OatFile* PatchAndRetrieveOat(const std::string& input, const std::string& output,
                                      const std::string& image_location, InstructionSet isa,
                                      std::string* error_msg)
@@ -752,6 +756,7 @@
   friend class ImageDumper;  // for FindOpenedOatFileFromOatLocation
   friend class ElfPatcher;  // for FindOpenedOatFileForDexFile & FindOpenedOatFileFromOatLocation
   friend class NoDex2OatTest;  // for FindOpenedOatFileForDexFile
+  friend class NoPatchoatTest;  // for FindOpenedOatFileForDexFile
   FRIEND_TEST(ClassLinkerTest, ClassRootDescriptors);
   FRIEND_TEST(mirror::DexCacheTest, Open);
   FRIEND_TEST(ExceptionTest, FindExceptionHandler);
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index b74b10f..7d9922d 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -45,7 +45,7 @@
                              std::string* error_msg) {
   CHECK(!oat_contents.empty()) << location;
   CheckLocation(location);
-  std::unique_ptr<OatFile> oat_file(new OatFile(location));
+  std::unique_ptr<OatFile> oat_file(new OatFile(location, false));
   oat_file->begin_ = &oat_contents[0];
   oat_file->end_ = &oat_contents[oat_contents.size()];
   return oat_file->Setup(error_msg) ? oat_file.release() : nullptr;
@@ -97,7 +97,7 @@
                              const std::string& location,
                              byte* requested_base,
                              std::string* error_msg) {
-  std::unique_ptr<OatFile> oat_file(new OatFile(location));
+  std::unique_ptr<OatFile> oat_file(new OatFile(location, true));
   bool success = oat_file->Dlopen(elf_filename, requested_base, error_msg);
   if (!success) {
     return nullptr;
@@ -111,7 +111,7 @@
                               bool writable,
                               bool executable,
                               std::string* error_msg) {
-  std::unique_ptr<OatFile> oat_file(new OatFile(location));
+  std::unique_ptr<OatFile> oat_file(new OatFile(location, executable));
   bool success = oat_file->ElfFileOpen(file, requested_base, writable, executable, error_msg);
   if (!success) {
     CHECK(!error_msg->empty());
@@ -120,8 +120,9 @@
   return oat_file.release();
 }
 
-OatFile::OatFile(const std::string& location)
-    : location_(location), begin_(NULL), end_(NULL), dlopen_handle_(NULL),
+OatFile::OatFile(const std::string& location, bool is_executable)
+    : location_(location), begin_(NULL), end_(NULL), is_executable_(is_executable),
+      dlopen_handle_(NULL),
       secondary_lookup_lock_("OatFile secondary lookup lock", kOatFileSecondaryLookupLock) {
   CHECK(!location_.empty());
 }
@@ -533,10 +534,15 @@
     methods_pointer_index = num_set_bits;
   }
   const OatMethodOffsets& oat_method_offsets = methods_pointer_[methods_pointer_index];
-  return OatMethod(
-      oat_file_->Begin(),
-      oat_method_offsets.code_offset_,
-      oat_method_offsets.gc_map_offset_);
+  if (oat_file_->IsExecutable() || Runtime::Current()->IsCompiler()) {
+    return OatMethod(
+        oat_file_->Begin(),
+        oat_method_offsets.code_offset_,
+        oat_method_offsets.gc_map_offset_);
+  } else {
+    // We aren't allowed to use the compiled code. We just force it down the interpreted version.
+    return OatMethod(oat_file_->Begin(), 0, 0);
+  }
 }
 
 
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 508bfc2..8535bf4 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -64,6 +64,10 @@
 
   ~OatFile();
 
+  bool IsExecutable() const {
+    return is_executable_;
+  }
+
   ElfFile* GetElfFile() const {
     CHECK_NE(reinterpret_cast<uintptr_t>(elf_file_.get()), reinterpret_cast<uintptr_t>(nullptr))
         << "Cannot get an elf file from " << GetLocation();
@@ -270,7 +274,7 @@
                               bool executable,
                               std::string* error_msg);
 
-  explicit OatFile(const std::string& filename);
+  explicit OatFile(const std::string& filename, bool executable);
   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);
@@ -287,6 +291,9 @@
   // Pointer to end of oat region for bounds checking.
   const byte* end_;
 
+  // Was this oat_file loaded executable?
+  const bool is_executable_;
+
   // Backing memory map for oat file during when opened by ElfWriter during initial compilation.
   std::unique_ptr<MemMap> mem_map_;