示例#1
0
文件: JarFile.cpp 项目: handgod/soma
/*
 * Checks the dependencies of the dex cache file corresponding
 * to the jar file at the absolute path "fileName".
 */
DexCacheStatus dvmDexCacheStatus(const char *fileName)
{
    ZipArchive archive;
    char* cachedName = NULL;
    int fd;
    DexCacheStatus result = DEX_CACHE_ERROR;
    ZipEntry entry;

    /* Always treat elements of the bootclasspath as up-to-date.
     * The fact that interpreted code is running at all means that this
     * should be true.
     */
    if (dvmClassPathContains(gDvm.bootClassPath, fileName)) {
        return DEX_CACHE_OK;
    }

    //TODO: match dvmJarFileOpen()'s logic.  Not super-important
    //      (the odex-first logic is only necessary for dexpreopt)
    //      but it would be nice to be consistent.

    /* Try to find the dex file inside of the archive.
     */
    if (dexZipOpenArchive(fileName, &archive) != 0) {
        return DEX_CACHE_BAD_ARCHIVE;
    }
    entry = dexZipFindEntry(&archive, kDexInJarName);
    if (entry != NULL) {
        bool newFile = false;

        /*
         * See if there's an up-to-date copy of the optimized dex
         * in the cache, but don't create one if there isn't.
         */
        ALOGV("dvmDexCacheStatus: Checking cache for %s", fileName);
        cachedName = dexOptGenerateCacheFileName(fileName, kDexInJarName);
        if (cachedName == NULL)
            return DEX_CACHE_BAD_ARCHIVE;

        fd = dvmOpenCachedDexFile(fileName, cachedName,
                dexGetZipEntryModTime(&archive, entry),
                dexGetZipEntryCrc32(&archive, entry),
                /*isBootstrap=*/false, &newFile, /*createIfMissing=*/false);
        ALOGV("dvmOpenCachedDexFile returned fd %d", fd);
        if (fd < 0) {
            result = DEX_CACHE_STALE;
            goto bail;
        }

        /* dvmOpenCachedDexFile locks the file as a side-effect.
         * Unlock and close it.
         */
        if (!dvmUnlockCachedDexFile(fd)) {
            /* uh oh -- this process needs to exit or we'll wedge the system */
            ALOGE("Unable to unlock DEX file");
            goto bail;
        }

        /* When createIfMissing is false, dvmOpenCachedDexFile() only
         * returns a valid fd if the cache file is up-to-date.
         */
    } else {
        /*
         * There's no dex file in the jar file.  See if there's an
         * optimized dex file living alongside the jar.
         */
        fd = openAlternateSuffix(fileName, "odex", O_RDONLY, &cachedName);
        if (fd < 0) {
            ALOGI("Zip is good, but no %s inside, and no .odex "
                    "file in the same directory", kDexInJarName);
            result = DEX_CACHE_BAD_ARCHIVE;
            goto bail;
        }

        ALOGV("Using alternate file (odex) for %s ...", fileName);
        if (!dvmCheckOptHeaderAndDependencies(fd, false, 0, 0, true, true)) {
            ALOGE("%s odex has stale dependencies", fileName);
            ALOGE("odex source not available -- failing");
            result = DEX_CACHE_STALE_ODEX;
            goto bail;
        } else {
            ALOGV("%s odex has good dependencies", fileName);
        }
    }
    result = DEX_CACHE_OK;

bail:
    dexZipCloseArchive(&archive);
    free(cachedName);
    if (fd >= 0) {
        close(fd);
    }
    return result;
}
示例#2
0
DexCacheStatus dvmDexCacheStatus(const char *fileName)
{
    ZipArchive archive;
    char* cachedName = NULL;
    int fd;
    DexCacheStatus result = DEX_CACHE_ERROR;
    ZipEntry entry;

    if (dvmClassPathContains(gDvm.bootClassPath, fileName)) {
        return DEX_CACHE_OK;
    }


    if (dexZipOpenArchive(fileName, &archive) != 0) {
        return DEX_CACHE_BAD_ARCHIVE;
    }
    entry = dexZipFindEntry(&archive, kDexInJarName);
    if (entry != NULL) {
        bool newFile = false;

        ALOGV("dvmDexCacheStatus: Checking cache for %s", fileName);
        cachedName = dexOptGenerateCacheFileName(fileName, kDexInJarName);
        if (cachedName == NULL)
            return DEX_CACHE_BAD_ARCHIVE;

        fd = dvmOpenCachedDexFile(fileName, cachedName,
                dexGetZipEntryModTime(&archive, entry),
                dexGetZipEntryCrc32(&archive, entry),
                /*isBootstrap=*/false, &newFile, /*createIfMissing=*/false);
        ALOGV("dvmOpenCachedDexFile returned fd %d", fd);
        if (fd < 0) {
            result = DEX_CACHE_STALE;
            goto bail;
        }

        if (!dvmUnlockCachedDexFile(fd)) {
            /* uh oh -- this process needs to exit or we'll wedge the system */
            ALOGE("Unable to unlock DEX file");
            goto bail;
        }

    } else {
        fd = openAlternateSuffix(fileName, "odex", O_RDONLY, &cachedName);
        if (fd < 0) {
            ALOGI("Zip is good, but no %s inside, and no .odex "
                    "file in the same directory", kDexInJarName);
            result = DEX_CACHE_BAD_ARCHIVE;
            goto bail;
        }

        ALOGV("Using alternate file (odex) for %s ...", fileName);
        if (!dvmCheckOptHeaderAndDependencies(fd, false, 0, 0, true, true)) {
            ALOGE("%s odex has stale dependencies", fileName);
            ALOGE("odex source not available -- failing");
            result = DEX_CACHE_STALE_ODEX;
            goto bail;
        } else {
            ALOGV("%s odex has good dependencies", fileName);
        }
    }
    result = DEX_CACHE_OK;

bail:
    dexZipCloseArchive(&archive);
    free(cachedName);
    if (fd >= 0) {
        close(fd);
    }
    return result;
}
/*
 * private static int openDexFile(String sourceName, String outputName,
 *     int flags) throws IOException
 *
 * Open a DEX file, returning a pointer to our internal data structure.
 *
 * "sourceName" should point to the "source" jar or DEX file.
 *
 * If "outputName" is NULL, the DEX code will automatically find the
 * "optimized" version in the cache directory, creating it if necessary.
 * If it's non-NULL, the specified file will be used instead.
 *
 * TODO: at present we will happily open the same file more than once.
 * To optimize this away we could search for existing entries in the hash
 * table and refCount them.  Requires atomic ops or adding "synchronized"
 * to the non-native code that calls here.
 */
