2 * Copyright (C) 2008 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * Access the contents of a Jar file.
20 * This isn't actually concerned with any of the Jar-like elements; it
21 * just wants a zip archive with "classes.dex" inside. In Android the
22 * most common example is ".apk".
26 #include "libdex/OptInvocation.h"
34 static const char* kDexInJarName = "classes.dex";
37 * Attempt to open a file whose name is similar to <fileName>,
38 * but with the supplied suffix. E.g.,
39 * openAlternateSuffix("Home.apk", "dex", O_RDONLY) will attempt
40 * to open "Home.dex". If the open succeeds, a pointer to a
41 * malloc()ed copy of the opened file name will be put in <*pCachedName>.
43 * <flags> is passed directly to open(). O_CREAT is not supported.
45 static int openAlternateSuffix(const char *fileName, const char *suffix,
46 int flags, char **pCachedName)
49 size_t fileNameLen = strlen(fileName);
50 size_t suffixLen = strlen(suffix);
51 size_t bufLen = fileNameLen + suffixLen + 1;
54 buf = (char*)malloc(bufLen);
60 /* Copy the original filename into the buffer, find
61 * the last dot, and copy the suffix to just after it.
63 memcpy(buf, fileName, fileNameLen + 1);
64 c = strrchr(buf, '.');
69 memcpy(c + 1, suffix, suffixLen + 1);
71 fd = open(buf, flags);
76 ALOGV("Couldn't open %s: %s", buf, strerror(errno));
83 * Checks the dependencies of the dex cache file corresponding
84 * to the jar file at the absolute path "fileName".
86 * Note: This should parallel the logic of dvmJarFileOpen.
88 DexCacheStatus dvmDexCacheStatus(const char *fileName)
91 char* cachedName = NULL;
93 DexCacheStatus result = DEX_CACHE_ERROR;
96 /* Always treat elements of the bootclasspath as up-to-date.
97 * The fact that interpreted code is running at all means that this
100 if (dvmClassPathContains(gDvm.bootClassPath, fileName)) {
104 /* Try to find the dex file inside of the archive.
106 if (dexZipOpenArchive(fileName, &archive) != 0) {
107 return DEX_CACHE_BAD_ARCHIVE;
110 /* First, look for a ".odex" alongside the jar file. It will
111 * have the same name/path except for the extension.
113 fd = openAlternateSuffix(fileName, "odex", O_RDONLY, &cachedName);
115 ALOGV("Using alternate file (odex) for %s ...", fileName);
116 if (!dvmCheckOptHeaderAndDependencies(fd, false, 0, 0, true, true)) {
117 ALOGE("%s odex has stale dependencies", fileName);
124 ALOGV("%s odex has good dependencies", fileName);
130 * Pre-created .odex absent or stale. Look inside the jar for a
133 if ((entry = dexZipFindEntry(&archive, kDexInJarName)) != NULL) {
134 bool newFile = false;
137 * See if there's an up-to-date copy of the optimized dex
138 * in the cache, but don't create one if there isn't.
140 ALOGV("dvmDexCacheStatus: Checking cache for %s", fileName);
141 cachedName = dexOptGenerateCacheFileName(fileName, kDexInJarName);
142 if (cachedName == NULL)
143 return DEX_CACHE_BAD_ARCHIVE;
145 fd = dvmOpenCachedDexFile(fileName, cachedName,
146 dexGetZipEntryModTime(&archive, entry),
147 dexGetZipEntryCrc32(&archive, entry),
148 /*isBootstrap=*/false, &newFile, /*createIfMissing=*/false);
149 ALOGV("dvmOpenCachedDexFile returned fd %d", fd);
151 result = DEX_CACHE_STALE;
155 /* dvmOpenCachedDexFile locks the file as a side-effect.
156 * Unlock and close it.
158 if (!dvmUnlockCachedDexFile(fd)) {
159 /* uh oh -- this process needs to exit or we'll wedge the system */
160 ALOGE("Unable to unlock DEX file");
164 ALOGI("Zip is good, but no %s inside, and no .odex "
165 "file in the same directory", kDexInJarName);
166 result = DEX_CACHE_BAD_ARCHIVE;
170 result = DEX_CACHE_OK;
173 dexZipCloseArchive(&archive);
182 * Open a Jar file. It's okay if it's just a Zip archive without all of
183 * the Jar trimmings, but we do insist on finding "classes.dex" inside
184 * or an appropriately-named ".odex" file alongside.
186 * If "isBootstrap" is not set, the optimizer/verifier regards this DEX as
187 * being part of a different class loader.
189 * Note: This should parallel the logic of dvmDexCacheStatus.
191 int dvmJarFileOpen(const char* fileName, const char* odexOutputName,
192 JarFile** ppJarFile, bool isBootstrap)
195 * TODO: This function has been duplicated and modified to become
196 * dvmRawDexFileOpen() in RawDexFile.c. This should be refactored.
200 DvmDex* pDvmDex = NULL;
201 char* cachedName = NULL;
202 bool archiveOpen = false;
207 /* Even if we're not going to look at the archive, we need to
208 * open it so we can stuff it into ppJarFile.
210 if (dexZipOpenArchive(fileName, &archive) != 0)
214 /* If we fork/exec into dexopt, don't let it inherit the archive's fd.
216 dvmSetCloseOnExec(dexZipGetArchiveFd(&archive));
218 /* First, look for a ".odex" alongside the jar file. It will
219 * have the same name/path except for the extension.
221 fd = openAlternateSuffix(fileName, "odex", O_RDONLY, &cachedName);
223 ALOGV("Using alternate file (odex) for %s ...", fileName);
224 if (!dvmCheckOptHeaderAndDependencies(fd, false, 0, 0, true, true)) {
225 ALOGE("%s odex has stale dependencies", fileName);
232 ALOGV("%s odex has good dependencies", fileName);
233 //TODO: make sure that the .odex actually corresponds
234 // to the classes.dex inside the archive (if present).
235 // For typical use there will be no classes.dex.
242 * Pre-created .odex absent or stale. Look inside the jar for a
245 entry = dexZipFindEntry(&archive, kDexInJarName);
247 bool newFile = false;
250 * We've found the one we want. See if there's an up-to-date copy
253 * On return, "fd" will be seeked just past the "opt" header.
255 * If a stale .odex file is present and classes.dex exists in
256 * the archive, this will *not* return an fd pointing to the
257 * .odex file; the fd will point into dalvik-cache like any
260 if (odexOutputName == NULL) {
261 cachedName = dexOptGenerateCacheFileName(fileName,
263 if (cachedName == NULL)
266 cachedName = strdup(odexOutputName);
268 ALOGV("dvmJarFileOpen: Checking cache for %s (%s)",
269 fileName, cachedName);
270 fd = dvmOpenCachedDexFile(fileName, cachedName,
271 dexGetZipEntryModTime(&archive, entry),
272 dexGetZipEntryCrc32(&archive, entry),
273 isBootstrap, &newFile, /*createIfMissing=*/true);
275 ALOGI("Unable to open or create cache for %s (%s)",
276 fileName, cachedName);
282 * If fd points to a new file (because there was no cached version,
283 * or the cached version was stale), generate the optimized DEX.
284 * The file descriptor returned is still locked, and is positioned
285 * just past the optimization header.
288 u8 startWhen, extractWhen, endWhen;
292 dexOffset = lseek(fd, 0, SEEK_CUR);
293 result = (dexOffset > 0);
296 startWhen = dvmGetRelativeTimeUsec();
297 result = dexZipExtractEntryToFile(&archive, entry, fd) == 0;
298 extractWhen = dvmGetRelativeTimeUsec();
301 result = dvmOptimizeDexFile(fd, dexOffset,
302 dexGetZipEntryUncompLen(&archive, entry),
304 dexGetZipEntryModTime(&archive, entry),
305 dexGetZipEntryCrc32(&archive, entry),
310 ALOGE("Unable to extract+optimize DEX from '%s'",
315 endWhen = dvmGetRelativeTimeUsec();
316 ALOGD("DEX prep '%s': unzip in %dms, rewrite %dms",
318 (int) (extractWhen - startWhen) / 1000,
319 (int) (endWhen - extractWhen) / 1000);
322 ALOGI("Zip is good, but no %s inside, and no valid .odex "
323 "file in the same directory", kDexInJarName);
329 * Map the cached version. This immediately rewinds the fd, so it
330 * doesn't have to be seeked anywhere in particular.
332 if (dvmDexFileOpenFromFd(fd, &pDvmDex) != 0) {
333 ALOGI("Unable to map %s in %s", kDexInJarName, fileName);
339 if (!dvmUnlockCachedDexFile(fd)) {
340 /* uh oh -- this process needs to exit or we'll wedge the system */
341 ALOGE("Unable to unlock DEX file");
347 ALOGV("Successfully opened '%s' in '%s'", kDexInJarName, fileName);
349 *ppJarFile = (JarFile*) calloc(1, sizeof(JarFile));
350 (*ppJarFile)->archive = archive;
351 (*ppJarFile)->cacheFileName = cachedName;
352 (*ppJarFile)->pDvmDex = pDvmDex;
353 cachedName = NULL; // don't free it below
357 /* clean up, closing the open file */
358 if (archiveOpen && result != 0)
359 dexZipCloseArchive(&archive);
363 (void) dvmUnlockCachedDexFile(fd);
370 * Close a Jar file and free the struct.
372 void dvmJarFileFree(JarFile* pJarFile)
374 if (pJarFile == NULL)
377 dvmDexFileFree(pJarFile->pDvmDex);
378 dexZipCloseArchive(&pJarFile->archive);
379 free(pJarFile->cacheFileName);