diff options
| -rw-r--r-- | runtime/gc/heap.cc | 12 | ||||
| -rw-r--r-- | runtime/gc/heap.h | 1 | ||||
| -rw-r--r-- | runtime/oat_file.h | 7 | ||||
| -rw-r--r-- | runtime/oat_file_assistant_test.cc | 4 | ||||
| -rw-r--r-- | runtime/oat_file_manager.cc | 31 | ||||
| -rw-r--r-- | test/2231-oat-require-app-image/expected.txt | 2 | ||||
| -rw-r--r-- | test/2231-oat-require-app-image/info.txt | 1 | ||||
| -rw-r--r-- | test/2231-oat-require-app-image/profile | 1 | ||||
| -rw-r--r-- | test/2231-oat-require-app-image/run | 18 | ||||
| -rw-r--r-- | test/2231-oat-require-app-image/src/Main.java | 31 | ||||
| -rw-r--r-- | test/common/runtime_state.cc | 8 |
11 files changed, 101 insertions, 15 deletions
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index b919cdda60..401394af6e 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -870,6 +870,18 @@ bool Heap::IsCompilingBoot() const { return true; } +bool Heap::HasAppImageSpace() const { + for (const auto& space : GetContinuousSpaces()) { + if (space->IsImageSpace()) { + const gc::space::ImageSpace* image_space = space->AsImageSpace(); + if (image_space->GetImageHeader().IsAppImage()) { + return true; + } + } + } + return false; +} + void Heap::IncrementDisableMovingGC(Thread* self) { // Need to do this holding the lock to prevent races where the GC is about to run / running when // we attempt to disable it. diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h index 515dcb3a6d..9008c01a2b 100644 --- a/runtime/gc/heap.h +++ b/runtime/gc/heap.h @@ -783,6 +783,7 @@ class Heap { bool HasBootImageSpace() const { return !boot_image_spaces_.empty(); } + bool HasAppImageSpace() const REQUIRES_SHARED(Locks::mutator_lock_); ReferenceProcessor* GetReferenceProcessor() { return reference_processor_.get(); diff --git a/runtime/oat_file.h b/runtime/oat_file.h index dce34d9728..75770d73f9 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -378,6 +378,13 @@ class OatFile { return external_dex_files_.empty(); } + // Returns whether an image (e.g. app image) is required to safely execute this OAT file. + inline bool RequiresImage() const { + // We currently require images only for speed profile and everything profile. + return GetCompilerFilter() == CompilerFilter::Filter::kSpeedProfile || + GetCompilerFilter() == CompilerFilter::Filter::kEverythingProfile; + } + protected: OatFile(const std::string& filename, bool executable); diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc index ed47ca3a6b..e8a7381296 100644 --- a/runtime/oat_file_assistant_test.cc +++ b/runtime/oat_file_assistant_test.cc @@ -1437,6 +1437,7 @@ TEST_F(OatFileAssistantTest, GetDexOptNeededWithOutOfDateContext) { TEST_F(OatFileAssistantTest, GetDexLocation) { std::string dex_location = GetScratchDir() + "/TestDex.jar"; std::string oat_location = GetOdexDir() + "/TestDex.odex"; + std::string art_location = GetOdexDir() + "/TestDex.art"; // Start the runtime to initialize the system's class loader. Thread::Current()->TransitionFromSuspendedToRunnable(); @@ -1463,6 +1464,7 @@ TEST_F(OatFileAssistantTest, GetDexLocation) { args.push_back("--dex-file=" + dex_location); args.push_back("--dex-location=TestDex.jar"); args.push_back("--oat-file=" + oat_location); + args.push_back("--app-image-file=" + art_location); std::string error_msg; ASSERT_TRUE(DexoptTest::Dex2Oat(args, &error_msg)) << error_msg; } @@ -1490,6 +1492,7 @@ TEST_F(OatFileAssistantTest, SystemFrameworkDir) { odex_dir = odex_dir + std::string(GetInstructionSetString(kRuntimeISA)); mkdir(odex_dir.c_str(), 0700); std::string oat_location = odex_dir + "/" + filebase + ".odex"; + std::string art_location = odex_dir + "/" + filebase + ".art"; // Clean up in case previous run crashed. remove(oat_location.c_str()); @@ -1527,6 +1530,7 @@ TEST_F(OatFileAssistantTest, SystemFrameworkDir) { args.push_back("--dex-file=" + dex_location); args.push_back("--dex-location=" + filebase + ".jar"); args.push_back("--oat-file=" + oat_location); + args.push_back("--app-image-file=" + art_location); std::string error_msg; ASSERT_TRUE(DexoptTest::Dex2Oat(args, &error_msg)) << error_msg; } diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc index ff743d5158..7101a23d43 100644 --- a/runtime/oat_file_manager.cc +++ b/runtime/oat_file_manager.cc @@ -492,13 +492,14 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( const OatFile* source_oat_file = nullptr; CheckCollisionResult check_collision_result = CheckCollisionResult::kPerformedHasCollisions; std::string error_msg; + bool accept_oat_file = false; if ((class_loader != nullptr || dex_elements != nullptr) && oat_file != nullptr) { // Prevent oat files from being loaded if no class_loader or dex_elements are provided. // This can happen when the deprecated DexFile.<init>(String) is called directly, and it // could load oat files without checking the classpath, which would be incorrect. // Take the file only if it has no collisions, or we must take it because of preopting. check_collision_result = CheckCollision(oat_file.get(), context.get(), /*out*/ &error_msg); - bool accept_oat_file = AcceptOatFile(check_collision_result); + accept_oat_file = AcceptOatFile(check_collision_result); if (!accept_oat_file) { // Failed the collision check. Print warning. if (runtime->IsDexFileFallbackEnabled()) { @@ -531,30 +532,24 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( LOG(WARNING) << error_msg; } - - if (accept_oat_file) { - VLOG(class_linker) << "Registering " << oat_file->GetLocation(); - source_oat_file = RegisterOatFile(std::move(oat_file)); - *out_oat_file = source_oat_file; - } } std::vector<std::unique_ptr<const DexFile>> dex_files; // Load the dex files from the oat file. - if (source_oat_file != nullptr) { - bool added_image_space = false; - if (source_oat_file->IsExecutable()) { + bool added_image_space = false; + if (accept_oat_file) { + if (oat_file->IsExecutable()) { ScopedTrace app_image_timing("AppImage:Loading"); // We need to throw away the image space if we are debuggable but the oat-file source of the // image is not otherwise we might get classes with inlined methods or other such things. std::unique_ptr<gc::space::ImageSpace> image_space; if (ShouldLoadAppImage(check_collision_result, - source_oat_file, + oat_file.get(), context.get(), &error_msg)) { - image_space = oat_file_assistant.OpenImageSpace(source_oat_file); + image_space = oat_file_assistant.OpenImageSpace(oat_file.get()); } if (image_space != nullptr) { ScopedObjectAccess soa(self); @@ -606,9 +601,9 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( } } } - if (!added_image_space) { + if (!added_image_space && !oat_file->RequiresImage()) { DCHECK(dex_files.empty()); - dex_files = oat_file_assistant.LoadDexFiles(*source_oat_file, dex_location); + dex_files = oat_file_assistant.LoadDexFiles(*oat_file.get(), dex_location); // Register for tracking. for (const auto& dex_file : dex_files) { @@ -616,7 +611,7 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( } } if (dex_files.empty()) { - error_msgs->push_back("Failed to open dex files from " + source_oat_file->GetLocation()); + error_msgs->push_back("Failed to open dex files from " + oat_file->GetLocation()); } else { // Opened dex files from an oat file, madvise them to their loaded state. for (const std::unique_ptr<const DexFile>& dex_file : dex_files) { @@ -625,6 +620,12 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( } } + if (accept_oat_file && (added_image_space || !oat_file->RequiresImage())) { + VLOG(class_linker) << "Registering " << oat_file->GetLocation(); + source_oat_file = RegisterOatFile(std::move(oat_file)); + *out_oat_file = source_oat_file; + } + // Fall back to running out of the original dex file if we couldn't load any // dex_files from the oat file. if (dex_files.empty()) { diff --git a/test/2231-oat-require-app-image/expected.txt b/test/2231-oat-require-app-image/expected.txt new file mode 100644 index 0000000000..95d58e9d79 --- /dev/null +++ b/test/2231-oat-require-app-image/expected.txt @@ -0,0 +1,2 @@ +JNI_OnLoad called +Test passed. diff --git a/test/2231-oat-require-app-image/info.txt b/test/2231-oat-require-app-image/info.txt new file mode 100644 index 0000000000..8e0b0693de --- /dev/null +++ b/test/2231-oat-require-app-image/info.txt @@ -0,0 +1 @@ +Make sure speed-profile OAT files do not load without an AppImage
\ No newline at end of file diff --git a/test/2231-oat-require-app-image/profile b/test/2231-oat-require-app-image/profile new file mode 100644 index 0000000000..36fb1bae49 --- /dev/null +++ b/test/2231-oat-require-app-image/profile @@ -0,0 +1 @@ +LMain;
\ No newline at end of file diff --git a/test/2231-oat-require-app-image/run b/test/2231-oat-require-app-image/run new file mode 100644 index 0000000000..c258a0ef45 --- /dev/null +++ b/test/2231-oat-require-app-image/run @@ -0,0 +1,18 @@ +#!/bin/bash +# +# Copyright (C) 2020 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. + +# We need a profile to tell dex2oat to include classes in the final app image +exec ${RUN} --no-app-image --profile $@ diff --git a/test/2231-oat-require-app-image/src/Main.java b/test/2231-oat-require-app-image/src/Main.java new file mode 100644 index 0000000000..1bac2cba7e --- /dev/null +++ b/test/2231-oat-require-app-image/src/Main.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2020 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) { + System.loadLibrary(args[0]); + + if ("speed-profile".equals(getCompilerFilter(Main.class)) && !hasAppImage() && hasOatFile()) { + System.out.println("Error: Loaded OAT file with no app image in speed-profile mode"); + } + + System.out.println("Test passed."); + } + + private native static boolean hasAppImage(); + private native static boolean hasOatFile(); + private native static Object getCompilerFilter(Class c); +} diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc index 6c76288663..48158e28ba 100644 --- a/test/common/runtime_state.cc +++ b/test/common/runtime_state.cc @@ -102,6 +102,14 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasImage(JNIEnv* env ATTRIBUTE_U return Runtime::Current()->GetHeap()->HasBootImageSpace(); } +// public static native boolean hasAppImage(); + +extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasAppImage(JNIEnv* env, + jclass cls ATTRIBUTE_UNUSED) { + ScopedObjectAccess soa(env); + return Runtime::Current()->GetHeap()->HasAppImageSpace(); +} + // public static native boolean isImageDex2OatEnabled(); extern "C" JNIEXPORT jboolean JNICALL Java_Main_isImageDex2OatEnabled(JNIEnv* env ATTRIBUTE_UNUSED, |