static void Dalvik_dalvik_system_DexFile_openDexFile(const u4* args,
    JValue* pResult)
{
    StringObject* sourceNameObj = (StringObject*) args[0];
    StringObject* outputNameObj = (StringObject*) args[1];
    int flags = args[2];
    DexOrJar* pDexOrJar = NULL;
    JarFile* pJarFile;
    RawDexFile* pRawDexFile;
    char* sourceName;
    char* outputName;

    if (sourceNameObj == NULL) {
        dvmThrowException("Ljava/lang/NullPointerException;", NULL);
        RETURN_VOID();
    }

    sourceName = dvmCreateCstrFromString(sourceNameObj);
    if (outputNameObj != NULL)
        outputName = dvmCreateCstrFromString(outputNameObj);
    else
        outputName = NULL;

    /*
     * We have to deal with the possibility that somebody might try to
     * open one of our bootstrap class DEX files.  The set of dependencies
     * will be different, and hence the results of optimization might be
     * different, which means we'd actually need to have two versions of
     * the optimized DEX: one that only knows about part of the boot class
     * path, and one that knows about everything in it.  The latter might
     * optimize field/method accesses based on a class that appeared later
     * in the class path.
     *
     * We can't let the user-defined class loader open it and start using
     * the classes, since the optimized form of the code skips some of
     * the method and field resolution that we would ordinarily do, and
     * we'd have the wrong semantics.
     *
     * We have to reject attempts to manually open a DEX file from the boot
     * class path.  The easiest way to do this is by filename, which works
     * out because variations in name (e.g. "/system/framework/./ext.jar")
     * result in us hitting a different dalvik-cache entry.  It's also fine
     * if the caller specifies their own output file.
     */
    if (dvmClassPathContains(gDvm.bootClassPath, sourceName)) {
        LOGW("Refusing to reopen boot DEX '%s'\n", sourceName);
        dvmThrowException("Ljava/io/IOException;",
            "Re-opening BOOTCLASSPATH DEX files is not allowed");
        free(sourceName);
        RETURN_VOID();
    }

    /*
     * Try to open it directly as a DEX.  If that fails, try it as a Zip
     * with a "classes.dex" inside.
     */
    if (dvmRawDexFileOpen(sourceName, outputName, &pRawDexFile, false) == 0) {
        LOGV("Opening DEX file '%s' (DEX)\n", sourceName);

        pDexOrJar = (DexOrJar*) malloc(sizeof(DexOrJar));
        pDexOrJar->isDex = true;
        pDexOrJar->pRawDexFile = pRawDexFile;
    } else if (dvmJarFileOpen(sourceName, outputName, &pJarFile, false) == 0) {
        LOGV("Opening DEX file '%s' (Jar)\n", sourceName);

        pDexOrJar = (DexOrJar*) malloc(sizeof(DexOrJar));
        pDexOrJar->isDex = false;
        pDexOrJar->pJarFile = pJarFile;
    } else {
        LOGV("Unable to open DEX file '%s'\n", sourceName);
        dvmThrowException("Ljava/io/IOException;", "unable to open DEX file");
    }

    if (pDexOrJar != NULL) {
        pDexOrJar->fileName = sourceName;

        /* add to hash table */
        u4 hash = dvmComputeUtf8Hash(sourceName);
        void* result;
        dvmHashTableLock(gDvm.userDexFiles);
        result = dvmHashTableLookup(gDvm.userDexFiles, hash, pDexOrJar,
                    hashcmpDexOrJar, true);
        dvmHashTableUnlock(gDvm.userDexFiles);
        if (result != pDexOrJar) {
            LOGE("Pointer has already been added?\n");
            dvmAbort();
        }

        pDexOrJar->okayToFree = true;
    } else
        free(sourceName);

    RETURN_PTR(pDexOrJar);
}
/*
 * private static int openDexFile(String sourceName, String outputName,
 *     int flags) throws IOException
 *
 * Open a DEX file, returning a pointer to our internal data structure.
 * 打开一个DEX文件,返回一个指向我们内部数据结构体
 * "sourceName" should point to the "source" jar or DEX file.
 * 'sourceName'应该是指jar或dex文件
 *
 * If "outputName" is NULL, the DEX code will automatically find the
 * "optimized" version in the cache directory, creating it if necessary.
 * If it's non-NULL, the specified file will be used instead.
 *
 * TODO: at present we will happily open the same file more than once.
 * To optimize this away we could search for existing entries in the hash
 * table and refCount them.  Requires atomic ops or adding "synchronized"
 * to the non-native code that calls here.
 *
 * TODO: should be using "long" for a pointer.
 */
