DexPrepare.cpp revision 64896a2543ee54e47c586f4cf26f54e7fdb366bd
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
322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include <zlib.h>
332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include <stdlib.h>
352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include <unistd.h>
362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include <sys/mman.h>
372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include <sys/stat.h>
382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include <sys/file.h>
392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include <sys/wait.h>
402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include <fcntl.h>
412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include <errno.h>
422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* fwd */
45cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenstatic bool rewriteDex(u1* addr, int len, u4* pHeaderFlags,
46cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    DexClassLookup** ppClassLookup);
47cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenstatic bool loadAllClasses(DvmDex* pDvmDex);
48cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenstatic void verifyAndOptimizeClasses(DexFile* pDexFile, bool doVerify,
49cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    bool doOpt);
50cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenstatic void verifyAndOptimizeClass(DexFile* pDexFile, ClassObject* clazz,
51cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    const DexClassDef* pClassDef, bool doVerify, bool doOpt);
522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic void updateChecksum(u1* addr, int len, DexHeader* pHeader);
532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic int writeDependencies(int fd, u4 modWhen, u4 crc);
542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool writeAuxData(int fd, const DexClassLookup* pClassLookup,\
552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const IndexMapSet* pIndexMapSet, const RegisterMapBuilder* pRegMapBuilder);
562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool computeFileChecksum(int fd, off_t start, size_t length, u4* pSum);
572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Return the fd of an open file in the DEX file cache area.  If the cache
612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * file doesn't exist or is out of date, this will remove the old entry,
622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * create a new one (writing only the file header), and return with the
632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * "new file" flag set.
642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * It's possible to execute from an unoptimized DEX file directly,
662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * assuming the byte ordering and structure alignment is correct, but
672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * disadvantageous because some significant optimizations are not possible.
682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * It's not generally possible to do the same from an uncompressed Jar
692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * file entry, because we have to guarantee 32-bit alignment in the
702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * memory-mapped file.
712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * For a Jar/APK file (a zip archive with "classes.dex" inside), "modWhen"
732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * and "crc32" come from the Zip directory entry.  For a stand-alone DEX
742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * file, it's the modification date of the file and the Adler32 from the
752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * DEX header (which immediately follows the magic).  If these don't
762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * match what's stored in the opt header, we reject the file immediately.
772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On success, the file descriptor will be positioned just past the "opt"
792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * file header, and will be locked with flock.  "*pCachedName" will point
802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * to newly-allocated storage.
812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenint dvmOpenCachedDexFile(const char* fileName, const char* cacheFileName,
832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u4 modWhen, u4 crc, bool isBootstrap, bool* pNewFile, bool createIfMissing)
842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int fd, cc;
862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    struct stat fdStat, fileStat;
872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bool readOnly = false;
882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    *pNewFile = false;
902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenretry:
922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Try to open the cache file.  If we've been asked to,
942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * create it if it doesn't exist.
952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    fd = createIfMissing ? open(cacheFileName, O_CREAT|O_RDWR, 0644) : -1;
972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (fd < 0) {
982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        fd = open(cacheFileName, O_RDONLY, 0);
992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (fd < 0) {
1002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (createIfMissing) {
1012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                LOGE("Can't open dex cache '%s': %s\n",
1022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    cacheFileName, strerror(errno));
1032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
1042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return fd;
1052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
1062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        readOnly = true;
1072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
1082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
1102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Grab an exclusive lock on the cache file.  If somebody else is
1112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * working on it, we'll block here until they complete.  Because
1122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * we're waiting on an external resource, we go into VMWAIT mode.
1132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
1142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int oldStatus;
1152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGV("DexOpt: locking cache file %s (fd=%d, boot=%d)\n",
1162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        cacheFileName, fd, isBootstrap);
1172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
1182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    cc = flock(fd, LOCK_EX | LOCK_NB);
1192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (cc != 0) {
1202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGD("DexOpt: sleeping on flock(%s)\n", cacheFileName);
1212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        cc = flock(fd, LOCK_EX);
1222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
1232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    dvmChangeStatus(NULL, oldStatus);
1242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (cc != 0) {
1252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGE("Can't lock dex cache '%s': %d\n", cacheFileName, cc);
1262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        close(fd);
1272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return -1;
1282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
1292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGV("DexOpt:  locked cache file\n");
1302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
1322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Check to see if the fd we opened and locked matches the file in
1332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * the filesystem.  If they don't, then somebody else unlinked ours
1342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * and created a new file, and we need to use that one instead.  (If
1352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * we caught them between the unlink and the create, we'll get an
1362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * ENOENT from the file stat.)
1372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
1382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    cc = fstat(fd, &fdStat);
1392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (cc != 0) {
1402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGE("Can't stat open file '%s'\n", cacheFileName);
1412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGVV("DexOpt: unlocking cache file %s\n", cacheFileName);
1422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto close_fail;
1432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
1442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    cc = stat(cacheFileName, &fileStat);
1452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (cc != 0 ||
1462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        fdStat.st_dev != fileStat.st_dev || fdStat.st_ino != fileStat.st_ino)
1472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    {
1482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGD("DexOpt: our open cache file is stale; sleeping and retrying\n");
1492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGVV("DexOpt: unlocking cache file %s\n", cacheFileName);
1502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        flock(fd, LOCK_UN);
1512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        close(fd);
1522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        usleep(250 * 1000);     /* if something is hosed, don't peg machine */
1532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto retry;
1542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
1552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
1572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * We have the correct file open and locked.  If the file size is zero,
1582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * then it was just created by us, and we want to fill in some fields
1592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * in the "opt" header and set "*pNewFile".  Otherwise, we want to
1602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * verify that the fields in the header match our expectations, and
1612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * reset the file if they don't.
1622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
1632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (fdStat.st_size == 0) {
1642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (readOnly) {
1652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGW("DexOpt: file has zero length and isn't writable\n");
1662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto close_fail;
1672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
1682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        cc = dexOptCreateEmptyHeader(fd);
1692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (cc != 0)
1702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto close_fail;
1712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        *pNewFile = true;
1722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGV("DexOpt: successfully initialized new cache file\n");
1732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    } else {
1742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        bool expectVerify, expectOpt;
1752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (gDvm.classVerifyMode == VERIFY_MODE_NONE)
1772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            expectVerify = false;
1782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        else if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE)
1792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            expectVerify = !isBootstrap;
1802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        else /*if (gDvm.classVerifyMode == VERIFY_MODE_ALL)*/
1812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            expectVerify = true;
1822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (gDvm.dexOptMode == OPTIMIZE_MODE_NONE)
1842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            expectOpt = false;
1852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        else if (gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED)
1862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            expectOpt = expectVerify;
1872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        else /*if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)*/
1882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            expectOpt = true;
1892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGV("checking deps, expecting vfy=%d opt=%d\n",
1912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            expectVerify, expectOpt);
1922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (!dvmCheckOptHeaderAndDependencies(fd, true, modWhen, crc,
1942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                expectVerify, expectOpt))
1952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        {
1962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (readOnly) {
1972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                /*
1982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 * We could unlink and rewrite the file if we own it or
1992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 * the "sticky" bit isn't set on the directory.  However,
2002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 * we're not able to truncate it, which spoils things.  So,
2012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 * give up now.
2022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 */
2032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                if (createIfMissing) {
2042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    LOGW("Cached DEX '%s' (%s) is stale and not writable\n",
2052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                        fileName, cacheFileName);
2062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                }
2072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                goto close_fail;
2082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
2092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /*
2112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * If we truncate the existing file before unlinking it, any
2122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * process that has it mapped will fail when it tries to touch
2132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * the pages.
2142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             *
2152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * This is very important.  The zygote process will have the
2162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * boot DEX files (core, framework, etc.) mapped early.  If
2172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * (say) core.dex gets updated, and somebody launches an app
2182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * that uses App.dex, then App.dex gets reoptimized because it's
2192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * dependent upon the boot classes.  However, dexopt will be
2202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * using the *new* core.dex to do the optimizations, while the
2212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * app will actually be running against the *old* core.dex
2222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * because it starts from zygote.
2232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             *
2242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * Even without zygote, it's still possible for a class loader
2252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * to pull in an APK that was optimized against an older set
2262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * of DEX files.  We must ensure that everything fails when a
2272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * boot DEX gets updated, and for general "why aren't my
2282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * changes doing anything" purposes its best if we just make
2292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * everything crash when a DEX they're using gets updated.
2302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             */
2312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGD("Stale deps in cache file; removing and retrying\n");
2322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (ftruncate(fd, 0) != 0) {
2332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                LOGW("Warning: unable to truncate cache file '%s': %s\n",
2342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    cacheFileName, strerror(errno));
2352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                /* keep going */
2362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
2372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (unlink(cacheFileName) != 0) {
2382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                LOGW("Warning: unable to remove cache file '%s': %d %s\n",
2392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    cacheFileName, errno, strerror(errno));
2402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                /* keep going; permission failure should probably be fatal */
2412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
2422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGVV("DexOpt: unlocking cache file %s\n", cacheFileName);
2432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            flock(fd, LOCK_UN);
2442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            close(fd);
2452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto retry;
2462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        } else {
2472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGV("DexOpt: good deps in cache file\n");
2482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
2492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
2502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(fd >= 0);
2522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return fd;
2532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenclose_fail:
2552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    flock(fd, LOCK_UN);
2562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    close(fd);
2572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return -1;
2582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
2592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
2612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Unlock the file descriptor.
2622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
2632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" on success.
2642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
2652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenbool dvmUnlockCachedDexFile(int fd)
2662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
2672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGVV("DexOpt: unlocking cache file fd=%d\n", fd);
2682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return (flock(fd, LOCK_UN) == 0);
2692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
2702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
2732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Given a descriptor for a file with DEX data in it, produce an
2742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * optimized version.
2752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
2762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * The file pointed to by "fd" is expected to be a locked shared resource
2772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * (or private); we make no efforts to enforce multi-process correctness
2782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * here.
2792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
2802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * "fileName" is only used for debug output.  "modWhen" and "crc" are stored
2812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * in the dependency set.
2822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
2832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * The "isBootstrap" flag determines how the optimizer and verifier handle
2842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * package-scope access checks.  When optimizing, we only load the bootstrap
2852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * class DEX files and the target DEX, so the flag determines whether the
2862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * target DEX classes are given a (synthetic) non-NULL classLoader pointer.
2872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * This only really matters if the target DEX contains classes that claim to
2882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * be in the same package as bootstrap classes.
2892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
2902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * The optimizer will need to load every class in the target DEX file.
2912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * This is generally undesirable, so we start a subprocess to do the
2922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * work and wait for it to complete.
2932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
2942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" on success.  All data will have been written to "fd".
2952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
2962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenbool dvmOptimizeDexFile(int fd, off_t dexOffset, long dexLength,
2972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const char* fileName, u4 modWhen, u4 crc, bool isBootstrap)
2982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
2992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const char* lastPart = strrchr(fileName, '/');
3002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (lastPart != NULL)
3012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        lastPart++;
3022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    else
3032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        lastPart = fileName;
3042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGD("DexOpt: --- BEGIN '%s' (bootstrap=%d) ---\n", lastPart, isBootstrap);
3062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    pid_t pid;
3082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
3102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * This could happen if something in our bootclasspath, which we thought
3112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * was all optimized, got rejected.
3122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
3132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (gDvm.optimizing) {
3142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGW("Rejecting recursive optimization attempt on '%s'\n", fileName);
3152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
3162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
3172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    pid = fork();
3192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (pid == 0) {
3202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        static const int kUseValgrind = 0;
3212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        static const char* kDexOptBin = "/bin/dexopt";
3222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        static const char* kValgrinder = "/usr/bin/valgrind";
3232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        static const int kFixedArgCount = 10;
3242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        static const int kValgrindArgCount = 5;
3252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        static const int kMaxIntLen = 12;   // '-'+10dig+'\0' -OR- 0x+8dig
3262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int bcpSize = dvmGetBootPathSize();
3272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int argc = kFixedArgCount + bcpSize
3282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            + (kValgrindArgCount * kUseValgrind);
3292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        char* argv[argc+1];             // last entry is NULL
3302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        char values[argc][kMaxIntLen];
3312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        char* execFile;
3322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        char* androidRoot;
3332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int flags;
3342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* change process groups, so we don't clash with ProcessManager */
3362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        setpgid(0, 0);
3372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* full path to optimizer */
3392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        androidRoot = getenv("ANDROID_ROOT");
3402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (androidRoot == NULL) {
3412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGW("ANDROID_ROOT not set, defaulting to /system\n");
3422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            androidRoot = "/system";
3432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
3442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        execFile = malloc(strlen(androidRoot) + strlen(kDexOptBin) + 1);
3452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        strcpy(execFile, androidRoot);
3462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        strcat(execFile, kDexOptBin);
3472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
3492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Create arg vector.
3502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
3512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int curArg = 0;
3522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (kUseValgrind) {
3542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* probably shouldn't ship the hard-coded path */
3552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            argv[curArg++] = (char*)kValgrinder;
3562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            argv[curArg++] = "--tool=memcheck";
3572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            argv[curArg++] = "--leak-check=yes";        // check for leaks too
3582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            argv[curArg++] = "--leak-resolution=med";   // increase from 2 to 4
3592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            argv[curArg++] = "--num-callers=16";        // default is 12
3602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            assert(curArg == kValgrindArgCount);
3612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
3622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = execFile;
3632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = "--dex";
3652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        sprintf(values[2], "%d", DALVIK_VM_BUILD);
3672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = values[2];
3682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        sprintf(values[3], "%d", fd);
3702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = values[3];
3712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        sprintf(values[4], "%d", (int) dexOffset);
3732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = values[4];
3742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        sprintf(values[5], "%d", (int) dexLength);
3762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = values[5];
3772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = (char*)fileName;
3792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        sprintf(values[7], "%d", (int) modWhen);
3812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = values[7];
3822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        sprintf(values[8], "%d", (int) crc);
3842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = values[8];
3852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        flags = 0;
3872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (gDvm.dexOptMode != OPTIMIZE_MODE_NONE) {
3882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            flags |= DEXOPT_OPT_ENABLED;
3892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)
3902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                flags |= DEXOPT_OPT_ALL;
3912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
3922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (gDvm.classVerifyMode != VERIFY_MODE_NONE) {
3932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            flags |= DEXOPT_VERIFY_ENABLED;
3942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (gDvm.classVerifyMode == VERIFY_MODE_ALL)
3952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                flags |= DEXOPT_VERIFY_ALL;
3962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
3972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (isBootstrap)
3982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            flags |= DEXOPT_IS_BOOTSTRAP;
3992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (gDvm.generateRegisterMaps)
4002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            flags |= DEXOPT_GEN_REGISTER_MAP;
4012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        sprintf(values[9], "%d", flags);
4022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = values[9];
4032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        assert(((!kUseValgrind && curArg == kFixedArgCount) ||
4052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden               ((kUseValgrind && curArg == kFixedArgCount+kValgrindArgCount))));
4062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ClassPathEntry* cpe;
4082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
4092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            argv[curArg++] = cpe->fileName;
4102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
4112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        assert(curArg == argc);
4122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg] = NULL;
4142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (kUseValgrind)
4162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            execv(kValgrinder, argv);
4172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        else
4182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            execv(execFile, argv);
4192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGE("execv '%s'%s failed: %s\n", execFile,
4212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            kUseValgrind ? " [valgrind]" : "", strerror(errno));
4222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        exit(1);
4232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    } else {
4242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGV("DexOpt: waiting for verify+opt, pid=%d\n", (int) pid);
4252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int status;
4262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pid_t gotPid;
4272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int oldStatus;
4282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
4302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Wait for the optimization process to finish.  We go into VMWAIT
4312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * mode here so GC suspension won't have to wait for us.
4322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
4332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
4342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        while (true) {
4352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            gotPid = waitpid(pid, &status, 0);
4362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (gotPid == -1 && errno == EINTR) {
4372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                LOGD("waitpid interrupted, retrying\n");
4382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            } else {
4392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                break;
4402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
4412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
4422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmChangeStatus(NULL, oldStatus);
4432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (gotPid != pid) {
4442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGE("waitpid failed: wanted %d, got %d: %s\n",
4452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                (int) pid, (int) gotPid, strerror(errno));
4462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return false;
4472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
4482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
4502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGD("DexOpt: --- END '%s' (success) ---\n", lastPart);
4512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return true;
4522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        } else {
4532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGW("DexOpt: --- END '%s' --- status=0x%04x, process failed\n",
4542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                lastPart, status);
4552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return false;
4562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
4572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
4582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
4592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
461cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * Do the actual optimization.  This is executed in the dexopt process.
4622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
4632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * For best use of disk/memory, we want to extract once and perform
4642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * optimizations in place.  If the file has to expand or contract
4652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * to match local structure padding/alignment expectations, we want
4662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * to do the rewrite as part of the extract, rather than extracting
4672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * into a temp file and slurping it back out.  (The structure alignment
4682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * is currently correct for all platforms, and this isn't expected to
4692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * change, so we should be okay with having it already extracted.)
4702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
4712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" on success.
4722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
4732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenbool dvmContinueOptimization(int fd, off_t dexOffset, long dexLength,
4742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const char* fileName, u4 modWhen, u4 crc, bool isBootstrap)
4752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
4762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DexClassLookup* pClassLookup = NULL;
4772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    IndexMapSet* pIndexMapSet = NULL;
4782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    RegisterMapBuilder* pRegMapBuilder = NULL;
4792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u4 headerFlags = 0;
4802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
481cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    assert(gDvm.optimizing);
4822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGV("Continuing optimization (%s, isb=%d, vfy=%d, opt=%d)\n",
4842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        fileName, isBootstrap, doVerify, doOpt);
4852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(dexOffset >= 0);
4872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* quick test so we don't blow up on empty file */
4892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (dexLength < (int) sizeof(DexHeader)) {
4902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGE("too small to be DEX\n");
4912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
4922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
4932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (dexOffset < (int) sizeof(DexOptHeader)) {
4942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGE("not enough room for opt header\n");
4952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
4962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
4972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bool result = false;
4992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
5012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Drop this into a global so we don't have to pass it around.  We could
5022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * also add a field to DexFile, but since it only pertains to DEX
5032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * creation that probably doesn't make sense.
5042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
5052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    gDvm.optimizingBootstrapClass = isBootstrap;
5062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    {
5082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
5092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Map the entire file (so we don't have to worry about page
5102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * alignment).  The expectation is that the output file contains
5112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * our DEX data plus room for a small header.
5122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
5132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        bool success;
5142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        void* mapAddr;
5152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        mapAddr = mmap(NULL, dexOffset + dexLength, PROT_READ|PROT_WRITE,
5162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    MAP_SHARED, fd, 0);
5172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (mapAddr == MAP_FAILED) {
5182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGE("unable to mmap DEX cache: %s\n", strerror(errno));
5192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto bail;
5202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
5212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
5232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Rewrite the file.  Byte reordering, structure realigning,
5242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * class verification, and bytecode optimization are all performed
5252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * here.
5262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         *
5272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * In theory the file could change size and bits could shift around.
5282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * In practice this would be annoying to deal with, so the file
5292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * layout is designed so that it can always be rewritten in place.
5302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         *
5312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * This sets "headerFlags" and creates the class lookup table as
5322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * part of doing the processing.
5332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
534cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        success = rewriteDex(((u1*) mapAddr) + dexOffset, dexLength,
535cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                    &headerFlags, &pClassLookup);
5362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (success) {
5382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            DvmDex* pDvmDex = NULL;
5392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            u1* dexAddr = ((u1*) mapAddr) + dexOffset;
5402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (dvmDexFileOpenPartial(dexAddr, dexLength, &pDvmDex) != 0) {
5422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                LOGE("Unable to create DexFile\n");
5432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                success = false;
5442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            } else {
5452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                /*
5462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 * If configured to do so, scan the instructions, looking
5472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 * for ways to reduce the size of the resolved-constant table.
5482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 * This is done post-optimization, across the instructions
5492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 * in all methods in all classes (even the ones that failed
5502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 * to load).
5512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 */
5522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                pIndexMapSet = dvmRewriteConstants(pDvmDex);
5532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                /*
555cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                 * If configured to do so, generate register map output
556cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                 * for all verified classes.  The register maps were
557cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                 * generated during verification, and will now be serialized.
5582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 */
5592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                if (gDvm.generateRegisterMaps) {
5602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    pRegMapBuilder = dvmGenerateRegisterMaps(pDvmDex);
5612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    if (pRegMapBuilder == NULL) {
5622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                        LOGE("Failed generating register maps\n");
5632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                        success = false;
5642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    }
5652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                }
5662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                DexHeader* pHeader = (DexHeader*)pDvmDex->pHeader;
5682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                updateChecksum(dexAddr, dexLength, pHeader);
5692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dvmDexFileFree(pDvmDex);
5712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
5722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
5732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* unmap the read-write version, forcing writes to disk */
5752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (msync(mapAddr, dexOffset + dexLength, MS_SYNC) != 0) {
5762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGW("msync failed: %s\n", strerror(errno));
5772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            // weird, but keep going
5782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
5792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#if 1
5802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
5812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * This causes clean shutdown to fail, because we have loaded classes
5822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * that point into it.  For the optimizer this isn't a problem,
5832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * because it's more efficient for the process to simply exit.
5842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Exclude this code when doing clean shutdown for valgrind.
5852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
5862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (munmap(mapAddr, dexOffset + dexLength) != 0) {
5872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGE("munmap failed: %s\n", strerror(errno));
5882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto bail;
5892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
5902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#endif
5912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (!success)
5932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto bail;
5942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
5952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* get start offset, and adjust deps start for 64-bit alignment */
5972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    off_t depsOffset, auxOffset, endOffset, adjOffset;
5982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int depsLength, auxLength;
5992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u4 optChecksum;
6002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    depsOffset = lseek(fd, 0, SEEK_END);
6022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (depsOffset < 0) {
6032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGE("lseek to EOF failed: %s\n", strerror(errno));
6042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
6052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
6062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    adjOffset = (depsOffset + 7) & ~(0x07);
6072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (adjOffset != depsOffset) {
6082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGV("Adjusting deps start from %d to %d\n",
6092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            (int) depsOffset, (int) adjOffset);
6102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        depsOffset = adjOffset;
6112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        lseek(fd, depsOffset, SEEK_SET);
6122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
6132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
6152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Append the dependency list.
6162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
6172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (writeDependencies(fd, modWhen, crc) != 0) {
6182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGW("Failed writing dependencies\n");
6192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
6202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
6212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* compute deps length, then adjust aux start for 64-bit alignment */
6232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    auxOffset = lseek(fd, 0, SEEK_END);
6242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    depsLength = auxOffset - depsOffset;
6252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    adjOffset = (auxOffset + 7) & ~(0x07);
6272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (adjOffset != auxOffset) {
6282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGV("Adjusting aux start from %d to %d\n",
6292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            (int) auxOffset, (int) adjOffset);
6302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        auxOffset = adjOffset;
6312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        lseek(fd, auxOffset, SEEK_SET);
6322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
6332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
6352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Append any auxillary pre-computed data structures.
6362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
6372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!writeAuxData(fd, pClassLookup, pIndexMapSet, pRegMapBuilder)) {
6382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGW("Failed writing aux data\n");
6392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
6402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
6412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    endOffset = lseek(fd, 0, SEEK_END);
6432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    auxLength = endOffset - auxOffset;
6442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* compute checksum from start of deps to end of aux area */
6462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!computeFileChecksum(fd, depsOffset,
6472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            (auxOffset+auxLength) - depsOffset, &optChecksum))
6482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    {
6492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
6502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
6512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
6532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Output the "opt" header with all values filled in and a correct
6542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * magic number.
6552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
6562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DexOptHeader optHdr;
6572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    memset(&optHdr, 0xff, sizeof(optHdr));
6582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    memcpy(optHdr.magic, DEX_OPT_MAGIC, 4);
6592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    memcpy(optHdr.magic+4, DEX_OPT_MAGIC_VERS, 4);
6602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    optHdr.dexOffset = (u4) dexOffset;
6612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    optHdr.dexLength = (u4) dexLength;
6622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    optHdr.depsOffset = (u4) depsOffset;
6632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    optHdr.depsLength = (u4) depsLength;
6642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    optHdr.auxOffset = (u4) auxOffset;
6652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    optHdr.auxLength = (u4) auxLength;
6662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    optHdr.flags = headerFlags;
6682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    optHdr.checksum = optChecksum;
6692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ssize_t actual;
6712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    lseek(fd, 0, SEEK_SET);
67264896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden    if (sysWriteFully(fd, &optHdr, sizeof(optHdr), "DexOpt opt header") != 0)
6732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
6742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGV("Successfully wrote DEX header\n");
6762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    result = true;
6772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    //dvmRegisterMapDumpStats();
6792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenbail:
6812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    dvmFreeIndexMapSet(pIndexMapSet);
6822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    dvmFreeRegisterMapBuilder(pRegMapBuilder);
6832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    free(pClassLookup);
6842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return result;
6852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
6862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
689cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * Perform in-place rewrites on a memory-mapped DEX file.
690cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden *
691cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * This happens in a short-lived child process, so we can go nutty with
692cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * loading classes and allocating memory.
693cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden */
694cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenstatic bool rewriteDex(u1* addr, int len, u4* pHeaderFlags,
695cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    DexClassLookup** ppClassLookup)
696cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden{
697cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    u8 prepWhen, loadWhen, verifyOptWhen;
698cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    DvmDex* pDvmDex = NULL;
699cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    bool doVerify, doOpt;
700cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    bool result = false;
701cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
702cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    *pHeaderFlags = 0;
703cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
704cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    /* if the DEX is in the wrong byte order, swap it now */
705cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    if (dexFixByteOrdering(addr, len) != 0)
706cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        goto bail;
707cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden#if __BYTE_ORDER != __LITTLE_ENDIAN
708cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    *pHeaderFlags |= DEX_OPT_FLAG_BIG;
709cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden#endif
710cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
711cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    if (gDvm.classVerifyMode == VERIFY_MODE_NONE)
712cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        doVerify = false;
713cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    else if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE)
714cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        doVerify = !gDvm.optimizingBootstrapClass;
715cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    else /*if (gDvm.classVerifyMode == VERIFY_MODE_ALL)*/
716cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        doVerify = true;
717cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
718cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    if (gDvm.dexOptMode == OPTIMIZE_MODE_NONE)
719cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        doOpt = false;
720cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    else if (gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED)
721cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        doOpt = doVerify;
722cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    else /*if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)*/
723cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        doOpt = true;
724cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
725cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    /* TODO: decide if this is actually useful */
726cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    if (doVerify)
727cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        *pHeaderFlags |= DEX_FLAG_VERIFIED;
728cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    if (doOpt)
729cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        *pHeaderFlags |= DEX_OPT_FLAG_FIELDS | DEX_OPT_FLAG_INVOCATIONS;
730cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
731cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    /*
732cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * Now that the DEX file can be read directly, create a DexFile struct
733cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * for it.
734cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     */
735cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    if (dvmDexFileOpenPartial(addr, len, &pDvmDex) != 0) {
736cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        LOGE("Unable to create DexFile\n");
737cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        goto bail;
738cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    }
739cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
740cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    /*
741cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * Create the class lookup table.  This will eventually be appended
742cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * to the end of the .odex.
743cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     */
744cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    *ppClassLookup = dexCreateClassLookup(pDvmDex->pDexFile);
745cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    if (*ppClassLookup == NULL)
746cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        goto bail;
747cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
748cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    /*
749cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * If we're not going to attempt to verify or optimize the classes,
750cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * there's no value in loading them, so bail out early.
751cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     */
752cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    if (!doVerify && !doOpt) {
753cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        result = true;
754cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        goto bail;
755cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    }
756cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
757cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    /* this is needed for the next part */
758cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    pDvmDex->pDexFile->pClassLookup = *ppClassLookup;
759cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
760cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    prepWhen = dvmGetRelativeTimeUsec();
761cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
762cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    /*
763cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * Load all classes found in this DEX file.  If they fail to load for
764cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * some reason, they won't get verified (which is as it should be).
765cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     */
766cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    if (!loadAllClasses(pDvmDex))
767cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        goto bail;
768cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    loadWhen = dvmGetRelativeTimeUsec();
769cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
770cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    /*
771cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * Verify and optimize all classes in the DEX file (command-line
772cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * options permitting).
773cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     *
774cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * This is best-effort, so there's really no way for dexopt to
775cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * fail at this point.
776cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     */
777cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    verifyAndOptimizeClasses(pDvmDex->pDexFile, doVerify, doOpt);
778cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    verifyOptWhen = dvmGetRelativeTimeUsec();
779cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
780cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    const char* msgStr = "???";
781cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    if (doVerify && doOpt)
782cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        msgStr = "verify+opt";
783cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    else if (doVerify)
784cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        msgStr = "verify";
785cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    else if (doOpt)
786cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        msgStr = "opt";
787cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    LOGD("DexOpt: load %dms, %s %dms\n",
788cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        (int) (loadWhen - prepWhen) / 1000,
789cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        msgStr,
790cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        (int) (verifyOptWhen - loadWhen) / 1000);
791cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
792cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    result = true;
793cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
794cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenbail:
795cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    /* free up storage */
796cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    dvmDexFileFree(pDvmDex);
797cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
798cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    return result;
799cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden}
800cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
801cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden/*
802cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * Try to load all classes in the specified DEX.  If they have some sort
803cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * of broken dependency, e.g. their superclass lives in a different DEX
804cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * that wasn't previously loaded into the bootstrap class path, loading
805cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * will fail.  This is the desired behavior.
806cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden *
807cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * We have no notion of class loader at this point, so we load all of
808cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * the classes with the bootstrap class loader.  It turns out this has
809cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * exactly the behavior we want, and has no ill side effects because we're
810cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * running in a separate process and anything we load here will be forgotten.
811cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden *
812cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * We set the CLASS_MULTIPLE_DEFS flag here if we see multiple definitions.
813cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * This works because we only call here as part of optimization / pre-verify,
814cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * not during verification as part of loading a class into a running VM.
815cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden *
816cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * This returns "false" if the world is too screwed up to do anything
817cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * useful at all.
818cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden */
819cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenstatic bool loadAllClasses(DvmDex* pDvmDex)
820cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden{
821cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    u4 count = pDvmDex->pDexFile->pHeader->classDefsSize;
822cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    u4 idx;
823cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    int loaded = 0;
824cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
825cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    LOGV("DexOpt: +++ trying to load %d classes\n", count);
826cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
827cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    dvmSetBootPathExtraDex(pDvmDex);
828cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
829cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    /*
830cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * We have some circularity issues with Class and Object that are most
831cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * easily avoided by ensuring that Object is never the first thing we
832cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * try to find.  Take care of that here.  (We only need to do this when
833cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * loading classes from the DEX file that contains Object, and only
834cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * when Object comes first in the list, but it costs very little to
835cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * do it in all cases.)
836cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     */
837cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    if (dvmFindSystemClass("Ljava/lang/Class;") == NULL) {
838cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        LOGE("ERROR: java.lang.Class does not exist!\n");
839cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        return false;
840cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    }
841cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
842cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    for (idx = 0; idx < count; idx++) {
843cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        const DexClassDef* pClassDef;
844cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        const char* classDescriptor;
845cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        ClassObject* newClass;
846cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
847cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        pClassDef = dexGetClassDef(pDvmDex->pDexFile, idx);
848cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        classDescriptor =
849cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            dexStringByTypeIdx(pDvmDex->pDexFile, pClassDef->classIdx);
850cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
851cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        LOGV("+++  loading '%s'", classDescriptor);
852cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        //newClass = dvmDefineClass(pDexFile, classDescriptor,
853cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        //        NULL);
854cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        newClass = dvmFindSystemClassNoInit(classDescriptor);
855cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        if (newClass == NULL) {
856cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            LOGV("DexOpt: failed loading '%s'\n", classDescriptor);
857cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            dvmClearOptException(dvmThreadSelf());
858cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        } else if (newClass->pDvmDex != pDvmDex) {
859cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            /*
860cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden             * We don't load the new one, and we tag the first one found
861cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden             * with the "multiple def" flag so the resolver doesn't try
862cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden             * to make it available.
863cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden             */
864cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            LOGD("DexOpt: '%s' has an earlier definition; blocking out\n",
865cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                classDescriptor);
866cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            SET_CLASS_FLAG(newClass, CLASS_MULTIPLE_DEFS);
867cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        } else {
868cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            loaded++;
869cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        }
870cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    }
871cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    LOGV("DexOpt: +++ successfully loaded %d classes\n", loaded);
872cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
873cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    dvmSetBootPathExtraDex(NULL);
874cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    return true;
875cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden}
876cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
877cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden/*
878cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * Verify and/or optimize all classes that were successfully loaded from
879cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * this DEX file.
880cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden */
881cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenstatic void verifyAndOptimizeClasses(DexFile* pDexFile, bool doVerify,
882cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    bool doOpt)
883cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden{
884cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    u4 count = pDexFile->pHeader->classDefsSize;
885cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    u4 idx;
886cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
887cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    /*
888cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * Create a data structure for use by the bytecode optimizer.  We
889cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * stuff it into a global so we don't have to pass it around as
890cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * a function argument.
891cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     *
892cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * We could create this at VM startup, but there's no need to do so
893cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * unless we're optimizing, which means we're in dexopt, and we're
894cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * only going to call here once.
895cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     */
896cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    if (doOpt) {
897cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        gDvm.inlineSubs = dvmCreateInlineSubsTable();
898cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        if (gDvm.inlineSubs == NULL)
899cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            return;
900cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    }
901cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
902cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    for (idx = 0; idx < count; idx++) {
903cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        const DexClassDef* pClassDef;
904cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        const char* classDescriptor;
905cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        ClassObject* clazz;
906cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
907cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        pClassDef = dexGetClassDef(pDexFile, idx);
908cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
909cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
910cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        /* all classes are loaded into the bootstrap class loader */
911cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        clazz = dvmLookupClass(classDescriptor, NULL, false);
912cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        if (clazz != NULL) {
913cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            verifyAndOptimizeClass(pDexFile, clazz, pClassDef, doVerify, doOpt);
914cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
915cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        } else {
916cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            // TODO: log when in verbose mode
917cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            LOGV("DexOpt: not optimizing unavailable class '%s'\n",
918cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                classDescriptor);
919cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        }
920cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    }
921cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
922cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    if (gDvm.inlineSubs != NULL) {
923cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        dvmFreeInlineSubsTable(gDvm.inlineSubs);
924cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        gDvm.inlineSubs = NULL;
925cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    }
926cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden}
927cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
928cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden/*
929cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * Verify and/or optimize a specific class.
930cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden */
931cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenstatic void verifyAndOptimizeClass(DexFile* pDexFile, ClassObject* clazz,
932cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    const DexClassDef* pClassDef, bool doVerify, bool doOpt)
933cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden{
934cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    const char* classDescriptor;
935cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    bool verified = false;
936cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
937cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
938cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
939cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    /*
940cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     * First, try to verify it.
941cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden     */
942cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    if (doVerify) {
943cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        if (clazz->pDvmDex->pDexFile != pDexFile) {
944cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            LOGD("DexOpt: not verifying '%s': multiple definitions\n",
945cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                classDescriptor);
946cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        } else {
947cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            if (dvmVerifyClass(clazz, VERIFY_DEFAULT)) {
948cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                /*
949cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                 * Set the "is preverified" flag in the DexClassDef.  We
950cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                 * do it here, rather than in the ClassObject structure,
951cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                 * because the DexClassDef is part of the odex file.
952cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                 */
953cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                assert((clazz->accessFlags & JAVA_FLAGS_MASK) ==
954cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                    pClassDef->accessFlags);
955cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                ((DexClassDef*)pClassDef)->accessFlags |=
956cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                    CLASS_ISPREVERIFIED;
957cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                verified = true;
958cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            } else {
959cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                // TODO: log when in verbose mode
960cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                LOGV("DexOpt: '%s' failed verification\n", classDescriptor);
961cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            }
962cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        }
963cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    }
964cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
965cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    if (doOpt) {
966cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        if (!verified && gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED) {
967cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            LOGV("DexOpt: not optimizing '%s': not verified\n",
968cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden                classDescriptor);
969cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        } else {
970cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            dvmOptimizeClass(clazz);
971cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
972cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            /* set the flag whether or not we actually changed anything */
973cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            ((DexClassDef*)pClassDef)->accessFlags |= CLASS_ISOPTIMIZED;
974cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        }
975cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    }
976cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden}
977cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
978cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
979cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden/*
9802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Get the cache file name from a ClassPathEntry.
9812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
9822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic const char* getCacheFileName(const ClassPathEntry* cpe)
9832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
9842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    switch (cpe->kind) {
9852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    case kCpeJar:
9862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return dvmGetJarFileCacheFileName((JarFile*) cpe->ptr);
9872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    case kCpeDex:
9882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return dvmGetRawDexFileCacheFileName((RawDexFile*) cpe->ptr);
9892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    default:
9902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGE("DexOpt: unexpected cpe kind %d\n", cpe->kind);
9912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmAbort();
9922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return NULL;
9932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
9942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
9952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
9972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Get the SHA-1 signature.
9982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
9992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic const u1* getSignature(const ClassPathEntry* cpe)
10002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
10012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DvmDex* pDvmDex;
10022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    switch (cpe->kind) {
10042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    case kCpeJar:
10052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pDvmDex = dvmGetJarFileDex((JarFile*) cpe->ptr);
10062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        break;
10072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    case kCpeDex:
10082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pDvmDex = dvmGetRawDexFileDex((RawDexFile*) cpe->ptr);
10092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        break;
10102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    default:
10112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGE("unexpected cpe kind %d\n", cpe->kind);
10122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmAbort();
10132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pDvmDex = NULL;         // make gcc happy
10142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
10152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(pDvmDex != NULL);
10172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return pDvmDex->pDexFile->pHeader->signature;
10182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
10192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
10222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Dependency layout:
10232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *  4b  Source file modification time, in seconds since 1970 UTC
10242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *  4b  CRC-32 from Zip entry, or Adler32 from source DEX header
10252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *  4b  Dalvik VM build number
10262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *  4b  Number of dependency entries that follow
10272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *  Dependency entries:
10282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *    4b  Name length (including terminating null)
10292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *    var Full path of cache entry (null terminated)
10302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *    20b SHA-1 signature from source DEX file
10312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
10322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * If this changes, update DEX_OPT_MAGIC_VERS.
10332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
10342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic const size_t kMinDepSize = 4 * 4;
10352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic const size_t kMaxDepSize = 4 * 4 + 1024;     // sanity check
10362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
10382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Read the "opt" header, verify it, then read the dependencies section
10392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * and verify that data as well.
10402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
10412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * If "sourceAvail" is "true", this will verify that "modWhen" and "crc"
10422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * match up with what is stored in the header.  If they don't, we reject
10432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * the file so that it can be recreated from the updated original.  If
10442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * "sourceAvail" isn't set, e.g. for a .odex file, we ignore these arguments.
10452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
10462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On successful return, the file will be seeked immediately past the
10472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * "opt" header.
10482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
10492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenbool dvmCheckOptHeaderAndDependencies(int fd, bool sourceAvail, u4 modWhen,
10502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u4 crc, bool expectVerify, bool expectOpt)
10512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
10522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DexOptHeader optHdr;
10532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u1* depData = NULL;
10542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const u1* magic;
10552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    off_t posn;
10562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int result = false;
10572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ssize_t actual;
10582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
10602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Start at the start.  The "opt" header, when present, will always be
10612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * the first thing in the file.
10622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
10632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (lseek(fd, 0, SEEK_SET) != 0) {
10642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGE("DexOpt: failed to seek to start of file: %s\n", strerror(errno));
10652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
10662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
10672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
10692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Read and do trivial verification on the opt header.  The header is
10702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * always in host byte order.
10712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
10722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (read(fd, &optHdr, sizeof(optHdr)) != sizeof(optHdr)) {
10732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGE("DexOpt: failed reading opt header: %s\n", strerror(errno));
10742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
10752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
10762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    magic = optHdr.magic;
10782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (memcmp(magic, DEX_OPT_MAGIC, 4) != 0) {
10792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* not a DEX file, or previous attempt was interrupted */
10802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGD("DexOpt: incorrect opt magic number (0x%02x %02x %02x %02x)\n",
10812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            magic[0], magic[1], magic[2], magic[3]);
10822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
10832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
10842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (memcmp(magic+4, DEX_OPT_MAGIC_VERS, 4) != 0) {
10852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGW("DexOpt: stale opt version (0x%02x %02x %02x %02x)\n",
10862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            magic[4], magic[5], magic[6], magic[7]);
10872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
10882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
10892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (optHdr.depsLength < kMinDepSize || optHdr.depsLength > kMaxDepSize) {
10902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGW("DexOpt: weird deps length %d, bailing\n", optHdr.depsLength);
10912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
10922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
10932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
10952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Do the header flags match up with what we want?
10962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     *
10972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * This is useful because it allows us to automatically regenerate
10982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * a file when settings change (e.g. verification is now mandatory),
10992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * but can cause difficulties if the bootstrap classes we depend upon
11002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * were handled differently than the current options specify.  We get
11012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * upset because they're not verified or optimized, but we're not able
11022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * to regenerate them because the installer won't let us.
11032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     *
11042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * (This is also of limited value when !sourceAvail.)
11052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     *
11062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * So, for now, we essentially ignore "expectVerify" and "expectOpt"
11072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * by limiting the match mask.
11082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     *
11092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * The only thing we really can't handle is incorrect byte-ordering.
11102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
11112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const u4 matchMask = DEX_OPT_FLAG_BIG;
11122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u4 expectedFlags = 0;
11132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#if __BYTE_ORDER != __LITTLE_ENDIAN
11142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    expectedFlags |= DEX_OPT_FLAG_BIG;
11152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#endif
11162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (expectVerify)
11172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        expectedFlags |= DEX_FLAG_VERIFIED;
11182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (expectOpt)
11192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        expectedFlags |= DEX_OPT_FLAG_FIELDS | DEX_OPT_FLAG_INVOCATIONS;
11202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if ((expectedFlags & matchMask) != (optHdr.flags & matchMask)) {
11212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGI("DexOpt: header flag mismatch (0x%02x vs 0x%02x, mask=0x%02x)\n",
11222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            expectedFlags, optHdr.flags, matchMask);
11232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
11242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
11252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    posn = lseek(fd, optHdr.depsOffset, SEEK_SET);
11272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (posn < 0) {
11282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGW("DexOpt: seek to deps failed: %s\n", strerror(errno));
11292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
11302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
11312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
11332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Read all of the dependency stuff into memory.
11342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
11352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    depData = (u1*) malloc(optHdr.depsLength);
11362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (depData == NULL) {
11372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGW("DexOpt: unable to allocate %d bytes for deps\n",
11382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            optHdr.depsLength);
11392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
11402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
11412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    actual = read(fd, depData, optHdr.depsLength);
11422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (actual != (ssize_t) optHdr.depsLength) {
11432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGW("DexOpt: failed reading deps: %d of %d (err=%s)\n",
11442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            (int) actual, optHdr.depsLength, strerror(errno));
11452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
11462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
11472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
11492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Verify simple items.
11502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
11512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const u1* ptr;
11522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u4 val;
11532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ptr = depData;
11552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    val = read4LE(&ptr);
11562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (sourceAvail && val != modWhen) {
11572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGI("DexOpt: source file mod time mismatch (%08x vs %08x)\n",
11582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            val, modWhen);
11592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
11602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
11612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    val = read4LE(&ptr);
11622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (sourceAvail && val != crc) {
11632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGI("DexOpt: source file CRC mismatch (%08x vs %08x)\n", val, crc);
11642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
11652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
11662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    val = read4LE(&ptr);
11672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (val != DALVIK_VM_BUILD) {
11682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGD("DexOpt: VM build version mismatch (%d vs %d)\n",
11692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            val, DALVIK_VM_BUILD);
11702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
11712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
11722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
11742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Verify dependencies on other cached DEX files.  It must match
11752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * exactly with what is currently defined in the bootclasspath.
11762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
11772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassPathEntry* cpe;
11782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u4 numDeps;
11792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    numDeps = read4LE(&ptr);
11812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGV("+++ DexOpt: numDeps = %d\n", numDeps);
11822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
11832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const char* cacheFileName = getCacheFileName(cpe);
11842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const u1* signature = getSignature(cpe);
11852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        size_t len = strlen(cacheFileName) +1;
11862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        u4 storedStrLen;
11872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (numDeps == 0) {
11892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* more entries in bootclasspath than in deps list */
11902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGI("DexOpt: not all deps represented\n");
11912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto bail;
11922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
11932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        storedStrLen = read4LE(&ptr);
11952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (len != storedStrLen ||
11962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            strcmp(cacheFileName, (const char*) ptr) != 0)
11972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        {
11982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGI("DexOpt: mismatch dep name: '%s' vs. '%s'\n",
11992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                cacheFileName, ptr);
12002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto bail;
12012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
12022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ptr += storedStrLen;
12042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (memcmp(signature, ptr, kSHA1DigestLen) != 0) {
12062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGI("DexOpt: mismatch dep signature for '%s'\n", cacheFileName);
12072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto bail;
12082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
12092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ptr += kSHA1DigestLen;
12102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGV("DexOpt: dep match on '%s'\n", cacheFileName);
12122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        numDeps--;
12142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
12152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (numDeps != 0) {
12172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* more entries in deps list than in classpath */
12182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGI("DexOpt: Some deps went away\n");
12192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
12202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
12212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    // consumed all data and no more?
12232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (ptr != depData + optHdr.depsLength) {
12242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGW("DexOpt: Spurious dep data? %d vs %d\n",
12252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            (int) (ptr - depData), optHdr.depsLength);
12262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        assert(false);
12272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
12282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    result = true;
12302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenbail:
12322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    free(depData);
12332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return result;
12342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
12352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
12372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Write the dependency info to "fd" at the current file position.
12382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
12392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic int writeDependencies(int fd, u4 modWhen, u4 crc)
12402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
12412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u1* buf = NULL;
12422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ssize_t actual;
12432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int result = -1;
12442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ssize_t bufLen;
12452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassPathEntry* cpe;
12462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int i, numDeps;
12472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
12492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Count up the number of completed entries in the bootclasspath.
12502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
12512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    numDeps = 0;
12522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bufLen = 0;
12532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
12542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const char* cacheFileName = getCacheFileName(cpe);
12552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGV("+++ DexOpt: found dep '%s'\n", cacheFileName);
12562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        numDeps++;
12582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        bufLen += strlen(cacheFileName) +1;
12592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
12602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bufLen += 4*4 + numDeps * (4+kSHA1DigestLen);
12622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    buf = malloc(bufLen);
12642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    set4LE(buf+0, modWhen);
12662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    set4LE(buf+4, crc);
12672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    set4LE(buf+8, DALVIK_VM_BUILD);
12682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    set4LE(buf+12, numDeps);
12692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    // TODO: do we want to add dvmGetInlineOpsTableLength() here?  Won't
12712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    // help us if somebody replaces an existing entry, but it'd catch
12722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    // additions/removals.
12732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u1* ptr = buf + 4*4;
12752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
12762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const char* cacheFileName = getCacheFileName(cpe);
12772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const u1* signature = getSignature(cpe);
12782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int len = strlen(cacheFileName) +1;
12792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (ptr + 4 + len + kSHA1DigestLen > buf + bufLen) {
12812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGE("DexOpt: overran buffer\n");
12822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dvmAbort();
12832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
12842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        set4LE(ptr, len);
12862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ptr += 4;
12872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        memcpy(ptr, cacheFileName, len);
12882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ptr += len;
12892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        memcpy(ptr, signature, kSHA1DigestLen);
12902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ptr += kSHA1DigestLen;
12912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
12922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(ptr == buf + bufLen);
12942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
129564896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden    result = sysWriteFully(fd, buf, bufLen, "DexOpt dep info");
12962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    free(buf);
12982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return result;
12992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
13002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
13032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Write a block of data in "chunk" format.
13042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
13052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * The chunk header fields are always in "native" byte order.  If "size"
13062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * is not a multiple of 8 bytes, the data area is padded out.
13072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
13082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool writeChunk(int fd, u4 type, const void* data, size_t size)
13092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
13102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ssize_t actual;
13112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    union {             /* save a syscall by grouping these together */
13122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        char raw[8];
13132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        struct {
13142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            u4 type;
13152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            u4 size;
13162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        } ts;
13172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    } header;
13182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(sizeof(header) == 8);
13202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGV("Writing chunk, type=%.4s size=%d\n", (char*) &type, size);
13222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    header.ts.type = type;
13242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    header.ts.size = (u4) size;
132564896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden    if (sysWriteFully(fd, &header, sizeof(header),
132664896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden            "DexOpt aux chunk header write") != 0)
132764896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden    {
13282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
13292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
13302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (size > 0) {
133264896a2543ee54e47c586f4cf26f54e7fdb366bdAndy McFadden        if (sysWriteFully(fd, data, size, "DexOpt aux chunk write") != 0)
13332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return false;
13342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
13352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* if necessary, pad to 64-bit alignment */
13372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if ((size & 7) != 0) {
13382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int padSize = 8 - (size & 7);
13392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGV("size was %d, inserting %d pad bytes\n", size, padSize);
13402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        lseek(fd, padSize, SEEK_CUR);
13412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
13422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert( ((int)lseek(fd, 0, SEEK_CUR) & 7) == 0);
13442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return true;
13462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
13472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
13492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Write aux data.
13502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
13512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * We have different pieces, some of which may be optional.  To make the
13522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * most effective use of space, we use a "chunk" format, with a 4-byte
13532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * type and a 4-byte length.  We guarantee 64-bit alignment for the data,
13542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * so it can be used directly when the file is mapped for reading.
13552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
13562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool writeAuxData(int fd, const DexClassLookup* pClassLookup,
13572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const IndexMapSet* pIndexMapSet, const RegisterMapBuilder* pRegMapBuilder)
13582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
13592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* pre-computed class lookup hash table */
13602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!writeChunk(fd, (u4) kDexChunkClassLookup,
13612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            pClassLookup, pClassLookup->size))
13622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    {
13632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
13642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
13652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* remapped constants (optional) */
13672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (pIndexMapSet != NULL) {
13682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (!writeChunk(fd, pIndexMapSet->chunkType,
13692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                pIndexMapSet->chunkData, pIndexMapSet->chunkDataLen))
13702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        {
13712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return false;
13722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
13732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
13742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* register maps (optional) */
13762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (pRegMapBuilder != NULL) {
13772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (!writeChunk(fd, (u4) kDexChunkRegisterMaps,
13782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                pRegMapBuilder->data, pRegMapBuilder->size))
13792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        {
13802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return false;
13812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
13822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
13832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* write the end marker */
13852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!writeChunk(fd, (u4) kDexChunkEnd, NULL, 0)) {
13862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
13872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
13882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return true;
13902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
13912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
13922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
13932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Compute a checksum on a piece of an open file.
13942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
13952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * File will be positioned at end of checksummed area.
13962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
13972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" on success.
13982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
13992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool computeFileChecksum(int fd, off_t start, size_t length, u4* pSum)
14002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
14012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    unsigned char readBuf[8192];
14022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ssize_t actual;
14032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    uLong adler;
14042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
14052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (lseek(fd, start, SEEK_SET) != start) {
14062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGE("Unable to seek to start of checksum area (%ld): %s\n",
14072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            (long) start, strerror(errno));
14082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
14092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
14102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
14112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    adler = adler32(0L, Z_NULL, 0);
14122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
14132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    while (length != 0) {
14142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        size_t wanted = (length < sizeof(readBuf)) ? length : sizeof(readBuf);
14152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        actual = read(fd, readBuf, wanted);
14162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (actual <= 0) {
14172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGE("Read failed (%d) while computing checksum (len=%zu): %s\n",
14182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                (int) actual, length, strerror(errno));
14192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return false;
14202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
14212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
14222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        adler = adler32(adler, readBuf, actual);
14232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
14242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        length -= actual;
14252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
14262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
14272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    *pSum = adler;
14282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return true;
14292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
14302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
14312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
14322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Update the Adler-32 checksum stored in the DEX file.  This covers the
14332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * swapped and optimized DEX data, but does not include the opt header
14342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * or auxillary data.
14352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
14362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic void updateChecksum(u1* addr, int len, DexHeader* pHeader)
14372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
14382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
14392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Rewrite the checksum.  We leave the SHA-1 signature alone.
14402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
14412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    uLong adler = adler32(0L, Z_NULL, 0);
14422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum);
14432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
14442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    adler = adler32(adler, addr + nonSum, len - nonSum);
14452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    pHeader->checksum = adler;
14462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
14472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1448