/* * 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); }