diff options
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/Android.bp | 1 | ||||
-rw-r--r-- | runtime/class_loader_context.cc | 31 | ||||
-rw-r--r-- | runtime/class_loader_context.h | 22 | ||||
-rw-r--r-- | runtime/class_loader_context_test.cc | 44 | ||||
-rw-r--r-- | runtime/oat_file_assistant.cc | 4 | ||||
-rw-r--r-- | runtime/oat_file_manager.cc | 96 | ||||
-rw-r--r-- | runtime/oat_file_manager.h | 26 |
7 files changed, 62 insertions, 162 deletions
diff --git a/runtime/Android.bp b/runtime/Android.bp index 64e6796ba0..116453b1bf 100644 --- a/runtime/Android.bp +++ b/runtime/Android.bp @@ -422,7 +422,6 @@ gensrcs { srcs: [ "arch/instruction_set.h", "base/mutex.h", - "class_loader_context.h", "class_status.h", "debugger.h", "gc_root.h", diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc index 2bd541118b..98174142f1 100644 --- a/runtime/class_loader_context.cc +++ b/runtime/class_loader_context.cc @@ -672,10 +672,9 @@ static bool IsAbsoluteLocation(const std::string& location) { return !location.empty() && location[0] == '/'; } -ClassLoaderContext::VerificationResult ClassLoaderContext::VerifyClassLoaderContextMatch( - const std::string& context_spec, - bool verify_names, - bool verify_checksums) const { +bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& context_spec, + bool verify_names, + bool verify_checksums) const { if (verify_names || verify_checksums) { DCHECK(dex_files_open_attempted_); DCHECK(dex_files_open_result_); @@ -684,21 +683,15 @@ ClassLoaderContext::VerificationResult ClassLoaderContext::VerifyClassLoaderCont ClassLoaderContext expected_context; if (!expected_context.Parse(context_spec, verify_checksums)) { LOG(WARNING) << "Invalid class loader context: " << context_spec; - return VerificationResult::kMismatch; + return false; } // Special shared library contexts always match. They essentially instruct the runtime // to ignore the class path check because the oat file is known to be loaded in different // contexts. OatFileManager will further verify if the oat file can be loaded based on the // collision check. - if (expected_context.special_shared_library_) { - // Special case where we are the only entry in the class path. - if (class_loader_chain_.size() == 1 && class_loader_chain_[0].classpath.size() == 0) { - return VerificationResult::kVerifies; - } - return VerificationResult::kForcedToSkipChecks; - } else if (special_shared_library_) { - return VerificationResult::kForcedToSkipChecks; + if (special_shared_library_ || expected_context.special_shared_library_) { + return true; } if (expected_context.class_loader_chain_.size() != class_loader_chain_.size()) { @@ -706,7 +699,7 @@ ClassLoaderContext::VerificationResult ClassLoaderContext::VerifyClassLoaderCont << expected_context.class_loader_chain_.size() << ", actual=" << class_loader_chain_.size() << " (" << context_spec << " | " << EncodeContextForOatFile("") << ")"; - return VerificationResult::kMismatch; + return false; } for (size_t i = 0; i < class_loader_chain_.size(); i++) { @@ -717,14 +710,14 @@ ClassLoaderContext::VerificationResult ClassLoaderContext::VerifyClassLoaderCont << ". expected=" << GetClassLoaderTypeName(expected_info.type) << ", found=" << GetClassLoaderTypeName(info.type) << " (" << context_spec << " | " << EncodeContextForOatFile("") << ")"; - return VerificationResult::kMismatch; + return false; } if (info.classpath.size() != expected_info.classpath.size()) { LOG(WARNING) << "ClassLoaderContext classpath size mismatch for position " << i << ". expected=" << expected_info.classpath.size() << ", found=" << info.classpath.size() << " (" << context_spec << " | " << EncodeContextForOatFile("") << ")"; - return VerificationResult::kMismatch; + return false; } if (verify_checksums) { @@ -779,7 +772,7 @@ ClassLoaderContext::VerificationResult ClassLoaderContext::VerifyClassLoaderCont << ". expected=" << expected_info.classpath[k] << ", found=" << info.classpath[k] << " (" << context_spec << " | " << EncodeContextForOatFile("") << ")"; - return VerificationResult::kMismatch; + return false; } // Compare the checksums. @@ -788,11 +781,11 @@ ClassLoaderContext::VerificationResult ClassLoaderContext::VerifyClassLoaderCont << ". expected=" << expected_info.checksums[k] << ", found=" << info.checksums[k] << " (" << context_spec << " | " << EncodeContextForOatFile("") << ")"; - return VerificationResult::kMismatch; + return false; } } } - return VerificationResult::kVerifies; + return true; } jclass ClassLoaderContext::GetClassLoaderClass(ClassLoaderType type) { diff --git a/runtime/class_loader_context.h b/runtime/class_loader_context.h index a4268aa09a..1c83007f41 100644 --- a/runtime/class_loader_context.h +++ b/runtime/class_loader_context.h @@ -22,10 +22,8 @@ #include "arch/instruction_set.h" #include "base/dchecked_vector.h" -#include "dex/dex_file.h" #include "handle_scope.h" #include "mirror/class_loader.h" -#include "oat_file.h" #include "scoped_thread_state_change.h" namespace art { @@ -36,18 +34,6 @@ class OatFile; // Utility class which holds the class loader context used during compilation/verification. class ClassLoaderContext { public: - enum class VerificationResult { - kVerifies, - kForcedToSkipChecks, - kMismatch, - }; - - enum ClassLoaderType { - kInvalidClassLoader = 0, - kPathClassLoader = 1, - kDelegateLastClassLoader = 2 - }; - ~ClassLoaderContext(); // Opens requested class path files and appends them to ClassLoaderInfo::opened_dex_files. @@ -123,7 +109,7 @@ class ClassLoaderContext { // This should be called after OpenDexFiles(). // Names are only verified if verify_names is true. // Checksums are only verified if verify_checksums is true. - VerificationResult VerifyClassLoaderContextMatch(const std::string& context_spec, + bool VerifyClassLoaderContextMatch(const std::string& context_spec, bool verify_names = true, bool verify_checksums = true) const; @@ -155,6 +141,12 @@ class ClassLoaderContext { static std::unique_ptr<ClassLoaderContext> Default(); private: + enum ClassLoaderType { + kInvalidClassLoader = 0, + kPathClassLoader = 1, + kDelegateLastClassLoader = 2 + }; + struct ClassLoaderInfo { // The type of this class loader. ClassLoaderType type; diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc index 5e3f48c100..4689ae4c3f 100644 --- a/runtime/class_loader_context_test.cc +++ b/runtime/class_loader_context_test.cc @@ -608,17 +608,6 @@ TEST_F(ClassLoaderContextTest, CreateContextForClassLoader) { VerifyClassLoaderPCLFromTestDex(context.get(), 3, "ForClassLoaderA"); } - -TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextFirstElement) { - std::string context_spec = "PCL[]"; - std::unique_ptr<ClassLoaderContext> context = ParseContextWithChecksums(context_spec); - ASSERT_TRUE(context != nullptr); - PretendContextOpenedDexFiles(context.get()); - // Ensure that the special shared library marks as verified for the first thing in the class path. - ASSERT_EQ(context->VerifyClassLoaderContextMatch(OatFile::kSpecialSharedLibrary), - ClassLoaderContext::VerificationResult::kVerifies); -} - TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatch) { std::string context_spec = "PCL[a.dex*123:b.dex*456];DLC[c.dex*890]"; std::unique_ptr<ClassLoaderContext> context = ParseContextWithChecksums(context_spec); @@ -630,36 +619,28 @@ TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatch) { VerifyClassLoaderPCL(context.get(), 0, "a.dex:b.dex"); VerifyClassLoaderDLC(context.get(), 1, "c.dex"); - ASSERT_EQ(context->VerifyClassLoaderContextMatch(context_spec), - ClassLoaderContext::VerificationResult::kVerifies); + ASSERT_TRUE(context->VerifyClassLoaderContextMatch(context_spec)); std::string wrong_class_loader_type = "PCL[a.dex*123:b.dex*456];PCL[c.dex*890]"; - ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_class_loader_type), - ClassLoaderContext::VerificationResult::kMismatch); + ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_class_loader_type)); std::string wrong_class_loader_order = "DLC[c.dex*890];PCL[a.dex*123:b.dex*456]"; - ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_class_loader_order), - ClassLoaderContext::VerificationResult::kMismatch); + ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_class_loader_order)); std::string wrong_classpath_order = "PCL[b.dex*456:a.dex*123];DLC[c.dex*890]"; - ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_classpath_order), - ClassLoaderContext::VerificationResult::kMismatch); + ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_classpath_order)); std::string wrong_checksum = "PCL[a.dex*999:b.dex*456];DLC[c.dex*890]"; - ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_checksum), - ClassLoaderContext::VerificationResult::kMismatch); + ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_checksum)); std::string wrong_extra_class_loader = "PCL[a.dex*123:b.dex*456];DLC[c.dex*890];PCL[d.dex*321]"; - ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_extra_class_loader), - ClassLoaderContext::VerificationResult::kMismatch); + ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_extra_class_loader)); std::string wrong_extra_classpath = "PCL[a.dex*123:b.dex*456];DLC[c.dex*890:d.dex*321]"; - ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_extra_classpath), - ClassLoaderContext::VerificationResult::kMismatch); + ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_extra_classpath)); std::string wrong_spec = "PCL[a.dex*999:b.dex*456];DLC["; - ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_spec), - ClassLoaderContext::VerificationResult::kMismatch); + ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_spec)); } TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatchAfterEncoding) { @@ -671,8 +652,7 @@ TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatchAfterEncoding) { std::unique_ptr<ClassLoaderContext> context = CreateContextForClassLoader(class_loader_d); std::string context_with_no_base_dir = context->EncodeContextForOatFile(""); - ASSERT_EQ(context->VerifyClassLoaderContextMatch(context_with_no_base_dir), - ClassLoaderContext::VerificationResult::kVerifies); + ASSERT_TRUE(context->VerifyClassLoaderContextMatch(context_with_no_base_dir)); std::string dex_location = GetTestDexFileName("ForClassLoaderA"); size_t pos = dex_location.rfind('/'); @@ -681,8 +661,7 @@ TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatchAfterEncoding) { std::string context_with_base_dir = context->EncodeContextForOatFile(parent); ASSERT_NE(context_with_base_dir, context_with_no_base_dir); - ASSERT_EQ(context->VerifyClassLoaderContextMatch(context_with_base_dir), - ClassLoaderContext::VerificationResult::kVerifies); + ASSERT_TRUE(context->VerifyClassLoaderContextMatch(context_with_base_dir)); } TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatchAfterEncodingMultidex) { @@ -690,8 +669,7 @@ TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatchAfterEncodingMultide std::unique_ptr<ClassLoaderContext> context = CreateContextForClassLoader(class_loader); - ASSERT_EQ(context->VerifyClassLoaderContextMatch(context->EncodeContextForOatFile("")), - ClassLoaderContext::VerificationResult::kVerifies); + ASSERT_TRUE(context->VerifyClassLoaderContextMatch(context->EncodeContextForOatFile(""))); } } // namespace art diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc index 241102ea83..9c8b6512a7 100644 --- a/runtime/oat_file_assistant.cc +++ b/runtime/oat_file_assistant.cc @@ -1217,9 +1217,7 @@ bool OatFileAssistant::OatFileInfo::ClassLoaderContextIsOkay(ClassLoaderContext* return false; } - - bool result = context->VerifyClassLoaderContextMatch(file->GetClassLoaderContext()) == - ClassLoaderContext::VerificationResult::kVerifies; + bool result = context->VerifyClassLoaderContextMatch(file->GetClassLoaderContext()); if (!result) { VLOG(oat) << "ClassLoaderContext check failed. Context was " << file->GetClassLoaderContext() diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc index 59a1045ba2..16e6cf375c 100644 --- a/runtime/oat_file_manager.cc +++ b/runtime/oat_file_manager.cc @@ -276,19 +276,9 @@ static void AddNext(/*inout*/DexFileAndClassPair& original, } } -static bool CheckClassCollision(const OatFile* oat_file, - const ClassLoaderContext* context, - std::string* error_msg /*out*/) { - std::vector<const DexFile*> dex_files_loaded = context->FlattenOpenedDexFiles(); - - // Vector that holds the newly opened dex files live, this is done to prevent leaks. - std::vector<std::unique_ptr<const DexFile>> opened_dex_files; - - ScopedTrace st("Collision check"); - // Add dex files from the oat file to check. - std::vector<const DexFile*> dex_files_unloaded; - AddDexFilesFromOat(oat_file, &dex_files_unloaded, &opened_dex_files); - +static bool CollisionCheck(std::vector<const DexFile*>& dex_files_loaded, + std::vector<const DexFile*>& dex_files_unloaded, + std::string* error_msg /*out*/) { // Generate type index information for each dex file. std::vector<TypeIndexInfo> loaded_types; for (const DexFile* dex_file : dex_files_loaded) { @@ -365,10 +355,9 @@ static bool CheckClassCollision(const OatFile* oat_file, // against the following top element. If the descriptor is the same, it is now checked whether // the two elements agree on whether their dex file was from an already-loaded oat-file or the // new oat file. Any disagreement indicates a collision. -OatFileManager::CheckCollisionResult OatFileManager::CheckCollision( - const OatFile* oat_file, - const ClassLoaderContext* context, - /*out*/ std::string* error_msg) const { +bool OatFileManager::HasCollisions(const OatFile* oat_file, + const ClassLoaderContext* context, + std::string* error_msg /*out*/) const { DCHECK(oat_file != nullptr); DCHECK(error_msg != nullptr); @@ -378,59 +367,28 @@ OatFileManager::CheckCollisionResult OatFileManager::CheckCollision( // Note that this has correctness implications as we cannot guarantee that the class resolution // used during compilation is OK (b/37777332). if (context == nullptr) { - LOG(WARNING) << "Skipping duplicate class check due to unsupported classloader"; - return CheckCollisionResult::kSkippedUnsupportedClassLoader; + LOG(WARNING) << "Skipping duplicate class check due to unsupported classloader"; + return false; } - // If the oat file loading context matches the context used during compilation then we accept + // If the pat file loading context matches the context used during compilation then we accept // the oat file without addition checks - ClassLoaderContext::VerificationResult result = context->VerifyClassLoaderContextMatch( - oat_file->GetClassLoaderContext(), - /*verify_names*/ true, - /*verify_checksums*/ true); - switch (result) { - case ClassLoaderContext::VerificationResult::kForcedToSkipChecks: - return CheckCollisionResult::kSkippedClassLoaderContextSharedLibrary; - case ClassLoaderContext::VerificationResult::kMismatch: - // Mismatched context, do the actual collision check. - break; - case ClassLoaderContext::VerificationResult::kVerifies: - return CheckCollisionResult::kNoCollisions; + if (context->VerifyClassLoaderContextMatch(oat_file->GetClassLoaderContext())) { + return false; } // The class loader context does not match. Perform a full duplicate classes check. - return CheckClassCollision(oat_file, context, error_msg) - ? CheckCollisionResult::kPerformedHasCollisions : CheckCollisionResult::kNoCollisions; -} -bool OatFileManager::AcceptOatFile(CheckCollisionResult result) const { - // Take the file only if it has no collisions, or we must take it because of preopting. - // Also accept oat files for shared libraries and unsupported class loaders. - return result != CheckCollisionResult::kPerformedHasCollisions; -} + std::vector<const DexFile*> dex_files_loaded = context->FlattenOpenedDexFiles(); -bool OatFileManager::ShouldLoadAppImage(CheckCollisionResult check_collision_result, - const OatFile* source_oat_file, - ClassLoaderContext* context, - std::string* error_msg) { - Runtime* const runtime = Runtime::Current(); - if (kEnableAppImage && (!runtime->IsJavaDebuggable() || source_oat_file->IsDebuggable())) { - // If we verified the class loader context (skipping due to the special marker doesn't - // count), then also avoid the collision check. - bool load_image = check_collision_result == CheckCollisionResult::kNoCollisions; - // If we skipped the collision check, we need to reverify to be sure its OK to load the - // image. - if (!load_image && - check_collision_result == - CheckCollisionResult::kSkippedClassLoaderContextSharedLibrary) { - // We can load the app image only if there are no collisions. If we know the - // class loader but didn't do the full collision check in HasCollisions(), - // do it now. b/77342775 - load_image = !CheckClassCollision(source_oat_file, context, error_msg); - } - return load_image; - } - return false; + // Vector that holds the newly opened dex files live, this is done to prevent leaks. + std::vector<std::unique_ptr<const DexFile>> opened_dex_files; + + ScopedTrace st("Collision check"); + // Add dex files from the oat file to check. + std::vector<const DexFile*> dex_files_unloaded; + AddDexFilesFromOat(oat_file, &dex_files_unloaded, &opened_dex_files); + return CollisionCheck(dex_files_loaded, dex_files_unloaded, error_msg); } std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( @@ -515,17 +473,16 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( << reinterpret_cast<uintptr_t>(oat_file.get()) << " (executable=" << (oat_file != nullptr ? oat_file->IsExecutable() : false) << ")"; - CheckCollisionResult check_collision_result = CheckCollisionResult::kPerformedHasCollisions; 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); + bool accept_oat_file = + !HasCollisions(oat_file.get(), context.get(), /*out*/ &error_msg); if (!accept_oat_file) { // Failed the collision check. Print warning. - if (runtime->IsDexFileFallbackEnabled()) { + if (Runtime::Current()->IsDexFileFallbackEnabled()) { if (!oat_file_assistant.HasOriginalDexFiles()) { // We need to fallback but don't have original dex files. We have to // fallback to opening the existing oat file. This is potentially @@ -572,11 +529,10 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( // 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, - context.get(), - &error_msg)) { + if (kEnableAppImage && (!runtime->IsJavaDebuggable() || source_oat_file->IsDebuggable())) { image_space = oat_file_assistant.OpenImageSpace(source_oat_file); + } else { + image_space = nullptr; } if (image_space != nullptr) { ScopedObjectAccess soa(self); diff --git a/runtime/oat_file_manager.h b/runtime/oat_file_manager.h index 80456e9b75..038474e31f 100644 --- a/runtime/oat_file_manager.h +++ b/runtime/oat_file_manager.h @@ -108,39 +108,23 @@ class OatFileManager { void SetOnlyUseSystemOatFiles(); private: - enum class CheckCollisionResult { - kSkippedUnsupportedClassLoader, - kSkippedClassLoaderContextSharedLibrary, - kNoCollisions, - kPerformedHasCollisions, - }; - // Check that the class loader context of the given oat file matches the given context. // This will perform a check that all class loaders in the chain have the same type and // classpath. // If the context is null (which means the initial class loader was null or unsupported) - // this returns kSkippedUnsupportedClassLoader. + // this returns false. // If the context does not validate the method will check for duplicate class definitions of // the given oat file against the oat files (either from the class loaders if possible or all // non-boot oat files otherwise). - // Return kPerformedHasCollisions if there are any class definition collisions in the oat_file. - CheckCollisionResult CheckCollision(const OatFile* oat_file, - const ClassLoaderContext* context, - /*out*/ std::string* error_msg) const + // Return true if there are any class definition collisions in the oat_file. + bool HasCollisions(const OatFile* oat_file, + const ClassLoaderContext* context, + /*out*/ std::string* error_msg) const REQUIRES(!Locks::oat_file_manager_lock_); const OatFile* FindOpenedOatFileFromOatLocationLocked(const std::string& oat_location) const REQUIRES(Locks::oat_file_manager_lock_); - // Return true if we should accept the oat file. - bool AcceptOatFile(CheckCollisionResult result) const; - - // Return true if we should attempt to load the app image. - bool ShouldLoadAppImage(CheckCollisionResult check_collision_result, - const OatFile* source_oat_file, - ClassLoaderContext* context, - std::string* error_msg); - std::set<std::unique_ptr<const OatFile>> oat_files_ GUARDED_BY(Locks::oat_file_manager_lock_); bool have_non_pic_oat_file_; |