Android培训班(69)Dex文件里类定义

本文详细解析了Dex文件类加载流程,包括从Dex文件中读取类信息、解析类名称和代码索引、使用特定方法定义类并初始化类加载过程。通过理解这些步骤,可以更深入地掌握类加载机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当在虚拟机里加载Dex文件后,这个文件的数据已经读取到内存里,能不能马上使用呢?能不能使用里面的类呢?显然是不行的,因为那些加载到内存的数据,只是储存的格式,不具备运行的条件,因此需要调用方法defineClass来定义类,才可以运行在虚拟机里。所有Java编译后的类保存在Dex文件里,使用上面介绍的方法openDexFile打开Dex文件,接着需要调用方法defineClass来定义类,其实就是调用原生的函数Dalvik_dalvik_system_DexFile_defineClass, 类的加载流程如下:

1)方法openDexFile里通过dvmDexFileOpenFromFd函数调用dexFileParse函数,分析Dex文件里每个类名称和类的代码所在索引,然后dexFileParse调用函数dexParseOptData来把类名称写对象pDexFile->pClassLookup里面,当然也更新了索引。

2)Dalvik_dalvik_system_DexFile_defineClass函数调用dvmDefineClass函数。

3)dvmDefineClass函数调用findClassNoInit来进类的初始化。

4)findClassNoInit调用dexFindClass找到类名称在文件中位置。

5)findClassNoInit调用loadClassFromDex从文件加载。

6)loadClassFromDex调用dexGetClassData函数获取类的索引地址。

7)loadClassFromDex调用loadClassFromDex0获取类接口、类成员变量、类的方法,这样就完成类从Dex文件里加载。


下面来依次分析调用的函数代码,理解其中细节,以及相应的代码,以便更加深入,达到修改代码的水平,Dalvik_dalvik_system_DexFile_defineClass函数代码如下:

staticvoid Dalvik_dalvik_system_DexFile_defineClass(const u4* args,

JValue* pResult)

{

StringObject* nameObj = (StringObject*)args[0];

这行代码是获取输入需要加载的类对象。


Object* loader = (Object*) args[1];

这行代码是获取类加载器对象。


int cookie = args[2];

这行代码是获取打开的Dex文件对象。


Object* pd = (Object*) args[3];

这行代码是获取保护域权限。


ClassObject* clazz = NULL;

DexOrJar* pDexOrJar = (DexOrJar*) cookie;

这行代码转换为Dex文件对象。


DvmDex* pDvmDex;

char* name;

char* descriptor;


name = dvmCreateCstrFromString(nameObj);

descriptor = dvmDotToDescriptor(name);

LOGV("--- Explicit class load '%s'0x%08x\n", descriptor, cookie);

free(name);

这段代码是把类名称对象转换为C字符串,然后从C字符串转换为类描述符。



if (!validateCookie(cookie))

RETURN_VOID();

这段代码是检查是否合法的Dex文件对象。



if (pDexOrJar->isDex)

pDvmDex =dvmGetRawDexFileDex(pDexOrJar->pRawDexFile);

else

pDvmDex =dvmGetJarFileDex(pDexOrJar->pJarFile);

这段代码是获取Dex文件对象,以便从Dex文件里获取到类数据。



/* once we load something, we can't unmapthe storage */

pDexOrJar->okayToFree = false;


clazz = dvmDefineClass(pDvmDex, descriptor,loader);

这行代码是调用函数dvmDefineClass从指定的Dex文件里,使用指定的类加载器加载指定类名称的类。


Thread* self = dvmThreadSelf();

if (dvmCheckException(self)) {

/*

* If we threw a "class not found"exception, stifle it, since the

* contract in the higher method says wesimply return null if

* the class is not found.

*/

Object* excep = dvmGetException(self);

if (strcmp(excep->clazz->descriptor,

"Ljava/lang/ClassNotFoundException;")== 0 ||

strcmp(excep->clazz->descriptor,

"Ljava/lang/NoClassDefFoundError;")== 0)

{

dvmClearException(self);

}

clazz = NULL;

}

这段代码是检查是否加载类的过程有异常发生。


/*

* Set the ProtectionDomain -- do we needthis to happen before we

* link the class and make it available? Ifso, we need to pass it

* through dvmDefineClass (and figure outsome other

* stuff, like where it comes from forbootstrap classes).

*/

if (clazz != NULL) {

//LOGI("SETTING pd '%s' to %p\n",clazz->descriptor, pd);

dvmSetFieldObject((Object*) clazz,gDvm.offJavaLangClass_pd, pd);

}

这段代码是设置类的保护域。



free(descriptor);

RETURN_PTR(clazz);

这行代码返回已经加载的类代码。


}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值