From b8e7c370ccfc53cca8c7caeee7535693668f70fe Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Tue, 20 Feb 2018 18:24:55 -0800 Subject: ART: Refactor known-classloader visits Refactor visiting dex Elements and DexFiles in known classloaders, unifying the walking code. Test: m test-art-host Change-Id: I4203ac4fbb0ee68660aadc0dfbf8affacbc03b8b --- runtime/class_loader_utils.h | 116 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 2 deletions(-) (limited to 'runtime/class_loader_utils.h') diff --git a/runtime/class_loader_utils.h b/runtime/class_loader_utils.h index d160a511de..1439f11636 100644 --- a/runtime/class_loader_utils.h +++ b/runtime/class_loader_utils.h @@ -17,8 +17,12 @@ #ifndef ART_RUNTIME_CLASS_LOADER_UTILS_H_ #define ART_RUNTIME_CLASS_LOADER_UTILS_H_ +#include "art_field-inl.h" +#include "base/mutex.h" #include "handle_scope.h" +#include "jni_internal.h" #include "mirror/class_loader.h" +#include "native/dalvik_system_DexFile.h" #include "scoped_thread_state_change-inl.h" #include "well_known_classes.h" @@ -26,7 +30,7 @@ namespace art { // Returns true if the given class loader is either a PathClassLoader or a DexClassLoader. // (they both have the same behaviour with respect to class lockup order) -static bool IsPathOrDexClassLoader(ScopedObjectAccessAlreadyRunnable& soa, +inline bool IsPathOrDexClassLoader(ScopedObjectAccessAlreadyRunnable& soa, Handle class_loader) REQUIRES_SHARED(Locks::mutator_lock_) { mirror::Class* class_loader_class = class_loader->GetClass(); @@ -37,7 +41,7 @@ static bool IsPathOrDexClassLoader(ScopedObjectAccessAlreadyRunnable& soa, soa.Decode(WellKnownClasses::dalvik_system_DexClassLoader)); } -static bool IsDelegateLastClassLoader(ScopedObjectAccessAlreadyRunnable& soa, +inline bool IsDelegateLastClassLoader(ScopedObjectAccessAlreadyRunnable& soa, Handle class_loader) REQUIRES_SHARED(Locks::mutator_lock_) { mirror::Class* class_loader_class = class_loader->GetClass(); @@ -45,6 +49,114 @@ static bool IsDelegateLastClassLoader(ScopedObjectAccessAlreadyRunnable& soa, soa.Decode(WellKnownClasses::dalvik_system_DelegateLastClassLoader); } +// Visit the DexPathList$Element instances in the given classloader with the given visitor. +// Constraints on the visitor: +// * The visitor should return true to continue visiting more Elements. +// * The last argument of the visitor is an out argument of RetType. It will be returned +// when the visitor ends the visit (by returning false). +// This function assumes that the given classloader is a subclass of BaseDexClassLoader! +template +inline RetType VisitClassLoaderDexElements(ScopedObjectAccessAlreadyRunnable& soa, + Handle class_loader, + Visitor fn, + RetType defaultReturn) + REQUIRES_SHARED(Locks::mutator_lock_) { + Thread* self = soa.Self(); + ObjPtr dex_path_list = + jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_pathList)-> + GetObject(class_loader.Get()); + if (dex_path_list != nullptr) { + // DexPathList has an array dexElements of Elements[] which each contain a dex file. + ObjPtr dex_elements_obj = + jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList_dexElements)-> + GetObject(dex_path_list); + // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look + // at the mCookie which is a DexFile vector. + if (dex_elements_obj != nullptr) { + StackHandleScope<1> hs(self); + Handle> dex_elements = + hs.NewHandle(dex_elements_obj->AsObjectArray()); + for (int32_t i = 0; i < dex_elements->GetLength(); ++i) { + ObjPtr element = dex_elements->GetWithoutChecks(i); + if (element == nullptr) { + // Should never happen, fail. + break; + } + RetType ret_value; + if (!fn(element, &ret_value)) { + return ret_value; + } + } + } + self->AssertNoPendingException(); + } + return defaultReturn; +} + +// Visit the DexFiles in the given classloader with the given visitor. +// Constraints on the visitor: +// * The visitor should return true to continue visiting more DexFiles. +// * The last argument of the visitor is an out argument of RetType. It will be returned +// when the visitor ends the visit (by returning false). +// This function assumes that the given classloader is a subclass of BaseDexClassLoader! +template +inline RetType VisitClassLoaderDexFiles(ScopedObjectAccessAlreadyRunnable& soa, + Handle class_loader, + Visitor fn, + RetType defaultReturn) + REQUIRES_SHARED(Locks::mutator_lock_) { + ArtField* const cookie_field = + jni::DecodeArtField(WellKnownClasses::dalvik_system_DexFile_cookie); + ArtField* const dex_file_field = + jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile); + if (dex_file_field == nullptr || cookie_field == nullptr) { + return defaultReturn; + } + auto visit_dex_files = [&](ObjPtr element, RetType* ret) + REQUIRES_SHARED(Locks::mutator_lock_) { + ObjPtr dex_file = dex_file_field->GetObject(element); + if (dex_file != nullptr) { + ObjPtr long_array = cookie_field->GetObject(dex_file)->AsLongArray(); + if (long_array == nullptr) { + // This should never happen so log a warning. + LOG(WARNING) << "Null DexFile::mCookie"; + *ret = defaultReturn; + return true; + } + int32_t long_array_size = long_array->GetLength(); + // First element is the oat file. + for (int32_t j = kDexFileIndexStart; j < long_array_size; ++j) { + const DexFile* cp_dex_file = reinterpret_cast(static_cast( + long_array->GetWithoutChecks(j))); + RetType ret_value; + if (!fn(cp_dex_file, /* out */ &ret_value)) { + *ret = ret_value; + return false; + } + } + } + return true; + }; + + return VisitClassLoaderDexElements(soa, class_loader, visit_dex_files, defaultReturn); +} + +// Simplified version of the above, w/o out argument. +template +inline void VisitClassLoaderDexFiles(ScopedObjectAccessAlreadyRunnable& soa, + Handle class_loader, + Visitor fn) + REQUIRES_SHARED(Locks::mutator_lock_) { + auto helper = [&fn](const art::DexFile* dex_file, void** ATTRIBUTE_UNUSED) + REQUIRES_SHARED(Locks::mutator_lock_) { + return fn(dex_file); + }; + VisitClassLoaderDexFiles(soa, + class_loader, + helper, + /* default */ nullptr); +} + } // namespace art #endif // ART_RUNTIME_CLASS_LOADER_UTILS_H_ -- cgit v1.2.3-59-g8ed1b