12e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
22e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Copyright (C) 2008 The Android Open Source Project
32e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
42e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Licensed under the Apache License, Version 2.0 (the "License");
52e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * you may not use this file except in compliance with the License.
62e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * You may obtain a copy of the License at
72e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
82e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *      http://www.apache.org/licenses/LICENSE-2.0
92e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Unless required by applicable law or agreed to in writing, software
112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * distributed under the License is distributed on an "AS IS" BASIS,
122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * See the License for the specific language governing permissions and
142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * limitations under the License.
152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Prepare a DEX file for use by the VM.  Depending upon the VM options
192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * we will attempt to verify and/or optimize the code, possibly appending
202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * register maps.
212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * TODO: the format of the optimized header is currently "whatever we
232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * happen to write", since the VM that writes it is by definition the same
242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * as the VM that reads it.  Still, it should be better documented and
252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * more rigorously structured.
262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include "Dalvik.h"
282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include "libdex/OptInvocation.h"
292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include "analysis/RegisterMap.h"
302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include "analysis/Optimize.h"
312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
320fbb7030fff58e25718291811394487d95d95a3eElliott Hughes#include <string>
332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
346f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein#include <libgen.h>
352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include <stdlib.h>
362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include <unistd.h>
372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include <sys/mman.h>
382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include <sys/stat.h>
392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include <sys/file.h>
406f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein#include <sys/stat.h>
416f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein#include <sys/types.h>
422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include <sys/wait.h>
432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include <fcntl.h>
442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include <errno.h>
456f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein#include <unistd.h>
460fbb7030fff58e25718291811394487d95d95a3eElliott Hughes#include <zlib.h>
472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* fwd */
4957fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFaddenstatic bool rewriteDex(u1* addr, int len, bool doVerify, bool doOpt,
5057fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    DexClassLookup** ppClassLookup, DvmDex** ppDvmDex);
51cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenstatic bool loadAllClasses(DvmDex* pDvmDex);
52cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenstatic void verifyAndOptimizeClasses(DexFile* pDexFile, bool doVerify,
53cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    bool doOpt);
54cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenstatic void verifyAndOptimizeClass(DexFile* pDexFile, ClassObject* clazz,
55cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    const DexClassDef* pClassDef, bool doVerify, bool doOpt);
562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic void updateChecksum(u1* addr, int len, DexHeader* pHeader);
572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic int writeDependencies(int fd, u4 modWhen, u4 crc);
58e377ef62a40267ab16c2dd20cc5f4c63af6397ccDan Bornsteinstatic bool writeOptData(int fd, const DexClassLookup* pClassLookup,\
59d394371bd84bacc51e96e2d2eacb8549d9110b1eDan Bornstein    const RegisterMapBuilder* pRegMapBuilder);
602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool computeFileChecksum(int fd, off_t start, size_t length, u4* pSum);
612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
626f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein/*
630fbb7030fff58e25718291811394487d95d95a3eElliott Hughes * Get just the directory portion of the given path. Equivalent to dirname(3).
646f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein */
650fbb7030fff58e25718291811394487d95d95a3eElliott Hughesstatic std::string saneDirName(const std::string& path) {
660fbb7030fff58e25718291811394487d95d95a3eElliott Hughes    size_t n = path.rfind('/');
670fbb7030fff58e25718291811394487d95d95a3eElliott Hughes    if (n == std::string::npos) {
680fbb7030fff58e25718291811394487d95d95a3eElliott Hughes        return ".";
696f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein    }
700fbb7030fff58e25718291811394487d95d95a3eElliott Hughes    return path.substr(0, n);
716f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein}
726f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein
736f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein/*
746f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein * Helper for dvmOpenCacheDexFile() in a known-error case: Check to
756f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein * see if the directory part of the given path (all but the last
766f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein * component) exists and is writable. Complain to the log if not.
776f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein */
780fbb7030fff58e25718291811394487d95d95a3eElliott Hughesstatic bool directoryIsValid(const std::string& fileName)
796f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein{
800fbb7030fff58e25718291811394487d95d95a3eElliott Hughes    std::string dirName(saneDirName(fileName));
816f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein
820fbb7030fff58e25718291811394487d95d95a3eElliott Hughes    struct stat sb;
830fbb7030fff58e25718291811394487d95d95a3eElliott Hughes    if (stat(dirName.c_str(), &sb) < 0) {
84c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("Could not stat dex cache directory '%s': %s", dirName.c_str(), strerror(errno));
856f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein        return false;
866f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein    }
876f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein
880fbb7030fff58e25718291811394487d95d95a3eElliott Hughes    if (!S_ISDIR(sb.st_mode)) {
89c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("Dex cache directory isn't a directory: %s", dirName.c_str());
900fbb7030fff58e25718291811394487d95d95a3eElliott Hughes        return false;
916f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein    }
926f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein
93a78b1255ad1ce8dcacad21338d4f88db4231c4cdAndy McFadden    if (access(dirName.c_str(), W_OK) < 0) {
94c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("Dex cache directory isn't writable: %s", dirName.c_str());
950fbb7030fff58e25718291811394487d95d95a3eElliott Hughes        return false;
966f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein    }
976f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein
98a78b1255ad1ce8dcacad21338d4f88db4231c4cdAndy McFadden    if (access(dirName.c_str(), R_OK) < 0) {
99c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("Dex cache directory isn't readable: %s", dirName.c_str());
1000fbb7030fff58e25718291811394487d95d95a3eElliott Hughes        return false;
1016f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein    }
1026f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein
1030fbb7030fff58e25718291811394487d95d95a3eElliott Hughes    return true;
1046f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein}
1052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
1072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Return the fd of an open file in the DEX file cache area.  If the cache
1082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * file doesn't exist or is out of date, this will remove the old entry,
1092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * create a new one (writing only the file header), and return with the
1102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * "new file" flag set.
1112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
1122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * It's possible to execute from an unoptimized DEX file directly,
1132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * assuming the byte ordering and structure alignment is correct, but
1142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * disadvantageous because some significant optimizations are not possible.
1152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * It's not generally possible to do the same from an uncompressed Jar
1162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * file entry, because we have to guarantee 32-bit alignment in the
1172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * memory-mapped file.
1182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
1192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * For a Jar/APK file (a zip archive with "classes.dex" inside), "modWhen"
1202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * and "crc32" come from the Zip directory entry.  For a stand-alone DEX
1212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * file, it's the modification date of the file and the Adler32 from the
1222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * DEX header (which immediately follows the magic).  If these don't
1232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * match what's stored in the opt header, we reject the file immediately.
1242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
1252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On success, the file descriptor will be positioned just past the "opt"
1262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * file header, and will be locked with flock.  "*pCachedName" will point
1272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * to newly-allocated storage.
1282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
1292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenint dvmOpenCachedDexFile(const char* fileName, const char* cacheFileName,
1302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u4 modWhen, u4 crc, bool isBootstrap, bool* pNewFile, bool createIfMissing)
1312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
1322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int fd, cc;
1332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    struct stat fdStat, fileStat;
1342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bool readOnly = false;
1352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    *pNewFile = false;
1372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenretry:
1392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
1402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Try to open the cache file.  If we've been asked to,
1412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * create it if it doesn't exist.
1422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
1432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    fd = createIfMissing ? open(cacheFileName, O_CREAT|O_RDWR, 0644) : -1;
1442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (fd < 0) {
1452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        fd = open(cacheFileName, O_RDONLY, 0);
1462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (fd < 0) {
1472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (createIfMissing) {
1480fbb7030fff58e25718291811394487d95d95a3eElliott Hughes                // TODO: write an equivalent of strerror_r that returns a std::string.
1490fbb7030fff58e25718291811394487d95d95a3eElliott Hughes                const std::string errnoString(strerror(errno));
1506f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein                if (directoryIsValid(cacheFileName)) {
151c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block                    ALOGE("Can't open dex cache file '%s': %s", cacheFileName, errnoString.c_str());
1526f9edbe7d3a83f7741c4d56f9f5be1414ecabc9fDan Bornstein                }
1532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
1542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return fd;
1552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
1562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        readOnly = true;
157780d3e25adde11603bb6bab1b42a1e8e985aec15Nick Kralevich    } else {
158780d3e25adde11603bb6bab1b42a1e8e985aec15Nick Kralevich        fchmod(fd, 0644);
1592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
1602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
1622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Grab an exclusive lock on the cache file.  If somebody else is
1632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * working on it, we'll block here until they complete.  Because
1642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * we're waiting on an external resource, we go into VMWAIT mode.
1652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
16692c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block    ALOGV("DexOpt: locking cache file %s (fd=%d, boot=%d)",
1672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        cacheFileName, fd, isBootstrap);
1681813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro    ThreadStatus oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
1692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    cc = flock(fd, LOCK_EX | LOCK_NB);
1702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (cc != 0) {
171062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block        ALOGD("DexOpt: sleeping on flock(%s)", cacheFileName);
1722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        cc = flock(fd, LOCK_EX);
1732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
1742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    dvmChangeStatus(NULL, oldStatus);
1752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (cc != 0) {
176c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("Can't lock dex cache '%s': %d", cacheFileName, cc);
1772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        close(fd);
1782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return -1;
1792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
18092c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block    ALOGV("DexOpt:  locked cache file");
1812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
1832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Check to see if the fd we opened and locked matches the file in
1842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * the filesystem.  If they don't, then somebody else unlinked ours
1852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * and created a new file, and we need to use that one instead.  (If
1862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * we caught them between the unlink and the create, we'll get an
1872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * ENOENT from the file stat.)
1882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
1892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    cc = fstat(fd, &fdStat);
1902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (cc != 0) {
191c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("Can't stat open file '%s'", cacheFileName);
19260fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGVV("DexOpt: unlocking cache file %s", cacheFileName);
1932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto close_fail;
1942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
1952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    cc = stat(cacheFileName, &fileStat);
1962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (cc != 0 ||
1972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        fdStat.st_dev != fileStat.st_dev || fdStat.st_ino != fileStat.st_ino)
1982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    {
199062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block        ALOGD("DexOpt: our open cache file is stale; sleeping and retrying");
20060fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGVV("DexOpt: unlocking cache file %s", cacheFileName);
2012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        flock(fd, LOCK_UN);
2022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        close(fd);
2032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        usleep(250 * 1000);     /* if something is hosed, don't peg machine */
2042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto retry;
2052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
2062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
2082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * We have the correct file open and locked.  If the file size is zero,
2092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * then it was just created by us, and we want to fill in some fields
2102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * in the "opt" header and set "*pNewFile".  Otherwise, we want to
2112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * verify that the fields in the header match our expectations, and
2122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * reset the file if they don't.
2132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
2142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (fdStat.st_size == 0) {
2152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (readOnly) {
216e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block            ALOGW("DexOpt: file has zero length and isn't writable");
2172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto close_fail;
2182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
2192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        cc = dexOptCreateEmptyHeader(fd);
2202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (cc != 0)
2212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto close_fail;
2222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        *pNewFile = true;
22392c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("DexOpt: successfully initialized new cache file");
2242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    } else {
2252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        bool expectVerify, expectOpt;
2262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
227d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden        if (gDvm.classVerifyMode == VERIFY_MODE_NONE) {
2282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            expectVerify = false;
229d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden        } else if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE) {
2302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            expectVerify = !isBootstrap;
231d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden        } else /*if (gDvm.classVerifyMode == VERIFY_MODE_ALL)*/ {
2322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            expectVerify = true;
233d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden        }
2342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
235d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden        if (gDvm.dexOptMode == OPTIMIZE_MODE_NONE) {
2362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            expectOpt = false;
237d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden        } else if (gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED ||
238d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                   gDvm.dexOptMode == OPTIMIZE_MODE_FULL) {
2392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            expectOpt = expectVerify;
240d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden        } else /*if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)*/ {
2412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            expectOpt = true;
242d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden        }
2432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
24492c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("checking deps, expecting vfy=%d opt=%d",
2452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            expectVerify, expectOpt);
2462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (!dvmCheckOptHeaderAndDependencies(fd, true, modWhen, crc,
2482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                expectVerify, expectOpt))
2492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        {
2502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (readOnly) {
2512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                /*
2522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 * We could unlink and rewrite the file if we own it or
2532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 * the "sticky" bit isn't set on the directory.  However,
2542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 * we're not able to truncate it, which spoils things.  So,
2552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 * give up now.
2562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 */
2572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                if (createIfMissing) {
258e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block                    ALOGW("Cached DEX '%s' (%s) is stale and not writable",
2592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                        fileName, cacheFileName);
2602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                }
2612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                goto close_fail;
2622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
2632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /*
2652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * If we truncate the existing file before unlinking it, any
2662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * process that has it mapped will fail when it tries to touch
2672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * the pages.
2682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             *
2692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * This is very important.  The zygote process will have the
2702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * boot DEX files (core, framework, etc.) mapped early.  If
2712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * (say) core.dex gets updated, and somebody launches an app
2722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * that uses App.dex, then App.dex gets reoptimized because it's
2732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * dependent upon the boot classes.  However, dexopt will be
2742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * using the *new* core.dex to do the optimizations, while the
2752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * app will actually be running against the *old* core.dex
2762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * because it starts from zygote.
2772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             *
2782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * Even without zygote, it's still possible for a class loader
2792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * to pull in an APK that was optimized against an older set
2802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * of DEX files.  We must ensure that everything fails when a
2812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * boot DEX gets updated, and for general "why aren't my
2822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * changes doing anything" purposes its best if we just make
2832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * everything crash when a DEX they're using gets updated.
2842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             */
285062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block            ALOGD("ODEX file is stale or bad; removing and retrying (%s)",
286e7ad112562af04d825fdd0d403deaf0ddd70a2eaAndy McFadden                cacheFileName);
2872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (ftruncate(fd, 0) != 0) {
288e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block                ALOGW("Warning: unable to truncate cache file '%s': %s",
2892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    cacheFileName, strerror(errno));
2902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                /* keep going */
2912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
2922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (unlink(cacheFileName) != 0) {
293e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block                ALOGW("Warning: unable to remove cache file '%s': %d %s",
2942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    cacheFileName, errno, strerror(errno));
2952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                /* keep going; permission failure should probably be fatal */
2962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
29760fc806b679a3655c228b4093058c59941a49cfeDan Bornstein            LOGVV("DexOpt: unlocking cache file %s", cacheFileName);
2982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            flock(fd, LOCK_UN);
2992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            close(fd);
3002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto retry;
3012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        } else {
30292c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block            ALOGV("DexOpt: good deps in cache file");
3032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
3042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
3052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(fd >= 0);
3072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return fd;
3082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenclose_fail:
3102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    flock(fd, LOCK_UN);
3112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    close(fd);
3122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return -1;
3132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
3142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
3162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Unlock the file descriptor.
3172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
3182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" on success.
3192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
3202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenbool dvmUnlockCachedDexFile(int fd)
3212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
32260fc806b679a3655c228b4093058c59941a49cfeDan Bornstein    LOGVV("DexOpt: unlocking cache file fd=%d", fd);
3232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return (flock(fd, LOCK_UN) == 0);
3242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
3252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
3282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Given a descriptor for a file with DEX data in it, produce an
3292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * optimized version.
3302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
3312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * The file pointed to by "fd" is expected to be a locked shared resource
3322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * (or private); we make no efforts to enforce multi-process correctness
3332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * here.
3342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
3352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * "fileName" is only used for debug output.  "modWhen" and "crc" are stored
3362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * in the dependency set.
3372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
3382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * The "isBootstrap" flag determines how the optimizer and verifier handle
3392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * package-scope access checks.  When optimizing, we only load the bootstrap
3402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * class DEX files and the target DEX, so the flag determines whether the
3412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * target DEX classes are given a (synthetic) non-NULL classLoader pointer.
3422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * This only really matters if the target DEX contains classes that claim to
3432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * be in the same package as bootstrap classes.
3442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
3452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * The optimizer will need to load every class in the target DEX file.
3462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * This is generally undesirable, so we start a subprocess to do the
3472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * work and wait for it to complete.
3482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
3492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" on success.  All data will have been written to "fd".
3502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
3512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenbool dvmOptimizeDexFile(int fd, off_t dexOffset, long dexLength,
3522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const char* fileName, u4 modWhen, u4 crc, bool isBootstrap)
3532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
3542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const char* lastPart = strrchr(fileName, '/');
3552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (lastPart != NULL)
3562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        lastPart++;
3572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    else
3582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        lastPart = fileName;
3592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
360062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block    ALOGD("DexOpt: --- BEGIN '%s' (bootstrap=%d) ---", lastPart, isBootstrap);
3612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    pid_t pid;
3632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
3652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * This could happen if something in our bootclasspath, which we thought
3662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * was all optimized, got rejected.
3672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
3682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (gDvm.optimizing) {
369e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("Rejecting recursive optimization attempt on '%s'", fileName);
3702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
3712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
3722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    pid = fork();
3742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (pid == 0) {
3752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        static const int kUseValgrind = 0;
3762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        static const char* kDexOptBin = "/bin/dexopt";
3772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        static const char* kValgrinder = "/usr/bin/valgrind";
3782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        static const int kFixedArgCount = 10;
3792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        static const int kValgrindArgCount = 5;
3802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        static const int kMaxIntLen = 12;   // '-'+10dig+'\0' -OR- 0x+8dig
3812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int bcpSize = dvmGetBootPathSize();
3822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int argc = kFixedArgCount + bcpSize
3832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            + (kValgrindArgCount * kUseValgrind);
3841813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro        const char* argv[argc+1];             // last entry is NULL
3852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        char values[argc][kMaxIntLen];
3862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        char* execFile;
3871813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro        const char* androidRoot;
3882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int flags;
3892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* change process groups, so we don't clash with ProcessManager */
3912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        setpgid(0, 0);
3922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* full path to optimizer */
3942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        androidRoot = getenv("ANDROID_ROOT");
3952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (androidRoot == NULL) {
396e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block            ALOGW("ANDROID_ROOT not set, defaulting to /system");
3972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            androidRoot = "/system";
3982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
39963cd4b08e623242066c63563bad3a9f414a2bd2dAndy McFadden        execFile = (char*)alloca(strlen(androidRoot) + strlen(kDexOptBin) + 1);
4002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        strcpy(execFile, androidRoot);
4012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        strcat(execFile, kDexOptBin);
4022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
4042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Create arg vector.
4052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
4062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int curArg = 0;
4072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (kUseValgrind) {
4092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* probably shouldn't ship the hard-coded path */
4102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            argv[curArg++] = (char*)kValgrinder;
4112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            argv[curArg++] = "--tool=memcheck";
4122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            argv[curArg++] = "--leak-check=yes";        // check for leaks too
4132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            argv[curArg++] = "--leak-resolution=med";   // increase from 2 to 4
4142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            argv[curArg++] = "--num-callers=16";        // default is 12
4152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            assert(curArg == kValgrindArgCount);
4162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
4172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = execFile;
4182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = "--dex";
4202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        sprintf(values[2], "%d", DALVIK_VM_BUILD);
4222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = values[2];
4232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        sprintf(values[3], "%d", fd);
4252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = values[3];
4262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        sprintf(values[4], "%d", (int) dexOffset);
4282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = values[4];
4292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        sprintf(values[5], "%d", (int) dexLength);
4312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = values[5];
4322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = (char*)fileName;
4342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        sprintf(values[7], "%d", (int) modWhen);
4362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = values[7];
4372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        sprintf(values[8], "%d", (int) crc);
4392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = values[8];
4402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        flags = 0;
4422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (gDvm.dexOptMode != OPTIMIZE_MODE_NONE) {
4432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            flags |= DEXOPT_OPT_ENABLED;
4442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)
4452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                flags |= DEXOPT_OPT_ALL;
4462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
4472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (gDvm.classVerifyMode != VERIFY_MODE_NONE) {
4482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            flags |= DEXOPT_VERIFY_ENABLED;
4492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (gDvm.classVerifyMode == VERIFY_MODE_ALL)
4502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                flags |= DEXOPT_VERIFY_ALL;
4512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
4522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (isBootstrap)
4532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            flags |= DEXOPT_IS_BOOTSTRAP;
4542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (gDvm.generateRegisterMaps)
455d8b5f50d0c6c9a0ce157e89df4ee1e8eb8b334c3Andy McFadden            flags |= DEXOPT_GEN_REGISTER_MAPS;
4562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        sprintf(values[9], "%d", flags);
4572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = values[9];
4582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        assert(((!kUseValgrind && curArg == kFixedArgCount) ||
4602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden               ((kUseValgrind && curArg == kFixedArgCount+kValgrindArgCount))));
4612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ClassPathEntry* cpe;
4632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
4642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            argv[curArg++] = cpe->fileName;
4652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
4662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        assert(curArg == argc);
4672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg] = NULL;
4692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (kUseValgrind)
4711813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro            execv(kValgrinder, const_cast<char**>(argv));
4722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        else
4731813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro            execv(execFile, const_cast<char**>(argv));
4742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
475c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("execv '%s'%s failed: %s", execFile,
4762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            kUseValgrind ? " [valgrind]" : "", strerror(errno));
4772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        exit(1);
4782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    } else {
47992c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("DexOpt: waiting for verify+opt, pid=%d", (int) pid);
4802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int status;
4812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pid_t gotPid;
4822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
4842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Wait for the optimization process to finish.  We go into VMWAIT
4852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * mode here so GC suspension won't have to wait for us.
4862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
4871813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro        ThreadStatus oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
4882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        while (true) {
4892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            gotPid = waitpid(pid, &status, 0);
4902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (gotPid == -1 && errno == EINTR) {
491062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block                ALOGD("waitpid interrupted, retrying");
4922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            } else {
4932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                break;
4942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
4952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
4962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmChangeStatus(NULL, oldStatus);
4972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (gotPid != pid) {
498c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block            ALOGE("waitpid failed: wanted %d, got %d: %s",
4992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                (int) pid, (int) gotPid, strerror(errno));
5002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return false;
5012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
5022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
504062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block            ALOGD("DexOpt: --- END '%s' (success) ---", lastPart);
5052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return true;
5062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        } else {
507e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block            ALOGW("DexOpt: --- END '%s' --- status=0x%04x, process failed",
5082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                lastPart, status);
5092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return false;
5102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
5112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
5122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
5132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
515cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * Do the actual optimization.  This is executed in the dexopt process.
5162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
5172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * For best use of disk/memory, we want to extract once and perform
5182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * optimizations in place.  If the file has to expand or contract
5192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * to match local structure padding/alignment expectations, we want
5202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * to do the rewrite as part of the extract, rather than extracting
5212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * into a temp file and slurping it back out.  (The structure alignment
5222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * is currently correct for all platforms, and this isn't expected to
5232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * change, so we should be okay with having it already extracted.)
5242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
5252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" on success.
5262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
5272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenbool dvmContinueOptimization(int fd, off_t dexOffset, long dexLength,
5282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const char* fileName, u4 modWhen, u4 crc, bool isBootstrap)
5292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
5302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DexClassLookup* pClassLookup = NULL;
5312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    RegisterMapBuilder* pRegMapBuilder = NULL;
5322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
533cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    assert(gDvm.optimizing);
5342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
53592c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block    ALOGV("Continuing optimization (%s, isb=%d)", fileName, isBootstrap);
5362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(dexOffset >= 0);
5382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* quick test so we don't blow up on empty file */
5402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (dexLength < (int) sizeof(DexHeader)) {
541c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("too small to be DEX");
5422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
5432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
5442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (dexOffset < (int) sizeof(DexOptHeader)) {
545c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("not enough room for opt header");
5462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
5472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
5482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bool result = false;
5502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
5522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Drop this into a global so we don't have to pass it around.  We could
5532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * also add a field to DexFile, but since it only pertains to DEX
5542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * creation that probably doesn't make sense.
5552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
5562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    gDvm.optimizingBootstrapClass = isBootstrap;
5572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    {
5592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
5602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Map the entire file (so we don't have to worry about page
5612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * alignment).  The expectation is that the output file contains
5622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * our DEX data plus room for a small header.
5632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
5642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        bool success;
5652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        void* mapAddr;
5662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        mapAddr = mmap(NULL, dexOffset + dexLength, PROT_READ|PROT_WRITE,
5672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    MAP_SHARED, fd, 0);
5682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (mapAddr == MAP_FAILED) {
569c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block            ALOGE("unable to mmap DEX cache: %s", strerror(errno));
5702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto bail;
5712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
5722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
57357fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden        bool doVerify, doOpt;
57457fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden        if (gDvm.classVerifyMode == VERIFY_MODE_NONE) {
57557fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden            doVerify = false;
57657fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden        } else if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE) {
57757fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden            doVerify = !gDvm.optimizingBootstrapClass;
57857fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden        } else /*if (gDvm.classVerifyMode == VERIFY_MODE_ALL)*/ {
57957fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden            doVerify = true;
58057fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden        }
58157fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden
58257fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden        if (gDvm.dexOptMode == OPTIMIZE_MODE_NONE) {
58357fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden            doOpt = false;
58457fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden        } else if (gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED ||
58557fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden                   gDvm.dexOptMode == OPTIMIZE_MODE_FULL) {
58657fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden            doOpt = doVerify;
58757fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden        } else /*if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)*/ {
58857fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden            doOpt = true;
58957fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden        }
59057fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden
5912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
5922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Rewrite the file.  Byte reordering, structure realigning,
5932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * class verification, and bytecode optimization are all performed
5942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * here.
5952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         *
5962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * In theory the file could change size and bits could shift around.
5972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * In practice this would be annoying to deal with, so the file
5982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * layout is designed so that it can always be rewritten in place.
5992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         *
60057fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden         * This creates the class lookup table as part of doing the processing.
6012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
602cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        success = rewriteDex(((u1*) mapAddr) + dexOffset, dexLength,
60357fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden                    doVerify, doOpt, &pClassLookup, NULL);
6042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (success) {
6062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            DvmDex* pDvmDex = NULL;
6072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            u1* dexAddr = ((u1*) mapAddr) + dexOffset;
6082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (dvmDexFileOpenPartial(dexAddr, dexLength, &pDvmDex) != 0) {
610c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block                ALOGE("Unable to create DexFile");
6112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                success = false;
6122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            } else {
6132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                /*
614cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                 * If configured to do so, generate register map output
615cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                 * for all verified classes.  The register maps were
616cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                 * generated during verification, and will now be serialized.
6172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 */
6182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                if (gDvm.generateRegisterMaps) {
6192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    pRegMapBuilder = dvmGenerateRegisterMaps(pDvmDex);
6202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    if (pRegMapBuilder == NULL) {
621c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block                        ALOGE("Failed generating register maps");
6222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                        success = false;
6232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    }
6242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                }
6252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                DexHeader* pHeader = (DexHeader*)pDvmDex->pHeader;
6272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                updateChecksum(dexAddr, dexLength, pHeader);
6282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dvmDexFileFree(pDvmDex);
6302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
6312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
6322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* unmap the read-write version, forcing writes to disk */
6342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (msync(mapAddr, dexOffset + dexLength, MS_SYNC) != 0) {
635e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block            ALOGW("msync failed: %s", strerror(errno));
6362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            // weird, but keep going
6372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
6382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#if 1
6392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
6402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * This causes clean shutdown to fail, because we have loaded classes
6412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * that point into it.  For the optimizer this isn't a problem,
6422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * because it's more efficient for the process to simply exit.
6432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Exclude this code when doing clean shutdown for valgrind.
6442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
6452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (munmap(mapAddr, dexOffset + dexLength) != 0) {
646c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block            ALOGE("munmap failed: %s", strerror(errno));
6472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto bail;
6482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
6492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#endif
6502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (!success)
6522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto bail;
6532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
6542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* get start offset, and adjust deps start for 64-bit alignment */
656e377ef62a40267ab16c2dd20cc5f4c63af6397ccDan Bornstein    off_t depsOffset, optOffset, endOffset, adjOffset;
657e377ef62a40267ab16c2dd20cc5f4c63af6397ccDan Bornstein    int depsLength, optLength;
6582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u4 optChecksum;
6592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    depsOffset = lseek(fd, 0, SEEK_END);
6612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (depsOffset < 0) {
662c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("lseek to EOF failed: %s", strerror(errno));
6632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
6642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
6652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    adjOffset = (depsOffset + 7) & ~(0x07);
6662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (adjOffset != depsOffset) {
66792c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("Adjusting deps start from %d to %d",
6682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            (int) depsOffset, (int) adjOffset);
6692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        depsOffset = adjOffset;
6702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        lseek(fd, depsOffset, SEEK_SET);
6712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
6722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
6742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Append the dependency list.
6752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
6762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (writeDependencies(fd, modWhen, crc) != 0) {
677e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("Failed writing dependencies");
6782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
6792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
6802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
681e377ef62a40267ab16c2dd20cc5f4c63af6397ccDan Bornstein    /* compute deps length, then adjust opt start for 64-bit alignment */
682e377ef62a40267ab16c2dd20cc5f4c63af6397ccDan Bornstein    optOffset = lseek(fd, 0, SEEK_END);
683e377ef62a40267ab16c2dd20cc5f4c63af6397ccDan Bornstein    depsLength = optOffset - depsOffset;
6842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
685e377ef62a40267ab16c2dd20cc5f4c63af6397ccDan Bornstein    adjOffset = (optOffset + 7) & ~(0x07);
686e377ef62a40267ab16c2dd20cc5f4c63af6397ccDan Bornstein    if (adjOffset != optOffset) {
68792c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("Adjusting opt start from %d to %d",
688e377ef62a40267ab16c2dd20cc5f4c63af6397ccDan Bornstein            (int) optOffset, (int) adjOffset);
689e377ef62a40267ab16c2dd20cc5f4c63af6397ccDan Bornstein        optOffset = adjOffset;
690e377ef62a40267ab16c2dd20cc5f4c63af6397ccDan Bornstein        lseek(fd, optOffset, SEEK_SET);
6912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
6922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
694e377ef62a40267ab16c2dd20cc5f4c63af6397ccDan Bornstein     * Append any optimized pre-computed data structures.
6952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
696d394371bd84bacc51e96e2d2eacb8549d9110b1eDan Bornstein    if (!writeOptData(fd, pClassLookup, pRegMapBuilder)) {
697e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("Failed writing opt data");
6982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
6992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
7002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    endOffset = lseek(fd, 0, SEEK_END);
702e377ef62a40267ab16c2dd20cc5f4c63af6397ccDan Bornstein    optLength = endOffset - optOffset;
7032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
704e377ef62a40267ab16c2dd20cc5f4c63af6397ccDan Bornstein    /* compute checksum from start of deps to end of opt area */
7052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!computeFileChecksum(fd, depsOffset,
706e377ef62a40267ab16c2dd20cc5f4c63af6397ccDan Bornstein            (optOffset+optLength) - depsOffset, &optChecksum))
7072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    {
7082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
7092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
7102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
7122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Output the "opt" header with all values filled in and a correct
7132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * magic number.
7142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
7152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DexOptHeader optHdr;
7162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    memset(&optHdr, 0xff, sizeof(optHdr));
7172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    memcpy(optHdr.magic, DEX_OPT_MAGIC, 4);
7182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    memcpy(optHdr.magic+4, DEX_OPT_MAGIC_VERS, 4);
7192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    optHdr.dexOffset = (u4) dexOffset;
7202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    optHdr.dexLength = (u4) dexLength;
7212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    optHdr.depsOffset = (u4) depsOffset;
7222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    optHdr.depsLength = (u4) depsLength;
723e377ef62a40267ab16c2dd20cc5f4c63af6397ccDan Bornstein    optHdr.optOffset = (u4) optOffset;
724e377ef62a40267ab16c2dd20cc5f4c63af6397ccDan Bornstein    optHdr.optLength = (u4) optLength;
72557fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden#if __BYTE_ORDER != __LITTLE_ENDIAN
72657fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    optHdr.flags = DEX_OPT_FLAG_BIG;
72757fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden#else
72857fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    optHdr.flags = 0;
72957fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden#endif
7302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    optHdr.checksum = optChecksum;
7312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
732c650d2beb66896c0cf51f737d7a39476630dd142Andy McFadden    fsync(fd);      /* ensure previous writes go before header is written */
733c650d2beb66896c0cf51f737d7a39476630dd142Andy McFadden
7342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    lseek(fd, 0, SEEK_SET);
73564896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden    if (sysWriteFully(fd, &optHdr, sizeof(optHdr), "DexOpt opt header") != 0)
7362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
7372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
73892c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block    ALOGV("Successfully wrote DEX header");
7392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    result = true;
7402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    //dvmRegisterMapDumpStats();
7422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenbail:
7442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    dvmFreeRegisterMapBuilder(pRegMapBuilder);
7452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    free(pClassLookup);
7462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return result;
7472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
7482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
74957fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden/*
75057fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden * Prepare an in-memory DEX file.
75157fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden *
75257fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden * The data was presented to the VM as a byte array rather than a file.
75357fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden * We want to do the same basic set of operations, but we can just leave
75457fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden * them in memory instead of writing them out to a cached optimized DEX file.
75557fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden */
75657fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFaddenbool dvmPrepareDexInMemory(u1* addr, size_t len, DvmDex** ppDvmDex)
75757fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden{
75857fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    DexClassLookup* pClassLookup = NULL;
75957fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden
76057fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    /*
76157fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden     * Byte-swap, realign, verify basic DEX file structure.
76257fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden     *
76357fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden     * We could load + verify + optimize here as well, but that's probably
76457fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden     * not desirable.
76557fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden     *
76657fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden     * (The bulk-verification code is currently only setting the DEX
76757fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden     * file's "verified" flag, not updating the ClassObject.  This would
76857fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden     * also need to be changed, or we will try to verify the class twice,
76957fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden     * and possibly reject it when optimized opcodes are encountered.)
77057fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden     */
77157fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    if (!rewriteDex(addr, len, false, false, &pClassLookup, ppDvmDex)) {
77257fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden        return false;
77357fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    }
77457fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden
77557fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    (*ppDvmDex)->pDexFile->pClassLookup = pClassLookup;
77657fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden
77757fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    return true;
77857fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden}
7792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
781cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * Perform in-place rewrites on a memory-mapped DEX file.
782cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden *
78357fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden * If this is called from a short-lived child process (dexopt), we can
78457fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden * go nutty with loading classes and allocating memory.  When it's
78557fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden * called to prepare classes provided in a byte array, we may want to
78657fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden * be more conservative.
78757fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden *
78857fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden * If "ppClassLookup" is non-NULL, a pointer to a newly-allocated
78957fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden * DexClassLookup will be returned on success.
79057fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden *
79157fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden * If "ppDvmDex" is non-NULL, a newly-allocated DvmDex struct will be
79257fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden * returned on success.
793cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden */
79457fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFaddenstatic bool rewriteDex(u1* addr, int len, bool doVerify, bool doOpt,
79557fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    DexClassLookup** ppClassLookup, DvmDex** ppDvmDex)
796cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden{
79757fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    DexClassLookup* pClassLookup = NULL;
798cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    u8 prepWhen, loadWhen, verifyOptWhen;
799cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    DvmDex* pDvmDex = NULL;
800cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    bool result = false;
8011813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro    const char* msgStr = "???";
802cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
803cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    /* if the DEX is in the wrong byte order, swap it now */
8044b0750e8df91220690bb417f45d7ae8b7851b220Dan Bornstein    if (dexSwapAndVerify(addr, len) != 0)
805cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        goto bail;
806cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
807cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    /*
808cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * Now that the DEX file can be read directly, create a DexFile struct
809cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * for it.
810cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     */
811cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    if (dvmDexFileOpenPartial(addr, len, &pDvmDex) != 0) {
812c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("Unable to create DexFile");
813cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        goto bail;
814cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    }
815cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
816cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    /*
817cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * Create the class lookup table.  This will eventually be appended
818cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * to the end of the .odex.
81957fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden     *
82057fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden     * We create a temporary link from the DexFile for the benefit of
82157fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden     * class loading, below.
822cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     */
82357fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    pClassLookup = dexCreateClassLookup(pDvmDex->pDexFile);
82457fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    if (pClassLookup == NULL)
825cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        goto bail;
82657fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    pDvmDex->pDexFile->pClassLookup = pClassLookup;
827cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
828cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    /*
829cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * If we're not going to attempt to verify or optimize the classes,
830cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * there's no value in loading them, so bail out early.
831cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     */
832cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    if (!doVerify && !doOpt) {
833cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        result = true;
834cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        goto bail;
835cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    }
836cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
837cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    prepWhen = dvmGetRelativeTimeUsec();
838cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
839cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    /*
840cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * Load all classes found in this DEX file.  If they fail to load for
841cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * some reason, they won't get verified (which is as it should be).
842cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     */
843cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    if (!loadAllClasses(pDvmDex))
844cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        goto bail;
845cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    loadWhen = dvmGetRelativeTimeUsec();
846cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
847cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    /*
84865a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden     * Create a data structure for use by the bytecode optimizer.
84965a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden     * We need to look up methods in a few classes, so this may cause
85065a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden     * a bit of class loading.  We usually do this during VM init, but
85165a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden     * for dexopt on core.jar the order of operations gets a bit tricky,
85265a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden     * so we defer it to here.
85365a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden     */
85465a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden    if (!dvmCreateInlineSubsTable())
85565a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden        goto bail;
85665a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden
85765a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden    /*
858cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * Verify and optimize all classes in the DEX file (command-line
859cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * options permitting).
860cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     *
861cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * This is best-effort, so there's really no way for dexopt to
862cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * fail at this point.
863cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     */
864cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    verifyAndOptimizeClasses(pDvmDex->pDexFile, doVerify, doOpt);
865cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    verifyOptWhen = dvmGetRelativeTimeUsec();
866cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
867cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    if (doVerify && doOpt)
868cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        msgStr = "verify+opt";
869cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    else if (doVerify)
870cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        msgStr = "verify";
871cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    else if (doOpt)
872cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        msgStr = "opt";
8736ad3f100edffe51b2d4592dce893e1e2bb566161jeffhao    ALOGD("DexOpt: load %dms, %s %dms, %d bytes",
874cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        (int) (loadWhen - prepWhen) / 1000,
875cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        msgStr,
8766ad3f100edffe51b2d4592dce893e1e2bb566161jeffhao        (int) (verifyOptWhen - loadWhen) / 1000,
8776ad3f100edffe51b2d4592dce893e1e2bb566161jeffhao        gDvm.pBootLoaderAlloc->curOffset);
878cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
879cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    result = true;
880cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
881cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenbail:
88257fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    /*
88357fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden     * On success, return the pieces that the caller asked for.
88457fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden     */
885a78b1255ad1ce8dcacad21338d4f88db4231c4cdAndy McFadden
886a78b1255ad1ce8dcacad21338d4f88db4231c4cdAndy McFadden    if (pDvmDex != NULL) {
887a78b1255ad1ce8dcacad21338d4f88db4231c4cdAndy McFadden        /* break link between the two */
888a78b1255ad1ce8dcacad21338d4f88db4231c4cdAndy McFadden        pDvmDex->pDexFile->pClassLookup = NULL;
889a78b1255ad1ce8dcacad21338d4f88db4231c4cdAndy McFadden    }
890a78b1255ad1ce8dcacad21338d4f88db4231c4cdAndy McFadden
89157fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    if (ppDvmDex == NULL || !result) {
89257fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden        dvmDexFileFree(pDvmDex);
89357fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    } else {
89457fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden        *ppDvmDex = pDvmDex;
89557fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    }
89657fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden
89757fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    if (ppClassLookup == NULL || !result) {
89857fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden        free(pClassLookup);
89957fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    } else {
90057fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden        *ppClassLookup = pClassLookup;
90157fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    }
90257fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden
903cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    return result;
904cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden}
905cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
906cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden/*
907cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * Try to load all classes in the specified DEX.  If they have some sort
908cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * of broken dependency, e.g. their superclass lives in a different DEX
909cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * that wasn't previously loaded into the bootstrap class path, loading
910cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * will fail.  This is the desired behavior.
911cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden *
912cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * We have no notion of class loader at this point, so we load all of
913cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * the classes with the bootstrap class loader.  It turns out this has
914cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * exactly the behavior we want, and has no ill side effects because we're
915cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * running in a separate process and anything we load here will be forgotten.
916cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden *
917cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * We set the CLASS_MULTIPLE_DEFS flag here if we see multiple definitions.
918cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * This works because we only call here as part of optimization / pre-verify,
919cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * not during verification as part of loading a class into a running VM.
920cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden *
921cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * This returns "false" if the world is too screwed up to do anything
922cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * useful at all.
923cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden */
924cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenstatic bool loadAllClasses(DvmDex* pDvmDex)
925cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden{
926cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    u4 count = pDvmDex->pDexFile->pHeader->classDefsSize;
927cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    u4 idx;
928cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    int loaded = 0;
929cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
93092c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block    ALOGV("DexOpt: +++ trying to load %d classes", count);
931cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
932cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    dvmSetBootPathExtraDex(pDvmDex);
933cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
934cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    /*
9358521311b4e55847c650a87933d5a3f04618e4e69Dan Bornstein     * At this point, it is safe -- and necessary! -- to look up the
9368521311b4e55847c650a87933d5a3f04618e4e69Dan Bornstein     * VM's required classes and members, even when what we are in the
9378521311b4e55847c650a87933d5a3f04618e4e69Dan Bornstein     * process of processing is the core library that defines these
9384b5fa2e50860015beebcc5fc3a33265b266d6d34Dan Bornstein     * classes itself. (The reason it is necessary is that in the act
9394b5fa2e50860015beebcc5fc3a33265b266d6d34Dan Bornstein     * of initializing the class Class, below, the system will end up
9404b5fa2e50860015beebcc5fc3a33265b266d6d34Dan Bornstein     * referring to many of the class references that got set up by
9414b5fa2e50860015beebcc5fc3a33265b266d6d34Dan Bornstein     * this call.)
9428521311b4e55847c650a87933d5a3f04618e4e69Dan Bornstein     */
9434b5fa2e50860015beebcc5fc3a33265b266d6d34Dan Bornstein    if (!dvmFindRequiredClassesAndMembers()) {
9448521311b4e55847c650a87933d5a3f04618e4e69Dan Bornstein        return false;
9458521311b4e55847c650a87933d5a3f04618e4e69Dan Bornstein    }
9468521311b4e55847c650a87933d5a3f04618e4e69Dan Bornstein
9478521311b4e55847c650a87933d5a3f04618e4e69Dan Bornstein    /*
9488521311b4e55847c650a87933d5a3f04618e4e69Dan Bornstein     * We have some circularity issues with Class and Object that are
9498521311b4e55847c650a87933d5a3f04618e4e69Dan Bornstein     * most easily avoided by ensuring that Object is never the first
9508521311b4e55847c650a87933d5a3f04618e4e69Dan Bornstein     * thing we try to find-and-initialize. The call to
9518521311b4e55847c650a87933d5a3f04618e4e69Dan Bornstein     * dvmFindSystemClass() here takes care of that situation. (We
9528521311b4e55847c650a87933d5a3f04618e4e69Dan Bornstein     * only need to do this when loading classes from the DEX file
9538521311b4e55847c650a87933d5a3f04618e4e69Dan Bornstein     * that contains Object, and only when Object comes first in the
9548521311b4e55847c650a87933d5a3f04618e4e69Dan Bornstein     * list, but it costs very little to do it in all cases.)
955cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     */
9563111b0c80ca3f90e966371cbab606ac38ed17cadDan Bornstein    if (!dvmInitClass(gDvm.classJavaLangClass)) {
957c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("ERROR: failed to initialize the class Class!");
958cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        return false;
959cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    }
960cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
961cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    for (idx = 0; idx < count; idx++) {
962cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        const DexClassDef* pClassDef;
963cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        const char* classDescriptor;
964cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        ClassObject* newClass;
965cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
966cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        pClassDef = dexGetClassDef(pDvmDex->pDexFile, idx);
967cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        classDescriptor =
968cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            dexStringByTypeIdx(pDvmDex->pDexFile, pClassDef->classIdx);
969cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
97092c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("+++  loading '%s'", classDescriptor);
971cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        //newClass = dvmDefineClass(pDexFile, classDescriptor,
972cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        //        NULL);
973cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        newClass = dvmFindSystemClassNoInit(classDescriptor);
974cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        if (newClass == NULL) {
97592c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block            ALOGV("DexOpt: failed loading '%s'", classDescriptor);
976cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            dvmClearOptException(dvmThreadSelf());
977cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        } else if (newClass->pDvmDex != pDvmDex) {
978cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            /*
979cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden             * We don't load the new one, and we tag the first one found
980cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden             * with the "multiple def" flag so the resolver doesn't try
981cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden             * to make it available.
982cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden             */
983062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block            ALOGD("DexOpt: '%s' has an earlier definition; blocking out",
984cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                classDescriptor);
985cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            SET_CLASS_FLAG(newClass, CLASS_MULTIPLE_DEFS);
986cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        } else {
987cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            loaded++;
988cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        }
989cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    }
99092c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block    ALOGV("DexOpt: +++ successfully loaded %d classes", loaded);
991cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
992cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    dvmSetBootPathExtraDex(NULL);
993cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    return true;
994cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden}
995cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
996cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden/*
997cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * Verify and/or optimize all classes that were successfully loaded from
998cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * this DEX file.
999cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden */
1000cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenstatic void verifyAndOptimizeClasses(DexFile* pDexFile, bool doVerify,
1001cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    bool doOpt)
1002cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden{
1003cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    u4 count = pDexFile->pHeader->classDefsSize;
1004cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    u4 idx;
1005cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
1006cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    for (idx = 0; idx < count; idx++) {
1007cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        const DexClassDef* pClassDef;
1008cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        const char* classDescriptor;
1009cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        ClassObject* clazz;
1010cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
1011cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        pClassDef = dexGetClassDef(pDexFile, idx);
1012cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
1013cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
1014cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        /* all classes are loaded into the bootstrap class loader */
1015cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        clazz = dvmLookupClass(classDescriptor, NULL, false);
1016cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        if (clazz != NULL) {
1017cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            verifyAndOptimizeClass(pDexFile, clazz, pClassDef, doVerify, doOpt);
1018cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
1019cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        } else {
1020cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            // TODO: log when in verbose mode
102192c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block            ALOGV("DexOpt: not optimizing unavailable class '%s'",
1022cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                classDescriptor);
1023cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        }
1024cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    }
1025cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
1026470cbbbe39cffd9b1cf52562048c60be543004c6Andy McFadden#ifdef VERIFIER_STATS
10274308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block    ALOGI("Verifier stats:");
10284308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block    ALOGI(" methods examined        : %u", gDvm.verifierStats.methodsExamined);
10294308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block    ALOGI(" monitor-enter methods   : %u", gDvm.verifierStats.monEnterMethods);
10304308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block    ALOGI(" instructions examined   : %u", gDvm.verifierStats.instrsExamined);
10314308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block    ALOGI(" instructions re-examined: %u", gDvm.verifierStats.instrsReexamined);
10324308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block    ALOGI(" copying of register sets: %u", gDvm.verifierStats.copyRegCount);
10334308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block    ALOGI(" merging of register sets: %u", gDvm.verifierStats.mergeRegCount);
10344308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block    ALOGI(" ...that caused changes  : %u", gDvm.verifierStats.mergeRegChanged);
10354308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block    ALOGI(" uninit searches         : %u", gDvm.verifierStats.uninitSearches);
10364308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block    ALOGI(" max memory required     : %u", gDvm.verifierStats.biggestAlloc);
1037470cbbbe39cffd9b1cf52562048c60be543004c6Andy McFadden#endif
1038cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden}
1039cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
1040cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden/*
1041cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * Verify and/or optimize a specific class.
1042cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden */
1043cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenstatic void verifyAndOptimizeClass(DexFile* pDexFile, ClassObject* clazz,
1044cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    const DexClassDef* pClassDef, bool doVerify, bool doOpt)
1045cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden{
1046cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    const char* classDescriptor;
1047cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    bool verified = false;
1048cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
10493f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden    if (clazz->pDvmDex->pDexFile != pDexFile) {
10503f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden        /*
10513f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden         * The current DEX file defined a class that is also present in the
10523f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden         * bootstrap class path.  The class loader favored the bootstrap
10533f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden         * version, which means that we have a pointer to a class that is
10543f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden         * (a) not the one we want to examine, and (b) mapped read-only,
10553f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden         * so we will seg fault if we try to rewrite instructions inside it.
10563f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden         */
1057062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block        ALOGD("DexOpt: not verifying/optimizing '%s': multiple definitions",
10583f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden            clazz->descriptor);
10593f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden        return;
10603f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden    }
10613f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden
1062cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
1063cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
1064cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    /*
1065cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * First, try to verify it.
1066cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     */
1067cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    if (doVerify) {
10683f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden        if (dvmVerifyClass(clazz)) {
10693f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden            /*
10703f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden             * Set the "is preverified" flag in the DexClassDef.  We
10713f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden             * do it here, rather than in the ClassObject structure,
10723f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden             * because the DexClassDef is part of the odex file.
10733f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden             */
10743f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden            assert((clazz->accessFlags & JAVA_FLAGS_MASK) ==
10753f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden                pClassDef->accessFlags);
10763f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden            ((DexClassDef*)pClassDef)->accessFlags |= CLASS_ISPREVERIFIED;
10773f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden            verified = true;
1078cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        } else {
10793f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden            // TODO: log when in verbose mode
108092c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block            ALOGV("DexOpt: '%s' failed verification", classDescriptor);
1081cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        }
1082cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    }
1083cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
1084cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    if (doOpt) {
1085d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden        bool needVerify = (gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED ||
1086d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                           gDvm.dexOptMode == OPTIMIZE_MODE_FULL);
1087d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden        if (!verified && needVerify) {
108892c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block            ALOGV("DexOpt: not optimizing '%s': not verified",
1089cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                classDescriptor);
1090cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        } else {
1091fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            dvmOptimizeClass(clazz, false);
1092cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
1093cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            /* set the flag whether or not we actually changed anything */
1094cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            ((DexClassDef*)pClassDef)->accessFlags |= CLASS_ISOPTIMIZED;
1095cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        }
1096cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    }
1097cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden}
1098cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
1099cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
1100cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden/*
11012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Get the cache file name from a ClassPathEntry.
11022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
11032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic const char* getCacheFileName(const ClassPathEntry* cpe)
11042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
11052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    switch (cpe->kind) {
11062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    case kCpeJar:
11072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return dvmGetJarFileCacheFileName((JarFile*) cpe->ptr);
11082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    case kCpeDex:
11092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return dvmGetRawDexFileCacheFileName((RawDexFile*) cpe->ptr);
11102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    default:
1111c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("DexOpt: unexpected cpe kind %d", cpe->kind);
11122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmAbort();
11132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return NULL;
11142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
11152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
11162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
11182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Get the SHA-1 signature.
11192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
11202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic const u1* getSignature(const ClassPathEntry* cpe)
11212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
11222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DvmDex* pDvmDex;
11232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    switch (cpe->kind) {
11252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    case kCpeJar:
11262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pDvmDex = dvmGetJarFileDex((JarFile*) cpe->ptr);
11272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        break;
11282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    case kCpeDex:
11292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pDvmDex = dvmGetRawDexFileDex((RawDexFile*) cpe->ptr);
11302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        break;
11312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    default:
1132c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("unexpected cpe kind %d", cpe->kind);
11332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmAbort();
11342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pDvmDex = NULL;         // make gcc happy
11352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
11362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(pDvmDex != NULL);
11382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return pDvmDex->pDexFile->pHeader->signature;
11392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
11402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
11432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Dependency layout:
11442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *  4b  Source file modification time, in seconds since 1970 UTC
11452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *  4b  CRC-32 from Zip entry, or Adler32 from source DEX header
11462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *  4b  Dalvik VM build number
11472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *  4b  Number of dependency entries that follow
11482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *  Dependency entries:
11492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *    4b  Name length (including terminating null)
11502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *    var Full path of cache entry (null terminated)
11512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *    20b SHA-1 signature from source DEX file
11522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
11532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * If this changes, update DEX_OPT_MAGIC_VERS.
11542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
11552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic const size_t kMinDepSize = 4 * 4;
11568b31f73c2d72cfac18125f15bc69a74d3204389bJesse Wilsonstatic const size_t kMaxDepSize = 4 * 4 + 2048;     // sanity check
11572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
11592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Read the "opt" header, verify it, then read the dependencies section
11602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * and verify that data as well.
11612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
11622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * If "sourceAvail" is "true", this will verify that "modWhen" and "crc"
11632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * match up with what is stored in the header.  If they don't, we reject
11642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * the file so that it can be recreated from the updated original.  If
11652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * "sourceAvail" isn't set, e.g. for a .odex file, we ignore these arguments.
11662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
11672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On successful return, the file will be seeked immediately past the
11682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * "opt" header.
11692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
11702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenbool dvmCheckOptHeaderAndDependencies(int fd, bool sourceAvail, u4 modWhen,
11712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u4 crc, bool expectVerify, bool expectOpt)
11722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
11732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DexOptHeader optHdr;
11742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u1* depData = NULL;
11752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const u1* magic;
11762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    off_t posn;
11772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int result = false;
11782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ssize_t actual;
11792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
11812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Start at the start.  The "opt" header, when present, will always be
11822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * the first thing in the file.
11832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
11842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (lseek(fd, 0, SEEK_SET) != 0) {
1185c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("DexOpt: failed to seek to start of file: %s", strerror(errno));
11862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
11872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
11882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
11902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Read and do trivial verification on the opt header.  The header is
11912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * always in host byte order.
11922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
1193e7ad112562af04d825fdd0d403deaf0ddd70a2eaAndy McFadden    actual = read(fd, &optHdr, sizeof(optHdr));
1194e7ad112562af04d825fdd0d403deaf0ddd70a2eaAndy McFadden    if (actual < 0) {
1195c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("DexOpt: failed reading opt header: %s", strerror(errno));
11962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
1197e7ad112562af04d825fdd0d403deaf0ddd70a2eaAndy McFadden    } else if (actual != sizeof(optHdr)) {
1198c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("DexOpt: failed reading opt header (got %d of %zd)",
1199e7ad112562af04d825fdd0d403deaf0ddd70a2eaAndy McFadden            (int) actual, sizeof(optHdr));
1200e7ad112562af04d825fdd0d403deaf0ddd70a2eaAndy McFadden        goto bail;
12012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
12022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    magic = optHdr.magic;
1204e7ad112562af04d825fdd0d403deaf0ddd70a2eaAndy McFadden    if (memcmp(magic, DEX_MAGIC, 4) == 0) {
1205e7ad112562af04d825fdd0d403deaf0ddd70a2eaAndy McFadden        /* somebody probably pointed us at the wrong file */
1206062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block        ALOGD("DexOpt: expected optimized DEX, found unoptimized");
1207e7ad112562af04d825fdd0d403deaf0ddd70a2eaAndy McFadden        goto bail;
1208e7ad112562af04d825fdd0d403deaf0ddd70a2eaAndy McFadden    } else if (memcmp(magic, DEX_OPT_MAGIC, 4) != 0) {
12092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* not a DEX file, or previous attempt was interrupted */
1210062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block        ALOGD("DexOpt: incorrect opt magic number (0x%02x %02x %02x %02x)",
12112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            magic[0], magic[1], magic[2], magic[3]);
12122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
12132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
12142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (memcmp(magic+4, DEX_OPT_MAGIC_VERS, 4) != 0) {
1215e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("DexOpt: stale opt version (0x%02x %02x %02x %02x)",
12162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            magic[4], magic[5], magic[6], magic[7]);
12172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
12182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
12192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (optHdr.depsLength < kMinDepSize || optHdr.depsLength > kMaxDepSize) {
1220e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("DexOpt: weird deps length %d, bailing", optHdr.depsLength);
12212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
12222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
12232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
12252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Do the header flags match up with what we want?
12262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     *
122757fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden     * The only thing we really can't handle is incorrect byte ordering.
12282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
12291813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro    {
12301813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro        const u4 matchMask = DEX_OPT_FLAG_BIG;
12311813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro        u4 expectedFlags = 0;
12322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#if __BYTE_ORDER != __LITTLE_ENDIAN
12331813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro        expectedFlags |= DEX_OPT_FLAG_BIG;
12342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#endif
12351813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro        if ((expectedFlags & matchMask) != (optHdr.flags & matchMask)) {
12364308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block            ALOGI("DexOpt: header flag mismatch (0x%02x vs 0x%02x, mask=0x%02x)",
12371813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro                expectedFlags, optHdr.flags, matchMask);
12381813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro            goto bail;
12391813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro        }
12402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
12412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    posn = lseek(fd, optHdr.depsOffset, SEEK_SET);
12432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (posn < 0) {
1244e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("DexOpt: seek to deps failed: %s", strerror(errno));
12452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
12462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
12472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
12492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Read all of the dependency stuff into memory.
12502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
12512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    depData = (u1*) malloc(optHdr.depsLength);
12522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (depData == NULL) {
1253e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("DexOpt: unable to allocate %d bytes for deps",
12542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            optHdr.depsLength);
12552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
12562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
12572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    actual = read(fd, depData, optHdr.depsLength);
1258e7ad112562af04d825fdd0d403deaf0ddd70a2eaAndy McFadden    if (actual < 0) {
1259e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("DexOpt: failed reading deps: %s", strerror(errno));
1260e7ad112562af04d825fdd0d403deaf0ddd70a2eaAndy McFadden        goto bail;
1261e7ad112562af04d825fdd0d403deaf0ddd70a2eaAndy McFadden    } else if (actual != (ssize_t) optHdr.depsLength) {
1262e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("DexOpt: failed reading deps: got %d of %d",
1263e7ad112562af04d825fdd0d403deaf0ddd70a2eaAndy McFadden            (int) actual, optHdr.depsLength);
12642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
12652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
12662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
12682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Verify simple items.
12692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
12702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const u1* ptr;
12712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u4 val;
12722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ptr = depData;
12742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    val = read4LE(&ptr);
12752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (sourceAvail && val != modWhen) {
12764308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block        ALOGI("DexOpt: source file mod time mismatch (%08x vs %08x)",
12772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            val, modWhen);
12782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
12792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
12802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    val = read4LE(&ptr);
12812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (sourceAvail && val != crc) {
12824308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block        ALOGI("DexOpt: source file CRC mismatch (%08x vs %08x)", val, crc);
12832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
12842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
12852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    val = read4LE(&ptr);
12862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (val != DALVIK_VM_BUILD) {
1287062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block        ALOGD("DexOpt: VM build version mismatch (%d vs %d)",
12882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            val, DALVIK_VM_BUILD);
12892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
12902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
12912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
12932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Verify dependencies on other cached DEX files.  It must match
12942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * exactly with what is currently defined in the bootclasspath.
12952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
12962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassPathEntry* cpe;
12972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u4 numDeps;
12982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    numDeps = read4LE(&ptr);
130092c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block    ALOGV("+++ DexOpt: numDeps = %d", numDeps);
13012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
130232bc0787307ba57e92fa74c52da550e2ca22af7fDan Bornstein        const char* cacheFileName =
130332bc0787307ba57e92fa74c52da550e2ca22af7fDan Bornstein            dvmPathToAbsolutePortion(getCacheFileName(cpe));
130432bc0787307ba57e92fa74c52da550e2ca22af7fDan Bornstein        assert(cacheFileName != NULL); /* guaranteed by Class.c */
130532bc0787307ba57e92fa74c52da550e2ca22af7fDan Bornstein
13062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const u1* signature = getSignature(cpe);
13072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        size_t len = strlen(cacheFileName) +1;
13082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        u4 storedStrLen;
13092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (numDeps == 0) {
13112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* more entries in bootclasspath than in deps list */
13124308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block            ALOGI("DexOpt: not all deps represented");
13132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto bail;
13142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
13152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        storedStrLen = read4LE(&ptr);
13172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (len != storedStrLen ||
13182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            strcmp(cacheFileName, (const char*) ptr) != 0)
13192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        {
13204308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block            ALOGI("DexOpt: mismatch dep name: '%s' vs. '%s'",
13212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                cacheFileName, ptr);
13222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto bail;
13232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
13242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ptr += storedStrLen;
13262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (memcmp(signature, ptr, kSHA1DigestLen) != 0) {
13284308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block            ALOGI("DexOpt: mismatch dep signature for '%s'", cacheFileName);
13292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto bail;
13302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
13312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ptr += kSHA1DigestLen;
13322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
133392c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("DexOpt: dep match on '%s'", cacheFileName);
13342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        numDeps--;
13362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
13372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (numDeps != 0) {
13392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* more entries in deps list than in classpath */
13404308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block        ALOGI("DexOpt: Some deps went away");
13412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
13422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
13432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    // consumed all data and no more?
13452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (ptr != depData + optHdr.depsLength) {
1346e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("DexOpt: Spurious dep data? %d vs %d",
13472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            (int) (ptr - depData), optHdr.depsLength);
13482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        assert(false);
13492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
13502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    result = true;
13522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenbail:
13542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    free(depData);
13552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return result;
13562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
13572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
13592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Write the dependency info to "fd" at the current file position.
13602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
13612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic int writeDependencies(int fd, u4 modWhen, u4 crc)
13622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
13632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u1* buf = NULL;
13642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int result = -1;
13652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ssize_t bufLen;
13662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassPathEntry* cpe;
1367e3c01dac83e6eea7f82fe81ed89cfbdd9791dbc9Carl Shapiro    int numDeps;
13682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
13702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Count up the number of completed entries in the bootclasspath.
13712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
13722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    numDeps = 0;
13732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bufLen = 0;
13742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
137532bc0787307ba57e92fa74c52da550e2ca22af7fDan Bornstein        const char* cacheFileName =
137632bc0787307ba57e92fa74c52da550e2ca22af7fDan Bornstein            dvmPathToAbsolutePortion(getCacheFileName(cpe));
137732bc0787307ba57e92fa74c52da550e2ca22af7fDan Bornstein        assert(cacheFileName != NULL); /* guaranteed by Class.c */
137832bc0787307ba57e92fa74c52da550e2ca22af7fDan Bornstein
137992c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("+++ DexOpt: found dep '%s'", cacheFileName);
13802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        numDeps++;
13822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        bufLen += strlen(cacheFileName) +1;
13832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
13842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bufLen += 4*4 + numDeps * (4+kSHA1DigestLen);
13862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1387fc75f3ed87b55d625b6054e18645da5cbdba31c6Carl Shapiro    buf = (u1*)malloc(bufLen);
13882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    set4LE(buf+0, modWhen);
13902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    set4LE(buf+4, crc);
13912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    set4LE(buf+8, DALVIK_VM_BUILD);
13922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    set4LE(buf+12, numDeps);
13932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    // TODO: do we want to add dvmGetInlineOpsTableLength() here?  Won't
13952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    // help us if somebody replaces an existing entry, but it'd catch
13962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    // additions/removals.
13972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u1* ptr = buf + 4*4;
13992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
140032bc0787307ba57e92fa74c52da550e2ca22af7fDan Bornstein        const char* cacheFileName =
140132bc0787307ba57e92fa74c52da550e2ca22af7fDan Bornstein            dvmPathToAbsolutePortion(getCacheFileName(cpe));
140232bc0787307ba57e92fa74c52da550e2ca22af7fDan Bornstein        assert(cacheFileName != NULL); /* guaranteed by Class.c */
140332bc0787307ba57e92fa74c52da550e2ca22af7fDan Bornstein
14042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const u1* signature = getSignature(cpe);
14052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int len = strlen(cacheFileName) +1;
14062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
14072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (ptr + 4 + len + kSHA1DigestLen > buf + bufLen) {
1408c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block            ALOGE("DexOpt: overran buffer");
14092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dvmAbort();
14102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
14112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
14122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        set4LE(ptr, len);
14132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ptr += 4;
14142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        memcpy(ptr, cacheFileName, len);
14152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ptr += len;
14162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        memcpy(ptr, signature, kSHA1DigestLen);
14172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ptr += kSHA1DigestLen;
14182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
14192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
14202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(ptr == buf + bufLen);
14212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
142264896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden    result = sysWriteFully(fd, buf, bufLen, "DexOpt dep info");
14232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
14242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    free(buf);
14252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return result;
14262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
14272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
14282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
14292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
14302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Write a block of data in "chunk" format.
14312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
14322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * The chunk header fields are always in "native" byte order.  If "size"
14332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * is not a multiple of 8 bytes, the data area is padded out.
14342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
14352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool writeChunk(int fd, u4 type, const void* data, size_t size)
14362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
14372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    union {             /* save a syscall by grouping these together */
14382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        char raw[8];
14392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        struct {
14402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            u4 type;
14412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            u4 size;
14422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        } ts;
14432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    } header;
14442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
14452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(sizeof(header) == 8);
14462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
144792c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block    ALOGV("Writing chunk, type=%.4s size=%d", (char*) &type, size);
14482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
14492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    header.ts.type = type;
14502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    header.ts.size = (u4) size;
145164896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden    if (sysWriteFully(fd, &header, sizeof(header),
1452e377ef62a40267ab16c2dd20cc5f4c63af6397ccDan Bornstein            "DexOpt opt chunk header write") != 0)
145364896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden    {
14542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
14552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
14562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
14572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (size > 0) {
1458e377ef62a40267ab16c2dd20cc5f4c63af6397ccDan Bornstein        if (sysWriteFully(fd, data, size, "DexOpt opt chunk write") != 0)
14592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return false;
14602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
14612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
14622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* if necessary, pad to 64-bit alignment */
14632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if ((size & 7) != 0) {
14642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int padSize = 8 - (size & 7);
146592c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("size was %d, inserting %d pad bytes", size, padSize);
14662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        lseek(fd, padSize, SEEK_CUR);
14672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
14682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
14692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert( ((int)lseek(fd, 0, SEEK_CUR) & 7) == 0);
14702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
14712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return true;
14722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
14732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
14742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
1475e377ef62a40267ab16c2dd20cc5f4c63af6397ccDan Bornstein * Write opt data.
14762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
14772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * We have different pieces, some of which may be optional.  To make the
14782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * most effective use of space, we use a "chunk" format, with a 4-byte
14792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * type and a 4-byte length.  We guarantee 64-bit alignment for the data,
14802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * so it can be used directly when the file is mapped for reading.
14812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
1482e377ef62a40267ab16c2dd20cc5f4c63af6397ccDan Bornsteinstatic bool writeOptData(int fd, const DexClassLookup* pClassLookup,
1483d394371bd84bacc51e96e2d2eacb8549d9110b1eDan Bornstein    const RegisterMapBuilder* pRegMapBuilder)
14842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
14852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* pre-computed class lookup hash table */
14862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!writeChunk(fd, (u4) kDexChunkClassLookup,
14872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            pClassLookup, pClassLookup->size))
14882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    {
14892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
14902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
14912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
14922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* register maps (optional) */
14932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (pRegMapBuilder != NULL) {
14942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (!writeChunk(fd, (u4) kDexChunkRegisterMaps,
14952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                pRegMapBuilder->data, pRegMapBuilder->size))
14962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        {
14972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return false;
14982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
14992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
15002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
15012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* write the end marker */
15022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!writeChunk(fd, (u4) kDexChunkEnd, NULL, 0)) {
15032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
15042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
15052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
15062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return true;
15072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
15082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
15092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
15102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Compute a checksum on a piece of an open file.
15112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
15122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * File will be positioned at end of checksummed area.
15132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
15142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" on success.
15152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
15162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool computeFileChecksum(int fd, off_t start, size_t length, u4* pSum)
15172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
15182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    unsigned char readBuf[8192];
15192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ssize_t actual;
15202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    uLong adler;
15212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
15222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (lseek(fd, start, SEEK_SET) != start) {
1523c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("Unable to seek to start of checksum area (%ld): %s",
15242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            (long) start, strerror(errno));
15252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
15262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
15272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
15282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    adler = adler32(0L, Z_NULL, 0);
15292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
15302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    while (length != 0) {
15312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        size_t wanted = (length < sizeof(readBuf)) ? length : sizeof(readBuf);
15322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        actual = read(fd, readBuf, wanted);
15332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (actual <= 0) {
1534c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block            ALOGE("Read failed (%d) while computing checksum (len=%zu): %s",
15352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                (int) actual, length, strerror(errno));
15362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return false;
15372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
15382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
15392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        adler = adler32(adler, readBuf, actual);
15402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
15412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        length -= actual;
15422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
15432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
15442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    *pSum = adler;
15452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return true;
15462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
15472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
15482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
15492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Update the Adler-32 checksum stored in the DEX file.  This covers the
15502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * swapped and optimized DEX data, but does not include the opt header
1551e377ef62a40267ab16c2dd20cc5f4c63af6397ccDan Bornstein * or optimized data.
15522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
15532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic void updateChecksum(u1* addr, int len, DexHeader* pHeader)
15542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
15552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
15562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Rewrite the checksum.  We leave the SHA-1 signature alone.
15572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
15582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    uLong adler = adler32(0L, Z_NULL, 0);
15592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum);
15602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
15612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    adler = adler32(adler, addr + nonSum, len - nonSum);
15622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    pHeader->checksum = adler;
15632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
1564