/* * Uncompress an entry, in its entirety, to an open file descriptor. * * TODO: this doesn't verify the data's CRC, but probably should (especially * for uncompressed data). */ bool dexZipExtractEntryToFile(const ZipArchive* pArchive, const ZipEntry entry, int fd) { bool result = false; int ent = entryToIndex(pArchive, entry); if (ent < 0) return -1; const unsigned char* basePtr = (const unsigned char*)pArchive->mMap.addr; int method; long uncompLen, compLen; off_t offset; if (!dexZipGetEntryInfo(pArchive, entry, &method, &uncompLen, &compLen, &offset, NULL, NULL)) { goto bail; } if (method == kCompressStored) { ssize_t actual; actual = write(fd, basePtr + offset, uncompLen); if (actual < 0) { LOGE("Write failed: %s\n", strerror(errno)); goto bail; } else if (actual != uncompLen) { LOGE("Partial write during uncompress (%d of %ld)\n", (int) actual, uncompLen); goto bail; } else { LOGI("+++ successful write\n"); } } else { if (!inflateToFile(fd, basePtr+offset, uncompLen, compLen)) goto bail; } result = true; bail: return result; }
/* * Uncompress an entry, in its entirety, to an open file descriptor. * * TODO: this doesn't verify the data's CRC, but probably should (especially * for uncompressed data). */ int dexZipExtractEntryToFile(const ZipArchive* pArchive, const ZipEntry entry, int fd) { int result = -1; int ent = entryToIndex(pArchive, entry); if (ent < 0) { LOGW("Zip: extract can't find entry %p\n", entry); goto bail; } int method; size_t uncompLen, compLen; off_t dataOffset; if (dexZipGetEntryInfo(pArchive, entry, &method, &uncompLen, &compLen, &dataOffset, NULL, NULL) != 0) { goto bail; } if (lseek(pArchive->mFd, dataOffset, SEEK_SET) != dataOffset) { LOGW("Zip: lseek to data at %ld failed\n", (long) dataOffset); goto bail; } if (method == kCompressStored) { if (copyFileToFile(pArchive->mFd, fd, uncompLen) != 0) goto bail; } else { if (inflateToFile(pArchive->mFd, fd, uncompLen, compLen) != 0) goto bail; } result = 0; bail: return result; }
/* * 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; }