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