summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlmaz Mingaleev <mingaleev@google.com>2024-06-04 15:59:41 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2024-06-04 15:59:41 +0000
commit832d041f4f488388532cc25b81f7fb1046075a80 (patch)
tree5b8a3e1f7b03e16f024f57172a9cea9f49716dd4
parent7427fb0b87fdbaa692799d1e372ae93efe4d0a3b (diff)
parentd76863ead29a6df7a6b0f7fcf50ab4d13f1df30b (diff)
downloadicu-832d041f4f488388532cc25b81f7fb1046075a80.tar.gz
Merge "Revert^2 "Read files from versioned tzdata paths."" into main
-rw-r--r--android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/TimeZoneDataFiles.java3
-rw-r--r--android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/TzDataSetVersion.java10
-rw-r--r--android_icu4j/src/main/java/android/icu/platform/AndroidDataFiles.java25
-rw-r--r--android_icu4j/testing/src/android/icu/extratest/platform/AndroidDataFilesTest.java12
-rw-r--r--android_icu4j/testing/src/com/android/i18n/test/timezone/TimeZoneDataFilesTest.java12
-rw-r--r--android_icu4j/testing/src/com/android/i18n/test/timezone/TzDataSetVersionTest.java38
-rw-r--r--libandroidicuinit/IcuRegistration.cpp32
-rw-r--r--libandroidicuinit/IcuRegistration.h5
8 files changed, 117 insertions, 20 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..4bd971a3f 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
@@ -48,7 +48,8 @@ public final class TimeZoneDataFiles {
}
public static String getTimeZoneModuleTzFile(String fileName) {
- return getTimeZoneModuleFile("tz/" + fileName);
+ return getTimeZoneModuleFile("tz/versioned/"
+ + TzDataSetVersion.currentFormatMajorVersion() + "/" + fileName);
}
// Remove from CorePlatformApi when all users in platform code are removed. http://b/123398797
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..907e780ae 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,8 @@ 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. */
+ private 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" */
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..20ef055a6 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,13 @@ import java.util.stream.Stream;
public class AndroidDataFilesTest {
private static final Set<String> TZDATA_RES_FILES =
- Set.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");
+ 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 String ICU_DAT_PATH =
"/apex/com.android.i18n/etc/icu/icudt" + VersionInfo.ICU_VERSION.getMajor() + "l.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..403e90de0 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
@@ -53,13 +53,19 @@ public class TimeZoneDataFilesTest {
String icuDataPath = AndroidDataFiles.generateIcuDataPath();
String[] paths = icuDataPath.split(":");
- assertEquals(2, paths.length);
+ assertEquals(3, paths.length);
- String tzdataModulePath = paths[0];
+ 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[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..ba0098797 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,22 @@
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 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 +110,32 @@ 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() throws Throwable {
+ int versionLengthField =
+ (int) MethodHandles.privateLookupIn(TzDataSetVersion.class, MethodHandles.lookup())
+ .findStaticGetter(
+ TzDataSetVersion.class,
+ "FORMAT_VERSION_STRING_LENGTH",
+ int.class)
+ .invoke();
+
+ // Using method handles to not increase API surface.
+ MethodHandle TO_FORMAT_VERSION_MH =
+ MethodHandles.privateLookupIn(TzDataSetVersion.class, MethodHandles.lookup())
+ .findStatic(
+ TzDataSetVersion.class,
+ "toFormatVersionString",
+ methodType(String.class, int.class, int.class));
+ String formatVersion = (String) TO_FORMAT_VERSION_MH.invoke(CURRENT_FORMAT_MAJOR_VERSION,
+ CURRENT_FORMAT_MINOR_VERSION);
+ assertEquals(versionLengthField, 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();