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

在上面的函数里,提到使用dvmJarFileOpen函数找到classes.dex文件,并加载到内存里,然后提供后面的函数使用。现在就来分析这个函数的代码,如下:

intdvmJarFileOpen(const char* fileName, const char* odexOutputName,

JarFile** ppJarFile, bool isBootstrap)

{

在这里提供四个参数,第一个参数fileName是输入的Jar的文件名称;第二个参数odexOutputName是进行优化后的Dex输出文件;第三个参数ppJarFile是已经打开并缓存到内存里的文件对象;第四个参数isBootstrap是指示是否系统里Dex文件。


ZipArchive archive;

DvmDex* pDvmDex = NULL;

char* cachedName = NULL;

bool archiveOpen = false;

bool locked = false;

int fd = -1;

int result = -1;


/* Even if we're not going to look at thearchive, we need to

* open it so we can stuff it intoppJarFile.

*/

if (dexZipOpenArchive(fileName, &archive)!= 0)

goto bail;

archiveOpen = true;

这段代码是调用前面介绍的函数dexZipOpenArchive来打开Zip文件,并缓存到系统内存里。



/* If we fork/exec into dexopt, don't letit inherit the archive's fd.

*/

dvmSetCloseOnExec(dexZipGetArchiveFd(&archive));

这行代码设置当执行完成后,关闭这个文件句柄。


/* First, look for a ".odex"alongside the jar file. It will

* have the same name/path except for theextension.

*/

fd = openAlternateSuffix(fileName, "odex",O_RDONLY, &cachedName);

if (fd >= 0) {

这里优先处理优化的Dex文件。


LOGV("Using alternate file (odex)for %s ...\n", fileName);

if (!dvmCheckOptHeaderAndDependencies(fd,false, 0, 0, true, true)) {

LOGE("%s odex has staledependencies\n", fileName);

free(cachedName);

close(fd);

fd = -1;

goto tryArchive;

} else {

LOGV("%s odex has gooddependencies\n", fileName);

//TODO: make sure that the .odexactually corresponds

// to the classes.dex inside thearchive (if present).

// For typical use there will beno classes.dex.

}

}else {

ZipEntry entry;


tryArchive:

/*

* Pre-created .odex absent or stale. Look inside the jar for a

* "classes.dex".

*/

entry = dexZipFindEntry(&archive,kDexInJarName);

这行代码是从压缩包里找到Dex文件,然后打开这个文件。


if (entry != NULL) {

bool newFile = false;


/*

* We've found the one we want. Seeif there's an up-to-date copy

* in the cache.

*

* On return, "fd" will beseeked just past the "opt" header.

*

* If a stale .odex file is presentand classes.dex exists in

* the archive, this will *not*return an fd pointing to the

* .odex file; the fd will point intodalvik-cache like any

* other jar.

*/

if (odexOutputName == NULL) {

cachedName =dexOptGenerateCacheFileName(fileName,

kDexInJarName);

if (cachedName == NULL)

goto bail;

这段代码是把Dex文件进行优化处理,并输出到指定的文件。


} else {

cachedName =strdup(odexOutputName);

}

LOGV("dvmDexCacheStatus:Checking cache for %s (%s)\n",

fileName, cachedName);

fd = dvmOpenCachedDexFile(fileName,cachedName,

dexGetZipEntryModTime(&archive,entry),

dexGetZipEntryCrc32(&archive,entry),

isBootstrap, &newFile,/*createIfMissing=*/true);

这段代码创建缓存的优化文件。


if (fd < 0) {

LOGI("Unable to open orcreate cache for %s (%s)\n",

fileName, cachedName);

goto bail;

}

locked = true;


/*

* If fd points to a new file(because there was no cached version,

* or the cached version was stale),generate the optimized DEX.

* The file descriptor returned isstill locked, and is positioned

* just past the optimization header.

*/

if (newFile) {

u8 startWhen, extractWhen,endWhen;

bool result;

off_t dexOffset, fileLen;


dexOffset = lseek(fd, 0,SEEK_CUR);

result = (dexOffset > 0);


if (result) {

startWhen =dvmGetRelativeTimeUsec();

result =dexZipExtractEntryToFile(&archive, entry, fd);

extractWhen =dvmGetRelativeTimeUsec();

这段代码调用函数dexZipExtractEntryToFile从压缩包里解压文件出来。


}

if (result) {

result =dvmOptimizeDexFile(fd, dexOffset,

dexGetZipEntryUncompLen(&archive,entry),

fileName,

dexGetZipEntryModTime(&archive,entry),

dexGetZipEntryCrc32(&archive,entry),

isBootstrap);

这段代码调用函数dvmOptimizeDexFile对Dex文件进行优化处理。


}


if (!result) {

LOGE("Unable toextract+optimize DEX from '%s'\n",

fileName);

goto bail;

}


endWhen =dvmGetRelativeTimeUsec();

LOGD("DEX prep '%s': unzipin %dms, rewrite %dms\n",

fileName,

(int) (extractWhen -startWhen) / 1000,

(int) (endWhen - extractWhen)/ 1000);

}

} else {

LOGI("Zip is good, but no %sinside, and no valid .odex "

"file in the samedirectory\n", kDexInJarName);

goto bail;

}

}


/*

* Map the cached version. This immediatelyrewinds the fd, so it

* doesn't have to be seeked anywhere inparticular.

*/

if (dvmDexFileOpenFromFd(fd, &pDvmDex)!= 0) {

LOGI("Unable to map %s in %s\n",kDexInJarName, fileName);

goto bail;

}

这段代码是调用函数dvmDexFileOpenFromFd来缓存Dex文件,并分析文件的内容。比如标记是否优化的文件,通过签名检查Dex文件是否合法。



if (locked) {

/* unlock the fd */

if (!dvmUnlockCachedDexFile(fd)) {

/* uh oh -- this process needs toexit or we'll wedge the system */

LOGE("Unable to unlock DEXfile\n");

goto bail;

}

locked = false;

}

这段代码是保存文件到缓存里,标记这个文件句柄已经保存到缓存。



LOGV("Successfully opened '%s' in'%s'\n", kDexInJarName, fileName);


*ppJarFile = (JarFile*) calloc(1,sizeof(JarFile));

(*ppJarFile)->archive = archive;

(*ppJarFile)->cacheFileName =cachedName;

(*ppJarFile)->pDvmDex = pDvmDex;

cachedName = NULL; // don't free itbelow

result = 0;

这段代码已经成功打开压缩包,并读取Dex文件到内存缓存,这里只是设置一些相关信息返回前面的函数处理。


bail:

/* clean up, closing the open file */

if (archiveOpen && result != 0)

dexZipCloseArchive(&archive);

free(cachedName);

if (fd >= 0) {

if (locked)

(void) dvmUnlockCachedDexFile(fd);

close(fd);

}

return result;

}


本函数主要流程是打开压缩文件,然后找到Dex文件,读取出来,并进行分析,然后拷贝到缓存里,再返回给调用函数。

你可能感兴趣的:(android)