Remove changing uids/timestamps from zip/jar files

Pass -X to zip so that Unix UID/GID and extra timestamps aren't
saved into the zip files.

Add a new option to zipalign, -t, to replace all timestamps with static
timestamps (2008 Jan 1 00:00:00). Use this for all non-APK zip files.
APK zip timestamps are set based on the certificate date in SignApk.

Bug: 24201956
Change-Id: Ifb619fc499ba9d99fc624f2acd5f8de36d78ef8e
diff --git a/tools/zipalign/README.txt b/tools/zipalign/README.txt
index 0b80b35..1cdf612 100644
--- a/tools/zipalign/README.txt
+++ b/tools/zipalign/README.txt
@@ -6,6 +6,7 @@
   -c : check alignment only (does not modify file)
   -f : overwrite existing outfile.zip
   -p : page align stored shared object files
+  -t : remove dynamic timestamps
   -v : verbose output
   <align> is in bytes, e.g. "4" provides 32-bit alignment
   infile.zip is an existing Zip archive
@@ -38,3 +39,5 @@
 uncompressed in the zip archive, to a 4096-byte page boundary.  This
 facilitates directly loading shared libraries from inside a zip archive.
 
+The "-t" flag removes all timestamps that could change from the archive.
+
diff --git a/tools/zipalign/ZipAlign.cpp b/tools/zipalign/ZipAlign.cpp
index a2dfd02..2c81a03 100644
--- a/tools/zipalign/ZipAlign.cpp
+++ b/tools/zipalign/ZipAlign.cpp
@@ -39,6 +39,7 @@
     fprintf(stderr, "  -c: check alignment only (does not modify file)\n");
     fprintf(stderr, "  -f: overwrite existing outfile.zip\n");
     fprintf(stderr, "  -p: page align stored shared object files\n");
+    fprintf(stderr, "  -t: remove dynamic timestamps\n");
     fprintf(stderr, "  -v: verbose output\n");
     fprintf(stderr, "  -z: recompress using Zopfli\n");
 }
@@ -64,7 +65,7 @@
  * Copy all entries from "pZin" to "pZout", aligning as needed.
  */
 static int copyAndAlign(ZipFile* pZin, ZipFile* pZout, int alignment, bool zopfli,
-    bool pageAlignSharedLibs)
+    bool pageAlignSharedLibs, bool removeTime)
 {
     int numEntries = pZin->getNumEntries();
     ZipEntry* pEntry;
@@ -88,10 +89,10 @@
             //    (long) pEntry->getUncompressedLen());
 
             if (zopfli) {
-                status = pZout->addRecompress(pZin, pEntry, &pNewEntry);
+                status = pZout->addRecompress(pZin, pEntry, removeTime, &pNewEntry);
                 bias += pNewEntry->getCompressedLen() - pEntry->getCompressedLen();
             } else {
-                status = pZout->add(pZin, pEntry, padding, &pNewEntry);
+                status = pZout->add(pZin, pEntry, padding, removeTime, &pNewEntry);
             }
         } else {
             const int alignTo = getAlignment(pageAlignSharedLibs, alignment, pEntry);
@@ -107,7 +108,7 @@
             //printf("--- %s: orig at %ld(+%d) len=%ld, adding pad=%d\n",
             //    pEntry->getFileName(), (long) pEntry->getFileOffset(),
             //    bias, (long) pEntry->getUncompressedLen(), padding);
-            status = pZout->add(pZin, pEntry, padding, &pNewEntry);
+            status = pZout->add(pZin, pEntry, padding, removeTime, &pNewEntry);
         }
 
         if (status != NO_ERROR)
@@ -126,7 +127,8 @@
  * output file exists and "force" wasn't specified.
  */
 static int process(const char* inFileName, const char* outFileName,
-    int alignment, bool force, bool zopfli, bool pageAlignSharedLibs)
+    int alignment, bool force, bool zopfli, bool pageAlignSharedLibs,
+    bool removeTime)
 {
     ZipFile zin, zout;
 
@@ -157,7 +159,7 @@
         return 1;
     }
 
