OSDN Git Service

Merge branch 'aosp/honeycomb-LTE-release' into honeycomb-mr2-x86
[android-x86/dalvik.git] / dexopt / OptMain.c
index d897789..194a62b 100644 (file)
@@ -17,7 +17,7 @@
 /*
  * Command-line DEX optimization and verification entry point.
  *
- * There are two ways to launch this:
+ * There are three ways to launch this:
  * (1) From the VM.  This takes a dozen args, one of which is a file
  *     descriptor that acts as both input and output.  This allows us to
  *     remain ignorant of where the DEX data originally came from.
@@ -26,6 +26,9 @@
  *     a filename for debug messages.  Many assumptions are made about
  *     what's going on (verification + optimization are enabled, boot
  *     class path is in BOOTCLASSPATH, etc).
+ * (3) On the host during a build for preoptimization. This behaves
+ *     almost the same as (2), except it takes file names instead of
+ *     file descriptors.
  *
  * There are some fragile aspects around bootclasspath entries, owing
  * largely to the VM's history of working on whenever it thought it needed
 #include "utils/Log.h"
 #include "cutils/process_name.h"
 
+#include <fcntl.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
-#include <assert.h>
 
 static const char* kClassesDex = "classes.dex";
 
@@ -51,7 +55,7 @@ static const char* kClassesDex = "classes.dex";
  * up front for the DEX optimization header.
  */
 static int extractAndProcessZip(int zipFd, int cacheFd,
-    const char* debugFileName, int isBootstrap, const char* bootClassPath,
+    const char* debugFileName, bool isBootstrap, const char* bootClassPath,
     const char* dexoptFlagStr)
 {
     ZipArchive zippy;
@@ -121,12 +125,12 @@ static int extractAndProcessZip(int zipFd, int cacheFd,
         goto bail;
     }
 
-    /*
-     * Prep the VM and perform the optimization.
-     */
+    /* Parse the options. */
+
     DexClassVerifyMode verifyMode = VERIFY_MODE_ALL;
     DexOptimizerMode dexOptMode = OPTIMIZE_MODE_VERIFIED;
     int dexoptFlags = 0;        /* bit flags, from enum DexoptFlags */
+
     if (dexoptFlagStr[0] != '\0') {
         const char* opc;
         const char* val;
@@ -155,7 +159,21 @@ static int extractAndProcessZip(int zipFd, int cacheFd,
         if (opc != NULL) {
             dexoptFlags |= DEXOPT_GEN_REGISTER_MAPS;
         }
+
+        opc = strstr(dexoptFlagStr, "u=");      /* uniprocessor target */
+        if (opc != NULL) {
+            switch (*(opc+2)) {
+            case 'y':   dexoptFlags |= DEXOPT_UNIPROCESSOR;     break;
+            case 'n':   dexoptFlags |= DEXOPT_SMP;              break;
+            default:                                            break;
+            }
+        }
     }
+
+    /*
+     * Prep the VM and perform the optimization.
+     */
+
     if (dvmPrepForDexOpt(bootClassPath, dexOptMode, verifyMode,
             dexoptFlags) != 0)
     {
@@ -182,6 +200,60 @@ bail:
     return result;
 }
 
+/*
+ * Common functionality for normal device-side processing as well as
+ * preoptimization.
+ */
+static int processZipFile(int zipFd, int cacheFd, const char* zipName,
+        const char *dexoptFlags)
+{
+    int result = -1;
+    char* bcpCopy = NULL;
+
+    /*
+     * Check to see if this is a bootstrap class entry. If so, truncate
+     * the path.
+     */
+    const char* bcp = getenv("BOOTCLASSPATH");
+    if (bcp == NULL) {
+        LOGE("DexOptZ: BOOTCLASSPATH not set\n");
+        goto bail;
+    }
+
+    bool isBootstrap = false;
+    const char* match = strstr(bcp, zipName);
+    if (match != NULL) {
+        /*
+         * TODO: we have a partial string match, but that doesn't mean
+         * we've matched an entire path component. We should make sure
+         * that we're matching on the full zipName, and if not we
+         * should re-do the strstr starting at (match+1).
+         *
+         * The scenario would be a bootclasspath with something like
+         * "/system/framework/core.jar" while we're trying to optimize
+         * "/framework/core.jar". Not very likely since all paths are
+         * absolute and end with ".jar", but not impossible.
+         */
+        int matchOffset = match - bcp;
+        if (matchOffset > 0 && bcp[matchOffset-1] == ':')
+            matchOffset--;
+        LOGV("DexOptZ: found '%s' in bootclasspath, cutting off at %d\n",
+            zipName, matchOffset);
+        bcpCopy = strdup(bcp);
+        bcpCopy[matchOffset] = '\0';
+
+        bcp = bcpCopy;
+        LOGD("DexOptZ: truncated BOOTCLASSPATH to '%s'\n", bcp);
+        isBootstrap = true;
+    }
+
+    result = extractAndProcessZip(zipFd, cacheFd, zipName, isBootstrap,
+            bcp, dexoptFlags);
+
+bail:
+    free(bcpCopy);
+    return result;
+}
 
 /* advance to the next arg and extract it */
 #define GET_ARG(_var, _func, _msg)                                          \
@@ -201,8 +273,8 @@ bail:
  *   1. "--zip"
  *   2. zip fd (input, read-only)
  *   3. cache fd (output, read-write, locked with flock)
- *   4. filename of file being optimized (used for debug messages and
- *      for comparing against BOOTCLASSPATH -- does not need to be
+ *   4. filename of zipfile being optimized (used for debug messages and
+ *      for comparing against BOOTCLASSPATH; does not need to be
  *      accessible or even exist)
  *   5. dexopt flags
  *
@@ -217,10 +289,10 @@ bail:
 static int fromZip(int argc, char* const argv[])
 {
     int result = -1;
-    int zipFd, cacheFd, vmBuildVersion;
-    const char* inputFileName;
+    int zipFd, cacheFd;
+    const char* zipName;
     char* bcpCopy = NULL;
-    const char* dexoptFlagStr;
+    const char* dexoptFlags;
 
     if (argc != 6) {
         LOGE("Wrong number of args for --zip (found %d)\n", argc);
@@ -233,53 +305,85 @@ static int fromZip(int argc, char* const argv[])
 
     GET_ARG(zipFd, strtol, "bad zip fd");
     GET_ARG(cacheFd, strtol, "bad cache fd");
-    inputFileName = *++argv;
+    zipName = *++argv;
     --argc;
-    dexoptFlagStr = *++argv;
+    dexoptFlags = *++argv;
     --argc;
 
-    /*
-     * Check to see if this is a bootstrap class entry.  If so, truncate
-     * the path.
-     */
-    const char* bcp = getenv("BOOTCLASSPATH");
-    if (bcp == NULL) {
-        LOGE("DexOptZ: BOOTCLASSPATH not set\n");
-        goto bail;
-    }
+    result = processZipFile(zipFd, cacheFd, zipName, dexoptFlags);
 
-    int isBootstrap = false;
-    const char* match = strstr(bcp, inputFileName);
-    if (match != NULL) {
+bail:
+    return result;
+}
+
+/*
+ * Parse arguments for a preoptimization run. This is when dalvikvm is run
+ * on a host to optimize dex files for eventual running on a (different)
+ * device. We want:
+ *   0. (name of dexopt command -- ignored)
+ *   1. "--preopt"
+ *   2. zipfile name
+ *   3. output file name
+ *   4. dexopt flags
+ *
+ * The BOOTCLASSPATH environment variable is assumed to hold the correct
+ * boot class path.  If the filename provided appears in the boot class
+ * path, the path will be truncated just before that entry (so that, if
+ * you were to dexopt "core.jar", your bootclasspath would be empty).
+ *
+ * This does not try to normalize the boot class path name, so the
+ * filename test won't catch you if you get creative.
+ */
+static int preopt(int argc, char* const argv[])
+{
+    int zipFd = -1;
+    int outFd = -1;
+    int result = -1;
+
+    if (argc != 5) {
         /*
-         * TODO: we have a partial string match, but that doesn't mean
-         * we've matched an entire path component.  We should make sure
-         * that we're matching on the full inputFileName, and if not we
-         * should re-do the strstr starting at (match+1).
-         *
-         * The scenario would be a bootclasspath with something like
-         * "/system/framework/core.jar" while we're trying to optimize
-         * "/framework/core.jar".  Not very likely since all paths are
-         * absolute and end with ".jar", but not impossible.
+         * Use stderr here, since this variant is meant to be called on
+         * the host side.
          */
-        int matchOffset = match - bcp;
-        if (matchOffset > 0 && bcp[matchOffset-1] == ':')
-            matchOffset--;
-        LOGV("DexOptZ: found '%s' in bootclasspath, cutting off at %d\n",
-            inputFileName, matchOffset);
-        bcpCopy = strdup(bcp);
-        bcpCopy[matchOffset] = '\0';
+        fprintf(stderr, "Wrong number of args for --preopt (found %d)\n",
+                argc);
+        goto bail;
+    }
 
-        bcp = bcpCopy;
-        LOGD("DexOptZ: truncated BOOTCLASSPATH to '%s'\n", bcp);
-        isBootstrap = true;
+    const char* zipName = argv[2];
+    const char* outName = argv[3];
+    const char* dexoptFlags = argv[4];
+
+    if (strstr(dexoptFlags, "u=y") == NULL &&
+        strstr(dexoptFlags, "u=n") == NULL)
+    {
+        fprintf(stderr, "Either 'u=y' or 'u=n' must be specified\n");
+        goto bail;
+    }
+
+    zipFd = open(zipName, O_RDONLY);
+    if (zipFd < 0) {
+        perror(argv[0]);
+        goto bail;
+    }
+
+    outFd = open(outName, O_RDWR | O_EXCL | O_CREAT, 0666);
+    if (outFd < 0) {
+        perror(argv[0]);
+        goto bail;
     }
 
-    result = extractAndProcessZip(zipFd, cacheFd, inputFileName,
-                isBootstrap, bcp, dexoptFlagStr);
+    result = processZipFile(zipFd, outFd, zipName, dexoptFlags);
 
 bail:
-    free(bcpCopy);
+    if (zipFd >= 0) {
+        close(zipFd);
+    }
+
+    if (outFd >= 0) {
+        close(outFd);
+    }
+
     return result;
 }
 
@@ -390,7 +494,6 @@ static int fromDex(int argc, char* const argv[])
     bool onlyOptVerifiedDex = false;
     DexClassVerifyMode verifyMode;
     DexOptimizerMode dexOptMode;
-    int dexoptFlags = 0;
 
     /* ugh -- upgrade these to a bit field if they get any more complex */
     if ((flags & DEXOPT_VERIFY_ENABLED) != 0) {
@@ -409,13 +512,8 @@ static int fromDex(int argc, char* const argv[])
     } else {
         dexOptMode = OPTIMIZE_MODE_NONE;
     }
-    if ((flags & DEXOPT_GEN_REGISTER_MAP) != 0) {
-        dexoptFlags |= DEXOPT_GEN_REGISTER_MAPS;
-    }
 
-    if (dvmPrepForDexOpt(bootClassPath, dexOptMode, verifyMode,
-            dexoptFlags) != 0)
-    {
+    if (dvmPrepForDexOpt(bootClassPath, dexOptMode, verifyMode, flags) != 0) {
         LOGE("VM init failed\n");
         goto bail;
     }
@@ -481,9 +579,15 @@ int main(int argc, char* const argv[])
             return fromZip(argc, argv);
         else if (strcmp(argv[1], "--dex") == 0)
             return fromDex(argc, argv);
+        else if (strcmp(argv[1], "--preopt") == 0)
+            return preopt(argc, argv);
     }
 
-    fprintf(stderr, "Usage: don't use this\n");
+    fprintf(stderr,
+        "Usage:\n\n"
+        "Short version: Don't use this.\n\n"
+        "Slightly longer version: This system-internal tool is used to\n"
+        "produce optimized dex files. See the source code for details.\n");
+
     return 1;
 }
-