接着下来,来分析怎么样加载方法的代码,loadMethodFromDex函数的代码如下:
staticvoidloadMethodFromDex(ClassObject*clazz, const DexMethod*pDexMethod,
Method*meth)
{
这个函数传入三个参数,第一个参数clazz是类相关信息;第二个参数pDexMethod是要加载的方法相关信息;第三个参数meth是指向加载的方法,也就是可以运行的代码。
DexFile*pDexFile = clazz->pDvmDex->pDexFile;
这行代码是获取Dex文件。
constDexMethodId*pMethodId;
constDexCode*pDexCode;
pMethodId =dexGetMethodId(pDexFile, pDexMethod->methodIdx);
这行代码是从Dex文件里通过索引获取到方法的ID。
meth->name= dexStringById(pDexFile, pMethodId->nameIdx);
这行代码是获取方法的名称。
dexProtoSetFromMethodId(&meth->prototype,pDexFile, pMethodId);
meth->shorty= dexProtoGetShorty(&meth->prototype);
meth->accessFlags= pDexMethod->accessFlags;
meth->clazz= clazz;
meth->jniArgInfo= 0;
这段代码是设置方法的属性。
if(dvmCompareNameDescriptorAndMethod("finalize","()V",meth) == 0) {
SET_CLASS_FLAG(clazz,CLASS_ISFINALIZABLE);
}
这段代码是判断是否最后退出函数,如果是退出函数就设置标志。
pDexCode =dexGetCode(pDexFile, pDexMethod);
这行代码是获取方法执行代码,如果是本地方法或者抽像函数返回空。
if(pDexCode != NULL) {
/*integer constants, copy over for faster access */
meth->registersSize= pDexCode->registersSize;
meth->insSize= pDexCode->insSize;
meth->outsSize= pDexCode->outsSize;
/*pointer to code area */
meth->insns= pDexCode->insns;
这段代码是从Dex文件里获取到方法的代码,保存相应的方法结构里,以便后面使用。
} else{
/*
* We don't have a DexCodeblock, but we still want to know how
* much space is neededfor the arguments (so we don't have to
* compute it later). Wealso take this opportunity to compute
* JNI argument info.
*
* We do this for abstractmethods as well, because we want to
* be able to substituteour exception-throwing "stub" in.
*/
intargsSize = dvmComputeMethodArgsSize(meth);
这行代码是计算方法参数大小。
if(!dvmIsStaticMethod(meth))
argsSize++;
这段代码是静态方法需要增加参数。
meth->registersSize= meth->insSize= argsSize;
assert(meth->outsSize== 0);
assert(meth->insns== NULL);
if(dvmIsNativeMethod(meth)) {
meth->nativeFunc= dvmResolveNativeMethod;
meth->jniArgInfo= computeJniArgInfo(&meth->prototype);
}
这段代码是处理本地方法的调用。
}
}
到这里,就可以把每个方法的代码解释出来,获取到方法所有的相关信息,这样就可以备运行条件了。