/*
 * 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;
}
Пример #2
0
/*
 * 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;
}
Пример #3
0
/*
 * 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;
}