-    int result = copyAndAlign(&zin, &zout, alignment, zopfli, pageAlignSharedLibs);
+    int result = copyAndAlign(&zin, &zout, alignment, zopfli, pageAlignSharedLibs, removeTime);
     if (result != 0) {
         printf("zipalign: failed rewriting '%s' to '%s'\n",
             inFileName, outFileName);
@@ -228,6 +230,7 @@
     bool verbose = false;
     bool zopfli = false;
     bool pageAlignSharedLibs = false;
+    bool removeTime = false;
     int result = 1;
     int alignment;
     char* endp;
@@ -260,6 +263,9 @@
             case 'p':
                 pageAlignSharedLibs = true;
                 break;
+            case 't':
+                removeTime = true;
+                break;
             default:
                 fprintf(stderr, "ERROR: unknown flag -%c\n", *cp);
                 wantUsage = true;
@@ -290,7 +296,7 @@
         result = verify(argv[1], alignment, verbose, pageAlignSharedLibs);
     } else {
         /* create the new archive */
-        result = process(argv[1], argv[2], alignment, force, zopfli, pageAlignSharedLibs);
+        result = process(argv[1], argv[2], alignment, force, zopfli, pageAlignSharedLibs, removeTime);
 
         /* trust, but verify */
         if (result == 0) {
diff --git a/tools/zipalign/ZipEntry.cpp b/tools/zipalign/ZipEntry.cpp
index b2270cb..9347451 100644
--- a/tools/zipalign/ZipEntry.cpp
+++ b/tools/zipalign/ZipEntry.cpp
@@ -386,6 +386,14 @@
     mCDE.mLastModFileDate = mLFH.mLastModFileDate = zdate;
 }
 
+/*
+ * Set static timestamps
+ */
+void ZipEntry::removeTimestamps()
+{
+    mCDE.mLastModFileTime = mLFH.mLastModFileTime = 0;
+    mCDE.mLastModFileDate = mLFH.mLastModFileDate = 28 << 9 | 1 << 5 | 1;
+}
 
 /*
  * ===========================================================================
diff --git a/tools/zipalign/ZipEntry.h b/tools/zipalign/ZipEntry.h
index 7f721b4..0acd051 100644
--- a/tools/zipalign/ZipEntry.h
+++ b/tools/zipalign/ZipEntry.h
@@ -186,6 +186,12 @@
     void setModWhen(time_t when);
 
     /*
+     * Set a static modification date. This only affects the standard
+     * zip modification date, not the universal time extra field.
+     */
+    void removeTimestamps();
+
+    /*
      * Return the offset of the local file header.
      */
     off_t getLFHOffset(void) const { return mCDE.mLocalHeaderRelOffset; }
diff --git a/tools/zipalign/ZipFile.cpp b/tools/zipalign/ZipFile.cpp
index 3c5ec15..0ca4d0d 100644
--- a/tools/zipalign/ZipFile.cpp
+++ b/tools/zipalign/ZipFile.cpp
@@ -359,7 +359,7 @@
  */
 status_t ZipFile::addCommon(const char* fileName, const void* data, size_t size,
     const char* storageName, int sourceType, int compressionMethod,
-    ZipEntry** ppEntry)
+    bool removeTime, ZipEntry** ppEntry)
 {
     ZipEntry* pEntry = NULL;
     status_t result = NO_ERROR;
@@ -499,8 +499,12 @@
      */
     pEntry->setDataInfo(uncompressedLen, endPosn - startPosn, crc,
         compressionMethod);
-    modWhen = getModTime(inputFp ? fileno(inputFp) : fileno(mZipFp));
-    pEntry->setModWhen(modWhen);
+    if (removeTime) {
+        pEntry->removeTimestamps();
+    } else {
+        modWhen = getModTime(inputFp ? fileno(inputFp) : fileno(mZipFp));
+        pEntry->setModWhen(modWhen);
+    }
     pEntry->setLFHOffset(lfhPosn);
     mEOCD.mNumEntries++;
     mEOCD.mTotalNumEntries++;
@@ -539,7 +543,7 @@
  * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
  */
 status_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
-    int padding, ZipEntry** ppEntry)
+    int padding, bool removeTime, ZipEntry** ppEntry)
 {
     ZipEntry* pEntry = NULL;
     status_t result;
@@ -571,6 +575,8 @@
         if (result != NO_ERROR)
             goto bail;
     }
