Do not use DOS epoch for timestamps of zip entries in Android rules
**Background**
I noticed cache output inconsistencies between my local and CI builds. I traced it down to the zip library in Java includes the timezone info within the extra field section of each zip entry. This appears to be a problem starting with Java 8 (See comment from Gradle's ZipCopyAction source code for more info: https://github.com/gradle/gradle/blob/master/subprojects/core/src/main/java/org/gradle/api/internal/file/archive/ZipCopyAction.java#L42-L56)
**Changes**
* Switch to using `February 1, 1980` instead to avoid this edge case
**Test Plan**
Ensure unit tests pass
Closes #10976.
PiperOrigin-RevId: 317075345
diff --git a/src/test/java/com/google/devtools/build/android/RClassGeneratorActionTest.java b/src/test/java/com/google/devtools/build/android/RClassGeneratorActionTest.java
index 3dbf763..ca87e29 100644
--- a/src/test/java/com/google/devtools/build/android/RClassGeneratorActionTest.java
+++ b/src/test/java/com/google/devtools/build/android/RClassGeneratorActionTest.java
@@ -501,26 +501,23 @@
}
private static final class ZipMtimeAsserter {
- private static final long ZIP_EPOCH = Instant.parse("1980-01-01T00:00:00Z").getEpochSecond();
- private static final long ZIP_EPOCH_PLUS_ONE_DAY =
- Instant.parse("1980-01-02T00:00:00Z").getEpochSecond();
+ private static final long DEFAULT_TIMESTAMP =
+ Instant.parse("1980-02-01T00:00:00Z").getEpochSecond();
+ private static final long DEFAULT_TIMESTAMP_PLUS_ONE_DAY =
+ Instant.parse("1980-02-02T00:00:00Z").getEpochSecond();
public static void assertEntry(ZipEntry e) {
// getLastModifiedTime().toMillis() returns milliseconds, Instant.getEpochSecond() returns
// seconds.
long mtime = e.getLastModifiedTime().toMillis() / 1000;
- // The ZIP epoch is the same as the MS-DOS epoch, 1980-01-01T00:00:00Z.
- // AndroidResourceOutputs.ZipBuilder sets this to most of its entries, except for .class files
- // for which the ZipBuilder increments the timestamp by 2 seconds.
+ // AndroidResourceOutputs.ZipBuilder sets the timestamp to one month after ZIP epoch
+ // which is the same as the MS-DOS epoch, 1980-01-01T00:00:00Z.
+ // The one exception being .class files for which the ZipBuilder
+ // increments the timestamp by 2 seconds.
// We don't care about the details of this logic and asserting exact timestamps would couple
// the test to the code too tightly, so here we only assert that the timestamp is on
- // 1980-01-01, ignoring the exact time.
- // AndroidResourceOutputs.ZipBuilde sets the ZIP epoch (same as the MS-DOS epoch,
- // 1980-01-01T00:00:00Z) as the timestamp for all of its entries (except .class files, for
- // which it sets a timestamp 2 seconds later than the DOS epoch).
- // We don't care about the exact timestamps though, only that they are stable, so let's just
- // assert that they are all on the day of 1980-01-01.
- if (mtime < ZIP_EPOCH || mtime > ZIP_EPOCH_PLUS_ONE_DAY) {
+ // 1980-02-01, ignoring the exact time.
+ if (mtime < DEFAULT_TIMESTAMP || mtime > DEFAULT_TIMESTAMP_PLUS_ONE_DAY) {
Assert.fail(String.format("e=(%s) mtime=(%s)", e.getName(), e.getLastModifiedTime()));
}
}
diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceOutputs.java b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceOutputs.java
index f6a82cb..575c82b 100644
--- a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceOutputs.java
+++ b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceOutputs.java
@@ -58,9 +58,13 @@
// see http://www.info-zip.org/FAQ.html#limits
private static final long MINIMUM_TIMESTAMP_INCREMENT = 2000L;
- // The earliest date representable in a zip file, 1-1-1980 (the DOS epoch).
- private static final long ZIP_EPOCH =
- new GregorianCalendar(1980, Calendar.JANUARY, 01, 0, 0).getTimeInMillis();
+ /**
+ * Normalized timestamp for zip entries We use the system's default timezone and locale and
+ * additionally avoid using the DOS epoch to ensure Java's zip implementation does not add the
+ * System's timezone into the extra field of the zip entry
+ */
+ private static final long DEFAULT_TIMESTAMP =
+ new GregorianCalendar(1980, Calendar.FEBRUARY, 01, 0, 0).getTimeInMillis();
private final ZipOutputStream zip;
@@ -84,9 +88,9 @@
*/
protected long normalizeTime(String filename) {
if (filename.endsWith(".class")) {
- return ZIP_EPOCH + MINIMUM_TIMESTAMP_INCREMENT;
+ return DEFAULT_TIMESTAMP + MINIMUM_TIMESTAMP_INCREMENT;
} else {
- return ZIP_EPOCH;
+ return DEFAULT_TIMESTAMP;
}
}