图2 应用程序中的so文件保存目录
到了这里,我们知道了应用程序是如何安装的,安装后是如何存储的,那又是如何运行的呢?Dalvik虚拟机加载的是classes.dex文件,而APK文件是ZIP压缩格式,Dalvik虚拟机每次加载classes.dex文件,都要从APK文件中获取,这样会消耗很多CPU的时间,为了节省时间,应用程序安装后会在/data/dalvik-cache/目录下生成apk对应的优化文件,文件格式为odex,是classes.dex的优化后的文件。用户安装的保存在data/app目录下apk包名-1.apk程序对应的优化文件(odex格式),保存形式为data@app@apk包名-1.apk@classes.dex,这样应用程序再启动时就直接从/data/dalvik-cache目录下读取优化过的文件,节省时间,如图3所示:
图3 应用程序优化文件odex的保存目录
1. dex文件结构优化成odex文件结构
static const char* kClassesDex = "classes.dex";static int extractAndProcessZip(int zipFd, int cacheFd,const char* debugFileName, bool isBootstrap, const char* bootClassPath,const char* dexoptFlagStr){ ZipArchive zippy; /*描述zip压缩文件的数据结构 */ ZipEntry zipEntry; /*表示一个zip入口 */ size_t uncompLen; /* dex文件优化前的文件长度 */ long modWhen, crc32; /* dex优化前的时间戳和crc校验值 */ off_t dexOffset; /* dex文件的起始偏移 */ int err; int result = -1; int dexoptFlags = 0; /*优化标识符 */ DexClassVerifyMode verifyMode = VERIFY_MODE_ALL; DexOptimizerMode dexOptMode = OPTIMIZE_MODE_VERIFIED; memset(&zippy, 0, sizeof(zippy)); /*检测cacheFd文件是否为空文件,保证后期优化后的数据写在该文件中 */ if(lseek(cacheFd, 0, SEEK_END) != 0) { ALOGE("DexOptZ: new cache file '%s' is not empty", debugFileName); goto bail; } /*创建一个odex结构文件的头部 */ err = dexOptCreateEmptyHeader(cacheFd); if (err != 0) goto bail; /*取得odex文件中原dex文件的起始偏移,实际上是odex文件头部的长度,即开始+0x28字节 */ dexOffset = lseek(cacheFd, 0, SEEK_CUR); if(dexOffset < 0) goto bail; if(dexZipPrepArchive(zipFd, debugFileName, &zippy) != 0) { ALOGW("DexOptZ: unable to open zip archive '%s'", debugFileName); goto bail; }/*获取目标classes.dex文件的解压入口 */ zipEntry = dexZipFindEntry(&zippy, kClassesDex); if(zipEntry == NULL){ ALOGW("DexOptZ: zip archive '%s' does not include %s", debugFileName, kClassesDex); goto bail; } if(dexZipGetEntryInfo(&zippy, zipEntry, NULL, &uncompLen, NULL, NULL, &modWhen, &crc32) != 0) { ALOGW("DexOptZ: zip archive GetEntryInfo failed on %s", debugFileName); goto bail; } uncompLen = uncompLen; /*dex文件优化前的长度 */ modWhen = modWhen; /*dex文件优化前的时间戳 */ crc32 = crc32; /*dex文件优化前crc32值 */ /*将解压出的classes.dex文件写入odex文件,cacheFd指向odex文件,文件中已包含odex的头部信息 */ if (dexZipExtractEntryToFile(&zippy, zipEntry, cacheFd) != 0) { ALOGW("DexOptZ: extraction of %s from %s failed", kClassesDex, debugFileName); goto bail; } /*根据入口的参数,验证优化的需求 */ if (dexoptFlagStr[0] != '\0') { const char* opc; const char* val; /*设置验证模式 */ opc = strstr(dexoptFlagStr, "v="); /* verification */ if (opc != NULL) { switch (*(opc+2)) { case 'n': verifyMode = VERIFY_MODE_NONE; break; case 'r': verifyMode = VERIFY_MODE_REMOTE; break; case 'a': verifyMode = VERIFY_MODE_ALL; break; default: break; } } /*设置优化模式 */ opc = strstr(dexoptFlagStr, "o="); /* optimization */ if (opc != NULL) { switch (*(opc+2)) { case 'n': dexOptMode = OPTIMIZE_MODE_NONE; break; case 'v': dexOptMode = OPTIMIZE_MODE_VERIFIED; break; case 'a': dexOptMode = OPTIMIZE_MODE_ALL; break; case 'f': dexOptMode = OPTIMIZE_MODE_FULL; break; default: break; } } opc = strstr(dexoptFlagStr, "m=y"); /* register map */ if (opc != NULL) { dexoptFlags |= dexOPT_GEN_REGISTER_MAPS; } opc = strstr(dexoptFlagStr, "u="); /* uniprocessor target */ if (opc != NULL) { switch (*(opc+2)) { case 'y': dexoptFlags |= dexOPT_UNIPROCESSOR; break; case 'n': dexoptFlags |= dexOPT_SMP; break; default: break; } } } /*初始化虚拟机专用于优化工作 */ if (dvmPrepForDexOpt(bootClassPath, dexOptMode, verifyMode, dexoptFlags) != 0) { ALOGE("DexOptZ:VM init failed"); goto bail; } /*完成对dex文件的验证和优化 */ if(!dvmContinueOptimization(cacheFd, dexOffset, uncompLen, debugFileName,modWhen, crc32, isBootstrap)) { ALOGE("Optimization failed"); goto bail; } result = 0; /*成功 */bail: dexZipCloseArchive(&zippy);return result; }
/*fd:odex文件,包含了odex的头部信息和dex文件信息,dexOffset:dex文件的偏移地址,dexLength:dex文件的长度*/bool dvmContinueOptimization(int fd, off_t dexOffset, long dexLength, const char* fileName, u4 modWhen, u4 crc, bool isBootstrap){ /*dex类索引哈希表结构 */ DexClassLookup* pClassLookup = NULL; RegisterMapBuilder* pRegMapBuilder = NULL; assert(gDvm.optimizing); ALOGV("Continuing optimization (%s, isb=%d)", fileName, isBootstrap); assert(dexOffset >= 0); /*判断Odex头长度是否为0 */ /*校验dex文件,长度不能小于其文件头的长度 */ if(dexLength < (int)sizeof(DexHeader)){ ALOGE("too small to be dex"); return false; } /*校验dex文件的起始偏移量,不能小于odex文件头的长度 */ if (dexOffset < (int) sizeof(DexOptHeader)) { ALOGE("not enough room for opt header"); return false; } bool result = false; gDvm.optimizingBootstrapClass = isBootstrap; { bool success; void* mapAddr; /*内存映射起始位置 */ /*将fd所指的文件映射到某一位置,该位置的起始位置为mapAddr,大小为dexOffset + dexLength */ mapAddr = mmap(NULL, dexOffset + dexLength,PROT_READ|PROT_WRITE,MAP_SHARED, fd, 0); if (mapAddr == MAP_FAILED) { ALOGE("unable to mmap dex cache: %s", strerror(errno)); goto bail; } ... /*对dex文件进行验证、重写、字符调整、字节码替换等 */ success = rewriteDex(((u1*) mapAddr) + dexOffset, dexLength, doVerify, doOpt, &pClassLookup, NULL); if (success) { /*虚拟机解析的Dex文件结构指针 */ DvmDex* pDvmDex = NULL; u1* dexAddr = ((u1*) mapAddr) + dexOffset; /*调用此函数创建一个DexFile文件结构,dexAddr为dex文件的起始偏移,dexLength为dex文件的长度 */ if (dvmDexFileOpenPartial(dexAddr, dexLength, &pDvmDex) != 0) { ALOGE("Unable to create DexFile"); success = false; } else { if (gDvm.generateRegisterMaps) { /*生成映射池 */ pRegMapBuilder = dvmGenerateRegisterMaps(pDvmDex); if (pRegMapBuilder == NULL) { ALOGE("Failed generating register maps"); success = false; } } /*获取dex文件头部 */ DexHeader* pHeader = (DexHeader*)pDvmDex->pHeader; /*更新dex文件的crc32校验值 */ updateChecksum(dexAddr, dexLength, pHeader); dvmDexFileFree(pDvmDex); } } ... /*准备写入前,先进行8字节文件对齐处理 */ off_t depsOffset, optOffset, endOffset, adjOffset; int depsLength, optLength; u4 optChecksum; depsOffset=lseek(fd, 0, SEEK_END);/*获取当前fd所指文件的总长 */ if(depsOffset < 0){ ALOGE("lseek to EOF failed: %s", strerror(errno)); goto bail; } /*使depsOffset(dependency的起始地址 )8字节对齐,且adjOffset >= depsOffset */ adjOffset = (depsOffset + 7) & ~(0x07); if (adjOffset != depsOffset) { ALOGV("Adjusting deps start from %d to %d", (int) depsOffset, (int) adjOffset); depsOffset = adjOffset; /*odex文件依赖库列表偏移 */ lseek(fd, depsOffset, SEEK_SET); } /*写入依赖库信息,fd为Odex头+dex文件,modWhen为dex文件优化前时间戳,crc为dex文件优化前的crc32值 */ if (writeDependencies(fd, modWhen, crc) != 0) { ALOGW("Failed writing dependencies"); goto bail; } optOffset = lseek(fd, 0, SEEK_END); depsLength = optOffset - depsOffset; /*依赖库dependency总长度 */adjOffset = (optOffset + 7) & ~(0x07); if(adjOffset != optOffset){ ALOGV("Adjusting opt start from %d to %d", (int) optOffset, (int) adjOffset); optOffset = adjOffset; /*优化数据信息偏移量 */ lseek(fd, optOffset, SEEK_SET); } /*写入其他优化信息,包含类索引信息等 */ if (!writeOptData(fd, pClassLookup, pRegMapBuilder)) { ALOGW("Failed writing opt data"); goto bail; } endOffset = lseek(fd, 0, SEEK_END); optLength = endOffset - optOffset; /*优化数据的总长度 */ /*计算依赖库和优化数据总长的sum值 */ if (!computeFileChecksum(fd, depsOffset, (optOffset+optLength) - depsOffset, &optChecksum)) { goto bail; } /*重新修正odex文件的头部内容 */ DexOptHeader optHdr; memset(&optHdr, 0xff, sizeof(optHdr)); memcpy(optHdr.magic, dex_OPT_MAGIC, 4); /*odex版本标识 */ memcpy(optHdr.magic+4, dex_OPT_MAGIC_VERS, 4); optHdr.dexOffset = (u4)dexOffset; /*dex文件头偏移 */ optHdr.dexLength = (u4)dexLength; /*dex文件总长度 */ optHdr.depsOffset = (u4)depsOffset; /*依赖库列表偏移 */ optHdr.depsLength = (u4)depsLength; /*依赖库列表长度 */ optHdr.optOffset = (u4)optOffset; /*辅助数据偏移 */ optHdr.optLength = (u4)optLength; /*辅助数据总长度 */ #if __BYTE_ORDER != __LITTLE_ENDIAN optHdr.flags = dex_OPT_FLAG_BIG; /*标志 */ #else optHdr.flags = 0; #endif optHdr.checksum = optChecksum;/*依赖库与辅助数据的总和校验值 */ fsync(fd); lseek(fd, 0, SEEK_SET); if(sysWriteFully(fd, &optHdr, sizeof(optHdr), "DexOpt opt header") != 0) goto bail; ALOGV("Successfully wrote dex header"); result = true; /*成功 */ dvmRegisterMapDumpStats(); bail: dvmFreeRegisterMapBuilder(pRegMapBuilder); free(pClassLookup); return result;}