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

典型的反射调用形式为:

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(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 class_loader(hs.NewHandle(soa.Decode(javaLoader)));
    ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
    //核心调用,调用ClassLinker::FindClass()
    Handle c(
        hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor.c_str(), class_loader)));
    if (c.Get() == nullptr) {
        ScopedLocalRef cause(env, env->ExceptionOccurred());
        env->ExceptionClear();
        jthrowable cnfe = reinterpret_cast(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(c.Get());
}

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

3. ClassLinker::FindClass

mirror::Class* ClassLinker::FindClass(Thread* self,
                                      const char* descriptor,
                                      Handle 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(),
                           *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 class_loader_object(soa.Env(),
                                                    soa.AddLocalReference(class_loader.Get()));
        std::string class_name_string(DescriptorToDot(descriptor));

        ScopedLocalRef result(soa.Env(), nullptr);
        {
            ScopedThreadStateChange tsc(self, kNative);
            ScopedLocalRef 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(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 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(),
                                    *pair.first,
                                    *pair.second);
            }
            if (*result == nullptr) {
              self->ClearException();
            }
        } else {
            *result = nullptr;
        }
        return true;
    }
    //递归调用的终止条件
    //确保传入的ClassLoader必须是PathClassLoader
    if (class_loader->GetClass() != soa.Decode(
                        WellKnownClasses::dalvik_system_PathClassLoader)) {
      *result = nullptr;
      return false;
    }

    // Handles as RegisterDexFile may allocate dex caches (and cause thread suspension).
    StackHandleScope<4> hs(self);
    Handle 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> dex_elements =
                hs.NewHandle(dex_elements_obj->AsObjectArray());
            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(static_cast(
                          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对象)