Added additional DEX checksum.

We have a checksum on the base DEX data, but not on the stuff that
dexopt appends.  If a flash block goes "funny" we might not be able to
detect the problem.  This change adds a checksum field to the
"optimized" header.

The new checksum is verified under the same circumstances as the base
DEX checksum: when you use "dexdump", and when you enable additional
checking with -Xcheckdexsum (or the property dalvik.vm.check-dex-sum
is set to "true").

For bug 2255640.
diff --git a/vm/analysis/DexOptimize.c b/vm/analysis/DexOptimize.c
index 369d707..a5b8b6f 100644
--- a/vm/analysis/DexOptimize.c
+++ b/vm/analysis/DexOptimize.c
@@ -54,6 +54,7 @@
     const IndexMapSet* pIndexMapSet, const RegisterMapBuilder* pRegMapBuilder);
 static void logFailedWrite(size_t expected, ssize_t actual, const char* msg,
     int err);
+static bool computeFileChecksum(int fd, off_t start, size_t length, u4* pSum);
 
 static bool rewriteDex(u1* addr, int len, bool doVerify, bool doOpt,\
     u4* pHeaderFlags, DexClassLookup** ppClassLookup);
@@ -645,6 +646,7 @@
     /* get start offset, and adjust deps start for 64-bit alignment */
     off_t depsOffset, auxOffset, endOffset, adjOffset;
     int depsLength, auxLength;
+    u4 optChecksum;
 
     depsOffset = lseek(fd, 0, SEEK_END);
     if (depsOffset < 0) {
@@ -690,6 +692,13 @@
     endOffset = lseek(fd, 0, SEEK_END);
     auxLength = endOffset - auxOffset;
 
+    /* compute checksum from start of deps to end of aux area */
+    if (!computeFileChecksum(fd, depsOffset,
+            (auxOffset+auxLength) - depsOffset, &optChecksum))
+    {
+        goto bail;
+    }
+
     /*
      * Output the "opt" header with all values filled in and a correct
      * magic number.
@@ -706,6 +715,7 @@
     optHdr.auxLength = (u4) auxLength;
 
     optHdr.flags = headerFlags;
+    optHdr.checksum = optChecksum;
 
     ssize_t actual;
     lseek(fd, 0, SEEK_SET);
@@ -1160,6 +1170,45 @@
         msg, (int)actual, (int)expected, strerror(err));
 }
 
+/*
+ * Compute a checksum on a piece of an open file.
+ *
+ * File will be positioned at end of checksummed area.
+ *
+ * Returns "true" on success.
+ */
+static bool computeFileChecksum(int fd, off_t start, size_t length, u4* pSum)
+{
+    unsigned char readBuf[8192];
+    ssize_t actual;
+    uLong adler;
+
+    if (lseek(fd, start, SEEK_SET) != start) {
+        LOGE("Unable to seek to start of checksum area (%ld): %s\n",
+            (long) start, strerror(errno));
+        return false;
+    }
+
+    adler = adler32(0L, Z_NULL, 0);
+
+    while (length != 0) {
+        size_t wanted = (length < sizeof(readBuf)) ? length : sizeof(readBuf);
+        actual = read(fd, readBuf, wanted);
+        if (actual <= 0) {
+            LOGE("Read failed (%d) while computing checksum (len=%zu): %s\n",
+                (int) actual, length, strerror(errno));
+            return false;
+        }
+
+        adler = adler32(adler, readBuf, actual);
+
+        length -= actual;
+    }
+
+    *pSum = adler;
+    return true;
+}
+
 
 /*
  * ===========================================================================