/* * Open the specified file read-only. We memory-map the entire thing and * parse the contents. * * This will be called on non-Zip files, especially during VM startup, so * we don't want to be too noisy about certain types of failure. (Do * we want a "quiet" flag?) * * On success, we fill out the contents of "pArchive" and return 0. */ int dexZipOpenArchive(const char* fileName, ZipArchive* pArchive) { int fd, err; LOGV("Opening archive '%s' %p\n", fileName, pArchive); fd = open(fileName, O_RDONLY, 0); if (fd < 0) { err = errno ? errno : -1; LOGV("Unable to open '%s': %s\n", fileName, strerror(err)); return err; } return dexZipPrepArchive(fd, fileName, pArchive); }
/* * Open the specified file read-only. We examine the contents and verify * that it appears to be a valid zip file. * * This will be called on non-Zip files, especially during VM startup, so * we don't want to be too noisy about certain types of failure. (Do * we want a "quiet" flag?) * * On success, we fill out the contents of "pArchive" and return 0. On * failure we return the errno value. */ int dexZipOpenArchive(const char* fileName, ZipArchive* pArchive) { int fd, err; LOGV("Opening as zip '%s' %p\n", fileName, pArchive); memset(pArchive, 0, sizeof(ZipArchive)); fd = open(fileName, O_RDONLY /*| O_BINARY*/, 0); if (fd < 0) { err = errno ? errno : -1; LOGV("Unable to open '%s': %s\n", fileName, strerror(err)); return err; } return dexZipPrepArchive(fd, fileName, pArchive); }
/* * Extract "classes.dex" from zipFd into "cacheFd", leaving a little space * up front for the DEX optimization header. */ 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; long modWhen, crc32; off_t dexOffset; // 用于表示在Odex文件中,原Dex文件的起始地址 int err; int result = -1; int dexoptFlags = 0; /* bit flags, from enum DexoptFlags */ // 设置默认的优化模式 DexClassVerifyMode verifyMode = VERIFY_MODE_ALL; DexOptimizerMode dexOptMode = OPTIMIZE_MODE_VERIFIED; memset(&zippy, 0, sizeof(zippy)); /* make sure we're still at the start of an empty file */ if (lseek(cacheFd, 0, SEEK_END) != 0) { ALOGE("DexOptZ: new cache file '%s' is not empty", debugFileName); goto bail; } /* * Write a skeletal DEX optimization header. We want the classes.dex * to come just after it. */ err = dexOptCreateEmptyHeader(cacheFd); if (err != 0) goto bail; /* record the file position so we can get back here later */ // 取得Odex文件中原Dex文件的起始位置,实际就是一个Odex文件头部的长度 dexOffset = lseek(cacheFd, 0, SEEK_CUR); if (dexOffset < 0) goto bail; /* * Open the zip archive, find the DEX entry. */ if (dexZipPrepArchive(zipFd, debugFileName, &zippy) != 0) { ALOGW("DexOptZ: unable to open zip archive '%s'", debugFileName); goto bail; } // 获取目标Dex文件的解压入口 zipEntry = dexZipFindEntry(&zippy, kClassesDex); if (zipEntry == NULL) { ALOGW("DexOptZ: zip archive '%s' does not include %s", debugFileName, kClassesDex); goto bail; } /* * Extract some info about the zip entry. */ if (dexZipGetEntryInfo(&zippy, zipEntry, NULL, &uncompLen, NULL, NULL, &modWhen, &crc32) != 0) { ALOGW("DexOptZ: zip archive GetEntryInfo failed on %s", debugFileName); goto bail; } uncompLen = uncompLen; modWhen = modWhen; crc32 = crc32; /* * Extract the DEX data into the cache file at the current offset. * 从ZIP文件将目标Dex文件解压出来,并写入cacheFd所指文件,此时cacheFd所指文件非空, * 包括一个Odex文件头部加上一个原始的Dex文件 */ if (dexZipExtractEntryToFile(&zippy, zipEntry, cacheFd) != 0) { ALOGW("DexOptZ: extraction of %s from %s failed", kClassesDex, debugFileName); goto bail; } /* Parse the options. */ /* * 入口参数dexoptFlagStr,对验证优化需求进行分析,dexoptFlagStr实际上是一个字符串, * 记录了验证优化选项 */ 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; } } } /* * Prep the VM and perform the optimization. * 完成了原Dex文件的提取以及验证优化选项的设置,即可以开始真正的优化工作,需要 * 初始化一个虚拟机专门用于验证优化工作 */ if (dvmPrepForDexOpt(bootClassPath, dexOptMode, verifyMode, dexoptFlags) != 0) { ALOGE("DexOptZ: VM init failed"); goto bail; } //vmStarted = 1; /* do the optimization */ if (!dvmContinueOptimization(cacheFd, dexOffset, uncompLen, debugFileName, modWhen, crc32, isBootstrap)) { ALOGE("Optimization failed"); goto bail; } /* we don't shut the VM down -- process is about to exit */ result = 0; bail: dexZipCloseArchive(&zippy); return result; }