Merge "Change tzdatacheck to avoid hardcoding"
am: d29ed5628c

Change-Id: I2924a187debcb1dbfeca3ec6caba9dad665680ad
diff --git a/README.android b/README.android
index 127bd99..0a00001 100644
--- a/README.android
+++ b/README.android
@@ -117,24 +117,22 @@
 Changing the distro format version
 ----------------------------------
 
-1) Modify distro/core/src/main/com/android/timezone/distro/DistroVersion.java:
+1) Modify libcore/luni/src/main/java/libcore/timezone/TzDataSetVersion.java
   - CURRENT_FORMAT_MAJOR_VERSION, CURRENT_FORMAT_MINOR_VERSION
-2) Modify: tzdatacheck/tzdatacheck.cpp
-  - SUPPORTED_DISTRO_MAJOR_VERSION, SUPPORTED_DISTRO_MINOR_VERSION
-3) Run update-tzdata.py to regenerate the system/timezone/output_data,
+2) Run update-tzdata.py to regenerate the system/timezone/output_data,
   system/timezone/testing/data, external/icu runtime files and testing equivalents.
-4) Build/flash a device image with the changes and run CTS:
+3) Build/flash a device image with the changes and run CTS:
     cts-tradefed
     run cts -m CtsHostTzDataTests
     run cts -m CtsLibcoreTestCases
-5) Run non-CTS test cases:
+4) Run non-CTS test cases:
     make -j30 FrameworksServicesTests
     adb install -r -g \
         "${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk"
     adb shell am instrument -e package com.android.server.timezone -w \
         com.android.frameworks.servicestests \
         "com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner"
-6) Upload, review, submit the changes from system/timezone.
+5) Upload, review, submit the changes from system/timezone, libcore and external/icu.
 
 REMINDER: Any prebuilt apks of OEM-specific time zone data apps .apk files
 (i.e. ones that that contain distro files) will also need to be regenerated
diff --git a/tzdatacheck/tzdatacheck.cpp b/tzdatacheck/tzdatacheck.cpp
index 2a1defc..a117dce 100644
--- a/tzdatacheck/tzdatacheck.cpp
+++ b/tzdatacheck/tzdatacheck.cpp
@@ -47,47 +47,41 @@
 // See also com.android.timezone.distro.TimeZoneDistro / com.android.timezone.distro.DistroVersion.
 static const char* DISTRO_VERSION_FILENAME = "/distro_version";
 
-// distro_version is an ASCII file consisting of 17 bytes in the form: AAA.BBB|CCCCC|DDD
-// AAA.BBB is the major/minor version of the distro format (e.g. 001.001),
-// CCCCC is the rules version (e.g. 2016g)
-// DDD is the android revision for this rules version to allow for distro corrections (e.g. 001)
-// We only need the first 13 to determine if it is suitable for the device.
-static const int DISTRO_VERSION_LENGTH = 13;
+// The name of the file containing the base tz data set version information.
+// See also libcore.timezone.TzDataSetVersion.
+static const char* BASE_VERSION_FILENAME = "/tz_version";
 
-// The major version of the distro format supported by this code as a null-terminated char[].
-// See also com.android.timezone.distro.TimeZoneDistro / libcore.timezone.TzDataSetVersion.
-static const char SUPPORTED_DISTRO_MAJOR_VERSION[] = "003";
+// distro_version / tz_version are ASCII files consisting of at least 17 bytes in the
+// form: AAA.BBB|CCCCC|DDD
+// AAA.BBB is the major/minor version of the format (e.g. 004.001),
+// CCCCC is the rules version (e.g. 2016g),
+// DDD is the android revision for this rules version to allow for data corrections (e.g. 001),
+// We only use the first 13 to determine suitability of format / data.
+static const int READ_DATA_LENGTH = 13;
 
