DexPrepare.cpp revision 2e1ee50a08cc3dd07ce4e956b925c1f0f28cf329
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 */
452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic void updateChecksum(u1* addr, int len, DexHeader* pHeader);
462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic int writeDependencies(int fd, u4 modWhen, u4 crc);
472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool writeAuxData(int fd, const DexClassLookup* pClassLookup,\
482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const IndexMapSet* pIndexMapSet, const RegisterMapBuilder* pRegMapBuilder);
492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic void logFailedWrite(size_t expected, ssize_t actual, const char* msg,
502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int err);
512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool computeFileChecksum(int fd, off_t start, size_t length, u4* pSum);
522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Return the fd of an open file in the DEX file cache area.  If the cache
562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * file doesn't exist or is out of date, this will remove the old entry,
572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * create a new one (writing only the file header), and return with the
582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * "new file" flag set.
592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * It's possible to execute from an unoptimized DEX file directly,
612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * assuming the byte ordering and structure alignment is correct, but
622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * disadvantageous because some significant optimizations are not possible.
632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * It's not generally possible to do the same from an uncompressed Jar
642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * file entry, because we have to guarantee 32-bit alignment in the
652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * memory-mapped file.
662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * For a Jar/APK file (a zip archive with "classes.dex" inside), "modWhen"
682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * and "crc32" come from the Zip directory entry.  For a stand-alone DEX
692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * file, it's the modification date of the file and the Adler32 from the
702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * DEX header (which immediately follows the magic).  If these don't
712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * match what's stored in the opt header, we reject the file immediately.
722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On success, the file descriptor will be positioned just past the "opt"
742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * file header, and will be locked with flock.  "*pCachedName" will point
752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * to newly-allocated storage.
762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenint dvmOpenCachedDexFile(const char* fileName, const char* cacheFileName,
782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u4 modWhen, u4 crc, bool isBootstrap, bool* pNewFile, bool createIfMissing)
792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int fd, cc;
812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    struct stat fdStat, fileStat;
822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bool readOnly = false;
832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    *pNewFile = false;
852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenretry:
872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Try to open the cache file.  If we've been asked to,
892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * create it if it doesn't exist.
902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    fd = createIfMissing ? open(cacheFileName, O_CREAT|O_RDWR, 0644) : -1;
922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (fd < 0) {
932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        fd = open(cacheFileName, O_RDONLY, 0);
942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (fd < 0) {
952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (createIfMissing) {
962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                LOGE("Can't open dex cache '%s': %s\n",
972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    cacheFileName, strerror(errno));
982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return fd;
1002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
1012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        readOnly = true;
1022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
1032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
1052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Grab an exclusive lock on the cache file.  If somebody else is
1062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * working on it, we'll block here until they complete.  Because
1072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * we're waiting on an external resource, we go into VMWAIT mode.
1082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
1092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int oldStatus;
1102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGV("DexOpt: locking cache file %s (fd=%d, boot=%d)\n",
1112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        cacheFileName, fd, isBootstrap);
1122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
1132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    cc = flock(fd, LOCK_EX | LOCK_NB);
1142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (cc != 0) {
1152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGD("DexOpt: sleeping on flock(%s)\n", cacheFileName);
1162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        cc = flock(fd, LOCK_EX);
1172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
1182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    dvmChangeStatus(NULL, oldStatus);
1192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (cc != 0) {
1202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGE("Can't lock dex cache '%s': %d\n", cacheFileName, cc);
1212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        close(fd);
1222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return -1;
1232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
1242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGV("DexOpt:  locked cache file\n");
1252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
1272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Check to see if the fd we opened and locked matches the file in
1282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * the filesystem.  If they don't, then somebody else unlinked ours
1292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * and created a new file, and we need to use that one instead.  (If
1302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * we caught them between the unlink and the create, we'll get an
1312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * ENOENT from the file stat.)
1322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
1332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    cc = fstat(fd, &fdStat);
1342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (cc != 0) {
1352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGE("Can't stat open file '%s'\n", cacheFileName);
1362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGVV("DexOpt: unlocking cache file %s\n", cacheFileName);
1372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto close_fail;
1382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
1392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    cc = stat(cacheFileName, &fileStat);
1402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (cc != 0 ||
1412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        fdStat.st_dev != fileStat.st_dev || fdStat.st_ino != fileStat.st_ino)
1422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    {
1432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGD("DexOpt: our open cache file is stale; sleeping and retrying\n");
1442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGVV("DexOpt: unlocking cache file %s\n", cacheFileName);
1452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        flock(fd, LOCK_UN);
1462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        close(fd);
1472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        usleep(250 * 1000);     /* if something is hosed, don't peg machine */
1482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto retry;
1492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
1502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
1522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * We have the correct file open and locked.  If the file size is zero,
1532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * then it was just created by us, and we want to fill in some fields
1542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * in the "opt" header and set "*pNewFile".  Otherwise, we want to
1552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * verify that the fields in the header match our expectations, and
1562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * reset the file if they don't.
1572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
1582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (fdStat.st_size == 0) {
1592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (readOnly) {
1602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGW("DexOpt: file has zero length and isn't writable\n");
1612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto close_fail;
1622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
1632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        cc = dexOptCreateEmptyHeader(fd);
1642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (cc != 0)
1652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto close_fail;
1662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        *pNewFile = true;
1672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGV("DexOpt: successfully initialized new cache file\n");
1682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    } else {
1692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        bool expectVerify, expectOpt;
1702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (gDvm.classVerifyMode == VERIFY_MODE_NONE)
1722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            expectVerify = false;
1732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        else if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE)
1742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            expectVerify = !isBootstrap;
1752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        else /*if (gDvm.classVerifyMode == VERIFY_MODE_ALL)*/
1762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            expectVerify = true;
1772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (gDvm.dexOptMode == OPTIMIZE_MODE_NONE)
1792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            expectOpt = false;
1802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        else if (gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED)
1812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            expectOpt = expectVerify;
1822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        else /*if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)*/
1832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            expectOpt = true;
1842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGV("checking deps, expecting vfy=%d opt=%d\n",
1862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            expectVerify, expectOpt);
1872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (!dvmCheckOptHeaderAndDependencies(fd, true, modWhen, crc,
1892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                expectVerify, expectOpt))
1902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        {
1912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (readOnly) {
1922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                /*
1932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 * We could unlink and rewrite the file if we own it or
1942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 * the "sticky" bit isn't set on the directory.  However,
1952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 * we're not able to truncate it, which spoils things.  So,
1962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 * give up now.
1972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 */
1982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                if (createIfMissing) {
1992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    LOGW("Cached DEX '%s' (%s) is stale and not writable\n",
2002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                        fileName, cacheFileName);
2012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                }
2022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                goto close_fail;
2032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
2042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /*
2062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * If we truncate the existing file before unlinking it, any
2072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * process that has it mapped will fail when it tries to touch
2082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * the pages.
2092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             *
2102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * This is very important.  The zygote process will have the
2112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * boot DEX files (core, framework, etc.) mapped early.  If
2122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * (say) core.dex gets updated, and somebody launches an app
2132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * that uses App.dex, then App.dex gets reoptimized because it's
2142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * dependent upon the boot classes.  However, dexopt will be
2152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * using the *new* core.dex to do the optimizations, while the
2162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * app will actually be running against the *old* core.dex
2172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * because it starts from zygote.
2182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             *
2192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * Even without zygote, it's still possible for a class loader
2202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * to pull in an APK that was optimized against an older set
2212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * of DEX files.  We must ensure that everything fails when a
2222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * boot DEX gets updated, and for general "why aren't my
2232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * changes doing anything" purposes its best if we just make
2242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * everything crash when a DEX they're using gets updated.
2252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             */
2262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGD("Stale deps in cache file; removing and retrying\n");
2272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (ftruncate(fd, 0) != 0) {
2282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                LOGW("Warning: unable to truncate cache file '%s': %s\n",
2292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    cacheFileName, strerror(errno));
2302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                /* keep going */
2312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
2322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (unlink(cacheFileName) != 0) {
2332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                LOGW("Warning: unable to remove cache file '%s': %d %s\n",
2342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    cacheFileName, errno, strerror(errno));
2352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                /* keep going; permission failure should probably be fatal */
2362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
2372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGVV("DexOpt: unlocking cache file %s\n", cacheFileName);
2382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            flock(fd, LOCK_UN);
2392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            close(fd);
2402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto retry;
2412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        } else {
2422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGV("DexOpt: good deps in cache file\n");
2432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
2442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
2452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(fd >= 0);
2472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return fd;
2482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenclose_fail:
2502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    flock(fd, LOCK_UN);
2512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    close(fd);
2522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return -1;
2532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
2542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
2562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Unlock the file descriptor.
2572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
2582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" on success.
2592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
2602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenbool dvmUnlockCachedDexFile(int fd)
2612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
2622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGVV("DexOpt: unlocking cache file fd=%d\n", fd);
2632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return (flock(fd, LOCK_UN) == 0);
2642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
2652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
2682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Given a descriptor for a file with DEX data in it, produce an
2692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * optimized version.
2702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
2712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * The file pointed to by "fd" is expected to be a locked shared resource
2722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * (or private); we make no efforts to enforce multi-process correctness
2732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * here.
2742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
2752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * "fileName" is only used for debug output.  "modWhen" and "crc" are stored
2762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * in the dependency set.
2772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
2782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * The "isBootstrap" flag determines how the optimizer and verifier handle
2792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * package-scope access checks.  When optimizing, we only load the bootstrap
2802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * class DEX files and the target DEX, so the flag determines whether the
2812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * target DEX classes are given a (synthetic) non-NULL classLoader pointer.
2822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * This only really matters if the target DEX contains classes that claim to
2832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * be in the same package as bootstrap classes.
2842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
2852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * The optimizer will need to load every class in the target DEX file.
2862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * This is generally undesirable, so we start a subprocess to do the
2872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * work and wait for it to complete.
2882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
2892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" on success.  All data will have been written to "fd".
2902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
2912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenbool dvmOptimizeDexFile(int fd, off_t dexOffset, long dexLength,
2922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const char* fileName, u4 modWhen, u4 crc, bool isBootstrap)
2932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
2942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const char* lastPart = strrchr(fileName, '/');
2952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (lastPart != NULL)
2962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        lastPart++;
2972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    else
2982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        lastPart = fileName;
2992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
3012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * For basic optimizations (byte-swapping and structure aligning) we
3022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * don't need to fork().  It looks like fork+exec is causing problems
3032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * with gdb on our bewildered Linux distro, so in some situations we
3042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * want to avoid this.
3052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     *
3062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * For optimization and/or verification, we need to load all the classes.
3072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     *
3082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * We don't check gDvm.generateRegisterMaps, since that is dependent
3092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * upon the verifier state.
3102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
3112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (gDvm.classVerifyMode == VERIFY_MODE_NONE &&
3122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        (gDvm.dexOptMode == OPTIMIZE_MODE_NONE ||
3132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED))
3142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    {
3152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGD("DexOpt: --- BEGIN (quick) '%s' ---\n", lastPart);
3162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return dvmContinueOptimization(fd, dexOffset, dexLength,
3172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                fileName, modWhen, crc, isBootstrap);
3182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
3192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGD("DexOpt: --- BEGIN '%s' (bootstrap=%d) ---\n", lastPart, isBootstrap);
3222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    pid_t pid;
3242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
3262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * This could happen if something in our bootclasspath, which we thought
3272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * was all optimized, got rejected.
3282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
3292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (gDvm.optimizing) {
3302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGW("Rejecting recursive optimization attempt on '%s'\n", fileName);
3312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
3322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
3332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    pid = fork();
3352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (pid == 0) {
3362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        static const int kUseValgrind = 0;
3372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        static const char* kDexOptBin = "/bin/dexopt";
3382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        static const char* kValgrinder = "/usr/bin/valgrind";
3392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        static const int kFixedArgCount = 10;
3402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        static const int kValgrindArgCount = 5;
3412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        static const int kMaxIntLen = 12;   // '-'+10dig+'\0' -OR- 0x+8dig
3422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int bcpSize = dvmGetBootPathSize();
3432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int argc = kFixedArgCount + bcpSize
3442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            + (kValgrindArgCount * kUseValgrind);
3452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        char* argv[argc+1];             // last entry is NULL
3462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        char values[argc][kMaxIntLen];
3472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        char* execFile;
3482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        char* androidRoot;
3492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int flags;
3502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* change process groups, so we don't clash with ProcessManager */
3522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        setpgid(0, 0);
3532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* full path to optimizer */
3552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        androidRoot = getenv("ANDROID_ROOT");
3562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (androidRoot == NULL) {
3572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGW("ANDROID_ROOT not set, defaulting to /system\n");
3582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            androidRoot = "/system";
3592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
3602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        execFile = malloc(strlen(androidRoot) + strlen(kDexOptBin) + 1);
3612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        strcpy(execFile, androidRoot);
3622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        strcat(execFile, kDexOptBin);
3632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
3652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Create arg vector.
3662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
3672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int curArg = 0;
3682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (kUseValgrind) {
3702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* probably shouldn't ship the hard-coded path */
3712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            argv[curArg++] = (char*)kValgrinder;
3722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            argv[curArg++] = "--tool=memcheck";
3732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            argv[curArg++] = "--leak-check=yes";        // check for leaks too
3742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            argv[curArg++] = "--leak-resolution=med";   // increase from 2 to 4
3752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            argv[curArg++] = "--num-callers=16";        // default is 12
3762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            assert(curArg == kValgrindArgCount);
3772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
3782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = execFile;
3792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = "--dex";
3812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        sprintf(values[2], "%d", DALVIK_VM_BUILD);
3832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = values[2];
3842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        sprintf(values[3], "%d", fd);
3862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = values[3];
3872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        sprintf(values[4], "%d", (int) dexOffset);
3892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = values[4];
3902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        sprintf(values[5], "%d", (int) dexLength);
3922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = values[5];
3932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = (char*)fileName;
3952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        sprintf(values[7], "%d", (int) modWhen);
3972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = values[7];
3982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        sprintf(values[8], "%d", (int) crc);
4002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = values[8];
4012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        flags = 0;
4032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (gDvm.dexOptMode != OPTIMIZE_MODE_NONE) {
4042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            flags |= DEXOPT_OPT_ENABLED;
4052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)
4062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                flags |= DEXOPT_OPT_ALL;
4072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
4082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (gDvm.classVerifyMode != VERIFY_MODE_NONE) {
4092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            flags |= DEXOPT_VERIFY_ENABLED;
4102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (gDvm.classVerifyMode == VERIFY_MODE_ALL)
4112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                flags |= DEXOPT_VERIFY_ALL;
4122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
4132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (isBootstrap)
4142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            flags |= DEXOPT_IS_BOOTSTRAP;
4152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (gDvm.generateRegisterMaps)
4162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            flags |= DEXOPT_GEN_REGISTER_MAP;
4172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        sprintf(values[9], "%d", flags);
4182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg++] = values[9];
4192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        assert(((!kUseValgrind && curArg == kFixedArgCount) ||
4212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden               ((kUseValgrind && curArg == kFixedArgCount+kValgrindArgCount))));
4222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ClassPathEntry* cpe;
4242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
4252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            argv[curArg++] = cpe->fileName;
4262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
4272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        assert(curArg == argc);
4282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        argv[curArg] = NULL;
4302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (kUseValgrind)
4322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            execv(kValgrinder, argv);
4332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        else
4342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            execv(execFile, argv);
4352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGE("execv '%s'%s failed: %s\n", execFile,
4372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            kUseValgrind ? " [valgrind]" : "", strerror(errno));
4382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        exit(1);
4392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    } else {
4402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGV("DexOpt: waiting for verify+opt, pid=%d\n", (int) pid);
4412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int status;
4422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pid_t gotPid;
4432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int oldStatus;
4442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
4462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Wait for the optimization process to finish.  We go into VMWAIT
4472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * mode here so GC suspension won't have to wait for us.
4482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
4492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
4502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        while (true) {
4512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            gotPid = waitpid(pid, &status, 0);
4522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (gotPid == -1 && errno == EINTR) {
4532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                LOGD("waitpid interrupted, retrying\n");
4542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            } else {
4552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                break;
4562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
4572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
4582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmChangeStatus(NULL, oldStatus);
4592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (gotPid != pid) {
4602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGE("waitpid failed: wanted %d, got %d: %s\n",
4612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                (int) pid, (int) gotPid, strerror(errno));
4622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return false;
4632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
4642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
4662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGD("DexOpt: --- END '%s' (success) ---\n", lastPart);
4672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return true;
4682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        } else {
4692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGW("DexOpt: --- END '%s' --- status=0x%04x, process failed\n",
4702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                lastPart, status);
4712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return false;
4722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
4732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
4742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
4752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
4772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Do the actual optimization.  This is called directly for "minimal"
4782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * optimization, or from a newly-created process for "full" optimization.
4792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
4802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * For best use of disk/memory, we want to extract once and perform
4812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * optimizations in place.  If the file has to expand or contract
4822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * to match local structure padding/alignment expectations, we want
4832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * to do the rewrite as part of the extract, rather than extracting
4842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * into a temp file and slurping it back out.  (The structure alignment
4852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * is currently correct for all platforms, and this isn't expected to
4862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * change, so we should be okay with having it already extracted.)
4872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
4882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" on success.
4892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
4902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenbool dvmContinueOptimization(int fd, off_t dexOffset, long dexLength,
4912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const char* fileName, u4 modWhen, u4 crc, bool isBootstrap)
4922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
4932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DexClassLookup* pClassLookup = NULL;
4942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    IndexMapSet* pIndexMapSet = NULL;
4952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    RegisterMapBuilder* pRegMapBuilder = NULL;
4962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bool doVerify, doOpt;
4972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u4 headerFlags = 0;
4982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (gDvm.classVerifyMode == VERIFY_MODE_NONE)
5002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        doVerify = false;
5012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    else if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE)
5022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        doVerify = !isBootstrap;
5032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    else /*if (gDvm.classVerifyMode == VERIFY_MODE_ALL)*/
5042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        doVerify = true;
5052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (gDvm.dexOptMode == OPTIMIZE_MODE_NONE)
5072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        doOpt = false;
5082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    else if (gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED)
5092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        doOpt = doVerify;
5102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    else /*if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)*/
5112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        doOpt = true;
5122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGV("Continuing optimization (%s, isb=%d, vfy=%d, opt=%d)\n",
5142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        fileName, isBootstrap, doVerify, doOpt);
5152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(dexOffset >= 0);
5172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* quick test so we don't blow up on empty file */
5192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (dexLength < (int) sizeof(DexHeader)) {
5202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGE("too small to be DEX\n");
5212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
5222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
5232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (dexOffset < (int) sizeof(DexOptHeader)) {
5242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGE("not enough room for opt header\n");
5252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
5262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
5272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bool result = false;
5292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
5312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Drop this into a global so we don't have to pass it around.  We could
5322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * also add a field to DexFile, but since it only pertains to DEX
5332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * creation that probably doesn't make sense.
5342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
5352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    gDvm.optimizingBootstrapClass = isBootstrap;
5362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    {
5382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
5392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Map the entire file (so we don't have to worry about page
5402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * alignment).  The expectation is that the output file contains
5412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * our DEX data plus room for a small header.
5422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
5432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        bool success;
5442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        void* mapAddr;
5452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        mapAddr = mmap(NULL, dexOffset + dexLength, PROT_READ|PROT_WRITE,
5462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    MAP_SHARED, fd, 0);
5472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (mapAddr == MAP_FAILED) {
5482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGE("unable to mmap DEX cache: %s\n", strerror(errno));
5492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto bail;
5502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
5512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
5532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Rewrite the file.  Byte reordering, structure realigning,
5542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * class verification, and bytecode optimization are all performed
5552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * here.
5562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         *
5572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * In theory the file could change size and bits could shift around.
5582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * In practice this would be annoying to deal with, so the file
5592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * layout is designed so that it can always be rewritten in place.
5602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         *
5612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * This sets "headerFlags" and creates the class lookup table as
5622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * part of doing the processing.
5632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
5642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        success = dvmRewriteDex(((u1*) mapAddr) + dexOffset, dexLength,
5652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    doVerify, doOpt, &headerFlags, &pClassLookup);
5662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (success) {
5682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            DvmDex* pDvmDex = NULL;
5692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            u1* dexAddr = ((u1*) mapAddr) + dexOffset;
5702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (dvmDexFileOpenPartial(dexAddr, dexLength, &pDvmDex) != 0) {
5722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                LOGE("Unable to create DexFile\n");
5732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                success = false;
5742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            } else {
5752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                /*
5762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 * If configured to do so, scan the instructions, looking
5772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 * for ways to reduce the size of the resolved-constant table.
5782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 * This is done post-optimization, across the instructions
5792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 * in all methods in all classes (even the ones that failed
5802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 * to load).
5812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 */
5822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                pIndexMapSet = dvmRewriteConstants(pDvmDex);
5832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                /*
5852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 * If configured to do so, generate a full set of register
5862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 * maps for all verified classes.
5872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                 */
5882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                if (gDvm.generateRegisterMaps) {
5892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    pRegMapBuilder = dvmGenerateRegisterMaps(pDvmDex);
5902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    if (pRegMapBuilder == NULL) {
5912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                        LOGE("Failed generating register maps\n");
5922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                        success = false;
5932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    }
5942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                }
5952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                DexHeader* pHeader = (DexHeader*)pDvmDex->pHeader;
5972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                updateChecksum(dexAddr, dexLength, pHeader);
5982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dvmDexFileFree(pDvmDex);
6002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
6012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
6022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* unmap the read-write version, forcing writes to disk */
6042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (msync(mapAddr, dexOffset + dexLength, MS_SYNC) != 0) {
6052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGW("msync failed: %s\n", strerror(errno));
6062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            // weird, but keep going
6072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
6082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#if 1
6092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
6102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * This causes clean shutdown to fail, because we have loaded classes
6112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * that point into it.  For the optimizer this isn't a problem,
6122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * because it's more efficient for the process to simply exit.
6132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Exclude this code when doing clean shutdown for valgrind.
6142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
6152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (munmap(mapAddr, dexOffset + dexLength) != 0) {
6162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGE("munmap failed: %s\n", strerror(errno));
6172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto bail;
6182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
6192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#endif
6202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (!success)
6222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto bail;
6232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
6242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* get start offset, and adjust deps start for 64-bit alignment */
6262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    off_t depsOffset, auxOffset, endOffset, adjOffset;
6272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int depsLength, auxLength;
6282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u4 optChecksum;
6292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    depsOffset = lseek(fd, 0, SEEK_END);
6312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (depsOffset < 0) {
6322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGE("lseek to EOF failed: %s\n", strerror(errno));
6332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
6342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
6352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    adjOffset = (depsOffset + 7) & ~(0x07);
6362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (adjOffset != depsOffset) {
6372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGV("Adjusting deps start from %d to %d\n",
6382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            (int) depsOffset, (int) adjOffset);
6392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        depsOffset = adjOffset;
6402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        lseek(fd, depsOffset, SEEK_SET);
6412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
6422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
6442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Append the dependency list.
6452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
6462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (writeDependencies(fd, modWhen, crc) != 0) {
6472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGW("Failed writing dependencies\n");
6482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
6492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
6502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* compute deps length, then adjust aux start for 64-bit alignment */
6522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    auxOffset = lseek(fd, 0, SEEK_END);
6532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    depsLength = auxOffset - depsOffset;
6542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    adjOffset = (auxOffset + 7) & ~(0x07);
6562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (adjOffset != auxOffset) {
6572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGV("Adjusting aux start from %d to %d\n",
6582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            (int) auxOffset, (int) adjOffset);
6592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        auxOffset = adjOffset;
6602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        lseek(fd, auxOffset, SEEK_SET);
6612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
6622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
6642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Append any auxillary pre-computed data structures.
6652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
6662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!writeAuxData(fd, pClassLookup, pIndexMapSet, pRegMapBuilder)) {
6672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGW("Failed writing aux data\n");
6682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
6692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
6702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    endOffset = lseek(fd, 0, SEEK_END);
6722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    auxLength = endOffset - auxOffset;
6732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* compute checksum from start of deps to end of aux area */
6752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!computeFileChecksum(fd, depsOffset,
6762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            (auxOffset+auxLength) - depsOffset, &optChecksum))
6772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    {
6782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
6792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
6802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
6822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Output the "opt" header with all values filled in and a correct
6832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * magic number.
6842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
6852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DexOptHeader optHdr;
6862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    memset(&optHdr, 0xff, sizeof(optHdr));
6872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    memcpy(optHdr.magic, DEX_OPT_MAGIC, 4);
6882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    memcpy(optHdr.magic+4, DEX_OPT_MAGIC_VERS, 4);
6892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    optHdr.dexOffset = (u4) dexOffset;
6902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    optHdr.dexLength = (u4) dexLength;
6912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    optHdr.depsOffset = (u4) depsOffset;
6922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    optHdr.depsLength = (u4) depsLength;
6932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    optHdr.auxOffset = (u4) auxOffset;
6942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    optHdr.auxLength = (u4) auxLength;
6952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    optHdr.flags = headerFlags;
6972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    optHdr.checksum = optChecksum;
6982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ssize_t actual;
7002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    lseek(fd, 0, SEEK_SET);
7012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    actual = write(fd, &optHdr, sizeof(optHdr));
7022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (actual != sizeof(optHdr)) {
7032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        logFailedWrite(sizeof(optHdr), actual, "opt header", errno);
7042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
7052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
7062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGV("Successfully wrote DEX header\n");
7082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    result = true;
7092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    //dvmRegisterMapDumpStats();
7112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenbail:
7132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    dvmFreeIndexMapSet(pIndexMapSet);
7142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    dvmFreeRegisterMapBuilder(pRegMapBuilder);
7152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    free(pClassLookup);
7162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return result;
7172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
7182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
7212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Get the cache file name from a ClassPathEntry.
7222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
7232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic const char* getCacheFileName(const ClassPathEntry* cpe)
7242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
7252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    switch (cpe->kind) {
7262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    case kCpeJar:
7272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return dvmGetJarFileCacheFileName((JarFile*) cpe->ptr);
7282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    case kCpeDex:
7292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return dvmGetRawDexFileCacheFileName((RawDexFile*) cpe->ptr);
7302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    default:
7312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGE("DexOpt: unexpected cpe kind %d\n", cpe->kind);
7322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmAbort();
7332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return NULL;
7342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
7352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
7362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
7382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Get the SHA-1 signature.
7392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
7402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic const u1* getSignature(const ClassPathEntry* cpe)
7412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
7422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DvmDex* pDvmDex;
7432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    switch (cpe->kind) {
7452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    case kCpeJar:
7462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pDvmDex = dvmGetJarFileDex((JarFile*) cpe->ptr);
7472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        break;
7482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    case kCpeDex:
7492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pDvmDex = dvmGetRawDexFileDex((RawDexFile*) cpe->ptr);
7502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        break;
7512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    default:
7522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGE("unexpected cpe kind %d\n", cpe->kind);
7532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmAbort();
7542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pDvmDex = NULL;         // make gcc happy
7552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
7562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(pDvmDex != NULL);
7582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return pDvmDex->pDexFile->pHeader->signature;
7592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
7602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
7632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Dependency layout:
7642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *  4b  Source file modification time, in seconds since 1970 UTC
7652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *  4b  CRC-32 from Zip entry, or Adler32 from source DEX header
7662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *  4b  Dalvik VM build number
7672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *  4b  Number of dependency entries that follow
7682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *  Dependency entries:
7692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *    4b  Name length (including terminating null)
7702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *    var Full path of cache entry (null terminated)
7712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *    20b SHA-1 signature from source DEX file
7722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
7732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * If this changes, update DEX_OPT_MAGIC_VERS.
7742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
7752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic const size_t kMinDepSize = 4 * 4;
7762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic const size_t kMaxDepSize = 4 * 4 + 1024;     // sanity check
7772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
7792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Read the "opt" header, verify it, then read the dependencies section
7802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * and verify that data as well.
7812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
7822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * If "sourceAvail" is "true", this will verify that "modWhen" and "crc"
7832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * match up with what is stored in the header.  If they don't, we reject
7842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * the file so that it can be recreated from the updated original.  If
7852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * "sourceAvail" isn't set, e.g. for a .odex file, we ignore these arguments.
7862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
7872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On successful return, the file will be seeked immediately past the
7882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * "opt" header.
7892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
7902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenbool dvmCheckOptHeaderAndDependencies(int fd, bool sourceAvail, u4 modWhen,
7912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u4 crc, bool expectVerify, bool expectOpt)
7922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
7932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DexOptHeader optHdr;
7942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u1* depData = NULL;
7952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const u1* magic;
7962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    off_t posn;
7972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int result = false;
7982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ssize_t actual;
7992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
8012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Start at the start.  The "opt" header, when present, will always be
8022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * the first thing in the file.
8032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
8042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (lseek(fd, 0, SEEK_SET) != 0) {
8052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGE("DexOpt: failed to seek to start of file: %s\n", strerror(errno));
8062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
8072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
8082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
8102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Read and do trivial verification on the opt header.  The header is
8112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * always in host byte order.
8122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
8132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (read(fd, &optHdr, sizeof(optHdr)) != sizeof(optHdr)) {
8142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGE("DexOpt: failed reading opt header: %s\n", strerror(errno));
8152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
8162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
8172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    magic = optHdr.magic;
8192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (memcmp(magic, DEX_OPT_MAGIC, 4) != 0) {
8202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* not a DEX file, or previous attempt was interrupted */
8212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGD("DexOpt: incorrect opt magic number (0x%02x %02x %02x %02x)\n",
8222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            magic[0], magic[1], magic[2], magic[3]);
8232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
8242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
8252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (memcmp(magic+4, DEX_OPT_MAGIC_VERS, 4) != 0) {
8262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGW("DexOpt: stale opt version (0x%02x %02x %02x %02x)\n",
8272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            magic[4], magic[5], magic[6], magic[7]);
8282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
8292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
8302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (optHdr.depsLength < kMinDepSize || optHdr.depsLength > kMaxDepSize) {
8312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGW("DexOpt: weird deps length %d, bailing\n", optHdr.depsLength);
8322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
8332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
8342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
8362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Do the header flags match up with what we want?
8372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     *
8382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * This is useful because it allows us to automatically regenerate
8392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * a file when settings change (e.g. verification is now mandatory),
8402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * but can cause difficulties if the bootstrap classes we depend upon
8412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * were handled differently than the current options specify.  We get
8422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * upset because they're not verified or optimized, but we're not able
8432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * to regenerate them because the installer won't let us.
8442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     *
8452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * (This is also of limited value when !sourceAvail.)
8462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     *
8472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * So, for now, we essentially ignore "expectVerify" and "expectOpt"
8482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * by limiting the match mask.
8492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     *
8502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * The only thing we really can't handle is incorrect byte-ordering.
8512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
8522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const u4 matchMask = DEX_OPT_FLAG_BIG;
8532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u4 expectedFlags = 0;
8542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#if __BYTE_ORDER != __LITTLE_ENDIAN
8552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    expectedFlags |= DEX_OPT_FLAG_BIG;
8562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#endif
8572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (expectVerify)
8582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        expectedFlags |= DEX_FLAG_VERIFIED;
8592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (expectOpt)
8602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        expectedFlags |= DEX_OPT_FLAG_FIELDS | DEX_OPT_FLAG_INVOCATIONS;
8612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if ((expectedFlags & matchMask) != (optHdr.flags & matchMask)) {
8622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGI("DexOpt: header flag mismatch (0x%02x vs 0x%02x, mask=0x%02x)\n",
8632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            expectedFlags, optHdr.flags, matchMask);
8642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
8652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
8662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    posn = lseek(fd, optHdr.depsOffset, SEEK_SET);
8682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (posn < 0) {
8692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGW("DexOpt: seek to deps failed: %s\n", strerror(errno));
8702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
8712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
8722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
8742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Read all of the dependency stuff into memory.
8752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
8762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    depData = (u1*) malloc(optHdr.depsLength);
8772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (depData == NULL) {
8782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGW("DexOpt: unable to allocate %d bytes for deps\n",
8792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            optHdr.depsLength);
8802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
8812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
8822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    actual = read(fd, depData, optHdr.depsLength);
8832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (actual != (ssize_t) optHdr.depsLength) {
8842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGW("DexOpt: failed reading deps: %d of %d (err=%s)\n",
8852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            (int) actual, optHdr.depsLength, strerror(errno));
8862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
8872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
8882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
8902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Verify simple items.
8912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
8922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const u1* ptr;
8932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u4 val;
8942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ptr = depData;
8962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    val = read4LE(&ptr);
8972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (sourceAvail && val != modWhen) {
8982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGI("DexOpt: source file mod time mismatch (%08x vs %08x)\n",
8992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            val, modWhen);
9002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
9012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
9022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    val = read4LE(&ptr);
9032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (sourceAvail && val != crc) {
9042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGI("DexOpt: source file CRC mismatch (%08x vs %08x)\n", val, crc);
9052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
9062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
9072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    val = read4LE(&ptr);
9082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (val != DALVIK_VM_BUILD) {
9092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGD("DexOpt: VM build version mismatch (%d vs %d)\n",
9102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            val, DALVIK_VM_BUILD);
9112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
9122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
9132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
9152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Verify dependencies on other cached DEX files.  It must match
9162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * exactly with what is currently defined in the bootclasspath.
9172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
9182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassPathEntry* cpe;
9192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u4 numDeps;
9202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    numDeps = read4LE(&ptr);
9222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGV("+++ DexOpt: numDeps = %d\n", numDeps);
9232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
9242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const char* cacheFileName = getCacheFileName(cpe);
9252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const u1* signature = getSignature(cpe);
9262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        size_t len = strlen(cacheFileName) +1;
9272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        u4 storedStrLen;
9282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (numDeps == 0) {
9302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* more entries in bootclasspath than in deps list */
9312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGI("DexOpt: not all deps represented\n");
9322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto bail;
9332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
9342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        storedStrLen = read4LE(&ptr);
9362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (len != storedStrLen ||
9372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            strcmp(cacheFileName, (const char*) ptr) != 0)
9382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        {
9392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGI("DexOpt: mismatch dep name: '%s' vs. '%s'\n",
9402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                cacheFileName, ptr);
9412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto bail;
9422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
9432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ptr += storedStrLen;
9452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (memcmp(signature, ptr, kSHA1DigestLen) != 0) {
9472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGI("DexOpt: mismatch dep signature for '%s'\n", cacheFileName);
9482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto bail;
9492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
9502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ptr += kSHA1DigestLen;
9512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGV("DexOpt: dep match on '%s'\n", cacheFileName);
9532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        numDeps--;
9552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
9562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (numDeps != 0) {
9582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* more entries in deps list than in classpath */
9592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGI("DexOpt: Some deps went away\n");
9602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        goto bail;
9612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
9622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    // consumed all data and no more?
9642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (ptr != depData + optHdr.depsLength) {
9652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGW("DexOpt: Spurious dep data? %d vs %d\n",
9662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            (int) (ptr - depData), optHdr.depsLength);
9672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        assert(false);
9682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
9692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    result = true;
9712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenbail:
9732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    free(depData);
9742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return result;
9752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
9762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
9782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Write the dependency info to "fd" at the current file position.
9792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
9802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic int writeDependencies(int fd, u4 modWhen, u4 crc)
9812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
9822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u1* buf = NULL;
9832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ssize_t actual;
9842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int result = -1;
9852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ssize_t bufLen;
9862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassPathEntry* cpe;
9872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int i, numDeps;
9882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
9902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Count up the number of completed entries in the bootclasspath.
9912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
9922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    numDeps = 0;
9932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bufLen = 0;
9942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
9952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const char* cacheFileName = getCacheFileName(cpe);
9962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGV("+++ DexOpt: found dep '%s'\n", cacheFileName);
9972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        numDeps++;
9992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        bufLen += strlen(cacheFileName) +1;
10002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
10012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bufLen += 4*4 + numDeps * (4+kSHA1DigestLen);
10032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    buf = malloc(bufLen);
10052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    set4LE(buf+0, modWhen);
10072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    set4LE(buf+4, crc);
10082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    set4LE(buf+8, DALVIK_VM_BUILD);
10092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    set4LE(buf+12, numDeps);
10102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    // TODO: do we want to add dvmGetInlineOpsTableLength() here?  Won't
10122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    // help us if somebody replaces an existing entry, but it'd catch
10132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    // additions/removals.
10142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u1* ptr = buf + 4*4;
10162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
10172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const char* cacheFileName = getCacheFileName(cpe);
10182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const u1* signature = getSignature(cpe);
10192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int len = strlen(cacheFileName) +1;
10202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (ptr + 4 + len + kSHA1DigestLen > buf + bufLen) {
10222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGE("DexOpt: overran buffer\n");
10232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dvmAbort();
10242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
10252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        set4LE(ptr, len);
10272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ptr += 4;
10282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        memcpy(ptr, cacheFileName, len);
10292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ptr += len;
10302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        memcpy(ptr, signature, kSHA1DigestLen);
10312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ptr += kSHA1DigestLen;
10322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
10332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(ptr == buf + bufLen);
10352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    actual = write(fd, buf, bufLen);
10372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (actual != bufLen) {
10382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        result = (errno != 0) ? errno : -1;
10392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        logFailedWrite(bufLen, actual, "dep info", errno);
10402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    } else {
10412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        result = 0;
10422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
10432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    free(buf);
10452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return result;
10462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
10472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
10502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Write a block of data in "chunk" format.
10512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
10522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * The chunk header fields are always in "native" byte order.  If "size"
10532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * is not a multiple of 8 bytes, the data area is padded out.
10542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
10552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool writeChunk(int fd, u4 type, const void* data, size_t size)
10562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
10572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ssize_t actual;
10582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    union {             /* save a syscall by grouping these together */
10592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        char raw[8];
10602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        struct {
10612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            u4 type;
10622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            u4 size;
10632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        } ts;
10642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    } header;
10652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(sizeof(header) == 8);
10672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGV("Writing chunk, type=%.4s size=%d\n", (char*) &type, size);
10692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    header.ts.type = type;
10712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    header.ts.size = (u4) size;
10722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    actual = write(fd, &header, sizeof(header));
10732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (actual != sizeof(header)) {
10742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        logFailedWrite(size, actual, "aux chunk header write", errno);
10752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
10762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
10772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (size > 0) {
10792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        actual = write(fd, data, size);
10802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (actual != (ssize_t) size) {
10812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            logFailedWrite(size, actual, "aux chunk write", errno);
10822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return false;
10832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
10842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
10852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* if necessary, pad to 64-bit alignment */
10872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if ((size & 7) != 0) {
10882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int padSize = 8 - (size & 7);
10892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGV("size was %d, inserting %d pad bytes\n", size, padSize);
10902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        lseek(fd, padSize, SEEK_CUR);
10912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
10922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert( ((int)lseek(fd, 0, SEEK_CUR) & 7) == 0);
10942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return true;
10962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
10972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
10992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Write aux data.
11002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
11012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * We have different pieces, some of which may be optional.  To make the
11022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * most effective use of space, we use a "chunk" format, with a 4-byte
11032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * type and a 4-byte length.  We guarantee 64-bit alignment for the data,
11042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * so it can be used directly when the file is mapped for reading.
11052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
11062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool writeAuxData(int fd, const DexClassLookup* pClassLookup,
11072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const IndexMapSet* pIndexMapSet, const RegisterMapBuilder* pRegMapBuilder)
11082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
11092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* pre-computed class lookup hash table */
11102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!writeChunk(fd, (u4) kDexChunkClassLookup,
11112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            pClassLookup, pClassLookup->size))
11122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    {
11132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
11142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
11152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* remapped constants (optional) */
11172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (pIndexMapSet != NULL) {
11182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (!writeChunk(fd, pIndexMapSet->chunkType,
11192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                pIndexMapSet->chunkData, pIndexMapSet->chunkDataLen))
11202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        {
11212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return false;
11222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
11232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
11242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* register maps (optional) */
11262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (pRegMapBuilder != NULL) {
11272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (!writeChunk(fd, (u4) kDexChunkRegisterMaps,
11282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                pRegMapBuilder->data, pRegMapBuilder->size))
11292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        {
11302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return false;
11312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
11322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
11332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* write the end marker */
11352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!writeChunk(fd, (u4) kDexChunkEnd, NULL, 0)) {
11362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
11372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
11382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return true;
11402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
11412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
11432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Log a failed write.
11442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
11452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic void logFailedWrite(size_t expected, ssize_t actual, const char* msg,
11462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int err)
11472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
11482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGE("Write failed: %s (%d of %d): %s\n",
11492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        msg, (int)actual, (int)expected, strerror(err));
11502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
11512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
11532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Compute a checksum on a piece of an open file.
11542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
11552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * File will be positioned at end of checksummed area.
11562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
11572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" on success.
11582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
11592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool computeFileChecksum(int fd, off_t start, size_t length, u4* pSum)
11602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
11612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    unsigned char readBuf[8192];
11622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ssize_t actual;
11632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    uLong adler;
11642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (lseek(fd, start, SEEK_SET) != start) {
11662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGE("Unable to seek to start of checksum area (%ld): %s\n",
11672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            (long) start, strerror(errno));
11682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
11692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
11702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    adler = adler32(0L, Z_NULL, 0);
11722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    while (length != 0) {
11742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        size_t wanted = (length < sizeof(readBuf)) ? length : sizeof(readBuf);
11752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        actual = read(fd, readBuf, wanted);
11762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (actual <= 0) {
11772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGE("Read failed (%d) while computing checksum (len=%zu): %s\n",
11782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                (int) actual, length, strerror(errno));
11792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return false;
11802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
11812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        adler = adler32(adler, readBuf, actual);
11832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        length -= actual;
11852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
11862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    *pSum = adler;
11882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return true;
11892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
11902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
11922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Update the Adler-32 checksum stored in the DEX file.  This covers the
11932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * swapped and optimized DEX data, but does not include the opt header
11942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * or auxillary data.
11952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
11962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic void updateChecksum(u1* addr, int len, DexHeader* pHeader)
11972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
11982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
11992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Rewrite the checksum.  We leave the SHA-1 signature alone.
12002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
12012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    uLong adler = adler32(0L, Z_NULL, 0);
12022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum);
12032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    adler = adler32(adler, addr + nonSum, len - nonSum);
12052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    pHeader->checksum = adler;
12062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
12072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1208