反射支撑

以下讨论的都是Dalvik虚拟机,以 Android4.0.4 为基础


关于动态代理参见Dalvik 动态代理的实现

以无参构造为例

//@Class.java
public Constructor getConstructor(Class... parameterTypes) throws NoSuchMethodException {
  return (Constructor) getConstructorOrMethod("", false, true, parameterTypes);
}

/**
*  Returns a constructor or method with the specified name.
*
*  @params name the method name, or "" to return a constructor.
*  @param recursive true to search supertypes;
*/
private Member getConstructorOrMethod(String name, boolean recursive, boolean publicOnly, Class[] parameterTypes) throws NoSuchMethodException {
  ...
  Member result = recursive ? getPublicConstructorOrMethodRecursive(name, parameterTypes)
        : Class.getDeclaredConstructorOrMethod(this, name, parameterTypes);
  ...
}

从上面的说明可以看出来,在 4.0.4下,构造函数是视为函数名为""的特殊的函数。其反射获取和普通函数一样,传入函数名("")和参数类型(Class[ ] parameterTypes);同时 recursive 表示递归查询父类,在此处为 false,因此最终调用者为

static native Member getDeclaredConstructorOrMethod(Class clazz, String name, Class[ ] args);

接着来到 ./dalvik/vm/native/java_lang_Class.cpp 进入 native 层。

static void Dalvik_java_Class_getDeclaredConstructorOrMethod(const u4* args, JValue* pResult){
  ClassObject* clazz = (ClassObject*) args[0];
  StringObject* nameObject = (StringObject*) args[1];
  ArrayObject* methodArgs = (ArrayObject*) args[2];
  
  Object* methodObject;
  methodObject = dvmGetDeclaredConstructorOrMethod(clazz, nameObject, methodArgs);
  dvmReleaseTrackedAlloc(methodObj, NULL);
  
  RETURN_PTR(methodObj);
}

于是寻找目标方法的任务就转交给了 dvmGetDeclaredConstructorOrMethod( ) @Reflect.cpp

//./dalvik/vm/reflect/Reflect.cpp
Object* dvmGetDeclaredConstructorOrMethod(ClassObject* clazz, StringObject* nameObj, ArrayObject* args){
  Object* result = NULL;
  DexStringCache targetDescriptorCache;
  char* name;
  const char* targetDescriptor; 
  dexStringCacheInit(&targetDecriptorCache);
  
  name = dvmCreateCstrFromString(nameObj);
  createTargetDescriptor(args, &targetDescriptorCache);
  targetDescriptor = targetDescriptorCache.value;
  
  result = findConstructorOrMethodInArray(clazz->directMethodCount, clazz->directMethods, name, targetDescriptor);
  if(result == NULL){
    result = findConstructorOrMethodInArray(clazz->virtualMethodCount, clazz->virtualMethods, name, targetDescriptor);
  }
}

很明显,在寻找目标方法的过程中,优先从 directMethod 中寻找,其次再考虑从 virtualMethods中寻找

