From fb7775981c7e6ecca78dcce774e9cc4db63e6e99 Mon Sep 17 00:00:00 2001 From: Alex Light Date: Fri, 22 Aug 2014 17:49:35 -0700 Subject: [PATCH] Support booting without functioning boot.oat/art patchoat. Bug: 17000769 (cherry picked from commit 84d7605f93f1e6e86a16e02017e305c90e93117a) Change-Id: I89c26a905af12ea288742368c2c038afd57a879a --- runtime/class_linker.cc | 21 +++++++--- runtime/oat_file.cc | 12 ++++++ runtime/oat_file.h | 4 ++ runtime/runtime.cc | 69 ++++++++++++++++++++++++++++++++- test/119-noimage-patchoat/expected.txt | 6 +++ test/119-noimage-patchoat/info.txt | 1 + test/119-noimage-patchoat/run | 36 +++++++++++++++++ test/119-noimage-patchoat/src/Main.java | 38 ++++++++++++++++++ 8 files changed, 180 insertions(+), 7 deletions(-) create mode 100644 test/119-noimage-patchoat/expected.txt create mode 100644 test/119-noimage-patchoat/info.txt create mode 100644 test/119-noimage-patchoat/run create mode 100644 test/119-noimage-patchoat/src/Main.java diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 97f20d339..c2a3ab7b4 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -1171,6 +1171,7 @@ const OatFile* ClassLinker::FindOatFileContainingDexFileFromDexLocation( error_msg.c_str())); return nullptr; } else if (!oat_file->IsExecutable() && + Runtime::Current()->GetHeap()->HasImageSpace() && !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.", @@ -1253,6 +1254,7 @@ const OatFile* ClassLinker::OpenOatFileFromDexLocation(const std::string& dex_lo std::string odex_error_msg; bool should_patch_system = false; bool odex_checksum_verified = false; + bool have_system_odex = false; { // There is a high probability that these both these oat files map similar/the same address // spaces so we must scope them like this so they each gets its turn. @@ -1263,14 +1265,18 @@ const OatFile* ClassLinker::OpenOatFileFromDexLocation(const std::string& dex_lo &odex_error_msg)) { error_msgs->push_back(odex_error_msg); return odex_oat_file.release(); - } else if (odex_checksum_verified) { - // We can just relocate - should_patch_system = true; - odex_error_msg = "Image Patches are incorrect"; + } else { + if (odex_checksum_verified) { + // We can just relocate + should_patch_system = true; + odex_error_msg = "Image Patches are incorrect"; + } + if (odex_oat_file.get() != nullptr) { + have_system_odex = true; + } } } - std::string cache_error_msg; bool should_patch_cache = false; bool cache_checksum_verified = false; @@ -1306,6 +1312,8 @@ const OatFile* ClassLinker::OpenOatFileFromDexLocation(const std::string& dex_lo CHECK(have_dalvik_cache); ret = PatchAndRetrieveOat(cache_filename, cache_filename, image_location, isa, &error_msg); } + } else if (have_system_odex) { + ret = GetInterpretedOnlyOat(odex_filename, isa, &error_msg); } } if (ret == nullptr && have_dalvik_cache && OS::FileExists(cache_filename.c_str())) { @@ -1355,7 +1363,8 @@ const OatFile* ClassLinker::GetInterpretedOnlyOat(const std::string& oat_path, if (output.get() == nullptr) { return nullptr; } - if (VerifyOatImageChecksum(output.get(), isa)) { + if (!Runtime::Current()->GetHeap()->HasImageSpace() || + VerifyOatImageChecksum(output.get(), isa)) { return output.release(); } else { *error_msg = StringPrintf("Could not use oat file '%s', image checksum failed to verify.", diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 630599479..2ebdebd24 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -24,6 +24,7 @@ #include "base/stl_util.h" #include "base/unix_file/fd_file.h" #include "elf_file.h" +#include "elf_utils.h" #include "oat.h" #include "mirror/art_method.h" #include "mirror/art_method-inl.h" @@ -40,6 +41,17 @@ void OatFile::CheckLocation(const std::string& location) { CHECK(!location.empty()); } +OatFile* OatFile::OpenWithElfFile(ElfFile* elf_file, + const std::string& location, + std::string* error_msg) { + std::unique_ptr oat_file(new OatFile(location, false)); + oat_file->elf_file_.reset(elf_file); + Elf32_Shdr* hdr = elf_file->FindSectionByName(".rodata"); + oat_file->begin_ = elf_file->Begin() + hdr->sh_offset; + oat_file->end_ = elf_file->Begin() + hdr->sh_size + hdr->sh_offset; + return oat_file->Setup(error_msg) ? oat_file.release() : nullptr; +} + OatFile* OatFile::OpenMemory(std::vector& oat_contents, const std::string& location, std::string* error_msg) { diff --git a/runtime/oat_file.h b/runtime/oat_file.h index 5997cc49a..3fd43f3f4 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -40,6 +40,10 @@ class OatHeader; class OatFile { public: + // Opens an oat file contained within the given elf file. This is always opened as + // non-executable at the moment. + static OatFile* OpenWithElfFile(ElfFile* elf_file, const std::string& location, + std::string* error_msg); // Open an oat file. Returns NULL on failure. Requested base can // optionally be used to request where the file should be loaded. static OatFile* Open(const std::string& filename, diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 1744218b2..fdebedf32 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" @@ -549,9 +551,74 @@ void Runtime::StartDaemonThreads() { VLOG(startup) << "Runtime::StartDaemonThreads exiting"; } +static bool OpenDexFilesFromImage(const std::vector& dex_filenames, + const std::string& image_location, + std::vector& 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(OS::OpenFileForReading(oat_filename.c_str())); + if (file.get() == nullptr) { + return false; + } + std::unique_ptr elf_file(ElfFile::Open(file.release(), false, false, &error_msg)); + if (elf_file.get() == nullptr) { + return false; + } + std::unique_ptr 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 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& dex_filenames, + const std::string& image_location, std::vector& 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; @@ -715,7 +782,7 @@ bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized) std::vector dex_filenames; Split(boot_class_path_string_, ':', dex_filenames); std::vector 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); diff --git a/test/119-noimage-patchoat/expected.txt b/test/119-noimage-patchoat/expected.txt new file mode 100644 index 000000000..e864268a3 --- /dev/null +++ b/test/119-noimage-patchoat/expected.txt @@ -0,0 +1,6 @@ +Run -Xnoimage-dex2oat -Xpatchoat:/system/bin/false +Has image is false, is image dex2oat enabled is false. +Run -Ximage-dex2oat +Has image is true, is image dex2oat enabled is true. +Run default +Has image is true, is image dex2oat enabled is true. diff --git a/test/119-noimage-patchoat/info.txt b/test/119-noimage-patchoat/info.txt new file mode 100644 index 000000000..6b853688d --- /dev/null +++ b/test/119-noimage-patchoat/info.txt @@ -0,0 +1 @@ +Test that disables patchoat'ing the image. diff --git a/test/119-noimage-patchoat/run b/test/119-noimage-patchoat/run new file mode 100644 index 000000000..745b0c947 --- /dev/null +++ b/test/119-noimage-patchoat/run @@ -0,0 +1,36 @@ +#!/bin/bash +# +# Copyright (C) 2014 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Force relocation otherwise we will just use the already created core.oat/art pair. +flags="${@/--no-relocate/--relocate}" + +if [ $(basename $RUN) == 'host-run-test-jar' ]; then + false_bin="/bin/false" +else + false_bin="/system/bin/false" +fi + +# Make sure we can run without an image file, +echo "Run -Xnoimage-dex2oat -Xpatchoat:/system/bin/false" +${RUN} ${flags} ${BPATH} --runtime-option -Xnoimage-dex2oat --runtime-option -Xpatchoat:${false_bin} + +# Make sure we can run with the image file. +echo "Run -Ximage-dex2oat" +${RUN} ${flags} ${BPATH} --runtime-option -Ximage-dex2oat + +# Make sure we can run with the default settings. +echo "Run default" +${RUN} ${flags} ${BPATH} diff --git a/test/119-noimage-patchoat/src/Main.java b/test/119-noimage-patchoat/src/Main.java new file mode 100644 index 000000000..11c736a7d --- /dev/null +++ b/test/119-noimage-patchoat/src/Main.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class Main { + public static void main(String[] args) { + boolean hasImage = hasImage(); + System.out.println( + "Has image is " + hasImage + ", is image dex2oat enabled is " + + isImageDex2OatEnabled() + "."); + + if (hasImage && !isImageDex2OatEnabled()) { + throw new Error("Image with dex2oat disabled runs with an oat file"); + } else if (!hasImage && isImageDex2OatEnabled()) { + throw new Error("Image with dex2oat enabled runs without an oat file"); + } + } + + static { + System.loadLibrary("arttest"); + } + + private native static boolean hasImage(); + + private native static boolean isImageDex2OatEnabled(); +} -- 2.11.0