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 three 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).
29 * (3) On the host during a build for preoptimization. This behaves
30 * almost the same as (2), except it takes file names instead of
33 * There are some fragile aspects around bootclasspath entries, owing
34 * largely to the VM's history of working on whenever it thought it needed
35 * instead of strictly doing what it was told. If optimizing bootclasspath
36 * entries, always do them in the order in which they appear in the path.
39 #include "libdex/OptInvocation.h"
41 #include "utils/Log.h"
42 #include "cutils/process_name.h"
50 static const char* kClassesDex = "classes.dex";
54 * Extract "classes.dex" from zipFd into "cacheFd", leaving a little space
55 * up front for the DEX optimization header.
57 static int extractAndProcessZip(int zipFd, int cacheFd,
58 const char* debugFileName, bool isBootstrap, const char* bootClassPath,
59 const char* dexoptFlagStr)
69 memset(&zippy, 0, sizeof(zippy));
71 /* make sure we're still at the start of an empty file */
72 if (lseek(cacheFd, 0, SEEK_END) != 0) {
73 LOGE("DexOptZ: new cache file '%s' is not empty\n", debugFileName);
78 * Write a skeletal DEX optimization header. We want the classes.dex
79 * to come just after it.
81 err = dexOptCreateEmptyHeader(cacheFd);
85 /* record the file position so we can get back here later */
86 dexOffset = lseek(cacheFd, 0, SEEK_CUR);
91 * Open the zip archive, find the DEX entry.
93 if (dexZipPrepArchive(zipFd, debugFileName, &zippy) != 0) {
94 LOGW("DexOptZ: unable to open zip archive '%s'\n", debugFileName);
98 zipEntry = dexZipFindEntry(&zippy, kClassesDex);
99 if (zipEntry == NULL) {
100 LOGW("DexOptZ: zip archive '%s' does not include %s\n",
101 debugFileName, kClassesDex);
106 * Extract some info about the zip entry.
108 if (dexZipGetEntryInfo(&zippy, zipEntry, NULL, &uncompLen, NULL, NULL,
109 &modWhen, &crc32) != 0)
111 LOGW("DexOptZ: zip archive GetEntryInfo failed on %s\n", debugFileName);
115 uncompLen = uncompLen;
120 * Extract the DEX data into the cache file at the current offset.
122 if (dexZipExtractEntryToFile(&zippy, zipEntry, cacheFd) != 0) {
123 LOGW("DexOptZ: extraction of %s from %s failed\n",
124 kClassesDex, debugFileName);
129 * Prep the VM and perform the optimization.
131 DexClassVerifyMode verifyMode = VERIFY_MODE_ALL;
132 DexOptimizerMode dexOptMode = OPTIMIZE_MODE_VERIFIED;
133 int dexoptFlags = 0; /* bit flags, from enum DexoptFlags */
134 if (dexoptFlagStr[0] != '\0') {
138 opc = strstr(dexoptFlagStr, "v="); /* verification */
141 case 'n': verifyMode = VERIFY_MODE_NONE; break;
142 case 'r': verifyMode = VERIFY_MODE_REMOTE; break;
143 case 'a': verifyMode = VERIFY_MODE_ALL; break;
148 opc = strstr(dexoptFlagStr, "o="); /* optimization */
151 case 'n': dexOptMode = OPTIMIZE_MODE_NONE; break;
152 case 'v': dexOptMode = OPTIMIZE_MODE_VERIFIED; break;
153 case 'a': dexOptMode = OPTIMIZE_MODE_ALL; break;
158 opc = strstr(dexoptFlagStr, "m=y"); /* register map */
160 dexoptFlags |= DEXOPT_GEN_REGISTER_MAPS;
163 if (dvmPrepForDexOpt(bootClassPath, dexOptMode, verifyMode,
166 LOGE("DexOptZ: VM init failed\n");
172 /* do the optimization */
173 if (!dvmContinueOptimization(cacheFd, dexOffset, uncompLen, debugFileName,
174 modWhen, crc32, isBootstrap))
176 LOGE("Optimization failed\n");
180 /* we don't shut the VM down -- process is about to exit */
185 dexZipCloseArchive(&zippy);
190 * Common functionality for normal device-side processing as well as
193 static int processZipFile(int zipFd, int cacheFd, const char* zipName,
194 const char *dexoptFlags)
197 char* bcpCopy = NULL;
200 * Check to see if this is a bootstrap class entry. If so, truncate
203 const char* bcp = getenv("BOOTCLASSPATH");
205 LOGE("DexOptZ: BOOTCLASSPATH not set\n");
209 bool isBootstrap = false;
210 const char* match = strstr(bcp, zipName);
213 * TODO: we have a partial string match, but that doesn't mean
214 * we've matched an entire path component. We should make sure
215 * that we're matching on the full zipName, and if not we
216 * should re-do the strstr starting at (match+1).
218 * The scenario would be a bootclasspath with something like
219 * "/system/framework/core.jar" while we're trying to optimize
220 * "/framework/core.jar". Not very likely since all paths are
221 * absolute and end with ".jar", but not impossible.
223 int matchOffset = match - bcp;
224 if (matchOffset > 0 && bcp[matchOffset-1] == ':')
226 LOGV("DexOptZ: found '%s' in bootclasspath, cutting off at %d\n",
227 inputFileName, matchOffset);
228 bcpCopy = strdup(bcp);
229 bcpCopy[matchOffset] = '\0';
232 LOGD("DexOptZ: truncated BOOTCLASSPATH to '%s'\n", bcp);
236 result = extractAndProcessZip(zipFd, cacheFd, zipName, isBootstrap,
244 /* advance to the next arg and extract it */
245 #define GET_ARG(_var, _func, _msg) \
248 (_var) = _func(*++argv, &endp, 0); \
249 if (*endp != '\0') { \
250 LOGE("%s '%s'", _msg, *argv); \
257 * Parse arguments. We want:
258 * 0. (name of dexopt command -- ignored)
260 * 2. zip fd (input, read-only)
261 * 3. cache fd (output, read-write, locked with flock)
262 * 4. filename of zipfile being optimized (used for debug messages and
263 * for comparing against BOOTCLASSPATH; does not need to be
264 * accessible or even exist)
267 * The BOOTCLASSPATH environment variable is assumed to hold the correct
268 * boot class path. If the filename provided appears in the boot class
269 * path, the path will be truncated just before that entry (so that, if
270 * you were to dexopt "core.jar", your bootclasspath would be empty).
272 * This does not try to normalize the boot class path name, so the
273 * filename test won't catch you if you get creative.
275 static int fromZip(int argc, char* const argv[])
280 char* bcpCopy = NULL;
281 const char* dexoptFlags;
284 LOGE("Wrong number of args for --zip (found %d)\n", argc);
292 GET_ARG(zipFd, strtol, "bad zip fd");
293 GET_ARG(cacheFd, strtol, "bad cache fd");
296 dexoptFlags = *++argv;
299 result = processZipFile(zipFd, cacheFd, zipName, dexoptFlags);
306 * Parse arguments for a preoptimization run. This is when dalvikvm is run
307 * on a host to optimize dex files for eventual running on a (different)
309 * 0. (name of dexopt command -- ignored)
312 * 3. output file name
315 * The BOOTCLASSPATH environment variable is assumed to hold the correct
316 * boot class path. If the filename provided appears in the boot class
317 * path, the path will be truncated just before that entry (so that, if
318 * you were to dexopt "core.jar", your bootclasspath would be empty).
320 * This does not try to normalize the boot class path name, so the
321 * filename test won't catch you if you get creative.
323 static int preopt(int argc, char* const argv[])
331 * Use stderr here, since this variant is meant to be called on
334 fprintf(stderr, "Wrong number of args for --preopt (found %d)\n",
339 const char* zipName = argv[2];
340 const char* outName = argv[3];
341 const char* dexoptFlags = argv[4];
343 zipFd = open(zipName, O_RDONLY);
349 outFd = open(outName, O_RDWR | O_EXCL | O_CREAT, 0666);
355 result = processZipFile(zipFd, outFd, zipName, dexoptFlags);
370 * Parse arguments for an "old-style" invocation directly from the VM.
372 * Here's what we want:
373 * 0. (name of dexopt command -- ignored)
375 * 2. DALVIK_VM_BUILD value, as a sanity check
376 * 3. file descriptor, locked with flock, for DEX file being optimized
377 * 4. DEX offset within file
379 * 6. filename of file being optimized (for debug messages only)
380 * 7. modification date of source (goes into dependency section)
381 * 8. CRC of source (goes into dependency section)
382 * 9. flags (optimization level, isBootstrap)
383 * 10. bootclasspath entry #1
384 * 11. bootclasspath entry #2
387 * dvmOptimizeDexFile() in dalvik/vm/analysis/DexOptimize.c builds the
388 * argument list and calls this executable.
390 * The bootclasspath entries become the dependencies for this DEX file.
392 * The open file descriptor MUST NOT be for one of the bootclasspath files.
393 * The parent has the descriptor locked, and we'll try to lock it again as
394 * part of processing the bootclasspath. (We can catch this and return
395 * an error by comparing filenames or by opening the bootclasspath files
396 * and stat()ing them for inode numbers).
398 static int fromDex(int argc, char* const argv[])
401 bool vmStarted = false;
402 char* bootClassPath = NULL;
403 int fd, flags, vmBuildVersion;
405 const char* debugFileName;
410 /* don't have all mandatory args */
411 LOGE("Not enough arguments for --dex (found %d)\n", argc);
422 GET_ARG(vmBuildVersion, strtol, "bad vm build");
423 if (vmBuildVersion != DALVIK_VM_BUILD) {
424 LOGE("DexOpt: build rev does not match VM: %d vs %d\n",
425 vmBuildVersion, DALVIK_VM_BUILD);
428 GET_ARG(fd, strtol, "bad fd");
429 GET_ARG(offset, strtol, "bad offset");
430 GET_ARG(length, strtol, "bad length");
431 debugFileName = *++argv;
433 GET_ARG(modWhen, strtoul, "bad modWhen");
434 GET_ARG(crc, strtoul, "bad crc");
435 GET_ARG(flags, strtol, "bad flags");
437 LOGV("Args: fd=%d off=%ld len=%ld name='%s' mod=0x%x crc=0x%x flg=%d (argc=%d)\n",
438 fd, offset, length, debugFileName, modWhen, crc, flags, argc);
442 bootClassPath = strdup("");
449 for (i = 0, argp = argv; i < argc; i++) {
451 LOGV("DEP: '%s'\n", *argp);
452 bcpLen += strlen(*argp) + 1;
455 cp = bootClassPath = (char*) malloc(bcpLen +1);
456 for (i = 0, argp = argv; i < argc; i++) {
460 strLen = strlen(*argp);
463 memcpy(cp, *argp, strLen);
468 assert((int) strlen(bootClassPath) == bcpLen-1);
470 LOGV(" bootclasspath is '%s'\n", bootClassPath);
472 /* start the VM partway */
473 bool onlyOptVerifiedDex = false;
474 DexClassVerifyMode verifyMode;
475 DexOptimizerMode dexOptMode;
478 /* ugh -- upgrade these to a bit field if they get any more complex */
479 if ((flags & DEXOPT_VERIFY_ENABLED) != 0) {
480 if ((flags & DEXOPT_VERIFY_ALL) != 0)
481 verifyMode = VERIFY_MODE_ALL;
483 verifyMode = VERIFY_MODE_REMOTE;
485 verifyMode = VERIFY_MODE_NONE;
487 if ((flags & DEXOPT_OPT_ENABLED) != 0) {
488 if ((flags & DEXOPT_OPT_ALL) != 0)
489 dexOptMode = OPTIMIZE_MODE_ALL;
491 dexOptMode = OPTIMIZE_MODE_VERIFIED;
493 dexOptMode = OPTIMIZE_MODE_NONE;
495 if ((flags & DEXOPT_GEN_REGISTER_MAP) != 0) {
496 dexoptFlags |= DEXOPT_GEN_REGISTER_MAPS;
499 if (dvmPrepForDexOpt(bootClassPath, dexOptMode, verifyMode,
502 LOGE("VM init failed\n");
508 /* do the optimization */
509 if (!dvmContinueOptimization(fd, offset, length, debugFileName,
510 modWhen, crc, (flags & DEXOPT_IS_BOOTSTRAP) != 0))
512 LOGE("Optimization failed\n");
520 * In theory we should gracefully shut the VM down at this point. In
521 * practice that only matters if we're checking for memory leaks with
522 * valgrind -- simply exiting is much faster.
524 * As it turns out, the DEX optimizer plays a little fast and loose
525 * with class loading. We load all of the classes from a partially-
526 * formed DEX file, which is unmapped when we're done. If we want to
527 * do clean shutdown here, perhaps for testing with valgrind, we need
528 * to skip the munmap call there.
532 LOGI("DexOpt shutting down, result=%d\n", result);
537 //dvmLinearAllocDump(NULL);
541 extern int gDvm__totalInstr, gDvm__gcInstr, gDvm__gcData,
543 LOGI("GC DATA: totinst=%d, gcinst=%d, gcdata=%d simpled=%d\n",
544 gDvm__totalInstr, gDvm__gcInstr, gDvm__gcData, gDvm__gcSimpleData);
549 LOGV("DexOpt command complete (result=%d)\n", result);
554 * Main entry point. Decide where to go.
556 int main(int argc, char* const argv[])
558 set_process_name("dexopt");
560 setvbuf(stdout, NULL, _IONBF, 0);
563 if (strcmp(argv[1], "--zip") == 0)
564 return fromZip(argc, argv);
565 else if (strcmp(argv[1], "--dex") == 0)
566 return fromDex(argc, argv);
567 else if (strcmp(argv[1], "--preopt") == 0)
568 return preopt(argc, argv);
573 "Short version: Don't use this.\n\n"
574 "Slightly longer version: This system-internal tool is used to\n"
575 "produce optimized dex files. See the source code for details.\n");