static Object* findConstructorOrMethodInArrag(int methodsCount, Method* methods, const char* name, const char* parameterDescriptors){
  Method* method = NULL; 
  Method* result = NULL;
  int i;
  for(i = 0; i < methodsCount; i++){
    method = &methods[i];
    if(strcmp(name, method->name) != 0
        || dvmIsMirandaMethod(method)
        || dexProtoCpmpareToParameterDesriptors(&method->prototype, parameterDescriptors) != 0) {
      continue;
    }
    result = method;

    if(!dvmIsSyntheticMethod(method){
      break;
    }
  }
  if(result != NULL){
    return dvmCreateReflectObjForMethod(result->clazz, result);
  }
  return NULL;
}

在从 directMethods 和 virtualMethods 中寻找目标方法的过程中,先判断方法名,判断是否是 Miranda 方法,然后再判断参数是否一致。
可以看到整个方法反射解析的过程依赖于对于 Dex 中类的解析为 ClassObject 的过程。另外,虽然父类的一些方法被定为 virtual 方法是可以被子类继承的,但是如果子类没有显式得重写,那么改方法便不会进入子类的 ClassRef 的 virtualMethods 中,于是用子类去 getDeclaredMethod(String methodName)是找不到这个方法的。只能用父类去查找。一旦子类重写了,那么该方法便会进入子类的 virtualMethods 表中。
那为什么子类可以显式调用父类的这个方法呢,反编译后可以发现该方法的code的操作码是invoke-virtual。在 Android 4.0.4下的 Dalvik 的protable 解释器下,invoke-virtual下的 method 寻找有以下路径;

0. @ InterpC-portable.cpp 下的 invokevirtual 的解释
1.dvmDexGetResolvedMethod(methodClassDex, ref)@DvmDex.h, 如果找不到 则进入 2.
2.dvmResolveMethod(curMethod->clazz, ref, METHOD_VIRTUAL)@Resolve.cpp;
3.由于参数是 METHOD_VIRTUAL,于是 dvmFindVirtualMethodHier(resClass, name,&proto)@Object.cpp
4. findMethodInListByDescriptor(clazz, true, true, methodName, descriptor)@Object.cpp
5.根据传进入的参数,会依次向上遍历父类,直到找到该 virtual 为止

可以看到,在反射寻找virtual方法和 invoke-virtual 的不同,前者只会在该 ClassRef 的 virtualMethods 中寻找,后者会向上遍历父类去寻找。


字段的寻找

//@Class.java
public Field getDeclaredField(String name) throws NoSuchFieldException{
  ...
  Field result = getDeclaredField(this, name);
  ...
  return result;
}

//@java_lang_Class.cpp
static void Dalvik_java_lang_Class_getDeclaredField(const u4* args, JValue* pResult){
  ClassObject* clazz = (ClassObject*) args[0];
  StringObject* nameObj = (StringObject*) args[1];
  Object* fieldObject = dvmGetDeclaredField(clazz, nameObject);
  dvmReleaseTrackedAlloc((Object*) fieldObject, NULL);
  RETURN_PTR(fieldObj);
}

//@Reflect.cpp
Object* dvmGetDeclaredField(ClassObject* clazz, StringObject* nameObj){
  int i;
  Object* fieldObj = NULL;
  char* name = dvmCreateCstrFromString(nameObj);
  
  if(!dvmIsClassInitialized(gDvm.classJavaLangReflectField))
    dvmInitClass(gDvm.classJavaLangReflectField);

  for(i = 0; i < class.sfieldCount; i++){
    Field* field = &clazz->sfields[i];
    if(strcmp(name, field->name) == 0){
      fieldObj =createFieldObject(field, clazz);
      break;
    }
  }

  if(fieldObj == NULL){
    for(i = 0; i< clazz->ifieldCount; i++){
      Field* field = &clazz->ifields[i];
      if(strcmp(name, field->name) ==0){
        fieldObj = createFieldObject(field, clazz);
        break;
      }
    }
  }
}
free(name);
 return fieldObj;

在 classObject 中会优先从 static 的字段寻找,再去寻找成员字段。
同时也说明了getDeclaredField( )会从改类的所有字段去匹配。


我们知道getField( )只会去匹配目标类及其父类的 public 字段,来看下实现原理

//@Class.java
public Field getField(String name) throws NoSuchFieldException {
        if (name == null) {
            throw new NullPointerException("name == null");
        }
        Field result = getPublicFieldRecursive(name);
        if (result == null) {
            throw new NoSuchFieldException(name);
        }
        return result;
    }

    private Field getPublicFieldRecursive(String name) {
        // search superclasses
        for (Class c = this; c != null; c = c.getSuperclass()) {
            Field result = Class.getDeclaredField(c, name);
            if (result != null && (result.getModifiers() & Modifier.PUBLIC) != 0) {
                return result;
            }
        }

        // search implemented interfaces
        for (Class c = this; c != null; c = c.getSuperclass()) {
            for (Class ifc : c.getInterfaces()) {
                Field result = ifc.getPublicFieldRecursive(name);
                if (result != null && (result.getModifiers() & Modifier.PUBLIC) != 0) {
                    return result;
                }
            }
        }

        return null;
    }

从源码也可以看出,会依次从本类在父类循环遍历寻找 public 的字段,如果没有的话就循环遍历本类及其父类的实现接口。
于是优先顺序 本类字段->父类字段->父类的父类字段->...->本类实现接口->父类实现接口->父类的父类实现接口->...(均为 public 描述)


同理,在获取方法的时候都会调用到

private Member getConstructorOrMethod(String name, boolean recursive,
            boolean publicOnly, Class[ ] parameterTypes);

关键参数有 boolean recursive, boolean publicOnly;

  • 对于 getDeclaredMethod( ) ,recursive = false, publicOnly = false, 说明该方法在指定 class 所有方法寻找,而不遍历父类。

  • 对于 getMethod( ), recursive = true, publicOnly = true, 说明该方法会向上遍历父类并且只匹配 public 方法。

  • 对于 getConstructor( ), recursive = false, publicOnly = true.


  • 关于 invoke( )@Method;
//@Method.java
public Object invoke(Object receiver, Object... args){
  if(args == null){
    args = EmptyArrag.OBJECT;
  }
  return invokeNative(receiver, args, declaringClass, parameterTypes, returnType, slot, flag);
}

private native Object invokeNative(Object obj, Object[ ] args, Class declaringClass, Class paramterTypes, Class returnType, int slot, boolean noAccessCheck);

先来看参数:

  • Object obj : 调用改方法的对象,如果是 static 则为 Null
  • Object[ ] args : 具体的参数
  • Class declaringClass : 方法所属的类
  • Class[ ] parameterTypes : 参数列表
  • Class returnType : 对象
  • int slot : 方法在类方法表中的序号
  • boolean noAccessCheck : 是否检查权限(true 表示不检查)

其中的Object obj, Object[ ] args 是由外部传入的方法参数; Class declaringClass, Class[ ] parameterTypes, Class returnType, int slot 是在 native 层创建 Method 对象的时候确定下来的; 而 boolean noAccessCheck 默认是 false,即默认检查,在检查的情况下,比如方法的 private 就不允许 invoke,抛异常。
现在来看 native 层确定下来的参数。

//Reflect.cpp
Object* dvmCreateReflectMethodObject(const Method* meth){
  Object* result = NULL;
  ArrayObject* params = NULL;
  ArrayObject* exceptions = NULL;
  StringObject* exceptions = NULL;
  StringObject* nameObj = NULL;
  Object* methObj;
  ClassObject* returnType;
  DexStringCache mangle;
  char* cp;
  int slot;
  
  dexStringCacheInit(&mangle);

  methodObj = dvmAllocObject(gDvm.classJavaLangReflectMethod);

  cp = dvmCopyDescriptorStringFromMethod(meth, &mangle);
  params = convertSignatureToClassArray(&cp, meth->clazz);
  
  cp++;
  returnType = convertSignaturePartToClass(&cp, meth->clazz);

  exceptions = dvmGetMethodThrows(meth);

  nameObj = dvmCreateStringFromCstr(meth->name);

  slot = methodToSlot(meth);

  JValue unused;
  dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectMethod_init, methObj, &unused, meth->clazz, params, exceptions, returnType, nameObj, slot);

  result = methObj;
}

