diff options
author | Almaz Mingaleev <mingaleev@google.com> | 2024-06-05 09:13:02 +0000 |
---|---|---|
committer | Almaz Mingaleev <mingaleev@google.com> | 2024-06-05 16:20:08 +0100 |
commit | b3fab5322586985e718fd4d597616f3b28ab6959 (patch) | |
tree | f4205c5520570c2d9c8a41e58cc4c890efcc1a23 | |
parent | a98bbf49a102b0a9fa5ba4f647e236684e586785 (diff) | |
download | icu-b3fab5322586985e718fd4d597616f3b28ab6959.tar.gz |
Revert^4 "Read files from versioned tzdata paths."
Reverts aosp/3112092.
NO_IFTTT=Introducing linter checks.
Test: verified on -next target on goog/main
Test: see system/timezone
Change-Id: I49787b41a9e771ff3fe331ba340eddcb64c5f279
8 files changed, 133 insertions, 23 deletions
diff --git a/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/TimeZoneDataFiles.java b/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/TimeZoneDataFiles.java index 6f3b16eac..2ffdef015 100644 --- a/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/TimeZoneDataFiles.java +++ b/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/TimeZoneDataFiles.java @@ -39,14 +39,27 @@ public final class TimeZoneDataFiles { * Returns time zone file paths for the specified file name in an array in the order they * should be tried. See {@link AndroidDataFiles#generateIcuDataPath()} for ICU files instead. * <ul> - * <li>[0] - the location of the file from the time zone module under /apex (must exist).</li> + * <li>[0] - the location of the versioned file from the time zone module under /apex + * (must exist).</li> + * <li>[1] - old, unversioned location of the file from the time zone module under /apex. Will + * be removed once prebuilts are updated.</> * </ul> */ // VisibleForTesting public static String[] getTimeZoneFilePaths(String fileName) { - return new String[] { getTimeZoneModuleTzFile(fileName) }; + return new String[] { + // TODO(b/319103072) There should be only versioned path. + getTimeZoneModuleTzFile(fileName), + getVersionedTimeZoneModuleTzFile(fileName) }; } + // TODO(b/319103072) This should be removed once prebuilts are updated. + public static String getVersionedTimeZoneModuleTzFile(String fileName) { + return getTimeZoneModuleFile("tz/versioned/" + + TzDataSetVersion.currentFormatMajorVersion() + "/" + fileName); + } + + // TODO(b/319103072) This method should read from versioned directory. public static String getTimeZoneModuleTzFile(String fileName) { return getTimeZoneModuleFile("tz/" + fileName); } diff --git a/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/TzDataSetVersion.java b/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/TzDataSetVersion.java index c91745cbd..e3dd27581 100644 --- a/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/TzDataSetVersion.java +++ b/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/TzDataSetVersion.java @@ -61,7 +61,9 @@ public final class TzDataSetVersion { * version to 1 when doing so. */ // @VisibleForTesting : Keep this inline-able: it is used from CTS tests. + // LINT.IfChange public static final int CURRENT_FORMAT_MAJOR_VERSION = 8; // Android V + // LINT.ThenChange(external/icu/android_icu4j/src/main/java/android/icu/platform/AndroidDataFiles.java) /** * Returns the major tz data format version supported by this device. @@ -86,12 +88,9 @@ public final class TzDataSetVersion { return CURRENT_FORMAT_MINOR_VERSION; } - /** The full major + minor tz data format version for this device. */ - private static final String FULL_CURRENT_FORMAT_VERSION_STRING = - toFormatVersionString(CURRENT_FORMAT_MAJOR_VERSION, CURRENT_FORMAT_MINOR_VERSION); - - private static final int FORMAT_VERSION_STRING_LENGTH = - FULL_CURRENT_FORMAT_VERSION_STRING.length(); + /** The full major + minor tz data format version's length for this device. */ + // @VisibleForTesting + public static final int FORMAT_VERSION_STRING_LENGTH = 7; private static final Pattern FORMAT_VERSION_PATTERN = Pattern.compile("(\\d{3})\\.(\\d{3})"); /** A pattern that matches the IANA rules value of a rules update. e.g. "2016g" */ @@ -287,7 +286,8 @@ public final class TzDataSetVersion { return value; } - private static String toFormatVersionString(int majorFormatVersion, int minorFormatVersion) { + // @VisibleForTesting + public static String toFormatVersionString(int majorFormatVersion, int minorFormatVersion) { return to3DigitVersionString(majorFormatVersion) + "." + to3DigitVersionString(minorFormatVersion); } diff --git a/android_icu4j/src/main/java/android/icu/platform/AndroidDataFiles.java b/android_icu4j/src/main/java/android/icu/platform/AndroidDataFiles.java index 74ab82fc3..121197863 100644 --- a/android_icu4j/src/main/java/android/icu/platform/AndroidDataFiles.java +++ b/android_icu4j/src/main/java/android/icu/platform/AndroidDataFiles.java @@ -38,8 +38,19 @@ public class AndroidDataFiles { public static final String ANDROID_I18N_ROOT_ENV = "ANDROID_I18N_ROOT"; public static final String ANDROID_TZDATA_ROOT_ENV = "ANDROID_TZDATA_ROOT"; + /** + * This is identical to + * {@link com.android.i18n.timezone.TzDataSetVersion#CURRENT_FORMAT_MAJOR_VERSION}, but because + * dependency is in the opposite direction we can't refer to that field from this class. + * TzDataSetVersionTest ensures that their values are the same. + */ + // VisibleForTesting + // LINT.IfChange + public static final int CURRENT_MAJOR_VERSION = 8; + // LINT.ThenChange(external/icu/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/TzDataSetVersion.java) + // VisibleForTesting - public static String getTimeZoneModuleIcuFile(String fileName) { + public static String getTimeZoneModuleIcuFileAtOldLocation(String fileName) { return getTimeZoneModuleFile("icu/" + fileName); } @@ -47,6 +58,10 @@ public class AndroidDataFiles { return System.getenv(ANDROID_TZDATA_ROOT_ENV) + "/etc/" + fileName; } + private static String getTimeZoneModuleIcuFile(String fileName) { + return getTimeZoneModuleFile("tz/versioned/" + CURRENT_MAJOR_VERSION + "/icu/" + fileName); + } + // VisibleForTesting public static String getI18nModuleIcuFile(String fileName) { return getI18nModuleFile("icu/" + fileName); @@ -64,7 +79,13 @@ public class AndroidDataFiles { // ICU should look for a mounted time zone module file in /apex. This is used for // (optional) time zone data that can be updated with an APEX file. - String timeZoneModuleIcuDataPath = getTimeZoneModuleIcuFile(""); + paths.add(getTimeZoneModuleIcuFile("")); + + // TODO (b/319103072): remove this path once prebuilts are updated. + // Starting from V content of the tzdata module is versioned so it can be used across + // multiple Android releases. timeZoneModuleIcuDataPath will be removed once all prebuilts + // are updated. Production tzdata6 won't have ICU files under etc/icu. + String timeZoneModuleIcuDataPath = getTimeZoneModuleIcuFileAtOldLocation(""); paths.add(timeZoneModuleIcuDataPath); // ICU should always look in the i18n module path as this is where most of the data diff --git a/android_icu4j/testing/src/android/icu/extratest/platform/AndroidDataFilesTest.java b/android_icu4j/testing/src/android/icu/extratest/platform/AndroidDataFilesTest.java index 190fb3d1b..f91fbcac1 100644 --- a/android_icu4j/testing/src/android/icu/extratest/platform/AndroidDataFilesTest.java +++ b/android_icu4j/testing/src/android/icu/extratest/platform/AndroidDataFilesTest.java @@ -48,11 +48,21 @@ import java.util.stream.Stream; public class AndroidDataFilesTest { private static final Set<String> TZDATA_RES_FILES = - Set.of( + Stream.of( + "/apex/com.android.tzdata/etc/tz/versioned/%d/icu/metaZones.res", + "/apex/com.android.tzdata/etc/tz/versioned/%d/icu/windowsZones.res", + "/apex/com.android.tzdata/etc/tz/versioned/%d/icu/zoneinfo64.res", + "/apex/com.android.tzdata/etc/tz/versioned/%d/icu/timezoneTypes.res") + .map(path -> path.formatted(AndroidDataFiles.CURRENT_MAJOR_VERSION)) + .collect(toSet()); + + private static final Set<String> TZDATA_RES_FILES_AT_OLD_LOCATION = + Stream.of( "/apex/com.android.tzdata/etc/icu/metaZones.res", "/apex/com.android.tzdata/etc/icu/windowsZones.res", "/apex/com.android.tzdata/etc/icu/zoneinfo64.res", - "/apex/com.android.tzdata/etc/icu/timezoneTypes.res"); + "/apex/com.android.tzdata/etc/icu/timezoneTypes.res") + .collect(toSet()); private static final String ICU_DAT_PATH = "/apex/com.android.i18n/etc/icu/icudt" + VersionInfo.ICU_VERSION.getMajor() + "l.dat"; @@ -80,12 +90,16 @@ public class AndroidDataFilesTest { .map(f -> f.getPath()) .collect(toSet()); - for (String resFile : TZDATA_RES_FILES) { - assertContains(icuFiles, resFile); - } + assertTrue(containsAllResFiles(icuFiles)); + assertContains(icuFiles, ICU_DAT_PATH); } + private static boolean containsAllResFiles(Set<String> existingFiles) { + return existingFiles.containsAll(TZDATA_RES_FILES) + || existingFiles.containsAll(TZDATA_RES_FILES_AT_OLD_LOCATION); + } + private static boolean isIcuFile(File file) { return file.getName().endsWith(".res") || file.getName().endsWith(".dat"); } diff --git a/android_icu4j/testing/src/com/android/i18n/test/timezone/TimeZoneDataFilesTest.java b/android_icu4j/testing/src/com/android/i18n/test/timezone/TimeZoneDataFilesTest.java index 064c7bbe0..3b5aff459 100644 --- a/android_icu4j/testing/src/com/android/i18n/test/timezone/TimeZoneDataFilesTest.java +++ b/android_icu4j/testing/src/com/android/i18n/test/timezone/TimeZoneDataFilesTest.java @@ -41,7 +41,7 @@ public class TimeZoneDataFilesTest { @Test public void getTimeZoneFilePaths() { String[] paths = TimeZoneDataFiles.getTimeZoneFilePaths("foo"); - assertEquals(1, paths.length); + assertEquals(2, paths.length); assertTrue(paths[0].startsWith(System.getenv(ANDROID_TZDATA_ROOT_ENV))); assertTrue(paths[0].endsWith("/foo")); @@ -53,13 +53,19 @@ public class TimeZoneDataFilesTest { String icuDataPath = AndroidDataFiles.generateIcuDataPath(); String[] paths = icuDataPath.split(":"); - assertEquals(2, paths.length); + assertEquals(3, paths.length); + + String versionedTzdataModulePath = paths[0]; + assertTrue(versionedTzdataModulePath + " invalid", + versionedTzdataModulePath.startsWith(System.getenv(ANDROID_TZDATA_ROOT_ENV))); + assertTrue(versionedTzdataModulePath + " should be versioned", + versionedTzdataModulePath.contains("versioned")); - String tzdataModulePath = paths[0]; + String tzdataModulePath = paths[1]; assertTrue(tzdataModulePath + " invalid", tzdataModulePath.startsWith(System.getenv(ANDROID_TZDATA_ROOT_ENV))); - String runtimeModulePath = paths[1]; + String runtimeModulePath = paths[2]; assertTrue(runtimeModulePath + " invalid", runtimeModulePath.startsWith(System.getenv(ANDROID_I18N_ROOT_ENV))); assertTrue(runtimeModulePath + " invalid", runtimeModulePath.contains("/etc/icu")); diff --git a/android_icu4j/testing/src/com/android/i18n/test/timezone/TzDataSetVersionTest.java b/android_icu4j/testing/src/com/android/i18n/test/timezone/TzDataSetVersionTest.java index fdf7294bf..937ad5c12 100644 --- a/android_icu4j/testing/src/com/android/i18n/test/timezone/TzDataSetVersionTest.java +++ b/android_icu4j/testing/src/com/android/i18n/test/timezone/TzDataSetVersionTest.java @@ -16,12 +16,24 @@ package com.android.i18n.test.timezone; +import static com.android.i18n.timezone.TzDataSetVersion.CURRENT_FORMAT_MAJOR_VERSION; +import static com.android.i18n.timezone.TzDataSetVersion.CURRENT_FORMAT_MINOR_VERSION; +import static com.android.i18n.timezone.TzDataSetVersion.FORMAT_VERSION_STRING_LENGTH; +import static com.android.i18n.timezone.TzDataSetVersion.toFormatVersionString; + +import static java.lang.invoke.MethodType.methodType; + +import android.icu.platform.AndroidDataFiles; import android.icu.testsharding.MainTestShard; -import junit.framework.TestCase; import com.android.i18n.timezone.TzDataSetVersion; import com.android.i18n.timezone.TzDataSetVersion.TzDataSetException; +import junit.framework.TestCase; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; + @MainTestShard public class TzDataSetVersionTest extends TestCase { @@ -100,6 +112,17 @@ public class TzDataSetVersionTest extends TestCase { assertFalse(TzDataSetVersion.isCompatibleWithThisDevice(olderMinor)); } + public void testConsistency() { + String msg = "Major versions in TzDataSetVersion and AndroidDataFiles differ"; + assertEquals(msg, CURRENT_FORMAT_MAJOR_VERSION, AndroidDataFiles.CURRENT_MAJOR_VERSION); + } + + public void testFormatLength() { + String formatVersion = toFormatVersionString(CURRENT_FORMAT_MAJOR_VERSION, + CURRENT_FORMAT_MINOR_VERSION); + assertEquals(FORMAT_VERSION_STRING_LENGTH, formatVersion.length()); + } + private TzDataSetVersion createTzDataSetVersion(int majorFormatVersion, int minorFormatVersion) throws TzDataSetException { return new TzDataSetVersion(majorFormatVersion, minorFormatVersion, VALID_RULES_VERSION, 3); diff --git a/libandroidicuinit/IcuRegistration.cpp b/libandroidicuinit/IcuRegistration.cpp index 63397fd20..752527418 100644 --- a/libandroidicuinit/IcuRegistration.cpp +++ b/libandroidicuinit/IcuRegistration.cpp @@ -216,8 +216,9 @@ IcuRegistration::IcuRegistration() { // If it does, map it so we use its data in preference to later ones. // However, I18N apex is not expected to have the time zone data resources. // http://b/171542040 - std::string tzModulePath = getTimeZoneModulePath(); + std::string tzModulePath = getPreVTimeZoneModulePath(); std::string tzIcuDataPath = tzModulePath + "icu_tzdata.dat"; + std::string versionedTzIcuDataPath = getTimeZoneModulePath(); if (pathExists(tzIcuDataPath)) { AICU_LOGD("Time zone APEX ICU file found: %s", tzIcuDataPath.c_str()); icu_datamap_from_tz_module_ = impl::IcuDataMap::Create(tzIcuDataPath); @@ -225,6 +226,15 @@ IcuRegistration::IcuRegistration() { AICU_LOGW("TZ module .dat file %s exists but could not be loaded. Skipping.", tzIcuDataPath.c_str()); } + } else if (pathExists(versionedTzIcuDataPath)) { + UErrorCode status = U_ZERO_ERROR; + u_setTimeZoneFilesDirectory(versionedTzIcuDataPath.c_str(), &status); + if (U_SUCCESS(status)) { + AICU_LOGD("u_setTimeZoneFilesDirectory(\"%s\") succeeded. ", versionedTzIcuDataPath.c_str()); + } else { + AICU_LOGE("u_setTimeZoneFilesDirectory(\"%s\") failed: %s", + versionedTzIcuDataPath.c_str(), u_errorName(status)); + } } else { UErrorCode status = U_ZERO_ERROR; u_setTimeZoneFilesDirectory(tzModulePath.c_str(), &status); @@ -261,7 +271,7 @@ bool IcuRegistration::pathExists(const std::string& path) { // Returns a string containing the expected path of the /apex tz // module ICU data directory -std::string IcuRegistration::getTimeZoneModulePath() { +std::string IcuRegistration::getPreVTimeZoneModulePath() { const char* tzdataModulePathPrefix = getenv("ANDROID_TZDATA_ROOT"); if (tzdataModulePathPrefix == NULL) { AICU_LOGE("ANDROID_TZDATA_ROOT environment variable not set"); @@ -274,6 +284,24 @@ std::string IcuRegistration::getTimeZoneModulePath() { return tzdataModulePath; } +// Identical to TzDataSetVersion#CURRENT_MAJOR_FORMAT_VERSION. +// LINT.IfChange +static const std::string CURRENT_MAJOR_FORMAT_VERSION = "8"; +// LINT.ThenChange(external/icu/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/TzDataSetVersion.java) + +std::string IcuRegistration::getTimeZoneModulePath() { + const char* tzdataModulePathPrefix = getenv("ANDROID_TZDATA_ROOT"); + if (tzdataModulePathPrefix == NULL) { + AICU_LOGE("ANDROID_TZDATA_ROOT environment variable not set"); + abort(); + } + + std::string tzdataModulePath; + tzdataModulePath = tzdataModulePathPrefix; + tzdataModulePath += "/etc/tz/versioned/" + CURRENT_MAJOR_FORMAT_VERSION + "/icu"; + return tzdataModulePath; +} + std::string IcuRegistration::getI18nModulePath() { const char* i18nModulePathPrefix = getenv("ANDROID_I18N_ROOT"); if (i18nModulePathPrefix == NULL) { diff --git a/libandroidicuinit/IcuRegistration.h b/libandroidicuinit/IcuRegistration.h index e968dbdd6..b9065daed 100644 --- a/libandroidicuinit/IcuRegistration.h +++ b/libandroidicuinit/IcuRegistration.h @@ -127,6 +127,11 @@ class IcuRegistration final { IcuRegistration(); static bool pathExists(const std::string& path); + // TODO (b/319103072): remove this method once prebuilts are updated. + // Production tzdata6 will have versioned files only. Keeping this method while there are + // prebuilts which have ICU file(s) under /etc/icu and not /etc/tz/versioned/*/icu directory in + // the tzdata APEX. + static std::string getPreVTimeZoneModulePath(); static std::string getTimeZoneModulePath(); static std::string getI18nModulePath(); |