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 * Command-line DEX optimization and verification entry point.
20 * There are two ways to launch this:
21 * (1) From the VM. This takes a dozen args, one of which is a file
22 * descriptor that acts as both input and output. This allows us to
23 * remain ignorant of where the DEX data originally came from.
24 * (2) From installd or another native application. Pass in a file
25 * descriptor for a zip file, a file descriptor for the output, and
26 * a filename for debug messages. Many assumptions are made about
27 * what's going on (verification + optimization are enabled, boot
28 * class path is in BOOTCLASSPATH, etc).
30 * There are some fragile aspects around bootclasspath entries, owing
31 * largely to the VM's history of working on whenever it thought it needed
32 * instead of strictly doing what it was told. If optimizing bootclasspath
33 * entries, always do them in the order in which they appear in the path.
36 #include "libdex/OptInvocation.h"
38 #include "utils/Log.h"
39 #include "cutils/process_name.h"
46 static const char* kClassesDex = "classes.dex";
50 * Extract "classes.dex" from zipFd into "cacheFd", leaving a little space
51 * up front for the DEX optimization header.
53 static int extractAndProcessZip(int zipFd, int cacheFd,
54 const char* debugFileName, int isBootstrap, const char* bootClassPath,
55 const char* dexoptFlagStr)
65 memset(&zippy, 0, sizeof(zippy));
67 /* make sure we're still at the start of an empty file */
68 if (lseek(cacheFd, 0, SEEK_END) != 0) {
69 LOGE("DexOptZ: new cache file '%s' is not empty\n", debugFileName);
74 * Write a skeletal DEX optimization header. We want the classes.dex
75 * to come just after it.
77 err = dexOptCreateEmptyHeader(cacheFd);
81 /* record the file position so we can get back here later */
82 dexOffset = lseek(cacheFd, 0, SEEK_CUR);
87 * Open the zip archive, find the DEX entry.
89 if (dexZipPrepArchive(zipFd, debugFileName, &zippy) != 0) {
90 LOGW("DexOptZ: unable to open zip archive '%s'\n", debugFileName);
94 zipEntry = dexZipFindEntry(&zippy, kClassesDex);
95 if (zipEntry == NULL) {
96 LOGW("DexOptZ: zip archive '%s' does not include %s\n",
97 debugFileName, kClassesDex);
102 * Extract some info about the zip entry.
104 if (dexZipGetEntryInfo(&zippy, zipEntry, NULL, &uncompLen, NULL, NULL,
105 &modWhen, &crc32) != 0)
107 LOGW("DexOptZ: zip archive GetEntryInfo failed on %s\n", debugFileName);
111 uncompLen = uncompLen;
116 * Extract the DEX data into the cache file at the current offset.
118 if (dexZipExtractEntryToFile(&zippy, zipEntry, cacheFd) != 0) {
119 LOGW("DexOptZ: extraction of %s from %s failed\n",
120 kClassesDex, debugFileName);
125 * Prep the VM and perform the optimization.
127 DexClassVerifyMode verifyMode = VERIFY_MODE_ALL;
128 DexOptimizerMode dexOptMode = OPTIMIZE_MODE_VERIFIED;
129 int dexoptFlags = 0; /* bit flags, from enum DexoptFlags */
130 if (dexoptFlagStr[0] != '\0') {
134 opc = strstr(dexoptFlagStr, "v="); /* verification */
137 case 'n': verifyMode = VERIFY_MODE_NONE; break;
138 case 'r': verifyMode = VERIFY_MODE_REMOTE; break;
139 case 'a': verifyMode = VERIFY_MODE_ALL; break;
144 opc = strstr(dexoptFlagStr, "o="); /* optimization */
147 case 'n': dexOptMode = OPTIMIZE_MODE_NONE; break;
148 case 'v': dexOptMode = OPTIMIZE_MODE_VERIFIED; break;
149 case 'a': dexOptMode = OPTIMIZE_MODE_ALL; break;
154 opc = strstr(dexoptFlagStr, "m=y"); /* register map */
156 dexoptFlags |= DEXOPT_GEN_REGISTER_MAPS;
159 if (dvmPrepForDexOpt(bootClassPath, dexOptMode, verifyMode,
162 LOGE("DexOptZ: VM init failed\n");
168 /* do the optimization */
169 if (!dvmContinueOptimization(cacheFd, dexOffset, uncompLen, debugFileName,
170 modWhen, crc32, isBootstrap))
172 LOGE("Optimization failed\n");
176 /* we don't shut the VM down -- process is about to exit */
181 dexZipCloseArchive(&zippy);
186 /* advance to the next arg and extract it */
187 #define GET_ARG(_var, _func, _msg) \
190 (_var) = _func(*++argv, &endp, 0); \
191 if (*endp != '\0') { \
192 LOGE("%s '%s'", _msg, *argv); \
199 * Parse arguments. We want:
200 * 0. (name of dexopt command -- ignored)
202 * 2. zip fd (input, read-only)
203 * 3. cache fd (output, read-write, locked with flock)
204 * 4. filename of file being optimized (used for debug messages and
205 * for comparing against BOOTCLASSPATH -- does not need to be
206 * accessible or even exist)
209 * The BOOTCLASSPATH environment variable is assumed to hold the correct
210 * boot class path. If the filename provided appears in the boot class
211 * path, the path will be truncated just before that entry (so that, if
212 * you were to dexopt "core.jar", your bootclasspath would be empty).
214 * This does not try to normalize the boot class path name, so the
215 * filename test won't catch you if you get creative.
217 static int fromZip(int argc, char* const argv[])
220 int zipFd, cacheFd, vmBuildVersion;
221 const char* inputFileName;
222 char* bcpCopy = NULL;
223 const char* dexoptFlagStr;
226 LOGE("Wrong number of args for --zip (found %d)\n", argc);
234 GET_ARG(zipFd, strtol, "bad zip fd");
235 GET_ARG(cacheFd, strtol, "bad cache fd");
236 inputFileName = *++argv;
238 dexoptFlagStr = *++argv;
242 * Check to see if this is a bootstrap class entry. If so, truncate
245 const char* bcp = getenv("BOOTCLASSPATH");
247 LOGE("DexOptZ: BOOTCLASSPATH not set\n");
251 int isBootstrap = false;
252 const char* match = strstr(bcp, inputFileName);
255 * TODO: we have a partial string match, but that doesn't mean
256 * we've matched an entire path component. We should make sure
257 * that we're matching on the full inputFileName, and if not we
258 * should re-do the strstr starting at (match+1).
260 * The scenario would be a bootclasspath with something like
261 * "/system/framework/core.jar" while we're trying to optimize
262 * "/framework/core.jar". Not very likely since all paths are
263 * absolute and end with ".jar", but not impossible.
265 int matchOffset = match - bcp;
266 if (matchOffset > 0 && bcp[matchOffset-1] == ':')
268 LOGV("DexOptZ: found '%s' in bootclasspath, cutting off at %d\n",
269 inputFileName, matchOffset);
270 bcpCopy = strdup(bcp);
271 bcpCopy[matchOffset] = '\0';
274 LOGD("DexOptZ: truncated BOOTCLASSPATH to '%s'\n", bcp);
278 result = extractAndProcessZip(zipFd, cacheFd, inputFileName,
279 isBootstrap, bcp, dexoptFlagStr);
287 * Parse arguments for an "old-style" invocation directly from the VM.
289 * Here's what we want:
290 * 0. (name of dexopt command -- ignored)
292 * 2. DALVIK_VM_BUILD value, as a sanity check
293 * 3. file descriptor, locked with flock, for DEX file being optimized
294 * 4. DEX offset within file
296 * 6. filename of file being optimized (for debug messages only)
297 * 7. modification date of source (goes into dependency section)
298 * 8. CRC of source (goes into dependency section)
299 * 9. flags (optimization level, isBootstrap)
300 * 10. bootclasspath entry #1
301 * 11. bootclasspath entry #2
304 * dvmOptimizeDexFile() in dalvik/vm/analysis/DexOptimize.c builds the
305 * argument list and calls this executable.
307 * The bootclasspath entries become the dependencies for this DEX file.
309 * The open file descriptor MUST NOT be for one of the bootclasspath files.
310 * The parent has the descriptor locked, and we'll try to lock it again as
311 * part of processing the bootclasspath. (We can catch this and return
312 * an error by comparing filenames or by opening the bootclasspath files
313 * and stat()ing them for inode numbers).
315 static int fromDex(int argc, char* const argv[])
318 bool vmStarted = false;
319 char* bootClassPath = NULL;
320 int fd, flags, vmBuildVersion;
322 const char* debugFileName;
327 /* don't have all mandatory args */
328 LOGE("Not enough arguments for --dex (found %d)\n", argc);
339 GET_ARG(vmBuildVersion, strtol, "bad vm build");
340 if (vmBuildVersion != DALVIK_VM_BUILD) {
341 LOGE("DexOpt: build rev does not match VM: %d vs %d\n",
342 vmBuildVersion, DALVIK_VM_BUILD);
345 GET_ARG(fd, strtol, "bad fd");
346 GET_ARG(offset, strtol, "bad offset");
347 GET_ARG(length, strtol, "bad length");
348 debugFileName = *++argv;
350 GET_ARG(modWhen, strtoul, "bad modWhen");
351 GET_ARG(crc, strtoul, "bad crc");
352 GET_ARG(flags, strtol, "bad flags");
354 LOGV("Args: fd=%d off=%ld len=%ld name='%s' mod=0x%x crc=0x%x flg=%d (argc=%d)\n",
355 fd, offset, length, debugFileName, modWhen, crc, flags, argc);
359 bootClassPath = strdup("");
366 for (i = 0, argp = argv; i < argc; i++) {
368 LOGV("DEP: '%s'\n", *argp);
369 bcpLen += strlen(*argp) + 1;
372 cp = bootClassPath = (char*) malloc(bcpLen +1);
373 for (i = 0, argp = argv; i < argc; i++) {
377 strLen = strlen(*argp);
380 memcpy(cp, *argp, strLen);
385 assert((int) strlen(bootClassPath) == bcpLen-1);
387 LOGV(" bootclasspath is '%s'\n", bootClassPath);
389 /* start the VM partway */
390 bool onlyOptVerifiedDex = false;
391 DexClassVerifyMode verifyMode;
392 DexOptimizerMode dexOptMode;
395 /* ugh -- upgrade these to a bit field if they get any more complex */
396 if ((flags & DEXOPT_VERIFY_ENABLED) != 0) {
397 if ((flags & DEXOPT_VERIFY_ALL) != 0)
398 verifyMode = VERIFY_MODE_ALL;
400 verifyMode = VERIFY_MODE_REMOTE;
402 verifyMode = VERIFY_MODE_NONE;
404 if ((flags & DEXOPT_OPT_ENABLED) != 0) {
405 if ((flags & DEXOPT_OPT_ALL) != 0)
406 dexOptMode = OPTIMIZE_MODE_ALL;
408 dexOptMode = OPTIMIZE_MODE_VERIFIED;
410 dexOptMode = OPTIMIZE_MODE_NONE;
412 if ((flags & DEXOPT_GEN_REGISTER_MAP) != 0) {
413 dexoptFlags |= DEXOPT_GEN_REGISTER_MAPS;
416 if (dvmPrepForDexOpt(bootClassPath, dexOptMode, verifyMode,
419 LOGE("VM init failed\n");
425 /* do the optimization */
426 if (!dvmContinueOptimization(fd, offset, length, debugFileName,
427 modWhen, crc, (flags & DEXOPT_IS_BOOTSTRAP) != 0))
429 LOGE("Optimization failed\n");
437 * In theory we should gracefully shut the VM down at this point. In
438 * practice that only matters if we're checking for memory leaks with
439 * valgrind -- simply exiting is much faster.
441 * As it turns out, the DEX optimizer plays a little fast and loose
442 * with class loading. We load all of the classes from a partially-
443 * formed DEX file, which is unmapped when we're done. If we want to
444 * do clean shutdown here, perhaps for testing with valgrind, we need
445 * to skip the munmap call there.
449 LOGI("DexOpt shutting down, result=%d\n", result);
454 //dvmLinearAllocDump(NULL);
458 extern int gDvm__totalInstr, gDvm__gcInstr, gDvm__gcData,
460 LOGI("GC DATA: totinst=%d, gcinst=%d, gcdata=%d simpled=%d\n",
461 gDvm__totalInstr, gDvm__gcInstr, gDvm__gcData, gDvm__gcSimpleData);
466 LOGV("DexOpt command complete (result=%d)\n", result);
471 * Main entry point. Decide where to go.
473 int main(int argc, char* const argv[])
475 set_process_name("dexopt");
477 setvbuf(stdout, NULL, _IONBF, 0);
480 if (strcmp(argv[1], "--zip") == 0)
481 return fromZip(argc, argv);
482 else if (strcmp(argv[1], "--dex") == 0)
483 return fromDex(argc, argv);
486 fprintf(stderr, "Usage: don't use this\n");