Home | History | Annotate | Download | only in runtime
      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