1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License.
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License.
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Command-line DEX optimization and verification entry point.
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
204701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein * There are three ways to launch this:
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * (1) From the VM.  This takes a dozen args, one of which is a file
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     descriptor that acts as both input and output.  This allows us to
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     remain ignorant of where the DEX data originally came from.
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * (2) From installd or another native application.  Pass in a file
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     descriptor for a zip file, a file descriptor for the output, and
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     a filename for debug messages.  Many assumptions are made about
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     what's going on (verification + optimization are enabled, boot
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     class path is in BOOTCLASSPATH, etc).
294701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein * (3) On the host during a build for preoptimization. This behaves
304701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein *     almost the same as (2), except it takes file names instead of
314701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein *     file descriptors.
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * There are some fragile aspects around bootclasspath entries, owing
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * largely to the VM's history of working on whenever it thought it needed
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * instead of strictly doing what it was told.  If optimizing bootclasspath
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * entries, always do them in the order in which they appear in the path.
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "Dalvik.h"
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "libdex/OptInvocation.h"
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
41ac518bce0e538749b12c09d4400cb0d30c350391Elliott Hughes#include "cutils/log.h"
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "cutils/process_name.h"
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
444701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein#include <fcntl.h>
454701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein#include <stdbool.h>
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <stdlib.h>
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <stdio.h>
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <string.h>
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic const char* kClassesDex = "classes.dex";
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Extract "classes.dex" from zipFd into "cacheFd", leaving a little space
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * up front for the DEX optimization header.
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic int extractAndProcessZip(int zipFd, int cacheFd,
584701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    const char* debugFileName, bool isBootstrap, const char* bootClassPath,
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const char* dexoptFlagStr)
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    ZipArchive zippy;
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    ZipEntry zipEntry;
638911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden    size_t uncompLen;
648911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden    long modWhen, crc32;
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    off_t dexOffset;
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int err;
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int result = -1;
68bfc9799b1a53fd6f6136d07e6278d4538cf70f13Carl Shapiro    int dexoptFlags = 0;        /* bit flags, from enum DexoptFlags */
69bfc9799b1a53fd6f6136d07e6278d4538cf70f13Carl Shapiro    DexClassVerifyMode verifyMode = VERIFY_MODE_ALL;
70bfc9799b1a53fd6f6136d07e6278d4538cf70f13Carl Shapiro    DexOptimizerMode dexOptMode = OPTIMIZE_MODE_VERIFIED;
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    memset(&zippy, 0, sizeof(zippy));
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* make sure we're still at the start of an empty file */
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (lseek(cacheFd, 0, SEEK_END) != 0) {
76c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("DexOptZ: new cache file '%s' is not empty", debugFileName);
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Write a skeletal DEX optimization header.  We want the classes.dex
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * to come just after it.
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    err = dexOptCreateEmptyHeader(cacheFd);
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (err != 0)
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* record the file position so we can get back here later */
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dexOffset = lseek(cacheFd, 0, SEEK_CUR);
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (dexOffset < 0)
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Open the zip archive, find the DEX entry.
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (dexZipPrepArchive(zipFd, debugFileName, &zippy) != 0) {
97e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("DexOptZ: unable to open zip archive '%s'", debugFileName);
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    zipEntry = dexZipFindEntry(&zippy, kClassesDex);
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (zipEntry == NULL) {
103e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("DexOptZ: zip archive '%s' does not include %s",
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            debugFileName, kClassesDex);
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Extract some info about the zip entry.
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1118911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden    if (dexZipGetEntryInfo(&zippy, zipEntry, NULL, &uncompLen, NULL, NULL,
1128911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden            &modWhen, &crc32) != 0)
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
114e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("DexOptZ: zip archive GetEntryInfo failed on %s", debugFileName);
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    uncompLen = uncompLen;
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    modWhen = modWhen;
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    crc32 = crc32;
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Extract the DEX data into the cache file at the current offset.
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1258911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden    if (dexZipExtractEntryToFile(&zippy, zipEntry, cacheFd) != 0) {
126e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("DexOptZ: extraction of %s from %s failed",
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            kClassesDex, debugFileName);
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
131148283d71a7e35b9b506cbb49294b6822719c25eDan Bornstein    /* Parse the options. */
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (dexoptFlagStr[0] != '\0') {
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        const char* opc;
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        const char* val;
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        opc = strstr(dexoptFlagStr, "v=");      /* verification */
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (opc != NULL) {
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            switch (*(opc+2)) {
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            case 'n':   verifyMode = VERIFY_MODE_NONE;          break;
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            case 'r':   verifyMode = VERIFY_MODE_REMOTE;        break;
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            case 'a':   verifyMode = VERIFY_MODE_ALL;           break;
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            default:                                            break;
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        opc = strstr(dexoptFlagStr, "o=");      /* optimization */
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (opc != NULL) {
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            switch (*(opc+2)) {
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            case 'n':   dexOptMode = OPTIMIZE_MODE_NONE;        break;
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            case 'v':   dexOptMode = OPTIMIZE_MODE_VERIFIED;    break;
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            case 'a':   dexOptMode = OPTIMIZE_MODE_ALL;         break;
152d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden            case 'f':   dexOptMode = OPTIMIZE_MODE_FULL;        break;
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            default:                                            break;
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        opc = strstr(dexoptFlagStr, "m=y");     /* register map */
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (opc != NULL) {
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dexoptFlags |= DEXOPT_GEN_REGISTER_MAPS;
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
161148283d71a7e35b9b506cbb49294b6822719c25eDan Bornstein
162d8b5f50d0c6c9a0ce157e89df4ee1e8eb8b334c3Andy McFadden        opc = strstr(dexoptFlagStr, "u=");      /* uniprocessor target */
163148283d71a7e35b9b506cbb49294b6822719c25eDan Bornstein        if (opc != NULL) {
164d8b5f50d0c6c9a0ce157e89df4ee1e8eb8b334c3Andy McFadden            switch (*(opc+2)) {
165d8b5f50d0c6c9a0ce157e89df4ee1e8eb8b334c3Andy McFadden            case 'y':   dexoptFlags |= DEXOPT_UNIPROCESSOR;     break;
166d8b5f50d0c6c9a0ce157e89df4ee1e8eb8b334c3Andy McFadden            case 'n':   dexoptFlags |= DEXOPT_SMP;              break;
167d8b5f50d0c6c9a0ce157e89df4ee1e8eb8b334c3Andy McFadden            default:                                            break;
168d8b5f50d0c6c9a0ce157e89df4ee1e8eb8b334c3Andy McFadden            }
169148283d71a7e35b9b506cbb49294b6822719c25eDan Bornstein        }
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
171148283d71a7e35b9b506cbb49294b6822719c25eDan Bornstein
172148283d71a7e35b9b506cbb49294b6822719c25eDan Bornstein    /*
173148283d71a7e35b9b506cbb49294b6822719c25eDan Bornstein     * Prep the VM and perform the optimization.
174148283d71a7e35b9b506cbb49294b6822719c25eDan Bornstein     */
175148283d71a7e35b9b506cbb49294b6822719c25eDan Bornstein
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (dvmPrepForDexOpt(bootClassPath, dexOptMode, verifyMode,
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dexoptFlags) != 0)
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
179c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("DexOptZ: VM init failed");
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //vmStarted = 1;
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* do the optimization */
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (!dvmContinueOptimization(cacheFd, dexOffset, uncompLen, debugFileName,
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            modWhen, crc32, isBootstrap))
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
189c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("Optimization failed");
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* we don't shut the VM down -- process is about to exit */
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    result = 0;
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbail:
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dexZipCloseArchive(&zippy);
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return result;
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2024701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein/*
2034701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein * Common functionality for normal device-side processing as well as
2044701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein * preoptimization.
2054701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein */
2064701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornsteinstatic int processZipFile(int zipFd, int cacheFd, const char* zipName,
2074701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein        const char *dexoptFlags)
2084701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein{
2094701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    char* bcpCopy = NULL;
2104701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein
2114701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    /*
2124701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein     * Check to see if this is a bootstrap class entry. If so, truncate
2134701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein     * the path.
2144701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein     */
2154701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    const char* bcp = getenv("BOOTCLASSPATH");
2164701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    if (bcp == NULL) {
217c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("DexOptZ: BOOTCLASSPATH not set");
218bfc9799b1a53fd6f6136d07e6278d4538cf70f13Carl Shapiro        return -1;
2194701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    }
2204701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein
2214701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    bool isBootstrap = false;
2224701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    const char* match = strstr(bcp, zipName);
2234701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    if (match != NULL) {
2244701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein        /*
2254701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein         * TODO: we have a partial string match, but that doesn't mean
2264701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein         * we've matched an entire path component. We should make sure
2274701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein         * that we're matching on the full zipName, and if not we
2284701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein         * should re-do the strstr starting at (match+1).
2294701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein         *
2304701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein         * The scenario would be a bootclasspath with something like
2314701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein         * "/system/framework/core.jar" while we're trying to optimize
2324701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein         * "/framework/core.jar". Not very likely since all paths are
2334701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein         * absolute and end with ".jar", but not impossible.
2344701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein         */
2354701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein        int matchOffset = match - bcp;
2364701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein        if (matchOffset > 0 && bcp[matchOffset-1] == ':')
2374701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein            matchOffset--;
23892c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("DexOptZ: found '%s' in bootclasspath, cutting off at %d",
2392446f44302dacac8b68fc443b6fb41833653ab34Patrick Scott            zipName, matchOffset);
2404701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein        bcpCopy = strdup(bcp);
2414701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein        bcpCopy[matchOffset] = '\0';
2424701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein
2434701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein        bcp = bcpCopy;
244062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block        ALOGD("DexOptZ: truncated BOOTCLASSPATH to '%s'", bcp);
2454701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein        isBootstrap = true;
2464701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    }
2474701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein
248bfc9799b1a53fd6f6136d07e6278d4538cf70f13Carl Shapiro    int result = extractAndProcessZip(zipFd, cacheFd, zipName, isBootstrap,
2494701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein            bcp, dexoptFlags);
2504701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein
2514701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    free(bcpCopy);
2524701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    return result;
2534701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein}
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* advance to the next arg and extract it */
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define GET_ARG(_var, _func, _msg)                                          \
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {                                                                       \
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        char* endp;                                                         \
259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        (_var) = _func(*++argv, &endp, 0);                                  \
260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (*endp != '\0') {                                                \
261c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block            ALOGE("%s '%s'", _msg, *argv);                                   \
262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            goto bail;                                                      \
263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }                                                                   \
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        --argc;                                                             \
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Parse arguments.  We want:
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *   0. (name of dexopt command -- ignored)
270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *   1. "--zip"
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *   2. zip fd (input, read-only)
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *   3. cache fd (output, read-write, locked with flock)
2734701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein *   4. filename of zipfile being optimized (used for debug messages and
2744701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein *      for comparing against BOOTCLASSPATH; does not need to be
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      accessible or even exist)
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *   5. dexopt flags
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The BOOTCLASSPATH environment variable is assumed to hold the correct
279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * boot class path.  If the filename provided appears in the boot class
280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * path, the path will be truncated just before that entry (so that, if
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you were to dexopt "core.jar", your bootclasspath would be empty).
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This does not try to normalize the boot class path name, so the
284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * filename test won't catch you if you get creative.
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic int fromZip(int argc, char* const argv[])
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int result = -1;
2894701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    int zipFd, cacheFd;
2904701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    const char* zipName;
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    char* bcpCopy = NULL;
2924701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    const char* dexoptFlags;
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (argc != 6) {
295c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("Wrong number of args for --zip (found %d)", argc);
296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* skip "--zip" */
300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    argc--;
301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    argv++;
302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    GET_ARG(zipFd, strtol, "bad zip fd");
304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    GET_ARG(cacheFd, strtol, "bad cache fd");
3054701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    zipName = *++argv;
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    --argc;
3074701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    dexoptFlags = *++argv;
308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    --argc;
309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3104701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    result = processZipFile(zipFd, cacheFd, zipName, dexoptFlags);
3114701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein
3124701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornsteinbail:
3134701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    return result;
3144701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein}
3154701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein
3164701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein/*
3174701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein * Parse arguments for a preoptimization run. This is when dalvikvm is run
3184701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein * on a host to optimize dex files for eventual running on a (different)
3194701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein * device. We want:
3204701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein *   0. (name of dexopt command -- ignored)
3214701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein *   1. "--preopt"
3224701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein *   2. zipfile name
3234701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein *   3. output file name
3244701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein *   4. dexopt flags
3254701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein *
3264701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein * The BOOTCLASSPATH environment variable is assumed to hold the correct
3274701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein * boot class path.  If the filename provided appears in the boot class
3284701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein * path, the path will be truncated just before that entry (so that, if
3294701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein * you were to dexopt "core.jar", your bootclasspath would be empty).
3304701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein *
3314701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein * This does not try to normalize the boot class path name, so the
3324701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein * filename test won't catch you if you get creative.
3334701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein */
3344701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornsteinstatic int preopt(int argc, char* const argv[])
3354701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein{
336dd2502bd371ddca554b7a3d900fe120a3e7767ecDan Bornstein    int zipFd = -1;
337dd2502bd371ddca554b7a3d900fe120a3e7767ecDan Bornstein    int outFd = -1;
338dd2502bd371ddca554b7a3d900fe120a3e7767ecDan Bornstein    int result = -1;
339dd2502bd371ddca554b7a3d900fe120a3e7767ecDan Bornstein
3404701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    if (argc != 5) {
341dd2502bd371ddca554b7a3d900fe120a3e7767ecDan Bornstein        /*
342dd2502bd371ddca554b7a3d900fe120a3e7767ecDan Bornstein         * Use stderr here, since this variant is meant to be called on
343dd2502bd371ddca554b7a3d900fe120a3e7767ecDan Bornstein         * the host side.
344dd2502bd371ddca554b7a3d900fe120a3e7767ecDan Bornstein         */
345dd2502bd371ddca554b7a3d900fe120a3e7767ecDan Bornstein        fprintf(stderr, "Wrong number of args for --preopt (found %d)\n",
346dd2502bd371ddca554b7a3d900fe120a3e7767ecDan Bornstein                argc);
347bfc9799b1a53fd6f6136d07e6278d4538cf70f13Carl Shapiro        return -1;
348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3504701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    const char* zipName = argv[2];
3514701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    const char* outName = argv[3];
3524701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    const char* dexoptFlags = argv[4];
353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
354d8b5f50d0c6c9a0ce157e89df4ee1e8eb8b334c3Andy McFadden    if (strstr(dexoptFlags, "u=y") == NULL &&
355d8b5f50d0c6c9a0ce157e89df4ee1e8eb8b334c3Andy McFadden        strstr(dexoptFlags, "u=n") == NULL)
356d8b5f50d0c6c9a0ce157e89df4ee1e8eb8b334c3Andy McFadden    {
357d8b5f50d0c6c9a0ce157e89df4ee1e8eb8b334c3Andy McFadden        fprintf(stderr, "Either 'u=y' or 'u=n' must be specified\n");
358bfc9799b1a53fd6f6136d07e6278d4538cf70f13Carl Shapiro        return -1;
359d8b5f50d0c6c9a0ce157e89df4ee1e8eb8b334c3Andy McFadden    }
360d8b5f50d0c6c9a0ce157e89df4ee1e8eb8b334c3Andy McFadden
3614701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    zipFd = open(zipName, O_RDONLY);
3624701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    if (zipFd < 0) {
3634701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein        perror(argv[0]);
364bfc9799b1a53fd6f6136d07e6278d4538cf70f13Carl Shapiro        return -1;
3654701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    }
3664701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein
36746f7d54cbda931213bbe710c065e1bd82aa0af6cDan Bornstein    outFd = open(outName, O_RDWR | O_EXCL | O_CREAT, 0666);
3684701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    if (outFd < 0) {
3694701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein        perror(argv[0]);
3704701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein        goto bail;
371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
372f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3734701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    result = processZipFile(zipFd, outFd, zipName, dexoptFlags);
374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbail:
3764701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    if (zipFd >= 0) {
3774701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein        close(zipFd);
3784701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    }
3794701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein
3804701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    if (outFd >= 0) {
3814701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein        close(outFd);
3824701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    }
3834701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein
384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return result;
385f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
386f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
387f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
388f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Parse arguments for an "old-style" invocation directly from the VM.
389f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
390f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Here's what we want:
391f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *   0. (name of dexopt command -- ignored)
392f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *   1. "--dex"
393f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *   2. DALVIK_VM_BUILD value, as a sanity check
394f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *   3. file descriptor, locked with flock, for DEX file being optimized
395f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *   4. DEX offset within file
396f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *   5. DEX length
397f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *   6. filename of file being optimized (for debug messages only)
398f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *   7. modification date of source (goes into dependency section)
399f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *   8. CRC of source (goes into dependency section)
400f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *   9. flags (optimization level, isBootstrap)
401f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  10. bootclasspath entry #1
402f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  11. bootclasspath entry #2
403f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *   ...
404f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
405f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * dvmOptimizeDexFile() in dalvik/vm/analysis/DexOptimize.c builds the
406f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * argument list and calls this executable.
407f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
408f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The bootclasspath entries become the dependencies for this DEX file.
409f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
410f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The open file descriptor MUST NOT be for one of the bootclasspath files.
411f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The parent has the descriptor locked, and we'll try to lock it again as
412f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * part of processing the bootclasspath.  (We can catch this and return
413f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * an error by comparing filenames or by opening the bootclasspath files
414f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * and stat()ing them for inode numbers).
415f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
416f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic int fromDex(int argc, char* const argv[])
417f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
418f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int result = -1;
419f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    bool vmStarted = false;
420f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    char* bootClassPath = NULL;
421f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int fd, flags, vmBuildVersion;
422f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    long offset, length;
423f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const char* debugFileName;
424f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    u4 crc, modWhen;
425f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    char* endp;
426bfc9799b1a53fd6f6136d07e6278d4538cf70f13Carl Shapiro    bool onlyOptVerifiedDex = false;
427bfc9799b1a53fd6f6136d07e6278d4538cf70f13Carl Shapiro    DexClassVerifyMode verifyMode;
428bfc9799b1a53fd6f6136d07e6278d4538cf70f13Carl Shapiro    DexOptimizerMode dexOptMode;
429f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
430f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (argc < 10) {
431f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* don't have all mandatory args */
432c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("Not enough arguments for --dex (found %d)", argc);
433f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
434f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
435f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
436f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* skip "--dex" */
437f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    argc--;
438f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    argv++;
439f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
440f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
441f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Extract the args.
442f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
443f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    GET_ARG(vmBuildVersion, strtol, "bad vm build");
444f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (vmBuildVersion != DALVIK_VM_BUILD) {
445c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("DexOpt: build rev does not match VM: %d vs %d",
446f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            vmBuildVersion, DALVIK_VM_BUILD);
447f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
448f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
449f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    GET_ARG(fd, strtol, "bad fd");
450f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    GET_ARG(offset, strtol, "bad offset");
451f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    GET_ARG(length, strtol, "bad length");
452f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    debugFileName = *++argv;
453f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    --argc;
454f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    GET_ARG(modWhen, strtoul, "bad modWhen");
455f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    GET_ARG(crc, strtoul, "bad crc");
456f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    GET_ARG(flags, strtol, "bad flags");
457f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
45892c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block    ALOGV("Args: fd=%d off=%ld len=%ld name='%s' mod=%#x crc=%#x flg=%d (argc=%d)",
459f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        fd, offset, length, debugFileName, modWhen, crc, flags, argc);
460f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(argc > 0);
461f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
462f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (--argc == 0) {
463f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        bootClassPath = strdup("");
464f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
465f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int i, bcpLen;
466f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        char* const* argp;
467f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        char* cp;
468f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
469f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        bcpLen = 0;
470f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (i = 0, argp = argv; i < argc; i++) {
471f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ++argp;
47292c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block            ALOGV("DEP: '%s'", *argp);
473f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            bcpLen += strlen(*argp) + 1;
474f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
475f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
476f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        cp = bootClassPath = (char*) malloc(bcpLen +1);
477f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (i = 0, argp = argv; i < argc; i++) {
478f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int strLen;
479f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
480f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ++argp;
481f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            strLen = strlen(*argp);
482f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (i != 0)
483f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                *cp++ = ':';
484f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            memcpy(cp, *argp, strLen);
485f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cp += strLen;
486f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
487f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        *cp = '\0';
488f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
489f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        assert((int) strlen(bootClassPath) == bcpLen-1);
490f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
49192c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block    ALOGV("  bootclasspath is '%s'", bootClassPath);
492f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
493f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* start the VM partway */
494f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
495f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* ugh -- upgrade these to a bit field if they get any more complex */
496f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if ((flags & DEXOPT_VERIFY_ENABLED) != 0) {
497f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if ((flags & DEXOPT_VERIFY_ALL) != 0)
498f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            verifyMode = VERIFY_MODE_ALL;
499f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else
500f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            verifyMode = VERIFY_MODE_REMOTE;
501f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
502f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        verifyMode = VERIFY_MODE_NONE;
503f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
504f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if ((flags & DEXOPT_OPT_ENABLED) != 0) {
505f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if ((flags & DEXOPT_OPT_ALL) != 0)
506f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dexOptMode = OPTIMIZE_MODE_ALL;
507f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else
508f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dexOptMode = OPTIMIZE_MODE_VERIFIED;
509f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
510f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dexOptMode = OPTIMIZE_MODE_NONE;
511f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
512f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
513d8b5f50d0c6c9a0ce157e89df4ee1e8eb8b334c3Andy McFadden    if (dvmPrepForDexOpt(bootClassPath, dexOptMode, verifyMode, flags) != 0) {
514c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("VM init failed");
515f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
516f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
517f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
518f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    vmStarted = true;
519f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
520f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* do the optimization */
521f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (!dvmContinueOptimization(fd, offset, length, debugFileName,
522f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            modWhen, crc, (flags & DEXOPT_IS_BOOTSTRAP) != 0))
523f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
524c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("Optimization failed");
525f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
526f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
527f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
528f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    result = 0;
529f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
530f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbail:
531f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
532f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * In theory we should gracefully shut the VM down at this point.  In
533f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * practice that only matters if we're checking for memory leaks with
534f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * valgrind -- simply exiting is much faster.
535f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
536f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * As it turns out, the DEX optimizer plays a little fast and loose
537f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * with class loading.  We load all of the classes from a partially-
538f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * formed DEX file, which is unmapped when we're done.  If we want to
539f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * do clean shutdown here, perhaps for testing with valgrind, we need
540f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * to skip the munmap call there.
541f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
542f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#if 0
543f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (vmStarted) {
5444308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block        ALOGI("DexOpt shutting down, result=%d", result);
545f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmShutdown();
546f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
547f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif
548f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
549f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    free(bootClassPath);
55092c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block    ALOGV("DexOpt command complete (result=%d)", result);
551f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return result;
552f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
553f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
554f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
555f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Main entry point.  Decide where to go.
556f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
557f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectint main(int argc, char* const argv[])
558f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
559f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    set_process_name("dexopt");
560f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
561f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    setvbuf(stdout, NULL, _IONBF, 0);
562f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
563f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (argc > 1) {
564f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (strcmp(argv[1], "--zip") == 0)
565f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return fromZip(argc, argv);
566f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else if (strcmp(argv[1], "--dex") == 0)
567f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return fromDex(argc, argv);
5684701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein        else if (strcmp(argv[1], "--preopt") == 0)
5694701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein            return preopt(argc, argv);
570f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
571f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
5724701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein    fprintf(stderr,
5734701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein        "Usage:\n\n"
5744701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein        "Short version: Don't use this.\n\n"
5754701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein        "Slightly longer version: This system-internal tool is used to\n"
5764701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein        "produce optimized dex files. See the source code for details.\n");
5774701d5f8d0e691eeb9a0824311d5166d301a5aa5Dan Bornstein
578f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return 1;
579f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
580