Android培訓班 68 dex文件打開流程
在上面的函數裏,提到使用dvmJarFileOpen函數找到classes.dex文件,並加載到內存裏,然後提供後面的函數使用。現在就來分析這個函數的代碼,如下:
intdvmJarFileOpen(const char* fileName, const char* odexOutputName,
JarFile** ppJarFile, bool isBootstrap)
{
在這裏提供四個參數,第一個參數fileName是輸入的Jar的文件名稱;第二個參數odexOutputName是進行優化後的Dex輸出文件;第三個參數ppJarFile是已經打開並緩存到內存裏的文件對象;第四個參數isBootstrap
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文件,讀取出來,並進行分析,然後拷貝到緩存裏,再返回給調用函數。
再分享一下我老師大神的人工智能教程吧。零基礎!通俗易懂!風趣幽默!還帶黃段子!希望你也加入到我們人工智能的隊伍中來!https://blog.csdn.net/jiangjunshow
Android培訓班 68 dex文件打開流程