Change tzdatacheck to avoid hardcoding
Motivation: Remove hardcoding from tzdatacheck
and reduce futre risk of /system binary and format
version falling out of step on a device.
Switch from hardcoding format version information in
tzdatacheck.cpp to using the tz_version file instead.
A future change will track the movement of tz_version
from /system to inside /apex/com.android.runtime.
tzdatacheck will likely go away in an upcoming release but
it will be kept working for now.
tz_version also contains rules version information so
tzdatacheck does not need to read the tzdata file's header
any more.
README.android has also been updated to reflect this and other
recent changes.
Bug: 119851164
Test: run cts -m CtsHostTzDataTests
Change-Id: I752450b4f730a03a9dc3a39e30179f00229c9e0c
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;