我们来看 gDvm.methJavaLangReflectMethod_init,在 ./dalvik/vm/InitRefs.cpp中定义

static bool initConstructorReferences() {
    static struct { Method** method; const char* name; const char* descriptor; } constructors[] = {
        { &gDvm.methJavaLangStackTraceElement_init, "Ljava/lang/StackTraceElement;",
          "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V" },
        { &gDvm.methJavaLangReflectConstructor_init, "Ljava/lang/reflect/Constructor;",
          "(Ljava/lang/Class;[Ljava/lang/Class;[Ljava/lang/Class;I)V" },
        { &gDvm.methJavaLangReflectField_init, "Ljava/lang/reflect/Field;",
          "(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;I)V" },
        { &gDvm.methJavaLangReflectMethod_init, "Ljava/lang/reflect/Method;",
          "(Ljava/lang/Class;[Ljava/lang/Class;[Ljava/lang/Class;Ljava/lang/Class;"
          "Ljava/lang/String;I)V" },
        { &gDvm.methJavaNioReadWriteDirectByteBuffer_init, "Ljava/nio/ReadWriteDirectByteBuffer;",
          "(II)V" },
        { &gDvm.methOrgApacheHarmonyLangAnnotationAnnotationMember_init,
          "Lorg/apache/harmony/lang/annotation/AnnotationMember;",
          "(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/reflect/Method;)V" },
        { NULL, NULL, NULL }
    };

    int i;
    for (i = 0; constructors[i].method != NULL; i++) {
        if (!initDirectMethodReference(constructors[i].method, constructors[i].name,
                "", constructors[i].descriptor)) {
            return false;
        }
    }

    return true;
}

