diff options
author | 2018-02-20 18:24:55 -0800 | |
---|---|---|
committer | 2018-03-01 16:30:36 -0800 | |
commit | b8e7c370ccfc53cca8c7caeee7535693668f70fe (patch) | |
tree | df4ddcbc8eca282687cd41a1f8460d454b02d879 /runtime/class_loader_utils.h | |
parent | 7b414bac4b69309498cb8d0264cf152e4f328db6 (diff) |
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
Diffstat (limited to 'runtime/class_loader_utils.h')
-rw-r--r-- | runtime/class_loader_utils.h | 116 |
1 files changed, 114 insertions, 2 deletions
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<mirror::ClassLoader> 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<mirror::Class>(WellKnownClasses::dalvik_system_DexClassLoader)); } -static bool IsDelegateLastClassLoader(ScopedObjectAccessAlreadyRunnable& soa, +inline bool IsDelegateLastClassLoader(ScopedObjectAccessAlreadyRunnable& soa, Handle<mirror::ClassLoader> 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<mirror::Class>(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 <typename Visitor, typename RetType> +inline RetType VisitClassLoaderDexElements(ScopedObjectAccessAlreadyRunnable& soa, + Handle<mirror::ClassLoader> class_loader, + Visitor fn, + RetType defaultReturn) + REQUIRES_SHARED(Locks::mutator_lock_) { + Thread* self = soa.Self(); + ObjPtr<mirror::Object> 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<mirror::Object> 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<mirror::ObjectArray<mirror::Object>> dex_elements = + hs.NewHandle(dex_elements_obj->AsObjectArray<mirror::Object>()); + for (int32_t i = 0; i < dex_elements->GetLength(); ++i) { + ObjPtr<mirror::Object> 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 <typename Visitor, typename RetType> +inline RetType VisitClassLoaderDexFiles(ScopedObjectAccessAlreadyRunnable& soa, + Handle<mirror::ClassLoader> 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<mirror::Object> element, RetType* ret) + REQUIRES_SHARED(Locks::mutator_lock_) { + ObjPtr<mirror::Object> dex_file = dex_file_field->GetObject(element); + if (dex_file != nullptr) { + ObjPtr<mirror::LongArray> 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<const DexFile*>(static_cast<uintptr_t>( + 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 <typename Visitor> +inline void VisitClassLoaderDexFiles(ScopedObjectAccessAlreadyRunnable& soa, + Handle<mirror::ClassLoader> 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<decltype(helper), void*>(soa, + class_loader, + helper, + /* default */ nullptr); +} + } // namespace art #endif // ART_RUNTIME_CLASS_LOADER_UTILS_H_ |