static void Dalvik_dalvik_system_DexFile_openDexFile(const u4* args,
    JValue* pResult)
{
    StringObject* sourceNameObj = (StringObject*) args[0];
    StringObject* outputNameObj = (StringObject*) args[1];
    DexOrJar* pDexOrJar = NULL;
    JarFile* pJarFile;
    RawDexFile* pRawDexFile;
    char* sourceName;
    char* outputName;

    if (sourceNameObj == NULL) {
        dvmThrowNullPointerException("sourceName == null");
        RETURN_VOID();
    }

   /*转换java数据类型成为c数据类型*/
    sourceName = dvmCreateCstrFromString(sourceNameObj);
    if (outputNameObj != NULL)
        outputName = dvmCreateCstrFromString(outputNameObj);
    else
        outputName = NULL;

    /*
     * We have to deal with the possibility that somebody might try to
     * open one of our bootstrap class DEX files.  The set of dependencies
     * will be different, and hence the results of optimization might be
     * different, which means we'd actually need to have two versions of
     * the optimized DEX: one that only knows about part of the boot class
     * path, and one that knows about everything in it.  The latter might
     * optimize field/method accesses based on a class that appeared later
     * in the class path.
     *
     * We can't let the user-defined class loader open it and start using
     * the classes, since the optimized form of the code skips some of
     * the method and field resolution that we would ordinarily do, and
     * we'd have the wrong semantics.
     *
     * We have to reject attempts to manually open a DEX file from the boot
     * class path.  The easiest way to do this is by filename, which works
     * out because variations in name (e.g. "/system/framework/./ext.jar")
     * result in us hitting a different dalvik-cache entry.  It's also fine
     * if the caller specifies their own output file.
     */
    if (dvmClassPathContains(gDvm.bootClassPath, sourceName)) {
        ALOGW("Refusing to reopen boot DEX '%s'", sourceName);
        dvmThrowIOException(
            "Re-opening BOOTCLASSPATH DEX files is not allowed");
        free(sourceName);
        free(outputName);
        RETURN_VOID();
    }

    /*
     * Try to open it directly as a DEX if the name ends with ".dex".
     * If that fails (or isn't tried in the first place), try it as a
     * Zip with a "classes.dex" inside.
     */
    /*判断扩展后缀名.eg .dex或.jar*/
    if (hasDexExtension(sourceName)
            && dvmRawDexFileOpen(sourceName, outputName, &pRawDexFile, false) == 0) {
        ALOGV("Opening DEX file '%s' (DEX)", sourceName);

        pDexOrJar = (DexOrJar*) malloc(sizeof(DexOrJar));
        pDexOrJar->isDex = true;
        pDexOrJar->pRawDexFile = pRawDexFile;
        pDexOrJar->pDexMemory = NULL;
    } else if (dvmJarFileOpen(sourceName, outputName, &pJarFile, false) == 0) {
        ALOGV("Opening DEX file '%s' (Jar)", sourceName);

        pDexOrJar = (DexOrJar*) malloc(sizeof(DexOrJar));
        pDexOrJar->isDex = false;
        pDexOrJar->pJarFile = pJarFile;
        pDexOrJar->pDexMemory = NULL;
    } else {
        ALOGV("Unable to open DEX file '%s'", sourceName);
        dvmThrowIOException("unable to open DEX file");
    }

    if (pDexOrJar != NULL) {
        pDexOrJar->fileName = sourceName;
        addToDexFileTable(pDexOrJar);
    } else {
        free(sourceName);
    }

    RETURN_PTR(pDexOrJar);
}