DexPrepare.cpp revision 64896a2543ee54e47c586f4cf26f54e7fdb366bd
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * Prepare a DEX file for use by the VM.  Depending upon the VM options
19 * we will attempt to verify and/or optimize the code, possibly appending
20 * register maps.
21 *
22 * TODO: the format of the optimized header is currently "whatever we
23 * happen to write", since the VM that writes it is by definition the same
24 * as the VM that reads it.  Still, it should be better documented and
25 * more rigorously structured.
26 */
27#include "Dalvik.h"
28#include "libdex/OptInvocation.h"
29#include "analysis/RegisterMap.h"
30#include "analysis/Optimize.h"
31
32#include <zlib.h>
33
34#include <stdlib.h>
35#include <unistd.h>
36#include <sys/mman.h>
37#include <sys/stat.h>
38#include <sys/file.h>
39#include <sys/wait.h>
40#include <fcntl.h>
41#include <errno.h>
42
43
44/* fwd */
45static bool rewriteDex(u1* addr, int len, u4* pHeaderFlags,
46    DexClassLookup** ppClassLookup);
47static bool loadAllClasses(DvmDex* pDvmDex);
48static void verifyAndOptimizeClasses(DexFile* pDexFile, bool doVerify,
49    bool doOpt);
50static void verifyAndOptimizeClass(DexFile* pDexFile, ClassObject* clazz,
51    const DexClassDef* pClassDef, bool doVerify, bool doOpt);
52static void updateChecksum(u1* addr, int len, DexHeader* pHeader);
53static int writeDependencies(int fd, u4 modWhen, u4 crc);
54static bool writeAuxData(int fd, const DexClassLookup* pClassLookup,\
55    const IndexMapSet* pIndexMapSet, const RegisterMapBuilder* pRegMapBuilder);
56static bool computeFileChecksum(int fd, off_t start, size_t length, u4* pSum);
57
58
59/*
60 * Return the fd of an open file in the DEX file cache area.  If the cache
61 * file doesn't exist or is out of date, this will remove the old entry,
62 * create a new one (writing only the file header), and return with the
63 * "new file" flag set.
64 *
65 * It's possible to execute from an unoptimized DEX file directly,
66 * assuming the byte ordering and structure alignment is correct, but
67 * disadvantageous because some significant optimizations are not possible.
68 * It's not generally possible to do the same from an uncompressed Jar
69 * file entry, because we have to guarantee 32-bit alignment in the
70 * memory-mapped file.
71 *
72 * For a Jar/APK file (a zip archive with "classes.dex" inside), "modWhen"
73 * and "crc32" come from the Zip directory entry.  For a stand-alone DEX
74 * file, it's the modification date of the file and the Adler32 from the
75 * DEX header (which immediately follows the magic).  If these don't
76 * match what's stored in the opt header, we reject the file immediately.
77 *
78 * On success, the file descriptor will be positioned just past the "opt"
79 * file header, and will be locked with flock.  "*pCachedName" will point
80 * to newly-allocated storage.
81 */
82int dvmOpenCachedDexFile(const char* fileName, const char* cacheFileName,
83    u4 modWhen, u4 crc, bool isBootstrap, bool* pNewFile, bool createIfMissing)
84{
85    int fd, cc;
86    struct stat fdStat, fileStat;
87    bool readOnly = false;
88
89    *pNewFile = false;
90
91retry:
92    /*
93     * Try to open the cache file.  If we've been asked to,
94     * create it if it doesn't exist.
95     */
96    fd = createIfMissing ? open(cacheFileName, O_CREAT|O_RDWR, 0644) : -1;
97    if (fd < 0) {
98        fd = open(cacheFileName, O_RDONLY, 0);
99        if (fd < 0) {
100            if (createIfMissing) {
101                LOGE("Can't open dex cache '%s': %s\n",
102                    cacheFileName, strerror(errno));
103            }
104            return fd;
105        }
106        readOnly = true;
107    }
108
109    /*
110     * Grab an exclusive lock on the cache file.  If somebody else is
111     * working on it, we'll block here until they complete.  Because
112     * we're waiting on an external resource, we go into VMWAIT mode.
113     */
114    int oldStatus;
115    LOGV("DexOpt: locking cache file %s (fd=%d, boot=%d)\n",
116        cacheFileName, fd, isBootstrap);
117    oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
118    cc = flock(fd, LOCK_EX | LOCK_NB);
119    if (cc != 0) {
120        LOGD("DexOpt: sleeping on flock(%s)\n", cacheFileName);
121        cc = flock(fd, LOCK_EX);
122    }
123    dvmChangeStatus(NULL, oldStatus);
124    if (cc != 0) {
125        LOGE("Can't lock dex cache '%s': %d\n", cacheFileName, cc);
126        close(fd);
127        return -1;
128    }
129    LOGV("DexOpt:  locked cache file\n");
130
131    /*
132     * Check to see if the fd we opened and locked matches the file in
133     * the filesystem.  If they don't, then somebody else unlinked ours
134     * and created a new file, and we need to use that one instead.  (If
135     * we caught them between the unlink and the create, we'll get an
136     * ENOENT from the file stat.)
137     */
138    cc = fstat(fd, &fdStat);
139    if (cc != 0) {
140        LOGE("Can't stat open file '%s'\n", cacheFileName);
141        LOGVV("DexOpt: unlocking cache file %s\n", cacheFileName);
142        goto close_fail;
143    }
144    cc = stat(cacheFileName, &fileStat);
145    if (cc != 0 ||
146        fdStat.st_dev != fileStat.st_dev || fdStat.st_ino != fileStat.st_ino)
147    {
148        LOGD("DexOpt: our open cache file is stale; sleeping and retrying\n");
149        LOGVV("DexOpt: unlocking cache file %s\n", cacheFileName);
150        flock(fd, LOCK_UN);
151        close(fd);
152        usleep(250 * 1000);     /* if something is hosed, don't peg machine */
153        goto retry;
154    }
155
156    /*
157     * We have the correct file open and locked.  If the file size is zero,
158     * then it was just created by us, and we want to fill in some fields
159     * in the "opt" header and set "*pNewFile".  Otherwise, we want to
160     * verify that the fields in the header match our expectations, and
161     * reset the file if they don't.
162     */
163    if (fdStat.st_size == 0) {
164        if (readOnly) {
165            LOGW("DexOpt: file has zero length and isn't writable\n");
166            goto close_fail;
167        }
168        cc = dexOptCreateEmptyHeader(fd);
169        if (cc != 0)
170            goto close_fail;
171        *pNewFile = true;
172        LOGV("DexOpt: successfully initialized new cache file\n");
173    } else {
174        bool expectVerify, expectOpt;
175
176        if (gDvm.classVerifyMode == VERIFY_MODE_NONE)
177            expectVerify = false;
178        else if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE)
179            expectVerify = !isBootstrap;
180        else /*if (gDvm.classVerifyMode == VERIFY_MODE_ALL)*/
181            expectVerify = true;
182
183        if (gDvm.dexOptMode == OPTIMIZE_MODE_NONE)
184            expectOpt = false;
185        else if (gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED)
186            expectOpt = expectVerify;
187        else /*if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)*/
188            expectOpt = true;
189
190        LOGV("checking deps, expecting vfy=%d opt=%d\n",
191            expectVerify, expectOpt);
192
193        if (!dvmCheckOptHeaderAndDependencies(fd, true, modWhen, crc,
194                expectVerify, expectOpt))
195        {
196            if (readOnly) {
197                /*
198                 * We could unlink and rewrite the file if we own it or
199                 * the "sticky" bit isn't set on the directory.  However,
200                 * we're not able to truncate it, which spoils things.  So,
201                 * give up now.
202                 */
203                if (createIfMissing) {
204                    LOGW("Cached DEX '%s' (%s) is stale and not writable\n",
205                        fileName, cacheFileName);
206                }
207                goto close_fail;
208            }
209
210            /*
211             * If we truncate the existing file before unlinking it, any
212             * process that has it mapped will fail when it tries to touch
213             * the pages.
214             *
215             * This is very important.  The zygote process will have the
216             * boot DEX files (core, framework, etc.) mapped early.  If
217             * (say) core.dex gets updated, and somebody launches an app
218             * that uses App.dex, then App.dex gets reoptimized because it's
219             * dependent upon the boot classes.  However, dexopt will be
220             * using the *new* core.dex to do the optimizations, while the
221             * app will actually be running against the *old* core.dex
222             * because it starts from zygote.
223             *
224             * Even without zygote, it's still possible for a class loader
225             * to pull in an APK that was optimized against an older set
226             * of DEX files.  We must ensure that everything fails when a
227             * boot DEX gets updated, and for general "why aren't my
228             * changes doing anything" purposes its best if we just make
229             * everything crash when a DEX they're using gets updated.
230             */
231            LOGD("Stale deps in cache file; removing and retrying\n");
232            if (ftruncate(fd, 0) != 0) {
233                LOGW("Warning: unable to truncate cache file '%s': %s\n",
234                    cacheFileName, strerror(errno));
235                /* keep going */
236            }
237            if (unlink(cacheFileName) != 0) {
238                LOGW("Warning: unable to remove cache file '%s': %d %s\n",
239                    cacheFileName, errno, strerror(errno));
240                /* keep going; permission failure should probably be fatal */
241            }
242            LOGVV("DexOpt: unlocking cache file %s\n", cacheFileName);
243            flock(fd, LOCK_UN);
244            close(fd);
245            goto retry;
246        } else {
247            LOGV("DexOpt: good deps in cache file\n");
248        }
249    }
250
251    assert(fd >= 0);
252    return fd;
253
254close_fail:
255    flock(fd, LOCK_UN);
256    close(fd);
257    return -1;
258}
259
260/*
261 * Unlock the file descriptor.
262 *
263 * Returns "true" on success.
264 */
265bool dvmUnlockCachedDexFile(int fd)
266{
267    LOGVV("DexOpt: unlocking cache file fd=%d\n", fd);
268    return (flock(fd, LOCK_UN) == 0);
269}
270
271
272/*
273 * Given a descriptor for a file with DEX data in it, produce an
274 * optimized version.
275 *
276 * The file pointed to by "fd" is expected to be a locked shared resource
277 * (or private); we make no efforts to enforce multi-process correctness
278 * here.
279 *
280 * "fileName" is only used for debug output.  "modWhen" and "crc" are stored
281 * in the dependency set.
282 *
283 * The "isBootstrap" flag determines how the optimizer and verifier handle
284 * package-scope access checks.  When optimizing, we only load the bootstrap
285 * class DEX files and the target DEX, so the flag determines whether the
286 * target DEX classes are given a (synthetic) non-NULL classLoader pointer.
287 * This only really matters if the target DEX contains classes that claim to
288 * be in the same package as bootstrap classes.
289 *
290 * The optimizer will need to load every class in the target DEX file.
291 * This is generally undesirable, so we start a subprocess to do the
292 * work and wait for it to complete.
293 *
294 * Returns "true" on success.  All data will have been written to "fd".
295 */
296bool dvmOptimizeDexFile(int fd, off_t dexOffset, long dexLength,
297    const char* fileName, u4 modWhen, u4 crc, bool isBootstrap)
298{
299    const char* lastPart = strrchr(fileName, '/');
300    if (lastPart != NULL)
301        lastPart++;
302    else
303        lastPart = fileName;
304
305    LOGD("DexOpt: --- BEGIN '%s' (bootstrap=%d) ---\n", lastPart, isBootstrap);
306
307    pid_t pid;
308
309    /*
310     * This could happen if something in our bootclasspath, which we thought
311     * was all optimized, got rejected.
312     */
313    if (gDvm.optimizing) {
314        LOGW("Rejecting recursive optimization attempt on '%s'\n", fileName);
315        return false;
316    }
317
318    pid = fork();
319    if (pid == 0) {
320        static const int kUseValgrind = 0;
321        static const char* kDexOptBin = "/bin/dexopt";
322        static const char* kValgrinder = "/usr/bin/valgrind";
323        static const int kFixedArgCount = 10;
324        static const int kValgrindArgCount = 5;
325        static const int kMaxIntLen = 12;   // '-'+10dig+'\0' -OR- 0x+8dig
326        int bcpSize = dvmGetBootPathSize();
327        int argc = kFixedArgCount + bcpSize
328            + (kValgrindArgCount * kUseValgrind);
329        char* argv[argc+1];             // last entry is NULL
330        char values[argc][kMaxIntLen];
331        char* execFile;
332        char* androidRoot;
333        int flags;
334
335        /* change process groups, so we don't clash with ProcessManager */
336        setpgid(0, 0);
337
338        /* full path to optimizer */
339        androidRoot = getenv("ANDROID_ROOT");
340        if (androidRoot == NULL) {
341            LOGW("ANDROID_ROOT not set, defaulting to /system\n");
342            androidRoot = "/system";
343        }
344        execFile = malloc(strlen(androidRoot) + strlen(kDexOptBin) + 1);
345        strcpy(execFile, androidRoot);
346        strcat(execFile, kDexOptBin);
347
348        /*
349         * Create arg vector.
350         */
351        int curArg = 0;
352
353        if (kUseValgrind) {
354            /* probably shouldn't ship the hard-coded path */
355            argv[curArg++] = (char*)kValgrinder;
356            argv[curArg++] = "--tool=memcheck";
357            argv[curArg++] = "--leak-check=yes";        // check for leaks too
358            argv[curArg++] = "--leak-resolution=med";   // increase from 2 to 4
359            argv[curArg++] = "--num-callers=16";        // default is 12
360            assert(curArg == kValgrindArgCount);
361        }
362        argv[curArg++] = execFile;
363
364        argv[curArg++] = "--dex";
365
366        sprintf(values[2], "%d", DALVIK_VM_BUILD);
367        argv[curArg++] = values[2];
368
369        sprintf(values[3], "%d", fd);
370        argv[curArg++] = values[3];
371
372        sprintf(values[4], "%d", (int) dexOffset);
373        argv[curArg++] = values[4];
374
375        sprintf(values[5], "%d", (int) dexLength);
376        argv[curArg++] = values[5];
377
378        argv[curArg++] = (char*)fileName;
379
380        sprintf(values[7], "%d", (int) modWhen);
381        argv[curArg++] = values[7];
382
383        sprintf(values[8], "%d", (int) crc);
384        argv[curArg++] = values[8];
385
386        flags = 0;
387        if (gDvm.dexOptMode != OPTIMIZE_MODE_NONE) {
388            flags |= DEXOPT_OPT_ENABLED;
389            if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)
390                flags |= DEXOPT_OPT_ALL;
391        }
392        if (gDvm.classVerifyMode != VERIFY_MODE_NONE) {
393            flags |= DEXOPT_VERIFY_ENABLED;
394            if (gDvm.classVerifyMode == VERIFY_MODE_ALL)
395                flags |= DEXOPT_VERIFY_ALL;
396        }
397        if (isBootstrap)
398            flags |= DEXOPT_IS_BOOTSTRAP;
399        if (gDvm.generateRegisterMaps)
400            flags |= DEXOPT_GEN_REGISTER_MAP;
401        sprintf(values[9], "%d", flags);
402        argv[curArg++] = values[9];
403
404        assert(((!kUseValgrind && curArg == kFixedArgCount) ||
405               ((kUseValgrind && curArg == kFixedArgCount+kValgrindArgCount))));
406
407        ClassPathEntry* cpe;
408        for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
409            argv[curArg++] = cpe->fileName;
410        }
411        assert(curArg == argc);
412
413        argv[curArg] = NULL;
414
415        if (kUseValgrind)
416            execv(kValgrinder, argv);
417        else
418            execv(execFile, argv);
419
420        LOGE("execv '%s'%s failed: %s\n", execFile,
421            kUseValgrind ? " [valgrind]" : "", strerror(errno));
422        exit(1);
423    } else {
424        LOGV("DexOpt: waiting for verify+opt, pid=%d\n", (int) pid);
425        int status;
426        pid_t gotPid;
427        int oldStatus;
428
429        /*
430         * Wait for the optimization process to finish.  We go into VMWAIT
431         * mode here so GC suspension won't have to wait for us.
432         */
433        oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
434        while (true) {
435            gotPid = waitpid(pid, &status, 0);
436            if (gotPid == -1 && errno == EINTR) {
437                LOGD("waitpid interrupted, retrying\n");
438            } else {
439                break;
440            }
441        }
442        dvmChangeStatus(NULL, oldStatus);
443        if (gotPid != pid) {
444            LOGE("waitpid failed: wanted %d, got %d: %s\n",
445                (int) pid, (int) gotPid, strerror(errno));
446            return false;
447        }
448
449        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
450            LOGD("DexOpt: --- END '%s' (success) ---\n", lastPart);
451            return true;
452        } else {
453            LOGW("DexOpt: --- END '%s' --- status=0x%04x, process failed\n",
454                lastPart, status);
455            return false;
456        }
457    }
458}
459
460/*
461 * Do the actual optimization.  This is executed in the dexopt process.
462 *
463 * For best use of disk/memory, we want to extract once and perform
464 * optimizations in place.  If the file has to expand or contract
465 * to match local structure padding/alignment expectations, we want
466 * to do the rewrite as part of the extract, rather than extracting
467 * into a temp file and slurping it back out.  (The structure alignment
468 * is currently correct for all platforms, and this isn't expected to
469 * change, so we should be okay with having it already extracted.)
470 *
471 * Returns "true" on success.
472 */
473bool dvmContinueOptimization(int fd, off_t dexOffset, long dexLength,
474    const char* fileName, u4 modWhen, u4 crc, bool isBootstrap)
475{
476    DexClassLookup* pClassLookup = NULL;
477    IndexMapSet* pIndexMapSet = NULL;
478    RegisterMapBuilder* pRegMapBuilder = NULL;
479    u4 headerFlags = 0;
480
481    assert(gDvm.optimizing);
482
483    LOGV("Continuing optimization (%s, isb=%d, vfy=%d, opt=%d)\n",
484        fileName, isBootstrap, doVerify, doOpt);
485
486    assert(dexOffset >= 0);
487
488    /* quick test so we don't blow up on empty file */
489    if (dexLength < (int) sizeof(DexHeader)) {
490        LOGE("too small to be DEX\n");
491        return false;
492    }
493    if (dexOffset < (int) sizeof(DexOptHeader)) {
494        LOGE("not enough room for opt header\n");
495        return false;
496    }
497
498    bool result = false;
499
500    /*
501     * Drop this into a global so we don't have to pass it around.  We could
502     * also add a field to DexFile, but since it only pertains to DEX
503     * creation that probably doesn't make sense.
504     */
505    gDvm.optimizingBootstrapClass = isBootstrap;
506
507    {
508        /*
509         * Map the entire file (so we don't have to worry about page
510         * alignment).  The expectation is that the output file contains
511         * our DEX data plus room for a small header.
512         */
513        bool success;
514        void* mapAddr;
515        mapAddr = mmap(NULL, dexOffset + dexLength, PROT_READ|PROT_WRITE,
516                    MAP_SHARED, fd, 0);
517        if (mapAddr == MAP_FAILED) {
518            LOGE("unable to mmap DEX cache: %s\n", strerror(errno));
519            goto bail;
520        }
521
522        /*
523         * Rewrite the file.  Byte reordering, structure realigning,
524         * class verification, and bytecode optimization are all performed
525         * here.
526         *
527         * In theory the file could change size and bits could shift around.
528         * In practice this would be annoying to deal with, so the file
529         * layout is designed so that it can always be rewritten in place.
530         *
531         * This sets "headerFlags" and creates the class lookup table as
532         * part of doing the processing.
533         */
534        success = rewriteDex(((u1*) mapAddr) + dexOffset, dexLength,
535                    &headerFlags, &pClassLookup);
536
537        if (success) {
538            DvmDex* pDvmDex = NULL;
539            u1* dexAddr = ((u1*) mapAddr) + dexOffset;
540
541            if (dvmDexFileOpenPartial(dexAddr, dexLength, &pDvmDex) != 0) {
542                LOGE("Unable to create DexFile\n");
543                success = false;
544            } else {
545                /*
546                 * If configured to do so, scan the instructions, looking
547                 * for ways to reduce the size of the resolved-constant table.
548                 * This is done post-optimization, across the instructions
549                 * in all methods in all classes (even the ones that failed
550                 * to load).
551                 */
552                pIndexMapSet = dvmRewriteConstants(pDvmDex);
553
554                /*
555                 * If configured to do so, generate register map output
556                 * for all verified classes.  The register maps were
557                 * generated during verification, and will now be serialized.
558                 */
559                if (gDvm.generateRegisterMaps) {
560                    pRegMapBuilder = dvmGenerateRegisterMaps(pDvmDex);
561                    if (pRegMapBuilder == NULL) {
562                        LOGE("Failed generating register maps\n");
563                        success = false;
564                    }
565                }
566
567                DexHeader* pHeader = (DexHeader*)pDvmDex->pHeader;
568                updateChecksum(dexAddr, dexLength, pHeader);
569
570                dvmDexFileFree(pDvmDex);
571            }
572        }
573
574        /* unmap the read-write version, forcing writes to disk */
575        if (msync(mapAddr, dexOffset + dexLength, MS_SYNC) != 0) {
576            LOGW("msync failed: %s\n", strerror(errno));
577            // weird, but keep going
578        }
579#if 1
580        /*
581         * This causes clean shutdown to fail, because we have loaded classes
582         * that point into it.  For the optimizer this isn't a problem,
583         * because it's more efficient for the process to simply exit.
584         * Exclude this code when doing clean shutdown for valgrind.
585         */
586        if (munmap(mapAddr, dexOffset + dexLength) != 0) {
587            LOGE("munmap failed: %s\n", strerror(errno));
588            goto bail;
589        }
590#endif
591
592        if (!success)
593            goto bail;
594    }
595
596    /* get start offset, and adjust deps start for 64-bit alignment */
597    off_t depsOffset, auxOffset, endOffset, adjOffset;
598    int depsLength, auxLength;
599    u4 optChecksum;
600
601    depsOffset = lseek(fd, 0, SEEK_END);
602    if (depsOffset < 0) {
603        LOGE("lseek to EOF failed: %s\n", strerror(errno));
604        goto bail;
605    }
606    adjOffset = (depsOffset + 7) & ~(0x07);
607    if (adjOffset != depsOffset) {
608        LOGV("Adjusting deps start from %d to %d\n",
609            (int) depsOffset, (int) adjOffset);
610        depsOffset = adjOffset;
611        lseek(fd, depsOffset, SEEK_SET);
612    }
613
614    /*
615     * Append the dependency list.
616     */
617    if (writeDependencies(fd, modWhen, crc) != 0) {
618        LOGW("Failed writing dependencies\n");
619        goto bail;
620    }
621
622    /* compute deps length, then adjust aux start for 64-bit alignment */
623    auxOffset = lseek(fd, 0, SEEK_END);
624    depsLength = auxOffset - depsOffset;
625
626    adjOffset = (auxOffset + 7) & ~(0x07);
627    if (adjOffset != auxOffset) {
628        LOGV("Adjusting aux start from %d to %d\n",
629            (int) auxOffset, (int) adjOffset);
630        auxOffset = adjOffset;
631        lseek(fd, auxOffset, SEEK_SET);
632    }
633
634    /*
635     * Append any auxillary pre-computed data structures.
636     */
637    if (!writeAuxData(fd, pClassLookup, pIndexMapSet, pRegMapBuilder)) {
638        LOGW("Failed writing aux data\n");
639        goto bail;
640    }
641
642    endOffset = lseek(fd, 0, SEEK_END);
643    auxLength = endOffset - auxOffset;
644
645    /* compute checksum from start of deps to end of aux area */
646    if (!computeFileChecksum(fd, depsOffset,
647            (auxOffset+auxLength) - depsOffset, &optChecksum))
648    {
649        goto bail;
650    }
651
652    /*
653     * Output the "opt" header with all values filled in and a correct
654     * magic number.
655     */
656    DexOptHeader optHdr;
657    memset(&optHdr, 0xff, sizeof(optHdr));
658    memcpy(optHdr.magic, DEX_OPT_MAGIC, 4);
659    memcpy(optHdr.magic+4, DEX_OPT_MAGIC_VERS, 4);
660    optHdr.dexOffset = (u4) dexOffset;
661    optHdr.dexLength = (u4) dexLength;
662    optHdr.depsOffset = (u4) depsOffset;
663    optHdr.depsLength = (u4) depsLength;
664    optHdr.auxOffset = (u4) auxOffset;
665    optHdr.auxLength = (u4) auxLength;
666
667    optHdr.flags = headerFlags;
668    optHdr.checksum = optChecksum;
669
670    ssize_t actual;
671    lseek(fd, 0, SEEK_SET);
672    if (sysWriteFully(fd, &optHdr, sizeof(optHdr), "DexOpt opt header") != 0)
673        goto bail;
674
675    LOGV("Successfully wrote DEX header\n");
676    result = true;
677
678    //dvmRegisterMapDumpStats();
679
680bail:
681    dvmFreeIndexMapSet(pIndexMapSet);
682    dvmFreeRegisterMapBuilder(pRegMapBuilder);
683    free(pClassLookup);
684    return result;
685}
686
687
688/*
689 * Perform in-place rewrites on a memory-mapped DEX file.
690 *
691 * This happens in a short-lived child process, so we can go nutty with
692 * loading classes and allocating memory.
693 */
694static bool rewriteDex(u1* addr, int len, u4* pHeaderFlags,
695    DexClassLookup** ppClassLookup)
696{
697    u8 prepWhen, loadWhen, verifyOptWhen;
698    DvmDex* pDvmDex = NULL;
699    bool doVerify, doOpt;
700    bool result = false;
701
702    *pHeaderFlags = 0;
703
704    /* if the DEX is in the wrong byte order, swap it now */
705    if (dexFixByteOrdering(addr, len) != 0)
706        goto bail;
707#if __BYTE_ORDER != __LITTLE_ENDIAN
708    *pHeaderFlags |= DEX_OPT_FLAG_BIG;
709#endif
710
711    if (gDvm.classVerifyMode == VERIFY_MODE_NONE)
712        doVerify = false;
713    else if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE)
714        doVerify = !gDvm.optimizingBootstrapClass;
715    else /*if (gDvm.classVerifyMode == VERIFY_MODE_ALL)*/
716        doVerify = true;
717
718    if (gDvm.dexOptMode == OPTIMIZE_MODE_NONE)
719        doOpt = false;
720    else if (gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED)
721        doOpt = doVerify;
722    else /*if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)*/
723        doOpt = true;
724
725    /* TODO: decide if this is actually useful */
726    if (doVerify)
727        *pHeaderFlags |= DEX_FLAG_VERIFIED;
728    if (doOpt)
729        *pHeaderFlags |= DEX_OPT_FLAG_FIELDS | DEX_OPT_FLAG_INVOCATIONS;
730
731    /*
732     * Now that the DEX file can be read directly, create a DexFile struct
733     * for it.
734     */
735    if (dvmDexFileOpenPartial(addr, len, &pDvmDex) != 0) {
736        LOGE("Unable to create DexFile\n");
737        goto bail;
738    }
739
740    /*
741     * Create the class lookup table.  This will eventually be appended
742     * to the end of the .odex.
743     */
744    *ppClassLookup = dexCreateClassLookup(pDvmDex->pDexFile);
745    if (*ppClassLookup == NULL)
746        goto bail;
747
748    /*
749     * If we're not going to attempt to verify or optimize the classes,
750     * there's no value in loading them, so bail out early.
751     */
752    if (!doVerify && !doOpt) {
753        result = true;
754        goto bail;
755    }
756
757    /* this is needed for the next part */
758    pDvmDex->pDexFile->pClassLookup = *ppClassLookup;
759
760    prepWhen = dvmGetRelativeTimeUsec();
761
762    /*
763     * Load all classes found in this DEX file.  If they fail to load for
764     * some reason, they won't get verified (which is as it should be).
765     */
766    if (!loadAllClasses(pDvmDex))
767        goto bail;
768    loadWhen = dvmGetRelativeTimeUsec();
769
770    /*
771     * Verify and optimize all classes in the DEX file (command-line
772     * options permitting).
773     *
774     * This is best-effort, so there's really no way for dexopt to
775     * fail at this point.
776     */
777    verifyAndOptimizeClasses(pDvmDex->pDexFile, doVerify, doOpt);
778    verifyOptWhen = dvmGetRelativeTimeUsec();
779
780    const char* msgStr = "???";
781    if (doVerify && doOpt)
782        msgStr = "verify+opt";
783    else if (doVerify)
784        msgStr = "verify";
785    else if (doOpt)
786        msgStr = "opt";
787    LOGD("DexOpt: load %dms, %s %dms\n",
788        (int) (loadWhen - prepWhen) / 1000,
789        msgStr,
790        (int) (verifyOptWhen - loadWhen) / 1000);
791
792    result = true;
793
794bail:
795    /* free up storage */
796    dvmDexFileFree(pDvmDex);
797
798    return result;
799}
800
801/*
802 * Try to load all classes in the specified DEX.  If they have some sort
803 * of broken dependency, e.g. their superclass lives in a different DEX
804 * that wasn't previously loaded into the bootstrap class path, loading
805 * will fail.  This is the desired behavior.
806 *
807 * We have no notion of class loader at this point, so we load all of
808 * the classes with the bootstrap class loader.  It turns out this has
809 * exactly the behavior we want, and has no ill side effects because we're
810 * running in a separate process and anything we load here will be forgotten.
811 *
812 * We set the CLASS_MULTIPLE_DEFS flag here if we see multiple definitions.
813 * This works because we only call here as part of optimization / pre-verify,
814 * not during verification as part of loading a class into a running VM.
815 *
816 * This returns "false" if the world is too screwed up to do anything
817 * useful at all.
818 */
819static bool loadAllClasses(DvmDex* pDvmDex)
820{
821    u4 count = pDvmDex->pDexFile->pHeader->classDefsSize;
822    u4 idx;
823    int loaded = 0;
824
825    LOGV("DexOpt: +++ trying to load %d classes\n", count);
826
827    dvmSetBootPathExtraDex(pDvmDex);
828
829    /*
830     * We have some circularity issues with Class and Object that are most
831     * easily avoided by ensuring that Object is never the first thing we
832     * try to find.  Take care of that here.  (We only need to do this when
833     * loading classes from the DEX file that contains Object, and only
834     * when Object comes first in the list, but it costs very little to
835     * do it in all cases.)
836     */
837    if (dvmFindSystemClass("Ljava/lang/Class;") == NULL) {
838        LOGE("ERROR: java.lang.Class does not exist!\n");
839        return false;
840    }
841
842    for (idx = 0; idx < count; idx++) {
843        const DexClassDef* pClassDef;
844        const char* classDescriptor;
845        ClassObject* newClass;
846
847        pClassDef = dexGetClassDef(pDvmDex->pDexFile, idx);
848        classDescriptor =
849            dexStringByTypeIdx(pDvmDex->pDexFile, pClassDef->classIdx);
850
851        LOGV("+++  loading '%s'", classDescriptor);
852        //newClass = dvmDefineClass(pDexFile, classDescriptor,
853        //        NULL);
854        newClass = dvmFindSystemClassNoInit(classDescriptor);
855        if (newClass == NULL) {
856            LOGV("DexOpt: failed loading '%s'\n", classDescriptor);
857            dvmClearOptException(dvmThreadSelf());
858        } else if (newClass->pDvmDex != pDvmDex) {
859            /*
860             * We don't load the new one, and we tag the first one found
861             * with the "multiple def" flag so the resolver doesn't try
862             * to make it available.
863             */
864            LOGD("DexOpt: '%s' has an earlier definition; blocking out\n",
865                classDescriptor);
866            SET_CLASS_FLAG(newClass, CLASS_MULTIPLE_DEFS);
867        } else {
868            loaded++;
869        }
870    }
871    LOGV("DexOpt: +++ successfully loaded %d classes\n", loaded);
872
873    dvmSetBootPathExtraDex(NULL);
874    return true;
875}
876
877/*
878 * Verify and/or optimize all classes that were successfully loaded from
879 * this DEX file.
880 */
881static void verifyAndOptimizeClasses(DexFile* pDexFile, bool doVerify,
882    bool doOpt)
883{
884    u4 count = pDexFile->pHeader->classDefsSize;
885    u4 idx;
886
887    /*
888     * Create a data structure for use by the bytecode optimizer.  We
889     * stuff it into a global so we don't have to pass it around as
890     * a function argument.
891     *
892     * We could create this at VM startup, but there's no need to do so
893     * unless we're optimizing, which means we're in dexopt, and we're
894     * only going to call here once.
895     */
896    if (doOpt) {
897        gDvm.inlineSubs = dvmCreateInlineSubsTable();
898        if (gDvm.inlineSubs == NULL)
899            return;
900    }
901
902    for (idx = 0; idx < count; idx++) {
903        const DexClassDef* pClassDef;
904        const char* classDescriptor;
905        ClassObject* clazz;
906
907        pClassDef = dexGetClassDef(pDexFile, idx);
908        classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
909
910        /* all classes are loaded into the bootstrap class loader */
911        clazz = dvmLookupClass(classDescriptor, NULL, false);
912        if (clazz != NULL) {
913            verifyAndOptimizeClass(pDexFile, clazz, pClassDef, doVerify, doOpt);
914
915        } else {
916            // TODO: log when in verbose mode
917            LOGV("DexOpt: not optimizing unavailable class '%s'\n",
918                classDescriptor);
919        }
920    }
921
922    if (gDvm.inlineSubs != NULL) {
923        dvmFreeInlineSubsTable(gDvm.inlineSubs);
924        gDvm.inlineSubs = NULL;
925    }
926}
927
928/*
929 * Verify and/or optimize a specific class.
930 */
931static void verifyAndOptimizeClass(DexFile* pDexFile, ClassObject* clazz,
932    const DexClassDef* pClassDef, bool doVerify, bool doOpt)
933{
934    const char* classDescriptor;
935    bool verified = false;
936
937    classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
938
939    /*
940     * First, try to verify it.
941     */
942    if (doVerify) {
943        if (clazz->pDvmDex->pDexFile != pDexFile) {
944            LOGD("DexOpt: not verifying '%s': multiple definitions\n",
945                classDescriptor);
946        } else {
947            if (dvmVerifyClass(clazz, VERIFY_DEFAULT)) {
948                /*
949                 * Set the "is preverified" flag in the DexClassDef.  We
950                 * do it here, rather than in the ClassObject structure,
951                 * because the DexClassDef is part of the odex file.
952                 */
953                assert((clazz->accessFlags & JAVA_FLAGS_MASK) ==
954                    pClassDef->accessFlags);
955                ((DexClassDef*)pClassDef)->accessFlags |=
956                    CLASS_ISPREVERIFIED;
957                verified = true;
958            } else {
959                // TODO: log when in verbose mode
960                LOGV("DexOpt: '%s' failed verification\n", classDescriptor);
961            }
962        }
963    }
964
965    if (doOpt) {
966        if (!verified && gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED) {
967            LOGV("DexOpt: not optimizing '%s': not verified\n",
968                classDescriptor);
969        } else {
970            dvmOptimizeClass(clazz);
971
972            /* set the flag whether or not we actually changed anything */
973            ((DexClassDef*)pClassDef)->accessFlags |= CLASS_ISOPTIMIZED;
974        }
975    }
976}
977
978
979/*
980 * Get the cache file name from a ClassPathEntry.
981 */
982static const char* getCacheFileName(const ClassPathEntry* cpe)
983{
984    switch (cpe->kind) {
985    case kCpeJar:
986        return dvmGetJarFileCacheFileName((JarFile*) cpe->ptr);
987    case kCpeDex:
988        return dvmGetRawDexFileCacheFileName((RawDexFile*) cpe->ptr);
989    default:
990        LOGE("DexOpt: unexpected cpe kind %d\n", cpe->kind);
991        dvmAbort();
992        return NULL;
993    }
994}
995
996/*
997 * Get the SHA-1 signature.
998 */
999static const u1* getSignature(const ClassPathEntry* cpe)
1000{
1001    DvmDex* pDvmDex;
1002
1003    switch (cpe->kind) {
1004    case kCpeJar:
1005        pDvmDex = dvmGetJarFileDex((JarFile*) cpe->ptr);
1006        break;
1007    case kCpeDex:
1008        pDvmDex = dvmGetRawDexFileDex((RawDexFile*) cpe->ptr);
1009        break;
1010    default:
1011        LOGE("unexpected cpe kind %d\n", cpe->kind);
1012        dvmAbort();
1013        pDvmDex = NULL;         // make gcc happy
1014    }
1015
1016    assert(pDvmDex != NULL);
1017    return pDvmDex->pDexFile->pHeader->signature;
1018}
1019
1020
1021/*
1022 * Dependency layout:
1023 *  4b  Source file modification time, in seconds since 1970 UTC
1024 *  4b  CRC-32 from Zip entry, or Adler32 from source DEX header
1025 *  4b  Dalvik VM build number
1026 *  4b  Number of dependency entries that follow
1027 *  Dependency entries:
1028 *    4b  Name length (including terminating null)
1029 *    var Full path of cache entry (null terminated)
1030 *    20b SHA-1 signature from source DEX file
1031 *
1032 * If this changes, update DEX_OPT_MAGIC_VERS.
1033 */
1034static const size_t kMinDepSize = 4 * 4;
1035static const size_t kMaxDepSize = 4 * 4 + 1024;     // sanity check
1036
1037/*
1038 * Read the "opt" header, verify it, then read the dependencies section
1039 * and verify that data as well.
1040 *
1041 * If "sourceAvail" is "true", this will verify that "modWhen" and "crc"
1042 * match up with what is stored in the header.  If they don't, we reject
1043 * the file so that it can be recreated from the updated original.  If
1044 * "sourceAvail" isn't set, e.g. for a .odex file, we ignore these arguments.
1045 *
1046 * On successful return, the file will be seeked immediately past the
1047 * "opt" header.
1048 */
1049bool dvmCheckOptHeaderAndDependencies(int fd, bool sourceAvail, u4 modWhen,
1050    u4 crc, bool expectVerify, bool expectOpt)
1051{
1052    DexOptHeader optHdr;
1053    u1* depData = NULL;
1054    const u1* magic;
1055    off_t posn;
1056    int result = false;
1057    ssize_t actual;
1058
1059    /*
1060     * Start at the start.  The "opt" header, when present, will always be
1061     * the first thing in the file.
1062     */
1063    if (lseek(fd, 0, SEEK_SET) != 0) {
1064        LOGE("DexOpt: failed to seek to start of file: %s\n", strerror(errno));
1065        goto bail;
1066    }
1067
1068    /*
1069     * Read and do trivial verification on the opt header.  The header is
1070     * always in host byte order.
1071     */
1072    if (read(fd, &optHdr, sizeof(optHdr)) != sizeof(optHdr)) {
1073        LOGE("DexOpt: failed reading opt header: %s\n", strerror(errno));
1074        goto bail;
1075    }
1076
1077    magic = optHdr.magic;
1078    if (memcmp(magic, DEX_OPT_MAGIC, 4) != 0) {
1079        /* not a DEX file, or previous attempt was interrupted */
1080        LOGD("DexOpt: incorrect opt magic number (0x%02x %02x %02x %02x)\n",
1081            magic[0], magic[1], magic[2], magic[3]);
1082        goto bail;
1083    }
1084    if (memcmp(magic+4, DEX_OPT_MAGIC_VERS, 4) != 0) {
1085        LOGW("DexOpt: stale opt version (0x%02x %02x %02x %02x)\n",
1086            magic[4], magic[5], magic[6], magic[7]);
1087        goto bail;
1088    }
1089    if (optHdr.depsLength < kMinDepSize || optHdr.depsLength > kMaxDepSize) {
1090        LOGW("DexOpt: weird deps length %d, bailing\n", optHdr.depsLength);
1091        goto bail;
1092    }
1093
1094    /*
1095     * Do the header flags match up with what we want?
1096     *
1097     * This is useful because it allows us to automatically regenerate
1098     * a file when settings change (e.g. verification is now mandatory),
1099     * but can cause difficulties if the bootstrap classes we depend upon
1100     * were handled differently than the current options specify.  We get
1101     * upset because they're not verified or optimized, but we're not able
1102     * to regenerate them because the installer won't let us.
1103     *
1104     * (This is also of limited value when !sourceAvail.)
1105     *
1106     * So, for now, we essentially ignore "expectVerify" and "expectOpt"
1107     * by limiting the match mask.
1108     *
1109     * The only thing we really can't handle is incorrect byte-ordering.
1110     */
1111    const u4 matchMask = DEX_OPT_FLAG_BIG;
1112    u4 expectedFlags = 0;
1113#if __BYTE_ORDER != __LITTLE_ENDIAN
1114    expectedFlags |= DEX_OPT_FLAG_BIG;
1115#endif
1116    if (expectVerify)
1117        expectedFlags |= DEX_FLAG_VERIFIED;
1118    if (expectOpt)
1119        expectedFlags |= DEX_OPT_FLAG_FIELDS | DEX_OPT_FLAG_INVOCATIONS;
1120    if ((expectedFlags & matchMask) != (optHdr.flags & matchMask)) {
1121        LOGI("DexOpt: header flag mismatch (0x%02x vs 0x%02x, mask=0x%02x)\n",
1122            expectedFlags, optHdr.flags, matchMask);
1123        goto bail;
1124    }
1125
1126    posn = lseek(fd, optHdr.depsOffset, SEEK_SET);
1127    if (posn < 0) {
1128        LOGW("DexOpt: seek to deps failed: %s\n", strerror(errno));
1129        goto bail;
1130    }
1131
1132    /*
1133     * Read all of the dependency stuff into memory.
1134     */
1135    depData = (u1*) malloc(optHdr.depsLength);
1136    if (depData == NULL) {
1137        LOGW("DexOpt: unable to allocate %d bytes for deps\n",
1138            optHdr.depsLength);
1139        goto bail;
1140    }
1141    actual = read(fd, depData, optHdr.depsLength);
1142    if (actual != (ssize_t) optHdr.depsLength) {
1143        LOGW("DexOpt: failed reading deps: %d of %d (err=%s)\n",
1144            (int) actual, optHdr.depsLength, strerror(errno));
1145        goto bail;
1146    }
1147
1148    /*
1149     * Verify simple items.
1150     */
1151    const u1* ptr;
1152    u4 val;
1153
1154    ptr = depData;
1155    val = read4LE(&ptr);
1156    if (sourceAvail && val != modWhen) {
1157        LOGI("DexOpt: source file mod time mismatch (%08x vs %08x)\n",
1158            val, modWhen);
1159        goto bail;
1160    }
1161    val = read4LE(&ptr);
1162    if (sourceAvail && val != crc) {
1163        LOGI("DexOpt: source file CRC mismatch (%08x vs %08x)\n", val, crc);
1164        goto bail;
1165    }
1166    val = read4LE(&ptr);
1167    if (val != DALVIK_VM_BUILD) {
1168        LOGD("DexOpt: VM build version mismatch (%d vs %d)\n",
1169            val, DALVIK_VM_BUILD);
1170        goto bail;
1171    }
1172
1173    /*
1174     * Verify dependencies on other cached DEX files.  It must match
1175     * exactly with what is currently defined in the bootclasspath.
1176     */
1177    ClassPathEntry* cpe;
1178    u4 numDeps;
1179
1180    numDeps = read4LE(&ptr);
1181    LOGV("+++ DexOpt: numDeps = %d\n", numDeps);
1182    for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
1183        const char* cacheFileName = getCacheFileName(cpe);
1184        const u1* signature = getSignature(cpe);
1185        size_t len = strlen(cacheFileName) +1;
1186        u4 storedStrLen;
1187
1188        if (numDeps == 0) {
1189            /* more entries in bootclasspath than in deps list */
1190            LOGI("DexOpt: not all deps represented\n");
1191            goto bail;
1192        }
1193
1194        storedStrLen = read4LE(&ptr);
1195        if (len != storedStrLen ||
1196            strcmp(cacheFileName, (const char*) ptr) != 0)
1197        {
1198            LOGI("DexOpt: mismatch dep name: '%s' vs. '%s'\n",
1199                cacheFileName, ptr);
1200            goto bail;
1201        }
1202
1203        ptr += storedStrLen;
1204
1205        if (memcmp(signature, ptr, kSHA1DigestLen) != 0) {
1206            LOGI("DexOpt: mismatch dep signature for '%s'\n", cacheFileName);
1207            goto bail;
1208        }
1209        ptr += kSHA1DigestLen;
1210
1211        LOGV("DexOpt: dep match on '%s'\n", cacheFileName);
1212
1213        numDeps--;
1214    }
1215
1216    if (numDeps != 0) {
1217        /* more entries in deps list than in classpath */
1218        LOGI("DexOpt: Some deps went away\n");
1219        goto bail;
1220    }
1221
1222    // consumed all data and no more?
1223    if (ptr != depData + optHdr.depsLength) {
1224        LOGW("DexOpt: Spurious dep data? %d vs %d\n",
1225            (int) (ptr - depData), optHdr.depsLength);
1226        assert(false);
1227    }
1228
1229    result = true;
1230
1231bail:
1232    free(depData);
1233    return result;
1234}
1235
1236/*
1237 * Write the dependency info to "fd" at the current file position.
1238 */
1239static int writeDependencies(int fd, u4 modWhen, u4 crc)
1240{
1241    u1* buf = NULL;
1242    ssize_t actual;
1243    int result = -1;
1244    ssize_t bufLen;
1245    ClassPathEntry* cpe;
1246    int i, numDeps;
1247
1248    /*
1249     * Count up the number of completed entries in the bootclasspath.
1250     */
1251    numDeps = 0;
1252    bufLen = 0;
1253    for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
1254        const char* cacheFileName = getCacheFileName(cpe);
1255        LOGV("+++ DexOpt: found dep '%s'\n", cacheFileName);
1256
1257        numDeps++;
1258        bufLen += strlen(cacheFileName) +1;
1259    }
1260
1261    bufLen += 4*4 + numDeps * (4+kSHA1DigestLen);
1262
1263    buf = malloc(bufLen);
1264
1265    set4LE(buf+0, modWhen);
1266    set4LE(buf+4, crc);
1267    set4LE(buf+8, DALVIK_VM_BUILD);
1268    set4LE(buf+12, numDeps);
1269
1270    // TODO: do we want to add dvmGetInlineOpsTableLength() here?  Won't
1271    // help us if somebody replaces an existing entry, but it'd catch
1272    // additions/removals.
1273
1274    u1* ptr = buf + 4*4;
1275    for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
1276        const char* cacheFileName = getCacheFileName(cpe);
1277        const u1* signature = getSignature(cpe);
1278        int len = strlen(cacheFileName) +1;
1279
1280        if (ptr + 4 + len + kSHA1DigestLen > buf + bufLen) {
1281            LOGE("DexOpt: overran buffer\n");
1282            dvmAbort();
1283        }
1284
1285        set4LE(ptr, len);
1286        ptr += 4;
1287        memcpy(ptr, cacheFileName, len);
1288        ptr += len;
1289        memcpy(ptr, signature, kSHA1DigestLen);
1290        ptr += kSHA1DigestLen;
1291    }
1292
1293    assert(ptr == buf + bufLen);
1294
1295    result = sysWriteFully(fd, buf, bufLen, "DexOpt dep info");
1296
1297    free(buf);
1298    return result;
1299}
1300
1301
1302/*
1303 * Write a block of data in "chunk" format.
1304 *
1305 * The chunk header fields are always in "native" byte order.  If "size"
1306 * is not a multiple of 8 bytes, the data area is padded out.
1307 */
1308static bool writeChunk(int fd, u4 type, const void* data, size_t size)
1309{
1310    ssize_t actual;
1311    union {             /* save a syscall by grouping these together */
1312        char raw[8];
1313        struct {
1314            u4 type;
1315            u4 size;
1316        } ts;
1317    } header;
1318
1319    assert(sizeof(header) == 8);
1320
1321    LOGV("Writing chunk, type=%.4s size=%d\n", (char*) &type, size);
1322
1323    header.ts.type = type;
1324    header.ts.size = (u4) size;
1325    if (sysWriteFully(fd, &header, sizeof(header),
1326            "DexOpt aux chunk header write") != 0)
1327    {
1328        return false;
1329    }
1330
1331    if (size > 0) {
1332        if (sysWriteFully(fd, data, size, "DexOpt aux chunk write") != 0)
1333            return false;
1334    }
1335
1336    /* if necessary, pad to 64-bit alignment */
1337    if ((size & 7) != 0) {
1338        int padSize = 8 - (size & 7);
1339        LOGV("size was %d, inserting %d pad bytes\n", size, padSize);
1340        lseek(fd, padSize, SEEK_CUR);
1341    }
1342
1343    assert( ((int)lseek(fd, 0, SEEK_CUR) & 7) == 0);
1344
1345    return true;
1346}
1347
1348/*
1349 * Write aux data.
1350 *
1351 * We have different pieces, some of which may be optional.  To make the
1352 * most effective use of space, we use a "chunk" format, with a 4-byte
1353 * type and a 4-byte length.  We guarantee 64-bit alignment for the data,
1354 * so it can be used directly when the file is mapped for reading.
1355 */
1356static bool writeAuxData(int fd, const DexClassLookup* pClassLookup,
1357    const IndexMapSet* pIndexMapSet, const RegisterMapBuilder* pRegMapBuilder)
1358{
1359    /* pre-computed class lookup hash table */
1360    if (!writeChunk(fd, (u4) kDexChunkClassLookup,
1361            pClassLookup, pClassLookup->size))
1362    {
1363        return false;
1364    }
1365
1366    /* remapped constants (optional) */
1367    if (pIndexMapSet != NULL) {
1368        if (!writeChunk(fd, pIndexMapSet->chunkType,
1369                pIndexMapSet->chunkData, pIndexMapSet->chunkDataLen))
1370        {
1371            return false;
1372        }
1373    }
1374
1375    /* register maps (optional) */
1376    if (pRegMapBuilder != NULL) {
1377        if (!writeChunk(fd, (u4) kDexChunkRegisterMaps,
1378                pRegMapBuilder->data, pRegMapBuilder->size))
1379        {
1380            return false;
1381        }
1382    }
1383
1384    /* write the end marker */
1385    if (!writeChunk(fd, (u4) kDexChunkEnd, NULL, 0)) {
1386        return false;
1387    }
1388
1389    return true;
1390}
1391
1392/*
1393 * Compute a checksum on a piece of an open file.
1394 *
1395 * File will be positioned at end of checksummed area.
1396 *
1397 * Returns "true" on success.
1398 */
1399static bool computeFileChecksum(int fd, off_t start, size_t length, u4* pSum)
1400{
1401    unsigned char readBuf[8192];
1402    ssize_t actual;
1403    uLong adler;
1404
1405    if (lseek(fd, start, SEEK_SET) != start) {
1406        LOGE("Unable to seek to start of checksum area (%ld): %s\n",
1407            (long) start, strerror(errno));
1408        return false;
1409    }
1410
1411    adler = adler32(0L, Z_NULL, 0);
1412
1413    while (length != 0) {
1414        size_t wanted = (length < sizeof(readBuf)) ? length : sizeof(readBuf);
1415        actual = read(fd, readBuf, wanted);
1416        if (actual <= 0) {
1417            LOGE("Read failed (%d) while computing checksum (len=%zu): %s\n",
1418                (int) actual, length, strerror(errno));
1419            return false;
1420        }
1421
1422        adler = adler32(adler, readBuf, actual);
1423
1424        length -= actual;
1425    }
1426
1427    *pSum = adler;
1428    return true;
1429}
1430
1431/*
1432 * Update the Adler-32 checksum stored in the DEX file.  This covers the
1433 * swapped and optimized DEX data, but does not include the opt header
1434 * or auxillary data.
1435 */
1436static void updateChecksum(u1* addr, int len, DexHeader* pHeader)
1437{
1438    /*
1439     * Rewrite the checksum.  We leave the SHA-1 signature alone.
1440     */
1441    uLong adler = adler32(0L, Z_NULL, 0);
1442    const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum);
1443
1444    adler = adler32(adler, addr + nonSum, len - nonSum);
1445    pHeader->checksum = adler;
1446}
1447
1448