/* * 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; }
/* See documentation comment in header. */ int dvmRawDexFileOpen(const char* fileName, const char* odexOutputName, RawDexFile** ppRawDexFile, bool isBootstrap) { /* * TODO: This duplicates a lot of code from dvmJarFileOpen() in * JarFile.c. This should be refactored. */ DvmDex* pDvmDex = NULL; char* cachedName = NULL; int result = -1; int dexFd = -1; int optFd = -1; u4 modTime = 0; u4 adler32 = 0; size_t fileSize = 0; bool newFile = false; bool locked = false; dexFd = open(fileName, O_RDONLY); if (dexFd < 0) goto bail; /* If we fork/exec into dexopt, don't let it inherit the open fd. */ dvmSetCloseOnExec(dexFd); if (verifyMagicAndGetAdler32(dexFd, &adler32) < 0) { ALOGE("Error with header for %s", fileName); goto bail; } if (getModTimeAndSize(dexFd, &modTime, &fileSize) < 0) { ALOGE("Error with stat for %s", fileName); goto bail; } /* * See if the cached file matches. If so, optFd will become a reference * to the cached file and will have been seeked to just past the "opt" * header. */ if (odexOutputName == NULL) { cachedName = dexOptGenerateCacheFileName(fileName, NULL); if (cachedName == NULL) goto bail; } else { cachedName = strdup(odexOutputName); } ALOGV("dvmRawDexFileOpen: Checking cache for %s (%s)", fileName, cachedName); optFd = dvmOpenCachedDexFile(fileName, cachedName, modTime, adler32, isBootstrap, &newFile, /*createIfMissing=*/true); if (optFd < 0) { ALOGI("Unable to open or create cache for %s (%s)", fileName, cachedName); goto bail; } locked = true; /* * If optFd points to a new file (because there was no cached * version, or the cached version was stale), generate the * optimized DEX. The file descriptor returned is still locked, * and is positioned just past the optimization header. */ if (newFile) { u8 startWhen, copyWhen, endWhen; bool result; off_t dexOffset; dexOffset = lseek(optFd, 0, SEEK_CUR); result = (dexOffset > 0); if (result) { startWhen = dvmGetRelativeTimeUsec(); result = copyFileToFile(optFd, dexFd, fileSize) == 0; copyWhen = dvmGetRelativeTimeUsec(); } if (result) { result = dvmOptimizeDexFile(optFd, dexOffset, fileSize, fileName, modTime, adler32, isBootstrap); } if (!result) { ALOGE("Unable to extract+optimize DEX from '%s'", fileName); goto bail; } endWhen = dvmGetRelativeTimeUsec(); ALOGD("DEX prep '%s': copy in %dms, rewrite %dms", fileName, (int) (copyWhen - startWhen) / 1000, (int) (endWhen - copyWhen) / 1000); } /* * Map the cached version. This immediately rewinds the fd, so it * doesn't have to be seeked anywhere in particular. */ if (dvmDexFileOpenFromFd(optFd, &pDvmDex) != 0) { ALOGI("Unable to map cached %s", fileName); goto bail; } if (locked) { /* unlock the fd */ if (!dvmUnlockCachedDexFile(optFd)) { /* uh oh -- this process needs to exit or we'll wedge the system */ ALOGE("Unable to unlock DEX file"); goto bail; } locked = false; } ALOGV("Successfully opened '%s'", fileName); *ppRawDexFile = (RawDexFile*) calloc(1, sizeof(RawDexFile)); (*ppRawDexFile)->cacheFileName = cachedName; (*ppRawDexFile)->pDvmDex = pDvmDex; cachedName = NULL; // don't free it below result = 0; bail: free(cachedName); if (dexFd >= 0) { close(dexFd); } if (optFd >= 0) { if (locked) (void) dvmUnlockCachedDexFile(optFd); close(optFd); } return result; }
/* * Finish up the hprof dump. Returns true on success. */ bool hprofShutdown(hprof_context_t *tailCtx) { FILE *fp = NULL; /* flush output to the temp file, then prepare the output file */ hprofFlushCurrentRecord(tailCtx); LOGI("hprof: dumping heap strings to \"%s\".\n", tailCtx->fileName); if (!tailCtx->directToDdms) { fp = fopen(tailCtx->fileName, "w"); if (fp == NULL) { LOGE("can't open %s: %s\n", tailCtx->fileName, strerror(errno)); hprofFreeContext(tailCtx); return false; } } /* * Create a new context struct for the start of the file. We * heap-allocate it so we can share the "free" function. */ hprof_context_t *headCtx = malloc(sizeof(*headCtx)); if (headCtx == NULL) { LOGE("hprof: can't allocate context.\n"); if (fp != NULL) fclose(fp); hprofFreeContext(tailCtx); return NULL; } hprofContextInit(headCtx, strdup(tailCtx->fileName), fp, true, tailCtx->directToDdms); hprofDumpStrings(headCtx); hprofDumpClasses(headCtx); /* Write a dummy stack trace record so the analysis * tools don't freak out. */ hprofStartNewRecord(headCtx, HPROF_TAG_STACK_TRACE, HPROF_TIME); hprofAddU4ToRecord(&headCtx->curRec, HPROF_NULL_STACK_TRACE); hprofAddU4ToRecord(&headCtx->curRec, HPROF_NULL_THREAD); hprofAddU4ToRecord(&headCtx->curRec, 0); // no frames #if WITH_HPROF_STACK hprofDumpStackFrames(headCtx); hprofDumpStacks(headCtx); #endif hprofFlushCurrentRecord(headCtx); hprofShutdown_Class(); hprofShutdown_String(); #if WITH_HPROF_STACK hprofShutdown_Stack(); hprofShutdown_StackFrame(); #endif if (tailCtx->directToDdms) { /* flush to ensure memstream pointer and size are updated */ fflush(headCtx->fp); fflush(tailCtx->fp); /* send the data off to DDMS */ struct iovec iov[2]; iov[0].iov_base = headCtx->fileDataPtr; iov[0].iov_len = headCtx->fileDataSize; iov[1].iov_base = tailCtx->fileDataPtr; iov[1].iov_len = tailCtx->fileDataSize; dvmDbgDdmSendChunkV(CHUNK_TYPE("HPDS"), iov, 2); } else { /* * Append the contents of the temp file to the output file. The temp * file was removed immediately after being opened, so it will vanish * when we close it. */ rewind(tailCtx->fp); if (!copyFileToFile(headCtx->fp, tailCtx->fp)) { LOGW("hprof: file copy failed, hprof data may be incomplete\n"); /* finish up anyway */ } } hprofFreeContext(headCtx); hprofFreeContext(tailCtx); /* throw out a log message for the benefit of "runhat" */ LOGI("hprof: heap dump completed, temp file removed\n"); return true; }