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