• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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