+    if (removeTime)
+        pEntry->removeTimestamps();
 
     /*
      * From here on out, failures are more interesting.
@@ -646,7 +652,7 @@
  * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
  */
 status_t ZipFile::addRecompress(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
-    ZipEntry** ppEntry)
+    bool removeTime, ZipEntry** ppEntry)
 {
     ZipEntry* pEntry = NULL;
     status_t result;
@@ -674,6 +680,9 @@
     if (result != NO_ERROR)
         goto bail;
 
+    if (removeTime)
+        pEntry->removeTimestamps();
+
     /*
      * From here on out, failures are more interesting.
      */
diff --git a/tools/zipalign/ZipFile.h b/tools/zipalign/ZipFile.h
index b99cda5..787576f 100644
--- a/tools/zipalign/ZipFile.h
+++ b/tools/zipalign/ZipFile.h
@@ -77,17 +77,17 @@
      *
      * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
      */
-    status_t add(const char* fileName, int compressionMethod,
+    status_t add(const char* fileName, int compressionMethod, bool removeTime,
         ZipEntry** ppEntry)
     {
-        return add(fileName, fileName, compressionMethod, ppEntry);
+        return add(fileName, fileName, compressionMethod, removeTime, ppEntry);
     }
     status_t add(const char* fileName, const char* storageName,
-        int compressionMethod, ZipEntry** ppEntry)
+        int compressionMethod, bool removeTime, ZipEntry** ppEntry)
     {
         return addCommon(fileName, NULL, 0, storageName,
                          ZipEntry::kCompressStored,
-                         compressionMethod, ppEntry);
+                         compressionMethod, removeTime, ppEntry);
     }
 
     /*
@@ -96,11 +96,12 @@
      * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
      */
     status_t addGzip(const char* fileName, const char* storageName,
-        ZipEntry** ppEntry)
+        bool removeTime, ZipEntry** ppEntry)
     {
         return addCommon(fileName, NULL, 0, storageName,
                          ZipEntry::kCompressDeflated,
-                         ZipEntry::kCompressDeflated, ppEntry);
+                         ZipEntry::kCompressDeflated,
+                         removeTime, ppEntry);
     }
 
     /*
@@ -109,11 +110,11 @@
      * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
      */
     status_t add(const void* data, size_t size, const char* storageName,
-        int compressionMethod, ZipEntry** ppEntry)
+        int compressionMethod, bool removeTime, ZipEntry** ppEntry)
     {
         return addCommon(NULL, data, size, storageName,
                          ZipEntry::kCompressStored,
-                         compressionMethod, ppEntry);
+                         compressionMethod, removeTime, ppEntry);
     }
 
     /*
@@ -124,7 +125,7 @@
      * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
      */
     status_t add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
-        int padding, ZipEntry** ppEntry);
+        int padding, bool removeTime, ZipEntry** ppEntry);
 
     /*
      * Add an entry by copying it from another zip file, recompressing with
@@ -133,7 +134,7 @@
      * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
      */
     status_t addRecompress(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
-        ZipEntry** ppEntry);
+        bool removeTime, ZipEntry** ppEntry);
 
     /*
      * Mark an entry as having been removed.  It is not actually deleted
@@ -232,7 +233,7 @@
     /* common handler for all "add" functions */
     status_t addCommon(const char* fileName, const void* data, size_t size,
         const char* storageName, int sourceType, int compressionMethod,
-        ZipEntry** ppEntry);
+        bool removeTime, ZipEntry** ppEntry);
 
     /* copy all of "srcFp" into "dstFp" */
     status_t copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32);