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/locks.h"
22 #include "base/macros.h"
23 #include "handle_scope.h"
24 #include "jni/jni_internal.h"
25 #include "mirror/class_loader.h"
26 #include "mirror/object-inl.h"
27 #include "mirror/object.h"
28 #include "native/dalvik_system_DexFile.h"
29 #include "scoped_thread_state_change-inl.h"
30 #include "well_known_classes-inl.h"
31
32 namespace art HIDDEN {
33
34 // Returns true if the given class loader derives from BaseDexClassLoader.
IsInstanceOfBaseDexClassLoader(Handle<mirror::ClassLoader> class_loader)35 inline bool IsInstanceOfBaseDexClassLoader(Handle<mirror::ClassLoader> class_loader)
36 REQUIRES_SHARED(Locks::mutator_lock_) {
37 return class_loader->InstanceOf(WellKnownClasses::dalvik_system_BaseDexClassLoader.Get());
38 }
39
40 // Returns true if the given class loader is either a PathClassLoader or a DexClassLoader.
41 // (they both have the same behaviour with respect to class lookup order)
IsPathOrDexClassLoader(Handle<mirror::ClassLoader> class_loader)42 inline bool IsPathOrDexClassLoader(Handle<mirror::ClassLoader> class_loader)
43 REQUIRES_SHARED(Locks::mutator_lock_) {
44 ObjPtr<mirror::Class> class_loader_class = class_loader->GetClass();
45 return (class_loader_class == WellKnownClasses::dalvik_system_PathClassLoader) ||
46 (class_loader_class == WellKnownClasses::dalvik_system_DexClassLoader);
47 }
48
49 // Returns true if the given class loader is an InMemoryDexClassLoader.
IsInMemoryDexClassLoader(Handle<mirror::ClassLoader> class_loader)50 inline bool IsInMemoryDexClassLoader(Handle<mirror::ClassLoader> class_loader)
51 REQUIRES_SHARED(Locks::mutator_lock_) {
52 ObjPtr<mirror::Class> class_loader_class = class_loader->GetClass();
53 return (class_loader_class == WellKnownClasses::dalvik_system_InMemoryDexClassLoader);
54 }
55
IsDelegateLastClassLoader(Handle<mirror::ClassLoader> class_loader)56 inline bool IsDelegateLastClassLoader(Handle<mirror::ClassLoader> class_loader)
57 REQUIRES_SHARED(Locks::mutator_lock_) {
58 ObjPtr<mirror::Class> class_loader_class = class_loader->GetClass();
59 return class_loader_class == WellKnownClasses::dalvik_system_DelegateLastClassLoader;
60 }
61
62 // Visit the DexPathList$Element instances in the given classloader with the given visitor.
63 // Constraints on the visitor:
64 // * The visitor should return true to continue visiting more Elements.
65 // * The last argument of the visitor is an out argument of RetType. It will be returned
66 // when the visitor ends the visit (by returning false).
67 // This function assumes that the given classloader is a subclass of BaseDexClassLoader!
68 template <typename Visitor, typename RetType>
VisitClassLoaderDexElements(Thread * self,Handle<mirror::ClassLoader> class_loader,Visitor fn,RetType defaultReturn)69 inline RetType VisitClassLoaderDexElements(Thread* self,
70 Handle<mirror::ClassLoader> class_loader,
71 Visitor fn,
72 RetType defaultReturn)
73 REQUIRES_SHARED(Locks::mutator_lock_) {
74 ObjPtr<mirror::Object> dex_path_list =
75 WellKnownClasses::dalvik_system_BaseDexClassLoader_pathList->GetObject(class_loader.Get());
76 if (dex_path_list != nullptr) {
77 // DexPathList has an array dexElements of Elements[] which each contain a dex file.
78 ObjPtr<mirror::Object> dex_elements_obj =
79 WellKnownClasses::dalvik_system_DexPathList_dexElements->GetObject(dex_path_list);
80 // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look
81 // at the mCookie which is a DexFile vector.
82 if (dex_elements_obj != nullptr) {
83 StackHandleScope<1> hs(self);
84 Handle<mirror::ObjectArray<mirror::Object>> dex_elements =
85 hs.NewHandle(dex_elements_obj->AsObjectArray<mirror::Object>());
86 for (auto element : dex_elements.Iterate<mirror::Object>()) {
87 if (element == nullptr) {
88 // Should never happen, fail.
89 break;
90 }
91 RetType ret_value;
92 if (!fn(element, &ret_value)) {
93 return ret_value;
94 }
95 }
96 }
97 }
98 return defaultReturn;
99 }
100
101 // Visit the DexFiles in the given classloader with the given visitor.
102 // Constraints on the visitor:
103 // * The visitor should return true to continue visiting more DexFiles.
104 // * The last argument of the visitor is an out argument of RetType. It will be returned
105 // when the visitor ends the visit (by returning false).
106 // This function assumes that the given classloader is a subclass of BaseDexClassLoader!
107 template <typename Visitor, typename RetType>
VisitClassLoaderDexFiles(Thread * self,Handle<mirror::ClassLoader> class_loader,Visitor fn,RetType defaultReturn)108 inline RetType VisitClassLoaderDexFiles(Thread* self,
109 Handle<mirror::ClassLoader> class_loader,
110 Visitor fn,
111 RetType defaultReturn)
112 REQUIRES_SHARED(Locks::mutator_lock_) {
113 ArtField* const cookie_field = WellKnownClasses::dalvik_system_DexFile_cookie;
114 ArtField* const dex_file_field = WellKnownClasses::dalvik_system_DexPathList__Element_dexFile;
115 if (dex_file_field == nullptr || cookie_field == nullptr) {
116 return defaultReturn;
117 }
118 auto visit_dex_files = [&](ObjPtr<mirror::Object> element, RetType* ret)
119 REQUIRES_SHARED(Locks::mutator_lock_) {
120 ObjPtr<mirror::Object> dex_file = dex_file_field->GetObject(element);
121 if (dex_file != nullptr) {
122 StackHandleScope<1> hs(self);
123 Handle<mirror::LongArray> long_array =
124 hs.NewHandle(cookie_field->GetObject(dex_file)->AsLongArray());
125 if (long_array == nullptr) {
126 // This should never happen so log a warning.
127 LOG(WARNING) << "Null DexFile::mCookie";
128 *ret = defaultReturn;
129 return true;
130 }
131 int32_t long_array_size = long_array->GetLength();
132 // First element is the oat file.
133 for (int32_t j = kDexFileIndexStart; j < long_array_size; ++j) {
134 const DexFile* cp_dex_file = reinterpret_cast<const DexFile*>(static_cast<uintptr_t>(
135 long_array->GetWithoutChecks(j)));
136 RetType ret_value;
137 if (!fn(cp_dex_file, /* out */ &ret_value)) {
138 *ret = ret_value;
139 return false;
140 }
141 }
142 }
143 return true;
144 };
145
146 return VisitClassLoaderDexElements(self, class_loader, visit_dex_files, defaultReturn);
147 }
148
149 // Simplified version of the above, w/o out argument.
150 template <typename Visitor>
VisitClassLoaderDexFiles(Thread * self,Handle<mirror::ClassLoader> class_loader,Visitor fn)151 inline void VisitClassLoaderDexFiles(Thread* self,
152 Handle<mirror::ClassLoader> class_loader,
153 Visitor fn)
154 REQUIRES_SHARED(Locks::mutator_lock_) {
155 auto helper = [&fn](const art::DexFile* dex_file, void** ret)
156 REQUIRES_SHARED(Locks::mutator_lock_) {
157 #ifdef __clang_analyzer__
158 *ret = nullptr;
159 #else
160 UNUSED(ret);
161 #endif
162
163 return fn(dex_file);
164 };
165 VisitClassLoaderDexFiles<decltype(helper), void*>(self,
166 class_loader,
167 helper,
168 /* defaultReturn= */ nullptr);
169 }
170
171 } // namespace art
172
173 #endif // ART_RUNTIME_CLASS_LOADER_UTILS_H_
174