-// The length of the distro format major version excluding the \0
-static const size_t SUPPORTED_DISTRO_MAJOR_VERSION_LEN = sizeof(SUPPORTED_DISTRO_MAJOR_VERSION) - 1;
+// Version bytes are: AAA.BBB|CCCCC - the format version is AAA.BBB
+// The length of the format version,  e.g. "004.001" == 7 bytes
+static const size_t FORMAT_VERSION_LEN = 7;
 
-// The minor version of the distro format supported by this code as a null-terminated char[].
-// See also com.android.timezone.distro.TimeZoneDistro /
-// libcore.timezone.TzDataSetVersion
-static const char SUPPORTED_DISTRO_MINOR_VERSION[] = "001";
+// Version bytes are: AAA.BBB|CCCCC - the format major version is AAA
+static const size_t FORMAT_MAJOR_VERSION_LEN = 3;
 
-// The length of the distro format minor version excluding the \0
-static const size_t SUPPORTED_DISTRO_MINOR_VERSION_LEN = sizeof(SUPPORTED_DISTRO_MINOR_VERSION) - 1;
+// Version bytes are: AAA.BBB|CCCCC - the format major version is AAA
+static const size_t FORMAT_MAJOR_VERSION_IDX = 0;
 
-// The length of the distro format version. e.g. 001.001
-static const size_t SUPPORTED_DISTRO_VERSION_LEN =
-        SUPPORTED_DISTRO_MAJOR_VERSION_LEN + SUPPORTED_DISTRO_MINOR_VERSION_LEN + 1;
+// Version bytes are: AAA.BBB|CCCCC - the format major version is AAA
+static const size_t FORMAT_MINOR_VERSION_LEN = 3;
 
-// The length of the IANA rules version bytes. e.g. 2016a
+// Version bytes are: AAA.BBB|CCCCC - the format minor version is BBB
+static const size_t FORMAT_MINOR_VERSION_IDX = 4;
+
+// Version bytes are: AAA.BBB|CCCCC - the IANA rules version is CCCCC
+// The length of the IANA rules version bytes, e.g. 2016a
 static const size_t RULES_VERSION_LEN = 5;
 
-// Distro version bytes are: AAA.BBB|CCCCC - the rules version is CCCCC
-static const size_t DISTRO_VERSION_RULES_IDX = 8;
+// Version bytes are: AAA.BBB|CCCCC - the rules version is CCCCC
+static const size_t VERSION_RULES_IDX = 8;
 
-// See also com.android.timezone.distro.TimeZoneDistro.
-static const char* TZDATA_FILENAME = "/tzdata";
-
-// tzdata file header (as much as we need for the version):
-// byte[11] tzdata_version  -- e.g. "tzdata2012f"
-static const int TZ_HEADER_LENGTH = 11;
-
-static const char TZ_DATA_HEADER_PREFIX[] = "tzdata";
-static const size_t TZ_DATA_HEADER_PREFIX_LEN = sizeof(TZ_DATA_HEADER_PREFIX) - 1; // exclude \0
 
 static void usage() {
     std::cerr << "Usage: tzdatacheck SYSTEM_TZ_DIR DATA_TZ_DIR\n"
@@ -121,18 +115,6 @@
     return true;
 }
 
