Android培训班(67)dex文件打开流程

时间:2021-12-07 19:39:12

从上面可知调用函数Dalvik_dalvik_system_DexFile_openDexFile来打开Dex文件,这个函数的源码如下:

staticvoid Dalvik_dalvik_system_DexFile_openDexFile(const u4* args,

JValue* pResult)

{

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

这行是输入的Jar或Dex文件名参数。


StringObject* outputNameObj =(StringObject*) args[1];

这行是输出的文件名参数。


int flags = args[2];

这行是处理的标示。


DexOrJar* pDexOrJar = NULL;

JarFile* pJarFile;

RawDexFile* pRawDexFile;

char* sourceName;

char* outputName;


if (sourceNameObj == NULL) {

dvmThrowException("Ljava/lang/NullPointerException;",NULL);

RETURN_VOID();

}

这段代码是当输入文件名称为空对象时,就抛出异常。



sourceName =dvmCreateCstrFromString(sourceNameObj);

这行代码调用函数dvmCreateCstrFromStringjava字符串转换C字符串,由于Java对象表示的字符串并不能立即就使用到C语言里,所以需要转换才能使用。


if (outputNameObj != NULL)

outputName =dvmCreateCstrFromString(outputNameObj);

else

outputName = NULL;

这段代码是同样把输出字符串转换C字符串。



/*

* We have to deal with the possibility thatsomebody might try to

* open one of our bootstrap class DEXfiles. The set of dependencies

* will be different, and hence the resultsof optimization might be

* different, which means we'd actually needto have two versions of

* the optimized DEX: one that only knowsabout part of the boot class

* path, and one that knows about everythingin it. The latter might

* optimize field/method accesses based on aclass that appeared later

* in the class path.

*

* We can't let the user-defined classloader open it and start using

* the classes, since the optimized form ofthe code skips some of

* the method and field resolution that wewould ordinarily do, and

* we'd have the wrong semantics.

*

* We have to reject attempts to manuallyopen a DEX file from the boot

* class path. The easiest way to do thisis by filename, which works

* out because variations in name (e.g."/system/framework/./ext.jar")

* result in us hitting a differentdalvik-cache entry. It's also fine

* if the caller specifies their own outputfile.

*/

if(dvmClassPathContains(gDvm.bootClassPath, sourceName)) {

LOGW("Refusing to reopen boot DEX'%s'\n", sourceName);

dvmThrowException("Ljava/io/IOException;",

"Re-opening BOOTCLASSPATH DEXfiles is not allowed");

free(sourceName);

RETURN_VOID();

}

这段代码是判断用户是否加载系统目录下面的Dex文件,如果加载就要拒绝这样的操作,因为系统启动时已经加载了一份这样的优化代码,没有必要再次加载一次。



/*

* Try to open it directly as a DEX. Ifthat fails, try it as a Zip

* with a "classes.dex" inside.

*/

if (dvmRawDexFileOpen(sourceName,outputName, &pRawDexFile, false) == 0) {

LOGV("Opening DEX file '%s'(DEX)\n", sourceName);


pDexOrJar = (DexOrJar*)malloc(sizeof(DexOrJar));

pDexOrJar->isDex = true;

pDexOrJar->pRawDexFile = pRawDexFile;

这段代码是尝试加载Dex文件,但基本不存在直接加Dex文件的情况,因此在函数dvmRawDexFileOpen还是空函数,没有实际的内容。



}else if (dvmJarFileOpen(sourceName, outputName, &pJarFile, false)== 0) {

LOGV("Opening DEX file '%s'(Jar)\n", sourceName);


pDexOrJar = (DexOrJar*)malloc(sizeof(DexOrJar));

pDexOrJar->isDex = false;

pDexOrJar->pJarFile = pJarFile;

这段代码是加载Jar文件,就是从这里加载Dex文件到缓存里。


}else {

LOGV("Unable to open DEX file'%s'\n", sourceName);

dvmThrowException("Ljava/io/IOException;","unable to open DEX file");

}



if (pDexOrJar != NULL) {

pDexOrJar->fileName = sourceName;

这行代码保存文件名称到Dex文件对象里。


/* add to hash table */

u4 hash = dvmComputeUtf8Hash(sourceName);

这行代码通过文件名称计算HASH串,加速对文件的查找速度。


void* result;

dvmHashTableLock(gDvm.userDexFiles);

result =dvmHashTableLookup(gDvm.userDexFiles, hash, pDexOrJar,

hashcmpDexOrJar, true);

dvmHashTableUnlock(gDvm.userDexFiles);

这段代码添加HASH表里,以便后面查找使用。


if (result != pDexOrJar) {

LOGE("Pointer has already beenadded?\n");

dvmAbort();

}


pDexOrJar->okayToFree = true;

}else

free(sourceName);


RETURN_PTR(pDexOrJar);

这行代码返回打开的文件对象。


}


这个函数是通过JAVA调用时输入Dex文件名称,然后加载Dex文件,最后把这个文件名称放到HASH表里,然后返回打开的对象。