可见gDvm.methJavaLangReflectMethod_init映射到了 Java 层 Method.java 中的构造方法。

 private Method(Class declaring, Class[] paramTypes, Class[] exceptTypes, Class returnType, String name, int slot)
    {
        this.declaringClass = declaring;
        this.name = name;
        this.slot = slot;
        this.parameterTypes = paramTypes;
        this.exceptionTypes = exceptTypes;      // may be null
        this.returnType = returnType;
    }

于是利用在 native 从 ClassObject 获得方法的核心参数,然后利用 JNI 构造出一个 Java 层的 Method 对象,传递到 Java 层。
以 slot 为例,

/*
 * Convert a method pointer to a slot number.
 *
 * We use positive values starting from 0 for virtual methods, negative
 * values starting from -1 for static methods.
 */
static int methodToSlot(const Method* meth){
  ClassObject* clazz = meth>clazz;
  int slot;
  
  if(dvmIsDriectMethod(meth)){
    slot = meth - clazz->directMethods;
    slot = -(slot+1);
  }else {
    slot = meth - clazz->virtualMethods;
  }
  return slot;
}

知道了 Method 中的参数来由,接下来就要看 invokeNative 的正身了。

static void Dalvik_java_lang_reflect_Method_invokeNative(const u4* args,
    JValue* pResult)
{
    // ignore thisPtr in args[0]
    Object* methObj = (Object*) args[1];        // null for static methods
    ArrayObject* argList = (ArrayObject*) args[2];
    ClassObject* declaringClass = (ClassObject*) args[3];
    ArrayObject* params = (ArrayObject*) args[4];
    ClassObject* returnType = (ClassObject*) args[5];
    int slot = args[6];
    bool noAccessCheck = (args[7] != 0);
    const Method* meth;
    Object* result;

    /*
     * "If the underlying method is static, the class that declared the
     * method is initialized if it has not already been initialized."
     */
    meth = dvmSlotToMethod(declaringClass, slot);
    assert(meth != NULL);

    if (dvmIsStaticMethod(meth)) {
        if (!dvmIsClassInitialized(declaringClass)) {
            if (!dvmInitClass(declaringClass))
                goto init_failed;
        }
    } else {
        /* looks like interfaces need this too? */
        if (dvmIsInterfaceClass(declaringClass) &&
            !dvmIsClassInitialized(declaringClass))
        {
            if (!dvmInitClass(declaringClass))
                goto init_failed;
        }

        /* make sure the object is an instance of the expected class */
        if (!dvmVerifyObjectInClass(methObj, declaringClass)) {
            assert(dvmCheckException(dvmThreadSelf()));
            RETURN_VOID();
        }

        /* do the virtual table lookup for the method */
        meth = dvmGetVirtualizedMethod(methObj->clazz, meth);
        if (meth == NULL) {
            assert(dvmCheckException(dvmThreadSelf()));
            RETURN_VOID();
        }
    }

    /*
     * If the method has a return value, "result" will be an object or
     * a boxed primitive.
     */
    result = dvmInvokeMethod(methObj, meth, argList, params, returnType,
                noAccessCheck);

    RETURN_PTR(result);de

init_failed:
    /*
     * If initialization failed, an exception will be raised.
     */
    LOGD("Method.invoke() on bad class %s failed",
        declaringClass->descriptor);
    assert(dvmCheckException(dvmThreadSelf()));
    RETURN_VOID();
}