-/*
- * Checks the contents of headerBytes. Returns true if it is valid (starts with "tzdata"), false
- * otherwise.
- */
-static bool checkValidTzDataHeader(const std::string& fileName, const char* headerBytes) {
-    if (strncmp("tzdata", headerBytes, 6) != 0) {
-        LOG(WARNING) << fileName << " does not start with the expected bytes (tzdata)";
-        return false;
-    }
-    return true;
-}
-
 static bool checkDigits(const char* buffer, const size_t count, size_t* i) {
     for (size_t j = 0; j < count; j++) {
       char toCheck = buffer[(*i)++];
@@ -143,8 +125,8 @@
     return true;
 }
 
-static bool checkValidDistroVersion(const char* buffer) {
-    // See DISTRO_VERSION_LENGTH comments above for a description of the format.
+static bool checkValidVersionBytes(const char* buffer) {
+    // See READ_DATA_LENGTH comments above for a description of the format.
     size_t i = 0;
     if (!checkDigits(buffer, 3, &i)) {
       return false;
@@ -437,7 +419,7 @@
 }
 
 /*
- * After a platform update it is likely that timezone data found on the system partition will be
+ * After a platform update it is likely that the "base" timezone data found on the device will be
  * newer than the version found in the data partition. This tool detects this case and removes the
  * version in /data.
  *
@@ -455,7 +437,7 @@
         return 1;
     }
 
-    const char* systemZoneInfoDir = argv[1];
+    const char* baseZoneInfoDir = argv[1];
     const char* dataZoneInfoDir = argv[2];
 
     std::string dataStagedDirName(dataZoneInfoDir);
@@ -490,9 +472,9 @@
     std::string distroVersionFileName(dataCurrentDirName);
     distroVersionFileName += DISTRO_VERSION_FILENAME;
     std::vector<char> distroVersion;
-    distroVersion.reserve(DISTRO_VERSION_LENGTH);
+    distroVersion.reserve(READ_DATA_LENGTH);
     bool distroVersionReadOk =
-            readBytes(distroVersionFileName, distroVersion.data(), DISTRO_VERSION_LENGTH);
+            readBytes(distroVersionFileName, distroVersion.data(), READ_DATA_LENGTH);
     if (!distroVersionReadOk) {
         LOG(WARNING) << "distro version file " << distroVersionFileName
                 << " does not exist or is too short. Deleting distro dir.";
@@ -501,7 +483,7 @@
         return 3;
     }
 
-    if (!checkValidDistroVersion(distroVersion.data())) {
+    if (!checkValidVersionBytes(distroVersion.data())) {
         LOG(WARNING) << "distro version file " << distroVersionFileName
                 << " is not valid. Deleting distro dir.";
         // Implies the contents of the data partition is corrupt in some way. Try to clean up.
@@ -509,63 +491,65 @@
         return 4;
     }
 
-    std::string actualDistroVersion =
-            std::string(distroVersion.data(), SUPPORTED_DISTRO_VERSION_LEN);
-    // Check the first 3 bytes of the distro version: these are the major version (e.g. 001).
+    // Check the base tz data set version.
+    std::string baseVersionFileName(baseZoneInfoDir);
+    baseVersionFileName += BASE_VERSION_FILENAME;
+    std::vector<char> baseVersion;
+    baseVersion.reserve(READ_DATA_LENGTH);
+    bool baseVersionReadOk =
+            readBytes(baseVersionFileName, baseVersion.data(), READ_DATA_LENGTH);
+    if (!baseVersionReadOk) {
+        // Implies the contents of the system partition is corrupt in some way. Nothing we can do.
+        LOG(WARNING) << baseVersionFileName << " does not exist or could not be opened";
+        return 6;
+    }
+
+    if (!checkValidVersionBytes(baseVersion.data())) {
+        // Implies the contents of the system partition is corrupt in some way. Nothing we can do.
+        LOG(WARNING) << baseVersionFileName << " is not valid.";
+        return 7;
+    }
+
+    std::string actualDistroVersion = std::string(distroVersion.data(), FORMAT_VERSION_LEN);
+    std::string baseTzVersion = std::string(baseVersion.data(), FORMAT_VERSION_LEN);
+
+    // Check the first 3 bytes of the format version: these are the major version (e.g. 001).
     // It must match the one we support exactly to be ok.
     if (strncmp(
-            &distroVersion[0],
-            SUPPORTED_DISTRO_MAJOR_VERSION,
-            SUPPORTED_DISTRO_MAJOR_VERSION_LEN) != 0) {
+            &distroVersion[FORMAT_MAJOR_VERSION_IDX],
+            &baseTzVersion[FORMAT_MAJOR_VERSION_IDX],
+            FORMAT_MAJOR_VERSION_LEN) != 0) {
 
         LOG(INFO) << "distro version file " << distroVersionFileName
-                << " major version is not the required version " << SUPPORTED_DISTRO_MAJOR_VERSION
+                << " major version is not the required version " << baseTzVersion
                 << ", was \"" << actualDistroVersion << "\". Deleting distro dir.";
-        // This implies there has been an OTA and the installed distro is not compatible with the
+        // This implies there has been an OTA and the installed distro is not compatible with a
         // new version of Android. Remove the installed distro.
         deleteUpdateDistroDir(dataCurrentDirName);
         return 5;
     }
 
-    // Check the last 3 bytes of the distro version: these are the minor version (e.g. 001).
+    // Check the last 3 bytes of the format version: these are the minor version (e.g. 001).
     // If the version in the distro is < the minor version required by this device it cannot be
     // used.
     if (strncmp(
-            &distroVersion[4],
-            SUPPORTED_DISTRO_MINOR_VERSION,
-            SUPPORTED_DISTRO_MINOR_VERSION_LEN) < 0) {
+            &distroVersion[FORMAT_MINOR_VERSION_IDX],
+            &baseTzVersion[FORMAT_MINOR_VERSION_IDX],
+            FORMAT_MINOR_VERSION_LEN) < 0) {
 
         LOG(INFO) << "distro version file " << distroVersionFileName
-                << " minor version is not the required version " << SUPPORTED_DISTRO_MINOR_VERSION
+                << " minor version is not the required version " << baseTzVersion
                 << ", was \"" << actualDistroVersion << "\". Deleting distro dir.";
-        // This implies there has been an OTA and the installed distro is not compatible with the
+        // This implies there has been an OTA and the installed distro is not compatible with a
         // new version of Android. Remove the installed distro.
         deleteUpdateDistroDir(dataCurrentDirName);
         return 5;
     }
 
-    // Read the system rules version out of the /system tzdata file.
-    std::string systemTzDataFileName(systemZoneInfoDir);
-    systemTzDataFileName += TZDATA_FILENAME;
-    std::vector<char> systemTzDataHeader;
-    systemTzDataHeader.reserve(TZ_HEADER_LENGTH);
-    bool systemFileExists =
-            readBytes(systemTzDataFileName, systemTzDataHeader.data(), TZ_HEADER_LENGTH);
-    if (!systemFileExists) {
-        // Implies the contents of the system partition is corrupt in some way. Nothing we can do.
-        LOG(WARNING) << systemTzDataFileName << " does not exist or could not be opened";
-        return 6;
-    }
-    if (!checkValidTzDataHeader(systemTzDataFileName, systemTzDataHeader.data())) {
-        // Implies the contents of the system partition is corrupt in some way. Nothing we can do.
-        LOG(WARNING) << systemTzDataFileName << " does not have a valid header.";
-        return 7;
-    }
-
     // Compare the distro rules version against the system rules version.
     if (strncmp(
-            &systemTzDataHeader[TZ_DATA_HEADER_PREFIX_LEN],
-            &distroVersion[DISTRO_VERSION_RULES_IDX],
+            &baseVersion[VERSION_RULES_IDX],
+            &distroVersion[VERSION_RULES_IDX],
             RULES_VERSION_LEN) <= 0) {
         LOG(INFO) << "Found an installed distro but it is valid. No action taken.";
         // Implies there is an installed update, but it is good.
@@ -575,7 +559,7 @@
     // Implies there has been an OTA and the system version of the timezone rules is now newer
     // than the version installed in /data. Remove the installed distro.
     LOG(INFO) << "timezone distro in " << dataCurrentDirName << " is older than data in "
-            << systemTzDataFileName << "; fixing...";
+            << baseVersionFileName << "; fixing...";
 
     deleteUpdateDistroDir(dataCurrentDirName);
     return 0;