OSDN Git Service

Merge branch 'aosp/honeycomb-LTE-release' into honeycomb-mr2-x86
[android-x86/dalvik.git] / dexopt / OptMain.c
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 /*
18  * Command-line DEX optimization and verification entry point.
19  *
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
31  *     file descriptors.
32  *
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.
37  */
38 #include "Dalvik.h"
39 #include "libdex/OptInvocation.h"
40
41 #include "utils/Log.h"
42 #include "cutils/process_name.h"
43
44 #include <fcntl.h>
45 #include <stdbool.h>
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include <string.h>
49
50 static const char* kClassesDex = "classes.dex";
51
52
53 /*
54  * Extract "classes.dex" from zipFd into "cacheFd", leaving a little space
55  * up front for the DEX optimization header.
56  */
57 static int extractAndProcessZip(int zipFd, int cacheFd,
58     const char* debugFileName, bool isBootstrap, const char* bootClassPath,
59     const char* dexoptFlagStr)
60 {
61     ZipArchive zippy;
62     ZipEntry zipEntry;
63     size_t uncompLen;
64     long modWhen, crc32;
65     off_t dexOffset;
66     int err;
67     int result = -1;
68
69     memset(&zippy, 0, sizeof(zippy));
70
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);
74         goto bail;
75     }
76
77     /*
78      * Write a skeletal DEX optimization header.  We want the classes.dex
79      * to come just after it.
80      */
81     err = dexOptCreateEmptyHeader(cacheFd);
82     if (err != 0)
83         goto bail;
84
85     /* record the file position so we can get back here later */
86     dexOffset = lseek(cacheFd, 0, SEEK_CUR);
87     if (dexOffset < 0)
88         goto bail;
89
90     /*
91      * Open the zip archive, find the DEX entry.
92      */
93     if (dexZipPrepArchive(zipFd, debugFileName, &zippy) != 0) {
94         LOGW("DexOptZ: unable to open zip archive '%s'\n", debugFileName);
95         goto bail;
96     }
97
98     zipEntry = dexZipFindEntry(&zippy, kClassesDex);
99     if (zipEntry == NULL) {
100         LOGW("DexOptZ: zip archive '%s' does not include %s\n",
101             debugFileName, kClassesDex);
102         goto bail;
103     }
104
105     /*
106      * Extract some info about the zip entry.
107      */
108     if (dexZipGetEntryInfo(&zippy, zipEntry, NULL, &uncompLen, NULL, NULL,
109             &modWhen, &crc32) != 0)
110     {
111         LOGW("DexOptZ: zip archive GetEntryInfo failed on %s\n", debugFileName);
112         goto bail;
113     }
114
115     uncompLen = uncompLen;
116     modWhen = modWhen;
117     crc32 = crc32;
118
119     /*
120      * Extract the DEX data into the cache file at the current offset.
121      */
122     if (dexZipExtractEntryToFile(&zippy, zipEntry, cacheFd) != 0) {
123         LOGW("DexOptZ: extraction of %s from %s failed\n",
124             kClassesDex, debugFileName);
125         goto bail;
126     }
127
128     /* Parse the options. */
129
130     DexClassVerifyMode verifyMode = VERIFY_MODE_ALL;
131     DexOptimizerMode dexOptMode = OPTIMIZE_MODE_VERIFIED;
132     int dexoptFlags = 0;        /* bit flags, from enum DexoptFlags */
133
134     if (dexoptFlagStr[0] != '\0') {
135         const char* opc;
136         const char* val;
137
138         opc = strstr(dexoptFlagStr, "v=");      /* verification */
139         if (opc != NULL) {
140             switch (*(opc+2)) {
141             case 'n':   verifyMode = VERIFY_MODE_NONE;          break;
142             case 'r':   verifyMode = VERIFY_MODE_REMOTE;        break;
143             case 'a':   verifyMode = VERIFY_MODE_ALL;           break;
144             default:                                            break;
145             }
146         }
147
148         opc = strstr(dexoptFlagStr, "o=");      /* optimization */
149         if (opc != NULL) {
150             switch (*(opc+2)) {
151             case 'n':   dexOptMode = OPTIMIZE_MODE_NONE;        break;
152             case 'v':   dexOptMode = OPTIMIZE_MODE_VERIFIED;    break;
153             case 'a':   dexOptMode = OPTIMIZE_MODE_ALL;         break;
154             default:                                            break;
155             }
156         }
157
158         opc = strstr(dexoptFlagStr, "m=y");     /* register map */
159         if (opc != NULL) {
160             dexoptFlags |= DEXOPT_GEN_REGISTER_MAPS;
161         }
162
163         opc = strstr(dexoptFlagStr, "u=");      /* uniprocessor target */
164         if (opc != NULL) {
165             switch (*(opc+2)) {
166             case 'y':   dexoptFlags |= DEXOPT_UNIPROCESSOR;     break;
167             case 'n':   dexoptFlags |= DEXOPT_SMP;              break;
168             default:                                            break;
169             }
170         }
171     }
172
173     /*
174      * Prep the VM and perform the optimization.
175      */
176
177     if (dvmPrepForDexOpt(bootClassPath, dexOptMode, verifyMode,
178             dexoptFlags) != 0)
179     {
180         LOGE("DexOptZ: VM init failed\n");
181         goto bail;
182     }
183
184     //vmStarted = 1;
185
186     /* do the optimization */
187     if (!dvmContinueOptimization(cacheFd, dexOffset, uncompLen, debugFileName,
188             modWhen, crc32, isBootstrap))
189     {
190         LOGE("Optimization failed\n");
191         goto bail;
192     }
193
194     /* we don't shut the VM down -- process is about to exit */
195
196     result = 0;
197
198 bail:
199     dexZipCloseArchive(&zippy);
200     return result;
201 }
202
203 /*
204  * Common functionality for normal device-side processing as well as
205  * preoptimization.
206  */
207 static int processZipFile(int zipFd, int cacheFd, const char* zipName,
208         const char *dexoptFlags)
209 {
210     int result = -1;
211     char* bcpCopy = NULL;
212
213     /*
214      * Check to see if this is a bootstrap class entry. If so, truncate
215      * the path.
216      */
217     const char* bcp = getenv("BOOTCLASSPATH");
218     if (bcp == NULL) {
219         LOGE("DexOptZ: BOOTCLASSPATH not set\n");
220         goto bail;
221     }
222
223     bool isBootstrap = false;
224     const char* match = strstr(bcp, zipName);
225     if (match != NULL) {
226         /*
227          * TODO: we have a partial string match, but that doesn't mean
228          * we've matched an entire path component. We should make sure
229          * that we're matching on the full zipName, and if not we
230          * should re-do the strstr starting at (match+1).
231          *
232          * The scenario would be a bootclasspath with something like
233          * "/system/framework/core.jar" while we're trying to optimize
234          * "/framework/core.jar". Not very likely since all paths are
235          * absolute and end with ".jar", but not impossible.
236          */
237         int matchOffset = match - bcp;
238         if (matchOffset > 0 && bcp[matchOffset-1] == ':')
239             matchOffset--;
240         LOGV("DexOptZ: found '%s' in bootclasspath, cutting off at %d\n",
241             zipName, matchOffset);
242         bcpCopy = strdup(bcp);
243         bcpCopy[matchOffset] = '\0';
244
245         bcp = bcpCopy;
246         LOGD("DexOptZ: truncated BOOTCLASSPATH to '%s'\n", bcp);
247         isBootstrap = true;
248     }
249
250     result = extractAndProcessZip(zipFd, cacheFd, zipName, isBootstrap,
251             bcp, dexoptFlags);
252
253 bail:
254     free(bcpCopy);
255     return result;
256 }
257
258 /* advance to the next arg and extract it */
259 #define GET_ARG(_var, _func, _msg)                                          \
260     {                                                                       \
261         char* endp;                                                         \
262         (_var) = _func(*++argv, &endp, 0);                                  \
263         if (*endp != '\0') {                                                \
264             LOGE("%s '%s'", _msg, *argv);                                   \
265             goto bail;                                                      \
266         }                                                                   \
267         --argc;                                                             \
268     }
269
270 /*
271  * Parse arguments.  We want:
272  *   0. (name of dexopt command -- ignored)
273  *   1. "--zip"
274  *   2. zip fd (input, read-only)
275  *   3. cache fd (output, read-write, locked with flock)
276  *   4. filename of zipfile being optimized (used for debug messages and
277  *      for comparing against BOOTCLASSPATH; does not need to be
278  *      accessible or even exist)
279  *   5. dexopt flags
280  *
281  * The BOOTCLASSPATH environment variable is assumed to hold the correct
282  * boot class path.  If the filename provided appears in the boot class
283  * path, the path will be truncated just before that entry (so that, if
284  * you were to dexopt "core.jar", your bootclasspath would be empty).
285  *
286  * This does not try to normalize the boot class path name, so the
287  * filename test won't catch you if you get creative.
288  */
289 static int fromZip(int argc, char* const argv[])
290 {
291     int result = -1;
292     int zipFd, cacheFd;
293     const char* zipName;
294     char* bcpCopy = NULL;
295     const char* dexoptFlags;
296
297     if (argc != 6) {
298         LOGE("Wrong number of args for --zip (found %d)\n", argc);
299         goto bail;
300     }
301
302     /* skip "--zip" */
303     argc--;
304     argv++;
305
306     GET_ARG(zipFd, strtol, "bad zip fd");
307     GET_ARG(cacheFd, strtol, "bad cache fd");
308     zipName = *++argv;
309     --argc;
310     dexoptFlags = *++argv;
311     --argc;
312
313     result = processZipFile(zipFd, cacheFd, zipName, dexoptFlags);
314
315 bail:
316     return result;
317 }
318
319 /*
320  * Parse arguments for a preoptimization run. This is when dalvikvm is run
321  * on a host to optimize dex files for eventual running on a (different)
322  * device. We want:
323  *   0. (name of dexopt command -- ignored)
324  *   1. "--preopt"
325  *   2. zipfile name
326  *   3. output file name
327  *   4. dexopt flags
328  *
329  * The BOOTCLASSPATH environment variable is assumed to hold the correct
330  * boot class path.  If the filename provided appears in the boot class
331  * path, the path will be truncated just before that entry (so that, if
332  * you were to dexopt "core.jar", your bootclasspath would be empty).
333  *
334  * This does not try to normalize the boot class path name, so the
335  * filename test won't catch you if you get creative.
336  */
337 static int preopt(int argc, char* const argv[])
338 {
339     int zipFd = -1;
340     int outFd = -1;
341     int result = -1;
342
343     if (argc != 5) {
344         /*
345          * Use stderr here, since this variant is meant to be called on
346          * the host side.
347          */
348         fprintf(stderr, "Wrong number of args for --preopt (found %d)\n",
349                 argc);
350         goto bail;
351     }
352
353     const char* zipName = argv[2];
354     const char* outName = argv[3];
355     const char* dexoptFlags = argv[4];
356
357     if (strstr(dexoptFlags, "u=y") == NULL &&
358         strstr(dexoptFlags, "u=n") == NULL)
359     {
360         fprintf(stderr, "Either 'u=y' or 'u=n' must be specified\n");
361         goto bail;
362     }
363
364     zipFd = open(zipName, O_RDONLY);
365     if (zipFd < 0) {
366         perror(argv[0]);
367         goto bail;
368     }
369
370     outFd = open(outName, O_RDWR | O_EXCL | O_CREAT, 0666);
371     if (outFd < 0) {
372         perror(argv[0]);
373         goto bail;
374     }
375
376     result = processZipFile(zipFd, outFd, zipName, dexoptFlags);
377
378 bail:
379     if (zipFd >= 0) {
380         close(zipFd);
381     }
382
383     if (outFd >= 0) {
384         close(outFd);
385     }
386
387     return result;
388 }
389
390 /*
391  * Parse arguments for an "old-style" invocation directly from the VM.
392  *
393  * Here's what we want:
394  *   0. (name of dexopt command -- ignored)
395  *   1. "--dex"
396  *   2. DALVIK_VM_BUILD value, as a sanity check
397  *   3. file descriptor, locked with flock, for DEX file being optimized
398  *   4. DEX offset within file
399  *   5. DEX length
400  *   6. filename of file being optimized (for debug messages only)
401  *   7. modification date of source (goes into dependency section)
402  *   8. CRC of source (goes into dependency section)
403  *   9. flags (optimization level, isBootstrap)
404  *  10. bootclasspath entry #1
405  *  11. bootclasspath entry #2
406  *   ...
407  *
408  * dvmOptimizeDexFile() in dalvik/vm/analysis/DexOptimize.c builds the
409  * argument list and calls this executable.
410  *
411  * The bootclasspath entries become the dependencies for this DEX file.
412  *
413  * The open file descriptor MUST NOT be for one of the bootclasspath files.
414  * The parent has the descriptor locked, and we'll try to lock it again as
415  * part of processing the bootclasspath.  (We can catch this and return
416  * an error by comparing filenames or by opening the bootclasspath files
417  * and stat()ing them for inode numbers).
418  */
419 static int fromDex(int argc, char* const argv[])
420 {
421     int result = -1;
422     bool vmStarted = false;
423     char* bootClassPath = NULL;
424     int fd, flags, vmBuildVersion;
425     long offset, length;
426     const char* debugFileName;
427     u4 crc, modWhen;
428     char* endp;
429
430     if (argc < 10) {
431         /* don't have all mandatory args */
432         LOGE("Not enough arguments for --dex (found %d)\n", argc);
433         goto bail;
434     }
435
436     /* skip "--dex" */
437     argc--;
438     argv++;
439
440     /*
441      * Extract the args.
442      */
443     GET_ARG(vmBuildVersion, strtol, "bad vm build");
444     if (vmBuildVersion != DALVIK_VM_BUILD) {
445         LOGE("DexOpt: build rev does not match VM: %d vs %d\n",
446             vmBuildVersion, DALVIK_VM_BUILD);
447         goto bail;
448     }
449     GET_ARG(fd, strtol, "bad fd");
450     GET_ARG(offset, strtol, "bad offset");
451     GET_ARG(length, strtol, "bad length");
452     debugFileName = *++argv;
453     --argc;
454     GET_ARG(modWhen, strtoul, "bad modWhen");
455     GET_ARG(crc, strtoul, "bad crc");
456     GET_ARG(flags, strtol, "bad flags");
457
458     LOGV("Args: fd=%d off=%ld len=%ld name='%s' mod=0x%x crc=0x%x flg=%d (argc=%d)\n",
459         fd, offset, length, debugFileName, modWhen, crc, flags, argc);
460     assert(argc > 0);
461
462     if (--argc == 0) {
463         bootClassPath = strdup("");
464     } else {
465         int i, bcpLen;
466         char* const* argp;
467         char* cp;
468
469         bcpLen = 0;
470         for (i = 0, argp = argv; i < argc; i++) {
471             ++argp;
472             LOGV("DEP: '%s'\n", *argp);
473             bcpLen += strlen(*argp) + 1;
474         }
475
476         cp = bootClassPath = (char*) malloc(bcpLen +1);
477         for (i = 0, argp = argv; i < argc; i++) {
478             int strLen;
479
480             ++argp;
481             strLen = strlen(*argp);
482             if (i != 0)
483                 *cp++ = ':';
484             memcpy(cp, *argp, strLen);
485             cp += strLen;
486         }
487         *cp = '\0';
488
489         assert((int) strlen(bootClassPath) == bcpLen-1);
490     }
491     LOGV("  bootclasspath is '%s'\n", bootClassPath);
492
493     /* start the VM partway */
494     bool onlyOptVerifiedDex = false;
495     DexClassVerifyMode verifyMode;
496     DexOptimizerMode dexOptMode;
497
498     /* ugh -- upgrade these to a bit field if they get any more complex */
499     if ((flags & DEXOPT_VERIFY_ENABLED) != 0) {
500         if ((flags & DEXOPT_VERIFY_ALL) != 0)
501             verifyMode = VERIFY_MODE_ALL;
502         else
503             verifyMode = VERIFY_MODE_REMOTE;
504     } else {
505         verifyMode = VERIFY_MODE_NONE;
506     }
507     if ((flags & DEXOPT_OPT_ENABLED) != 0) {
508         if ((flags & DEXOPT_OPT_ALL) != 0)
509             dexOptMode = OPTIMIZE_MODE_ALL;
510         else
511             dexOptMode = OPTIMIZE_MODE_VERIFIED;
512     } else {
513         dexOptMode = OPTIMIZE_MODE_NONE;
514     }
515
516     if (dvmPrepForDexOpt(bootClassPath, dexOptMode, verifyMode, flags) != 0) {
517         LOGE("VM init failed\n");
518         goto bail;
519     }
520
521     vmStarted = true;
522
523     /* do the optimization */
524     if (!dvmContinueOptimization(fd, offset, length, debugFileName,
525             modWhen, crc, (flags & DEXOPT_IS_BOOTSTRAP) != 0))
526     {
527         LOGE("Optimization failed\n");
528         goto bail;
529     }
530
531     result = 0;
532
533 bail:
534     /*
535      * In theory we should gracefully shut the VM down at this point.  In
536      * practice that only matters if we're checking for memory leaks with
537      * valgrind -- simply exiting is much faster.
538      *
539      * As it turns out, the DEX optimizer plays a little fast and loose
540      * with class loading.  We load all of the classes from a partially-
541      * formed DEX file, which is unmapped when we're done.  If we want to
542      * do clean shutdown here, perhaps for testing with valgrind, we need
543      * to skip the munmap call there.
544      */
545 #if 0
546     if (vmStarted) {
547         LOGI("DexOpt shutting down, result=%d\n", result);
548         dvmShutdown();
549     }
550 #endif
551
552     //dvmLinearAllocDump(NULL);
553
554 #if 0
555     {
556         extern int gDvm__totalInstr, gDvm__gcInstr, gDvm__gcData,
557                gDvm__gcSimpleData;
558         LOGI("GC DATA: totinst=%d, gcinst=%d, gcdata=%d simpled=%d\n",
559             gDvm__totalInstr, gDvm__gcInstr, gDvm__gcData, gDvm__gcSimpleData);
560     }
561 #endif
562
563     free(bootClassPath);
564     LOGV("DexOpt command complete (result=%d)\n", result);
565     return result;
566 }
567
568 /*
569  * Main entry point.  Decide where to go.
570  */
571 int main(int argc, char* const argv[])
572 {
573     set_process_name("dexopt");
574
575     setvbuf(stdout, NULL, _IONBF, 0);
576
577     if (argc > 1) {
578         if (strcmp(argv[1], "--zip") == 0)
579             return fromZip(argc, argv);
580         else if (strcmp(argv[1], "--dex") == 0)
581             return fromDex(argc, argv);
582         else if (strcmp(argv[1], "--preopt") == 0)
583             return preopt(argc, argv);
584     }
585
586     fprintf(stderr,
587         "Usage:\n\n"
588         "Short version: Don't use this.\n\n"
589         "Slightly longer version: This system-internal tool is used to\n"
590         "produce optimized dex files. See the source code for details.\n");
591
592     return 1;
593 }