以下讨论的都是Dalvik虚拟机,以 Android4.0.4 为基础
关于动态代理参见Dalvik 动态代理的实现
以无参构造为例
//@Class.java
public Constructor<T> getConstructor(Class<?>... parameterTypes) throws NoSuchMethodException {
return (Constructor) getConstructorOrMethod("<init>", false, true, parameterTypes);
}
/**
* Returns a constructor or method with the specified name.
*
* @params name the method name, or "<init>" 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下,构造函数是视为函数名为"<init>"的特殊的函数。其反射获取和普通函数一样,传入函数名("<init>")和参数类型(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,
"<init>", 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;后面越研究越发现动态代理的诡异。还是特地开一篇好了。
网友评论