没什么说的,就是将由 JNI 传来的参数转为 native 层的对象,然后利用 slot 寻找到 method,随后调用dvmInvokeMethod( )@Stack.cpp,然后根据是否是 native 方法,选择直接执行还是利用对应的解释器执行。


那么现在来看 Field 的set( ) 和 get( );
同理,我们先看createFieldObject( ) @Reflect.cpp

static Object* createFieldObject(Field* field, const ClassObject* clazz){
  Object* result = NULL;
  Object* fieldObj = NULL;
  StringObject* nameObj = NULL;
  ClassObject* type;
  char* mangle;
  char* cp;
  int slot;

  fieldObj = dvmAllocObject(gDvm.classJavaLangReflectField, ALLOC_DEFAULT);
  
  cp = mangle = strdup(field->signature);
  type = convertSignaturePartToClass(&cp, clazz);
  
  nameObj = dvmCreateStringFromCstr(field->name);
  
  slot = fieldToSlot(field, clazz);

 JValue unused;
 dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectField_init, fieldObj, &unused, clazz, type, nameObj, slot);

  result  fieldObj;
}

从 Method 的创建可以想到,Field 的创建也是相同的形式。当然继续跟踪也证明了这件事情。


接下里看 Field 的 set

//Field.java
public void set(Object object, Object value) throws IllegalAccessException, IllegalArgumentException{
  setField(object, declaringClass, type, slot, flag, value);

private native void setField(Object p, Class declaringClass, Class type, int slot, boolean noAccessCheck, Object value) throws IllegalAccessException;
}

//java_lang_reflect_Field.cpp

static void Dalvik_java_lang_reflect_Field_setField(const u4 args, JValue* pResult){
  Object* obj = (Object*) args[1];
  ClassObject* declaringClass = (ClassObject*) agrs[2];
  ClassObject* fieldType = (ClassObject*) args[3];
  int slot = args[4];
  boolean noAccessCheck = (args[5] != 0);
  Object* valueObj = (Object*) args[6];  
  Field* field;
  JValue value;

  field = validateFieldAccess(obj, declaringClass, slot, true, noAccessCheck);

  setFieldValue(field, obj, &value);
  
  RETURN_VOID();
}

static void setFieldValue(Field* field, Object* obj, const JValue* value){
  if(dvmIsStaticField(field){
    //可以看到,如果是 static field,那么 obj 传神马都是无关紧要的,因为会被忽略
    return setStaticFieldValue((StaticField*) field, value);
  }else{
    return setInstFieldValue((InstField*) field, obj, value);
  }
}  

static void setInstFieldValue(InstField* ifield, Object* obj, const JValue* value){
  // 可以看到,field 是否是 volatile 也会影响不同
  if(!dvmIsVolatileField(ifield)){
    switch(ifield->signature[0]){
      case 'Z':
        dvmSetFieldBoolean(obj, ifield->byteOffset, value->z);
        break;    
      ...
      case 'L':
      case '[':
        dvmSetFieldObject(obj, ifield->byteOffset, (Object*) value->l);
        break;
    }
  }else{
 switch(ifield->signature[0]){
      case 'Z':
        dvmSetFieldBooleanVilatile(obj, ifield->byteOffset, value->z);
        break;    
      ...
      case 'L':
      case '[':
        dvmSetFieldObjectVolatile(obj, ifield->byteOffset, (Object*) value->l);
        break;
    }
  }
}

我们只看非 volatile 的 field 的保存

//ObjectInlines.h
INLINE void dvmSetFieldObject(Object* obj, int offset, Object* val){
  JValue& lhs = (JValue*)BYTE_OFFSET(obj, offset);
  lhs->l = val;
  dvmWriteBarrierField(obj, &lhs->l);
}

//WriteBarrier.h
INLINE void dvmWriteBarrierField(const Object *obj, void *addr){
  dvmMarkCard(obj);
}

现在谈谈动态代理。稍微了解的一点的人都知道动态代理是虚拟机为你创建了 Proxy的内部类,并且实现了你传入的接口,同时使用了传入的 classLoader;后面越研究越发现动态代理的诡异。还是特地开一篇好了。

你可能感兴趣的:(反射支撑)