1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ART_RUNTIME_CLASS_LOADER_UTILS_H_ 18 #define ART_RUNTIME_CLASS_LOADER_UTILS_H_ 19 20 #include "art_field-inl.h" 21 #include "base/mutex.h" 22 #include "handle_scope.h" 23 #include "jni_internal.h" 24 #include "mirror/class_loader.h" 25 #include "native/dalvik_system_DexFile.h" 26 #include "scoped_thread_state_change-inl.h" 27 #include "well_known_classes.h" 28 29 namespace art { 30 31 // Returns true if the given class loader is either a PathClassLoader or a DexClassLoader. 32 // (they both have the same behaviour with respect to class lockup order) 33 inline bool IsPathOrDexClassLoader(ScopedObjectAccessAlreadyRunnable& soa, 34 Handle<mirror::ClassLoader> class_loader) 35 REQUIRES_SHARED(Locks::mutator_lock_) { 36 mirror::Class* class_loader_class = class_loader->GetClass(); 37 return 38 (class_loader_class == 39 soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader)) || 40 (class_loader_class == 41 soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_DexClassLoader)); 42 } 43 44 inline bool IsDelegateLastClassLoader(ScopedObjectAccessAlreadyRunnable& soa, 45 Handle<mirror::ClassLoader> class_loader) 46 REQUIRES_SHARED(Locks::mutator_lock_) { 47 mirror::Class* class_loader_class = class_loader->GetClass(); 48 return class_loader_class == 49 soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_DelegateLastClassLoader); 50 } 51 52 // Visit the DexPathList$Element instances in the given classloader with the given visitor. 53 // Constraints on the visitor: 54 // * The visitor should return true to continue visiting more Elements. 55 // * The last argument of the visitor is an out argument of RetType. It will be returned 56 // when the visitor ends the visit (by returning false). 57 // This function assumes that the given classloader is a subclass of BaseDexClassLoader! 58 template <typename Visitor, typename RetType> 59 inline RetType VisitClassLoaderDexElements(ScopedObjectAccessAlreadyRunnable& soa, 60 Handle<mirror::ClassLoader> class_loader, 61 Visitor fn, 62 RetType defaultReturn) 63 REQUIRES_SHARED(Locks::mutator_lock_) { 64 Thread* self = soa.Self(); 65 ObjPtr<mirror::Object> dex_path_list = 66 jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_pathList)-> 67 GetObject(class_loader.Get()); 68 if (dex_path_list != nullptr) { 69 // DexPathList has an array dexElements of Elements[] which each contain a dex file. 70 ObjPtr<mirror::Object> dex_elements_obj = 71 jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList_dexElements)-> 72 GetObject(dex_path_list); 73 // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look 74 // at the mCookie which is a DexFile vector. 75 if (dex_elements_obj != nullptr) { 76 StackHandleScope<1> hs(self); 77 Handle<mirror::ObjectArray<mirror::Object>> dex_elements = 78 hs.NewHandle(dex_elements_obj->AsObjectArray<mirror::Object>()); 79 for (int32_t i = 0; i < dex_elements->GetLength(); ++i) { 80 ObjPtr<mirror::Object> element = dex_elements->GetWithoutChecks(i); 81 if (element == nullptr) { 82 // Should never happen, fail. 83 break; 84 } 85 RetType ret_value; 86 if (!fn(element, &ret_value)) { 87 return ret_value; 88 } 89 } 90 } 91 self->AssertNoPendingException(); 92 } 93 return defaultReturn; 94 } 95 96 // Visit the DexFiles in the given classloader with the given visitor. 97 // Constraints on the visitor: 98 // * The visitor should return true to continue visiting more DexFiles. 99 // * The last argument of the visitor is an out argument of RetType. It will be returned 100 // when the visitor ends the visit (by returning false). 101 // This function assumes that the given classloader is a subclass of BaseDexClassLoader! 102 template <typename Visitor, typename RetType> 103 inline RetType VisitClassLoaderDexFiles(ScopedObjectAccessAlreadyRunnable& soa, 104 Handle<mirror::ClassLoader> class_loader, 105 Visitor fn, 106 RetType defaultReturn) 107 REQUIRES_SHARED(Locks::mutator_lock_) { 108 ArtField* const cookie_field = 109 jni::DecodeArtField(WellKnownClasses::dalvik_system_DexFile_cookie); 110 ArtField* const dex_file_field = 111 jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile); 112 if (dex_file_field == nullptr || cookie_field == nullptr) { 113 return defaultReturn; 114 } 115 auto visit_dex_files = [&](ObjPtr<mirror::Object> element, RetType* ret) 116 REQUIRES_SHARED(Locks::mutator_lock_) { 117 ObjPtr<mirror::Object> dex_file = dex_file_field->GetObject(element); 118 if (dex_file != nullptr) { 119 ObjPtr<mirror::LongArray> long_array = cookie_field->GetObject(dex_file)->AsLongArray(); 120 if (long_array == nullptr) { 121 // This should never happen so log a warning. 122 LOG(WARNING) << "Null DexFile::mCookie"; 123 *ret = defaultReturn; 124 return true; 125 } 126 int32_t long_array_size = long_array->GetLength(); 127 // First element is the oat file. 128 for (int32_t j = kDexFileIndexStart; j < long_array_size; ++j) { 129 const DexFile* cp_dex_file = reinterpret_cast<const DexFile*>(static_cast<uintptr_t>( 130 long_array->GetWithoutChecks(j))); 131 RetType ret_value; 132 if (!fn(cp_dex_file, /* out */ &ret_value)) { 133 *ret = ret_value; 134 return false; 135 } 136 } 137 } 138 return true; 139 }; 140 141 return VisitClassLoaderDexElements(soa, class_loader, visit_dex_files, defaultReturn); 142 } 143 144 // Simplified version of the above, w/o out argument. 145 template <typename Visitor> 146 inline void VisitClassLoaderDexFiles(ScopedObjectAccessAlreadyRunnable& soa, 147 Handle<mirror::ClassLoader> class_loader, 148 Visitor fn) 149 REQUIRES_SHARED(Locks::mutator_lock_) { 150 auto helper = [&fn](const art::DexFile* dex_file, void** ATTRIBUTE_UNUSED) 151 REQUIRES_SHARED(Locks::mutator_lock_) { 152 return fn(dex_file); 153 }; 154 VisitClassLoaderDexFiles<decltype(helper), void*>(soa, 155 class_loader, 156 helper, 157 /* default */ nullptr); 158 } 159 160 } // namespace art 161 162 #endif // ART_RUNTIME_CLASS_LOADER_UTILS_H_ 163