美文网首页
ART的反射调用(一)-获取Class对象

ART的反射调用(一)-获取Class对象

作者: 王小宝wy | 来源:发表于2016-12-27 13:57 被阅读0次

    典型的反射调用形式为:

    private static void classForName() {
        try {
            // 获取 Class 对象
            Class<?> clz = Class.forName("com.xx.xx.XX");
           ...
        } catch (Exception e) {
            e.printStackTrace();
    
        }
    }
    

    1. Class.forName

    public static Class<?> forName(String className)
                    throws ClassNotFoundException {
        return forName(className, true, VMStack.getCallingClassLoader());
    }
    
    public static Class<?> forName(String name, boolean initialize,ClassLoader loader)
              throws ClassNotFoundException{
        if (loader == null) {
            loader = BootClassLoader.getInstance();
        }
        Class<?> result;
        try {
            result = classForName(name, initialize, loader);
        } catch (ClassNotFoundException e) {
            Throwable cause = e.getCause();
            if (cause instanceof LinkageError) {
                throw (LinkageError) cause;
            }
            throw e;
        }
        return result;
    }
    
    static native Class<?> classForName(String className, boolean shouldInitialize,
                ClassLoader classLoader) throws ClassNotFoundException;
    

    Class.forName(String)函数实际是封装调用另一个重载版本的Class.forName(String,boolean,ClassLoader), 在传入第三个参数时首先调用VMStack.getCallingClassLoader方法,这个方法从函数名中大致可以判断出它的作用是获取当前调用者ClassLoader,最后再调用本地方法classForName

    1.1 VMStack.getCallingClassLoader

    native public static ClassLoader getCallingClassLoader();
    
    // 定义在art/runtime/native/dalvik_system_VMStack.cc
    static jobject VMStack_getCallingClassLoader(JNIEnv* env, jclass) {
      ScopedFastNativeObjectAccess soa(env);
      NthCallerVisitor visitor(soa.Self(), 2);
      visitor.WalkStack();
      if (UNLIKELY(visitor.caller == nullptr)) {
        // The caller is an attached native thread.
        return nullptr;
      }
      return soa.AddLocalReference<jobject>(visitor.caller->GetDeclaringClass()->GetClassLoader());
    }
    

    这个方法的核心调用是visitor.WalkStack(),WalkStack()的实现在art/runtime/stack.cc,具体的实现这里先不深究(由于时间原因,这块内容还未理解透彻),不过从代码中可以大致看出WalkStack()方法是根据函数调用栈帧获取到当前调用者,继而获取对应的ClassLoader

    2. Class_classForName

    // "name" is in "binary name" format, e.g. "dalvik.system.Debug$1".
    static jclass Class_classForName(JNIEnv* env, jclass, jstring javaName, jboolean initialize,
                                     jobject javaLoader) {
        ScopedFastNativeObjectAccess soa(env);
        ScopedUtfChars name(env, javaName);
        if (name.c_str() == nullptr) {
            return nullptr;
        }
    
        // 将com.xx.xx转换为com/xx/xx
        if (!IsValidBinaryClassName(name.c_str())) {
            soa.Self()->ThrowNewExceptionF("Ljava/lang/ClassNotFoundException;",
                                           "Invalid name: %s", name.c_str());
            return nullptr;
        }
    
        std::string descriptor(DotToDescriptor(name.c_str()));
        StackHandleScope<2> hs(soa.Self());
        Handle<mirror::ClassLoader> class_loader(hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader)));
        ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
        //核心调用,调用ClassLinker::FindClass()
        Handle<mirror::Class> c(
            hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor.c_str(), class_loader)));
        if (c.Get() == nullptr) {
            ScopedLocalRef<jthrowable> cause(env, env->ExceptionOccurred());
            env->ExceptionClear();
            jthrowable cnfe = reinterpret_cast<jthrowable>(env->NewObject(WellKnownClasses::java_lang_ClassNotFoundException,
                                                                          WellKnownClasses::java_lang_ClassNotFoundException_init,
                                                                          javaName, cause.get()));
            if (cnfe != nullptr) {
                // Make sure allocation didn't fail with an OOME.
                env->Throw(cnfe);
            }
            return nullptr;
        }
        if (initialize) {
            //确保类已经完成解析
            class_linker->EnsureInitialized(soa.Self(), c, true, true);
        }
        return soa.AddLocalReference<jclass>(c.Get());
    }
    

    从代码中可以看出核心调用是class_linker->FindClass(...)

    3. ClassLinker::FindClass

    mirror::Class* ClassLinker::FindClass(Thread* self,
                                          const char* descriptor,
                                          Handle<mirror::ClassLoader> class_loader) {
        ...
        self->AssertNoPendingException();
        if (descriptor[1] == '\0') {
            // 只有基础类型的descriptor是1个字符
            return FindPrimitiveClass(descriptor[0]);
        }
    
        const size_t hash = ComputeModifiedUtf8Hash(descriptor);
        // 在传入的ClassLoader的已加载表中查找类, [3.1]
        mirror::Class* klass = LookupClass(self, descriptor, hash, class_loader.Get());
        if (klass != nullptr) {
            //确保类已经被解析
            return EnsureResolved(self, descriptor, klass);
        }
    
        // 执行到这里,意味着没有找到类
        if (descriptor[0] == '[') {
            return CreateArrayClass(self, descriptor, hash, class_loader);
        } else if (class_loader.Get() == nullptr) {
            // 如果ClassLoader是nullptr,则在boot_class_path_中查找
            ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_);
            if (pair.second != nullptr) {
                return DefineClass(self,
                               descriptor,
                               hash,
                               ScopedNullHandle<mirror::ClassLoader>(),
                               *pair.first,
                               *pair.second);
            } else {
                //仍然没有找到的话,创建一个ClassNoDefFoundError
                mirror::Throwable* pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
                self->SetException(pre_allocated);
                return nullptr;
            }
        } else {
            ScopedObjectAccessUnchecked soa(self);
            mirror::Class* cp_klass;
            //递归的在传入的ClassLoader以及它的各级parent中查找类, [3.2]
            if (FindClassInPathClassLoader(soa, self, descriptor, hash, class_loader, &cp_klass)) {
                if (cp_klass != nullptr) {
                  //找到,直接返回
                  return cp_klass;
                }
            }
            //如果Runtime是编译器,则直接创建ClassNoDefFoundError,只有在dex2oat中创建的Runtime会是编译器
            if (Runtime::Current()->IsAotCompiler()) {
                mirror::Throwable* pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
                self->SetException(pre_allocated);
                return nullptr;
            }
    
            //执行到意味着仍然没有找到相应的类
            ScopedLocalRef<jobject> class_loader_object(soa.Env(),
                                                        soa.AddLocalReference<jobject>(class_loader.Get()));
            std::string class_name_string(DescriptorToDot(descriptor));
    
            ScopedLocalRef<jobject> result(soa.Env(), nullptr);
            {
                ScopedThreadStateChange tsc(self, kNative);
                ScopedLocalRef<jobject> class_name_object(soa.Env(),
                                                          soa.Env()->NewStringUTF(class_name_string.c_str()));
                if (class_name_object.get() == nullptr) {
                    return nullptr;
                }
                //调用ClassLoader的loadClass在传入的ClassLoader中查找
                result.reset(soa.Env()->CallObjectMethod(class_loader_object.get(),
                                                         WellKnownClasses::java_lang_ClassLoader_loadClass,
                                                         class_name_object.get()));
            }
            if (self->IsExceptionPending()) {
                // If the ClassLoader threw, pass that exception up.
                return nullptr;
            } else if (result.get() == nullptr) {
                // 抛出NullPointerException
                ThrowNullPointerException(StringPrintf("ClassLoader.loadClass returned null for %s",
                                                       class_name_string.c_str()).c_str());
                return nullptr;
            } else {
                // 终于找到
                return soa.Decode<mirror::Class*>(result.get());
            }
        }
        UNREACHABLE();
    }
    

    ClassLinker::FindClass的逻辑可以总结为:

    1. 如果要找的类是基础类型,则直接调用FindPrimitiveClass查找基础类型;如果不是则在传入的ClassLoader的已加载类表中查找类(首先会判断ClassLaoder是否为null,如果为null,就在boot_class_table_中查找,否则就在ClassLoader自己的ClassTable中查找),如果找到,确保类已经被解析并返回
    2. 如果在传入的ClassLoader的已加载类表中没有找到类,则首先判断ClassLoader是否为空,如果为空,在boot_class_path_中查找,如果不为空,则调用FindClassInPathClassLoader在传入的ClassLoader以及它的各级parent中查找类
    3. 如果仍然没有找到,则调用传入的ClassLoader的loadClass在传入的ClassLoader中查找,找到返回,否则抛出异常

    3.1 ClassLinker::LookupClass

    mirror::Class* ClassLinker::LookupClass(Thread* self,
                                            const char* descriptor,
                                            size_t hash,
                                            mirror::ClassLoader* class_loader) {
        {
            ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
            //获取ClassLoader对应的ClassTable,如果ClassLoader为null,则则返回boot_class_table_
            ClassTable* const class_table = ClassTableForClassLoader(class_loader);
            if (class_table != nullptr) {
                mirror::Class* result = class_table->Lookup(descriptor, hash);
                if (result != nullptr) {
                    return result;
                }
            }
        }
        if (class_loader != nullptr || !dex_cache_boot_image_class_lookup_required_) {
            return nullptr;
        }
    
        //在Image Space中查找类,Image Space映射的是boot.art和boot.oat
        mirror::Class* result = LookupClassFromBootImage(descriptor);
        if (result != nullptr) {
            result = InsertClass(descriptor, result, hash);
        } else {
            constexpr uint32_t kMaxFailedDexCacheLookups = 1000;
            if (++failed_dex_cache_class_lookups_ > kMaxFailedDexCacheLookups) {
                AddBootImageClassesToClassTable();
            }
        }
        return result;
    }
    
    ClassTable* ClassLinker::ClassTableForClassLoader(mirror::ClassLoader* class_loader) {
        return class_loader == nullptr ? &boot_class_table_ : class_loader->GetClassTable();
    }
    

    3.2 ClassLinker::FindClassInPathClassLoader

    bool ClassLinker::FindClassInPathClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
                                                 Thread* self,
                                                 const char* descriptor,
                                                 size_t hash,
                                                 Handle<mirror::ClassLoader> class_loader,
                                                 mirror::Class** result) {
        //递归调用的终止条件
        //如果是BootClassLoader,在boot_class_path_中查找类,并完成类的解析
        if (IsBootClassLoader(soa, class_loader.Get())) {
            ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_);
            if (pair.second != nullptr) {
                mirror::Class* klass = LookupClass(self, descriptor, hash, nullptr);
                if (klass != nullptr) {
                  *result = EnsureResolved(self, descriptor, klass);
                } else {
                  *result = DefineClass(self,descriptor,hash,
                                        ScopedNullHandle<mirror::ClassLoader>(),
                                        *pair.first,
                                        *pair.second);
                }
                if (*result == nullptr) {
                  self->ClearException();
                }
            } else {
                *result = nullptr;
            }
            return true;
        }
        //递归调用的终止条件
        //确保传入的ClassLoader必须是PathClassLoader
        if (class_loader->GetClass() != soa.Decode<mirror::Class*>(
                            WellKnownClasses::dalvik_system_PathClassLoader)) {
          *result = nullptr;
          return false;
        }
    
        // Handles as RegisterDexFile may allocate dex caches (and cause thread suspension).
        StackHandleScope<4> hs(self);
        Handle<mirror::ClassLoader> h_parent(hs.NewHandle(class_loader->GetParent()));
        //递归调用,在parent中查找,一般情况下,一个应用的PathClassLoader的parent层级为:
        //PathClassLoader(apk)-->PathClassLoader(system)->BootClassLoader
        //所以一般情况下,传入的ClassLoader的parent就是系统的PathClassLoader, 从而递归调用只会调用两次,即
        //h_parent第一次等于PathClassLoader(system),第二次h_parent等于BootClassLoader
        bool recursive_result = FindClassInPathClassLoader(soa, self, descriptor, hash, h_parent, result);
    
        if (!recursive_result) {
            // Something wrong up the chain.
            return false;
        }
    
        if (*result != nullptr) {
            // Found the class up the chain.
            return true;
        }
    
        //获取DexFile的mCookie变量,mCookie指向的是已加载的dex文件列表
        ArtField* const cookie_field = soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_cookie);
        //获取DexPathList的dexElements
        ArtField* const dex_file_field =
            soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile);
        //获取PathClassLoader的pathList属性
        mirror::Object* dex_path_list =
            soa.DecodeField(WellKnownClasses::dalvik_system_PathClassLoader_pathList)->
            GetObject(class_loader.Get());
    
        if (dex_path_list != nullptr && dex_file_field != nullptr && cookie_field != nullptr) {
            mirror::Object* dex_elements_obj =
                soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList_dexElements)->
                GetObject(dex_path_list);
    
            if (dex_elements_obj != nullptr) {
                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) {
                    mirror::Object* element = dex_elements->GetWithoutChecks(i);
                    if (element == nullptr) {
                        // Should never happen, fall back to java code to throw a NPE.
                        break;
                    }
                    mirror::Object* dex_file = dex_file_field->GetObject(element);
                    if (dex_file != nullptr) {
                      //将mCookie转换为LongArray*类型
                      mirror::LongArray* long_array = cookie_field->GetObject(dex_file)->AsLongArray();
                      if (long_array == nullptr) {
                          break;
                      }
                      int32_t long_array_size = long_array->GetLength();
                      for (int32_t j = kDexFileIndexStart; j < long_array_size; ++j) {
                          //将LongArray转换为DexFile*类型
                          const DexFile* cp_dex_file = reinterpret_cast<const DexFile*>(static_cast<uintptr_t>(
                              long_array->GetWithoutChecks(j)));
                          //查找ClassDef
                          const DexFile::ClassDef* dex_class_def = cp_dex_file->FindClassDef(descriptor, hash);
                          if (dex_class_def != nullptr) {
                              //解析类,加载属性,方法
                              mirror::Class* klass = DefineClass(self,
                                                                 descriptor,
                                                                 hash,
                                                                 class_loader,
                                                                 *cp_dex_file,
                                                                 *dex_class_def);
                              if (klass == nullptr) {
                                self->ClearException();
                                return true;
                              }
                              *result = klass;
                              return true;
                          }
                      }
                  }
              }
          }
          self->AssertNoPendingException();
        }
    
        // Result is still null from the parent call, no need to set it again...
        return true;
    }
    

    FindClassInPathClassLoader主要逻辑是递归的在传入的ClassLoader的各级parent中依次查找类(典型的双亲委派模式) , 一般情况下,一个应用的PathClassLoader的parent层级为:`PathClassLoader(apk)-->PathClassLoader(system)->BootClassLoader`所以一般情况下,传入的ClassLoader的parent就是系统的PathClassLoader, 从而递归调用只会调用两次,即h_parent第一次等于PathClassLoader(system),第二次h_parent等于BootClassLoader. 在双亲中如果找到类,则直接返回,如果没有找到,则依次获取几个重要的变量BaseDexClassLoader.pathList, DexPathList.dexElement, DexFile.mCookie,根据这几个变量在传入的ClassLoader所加载的dex文件列表中查找类

    4. 总结

    一般而言,反射获取一个类时会调用Class.forName(String),获取类的过程可以总结为以下几步:

    1. 根据函数调用栈帧获取调用者的ClassLoader(如果调用的是Class.forName(String, boolean, ClassLoader),就没有根据栈帧获取ClassLoader这一步)
    2. 每一个ClassLoader都有一个ClassTable,用来缓存已经加载的类.如果传入的ClassLoader为null,就在BootClassLoader对应的boot_class_table_中查找,如果ClassLaoder不为null,就在ClassLoader对应的ClassTable中查找;如果找到Class,确保Class已经解析后,返回,否则进入下一步
    3. 如果没有在缓存的ClassTable中找到类,首先判断传入的ClassLoader是否为null,如果是,就在boot_class_path_中查找,如果不是,则递归的依次在传入的ClassLoader各级parent以及自身当中查找类(除了BootClassLoader,其余parent以及自身ClassLoader都必须是PathClassLoader,查找类主要是通过在Java层的几个重要变量完成:BaseDexClassLoader.pathList, DexPathList.dexElement, DexFile.mCookie),如果找到则返回(查找的过程中,如果找到了类,会完成对类的解析过程),如果没找到则再进入下一步
    4. 以上几步都没有找到的话,再调用传入的ClassLoader的loadClass进行最后一次查找(loadClass的过程中如果找到类,也会完成对类的解析),找到则返回,没找到则抛出异常

    相关文章

      网友评论

          本文标题:ART的反射调用(一)-获取Class对象

          本文链接:https://www.haomeiwen.com/subject/pstevttx.html