summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--luni/src/main/java/libcore/util/ZoneInfoDB.java54
-rw-r--r--luni/src/test/java/libcore/util/ZoneInfoDBTest.java32
2 files changed, 62 insertions, 24 deletions
diff --git a/luni/src/main/java/libcore/util/ZoneInfoDB.java b/luni/src/main/java/libcore/util/ZoneInfoDB.java
index c53db120a8..e6559b5b4d 100644
--- a/luni/src/main/java/libcore/util/ZoneInfoDB.java
+++ b/luni/src/main/java/libcore/util/ZoneInfoDB.java
@@ -37,8 +37,8 @@ import libcore.io.MemoryMappedFile;
* @hide - used to implement TimeZone
*/
public final class ZoneInfoDB {
- private static final TzData DATA =
- new TzData(System.getenv("ANDROID_DATA") + "/misc/zoneinfo/current/tzdata",
+ private static final TzData DATA = TzData.loadTzDataWithFallback(
+ System.getenv("ANDROID_DATA") + "/misc/zoneinfo/current/tzdata",
System.getenv("ANDROID_ROOT") + "/usr/share/zoneinfo/tzdata");
public static class TzData {
@@ -83,10 +83,16 @@ public final class ZoneInfoDB {
}
};
- public TzData(String... paths) {
+ /**
+ * Loads the data at the specified paths in order, returning the first valid one as a
+ * {@link TzData} object. If there is no valid one found a basic fallback instance is created
+ * containing just GMT.
+ */
+ public static TzData loadTzDataWithFallback(String... paths) {
for (String path : paths) {
- if (loadData(path)) {
- return;
+ TzData tzData = new TzData();
+ if (tzData.loadData(path)) {
+ return tzData;
}
}
@@ -94,10 +100,28 @@ public final class ZoneInfoDB {
// This is actually implemented in TimeZone itself, so if this is the only time zone
// we report, we won't be asked any more questions.
System.logE("Couldn't find any tzdata!");
- version = "missing";
- zoneTab = "# Emergency fallback data.\n";
- ids = new String[] { "GMT" };
- byteOffsets = rawUtcOffsetsCache = new int[1];
+ return TzData.createFallback();
+ }
+
+ /**
+ * Loads the data at the specified path and returns the {@link TzData} object if it is valid,
+ * otherwise {@code null}.
+ */
+ public static TzData loadTzData(String path) {
+ TzData tzData = new TzData();
+ if (tzData.loadData(path)) {
+ return tzData;
+ }
+ return null;
+ }
+
+ private static TzData createFallback() {
+ TzData tzData = new TzData();
+ tzData.populateFallback();
+ return tzData;
+ }
+
+ private TzData() {
}
/**
@@ -115,6 +139,13 @@ public final class ZoneInfoDB {
return it;
}
+ private void populateFallback() {
+ version = "missing";
+ zoneTab = "# Emergency fallback data.\n";
+ ids = new String[] { "GMT" };
+ byteOffsets = rawUtcOffsetsCache = new int[1];
+ }
+
private boolean loadData(String path) {
try {
mappedFile = MemoryMappedFile.mmapRO(path);
@@ -125,6 +156,11 @@ public final class ZoneInfoDB {
readHeader();
return true;
} catch (Exception ex) {
+ try {
+ mappedFile.close();
+ } catch (ErrnoException ignored) {
+ }
+
// Something's wrong with the file.
// Log the problem and return false so we try the next choice.
System.logE("tzdata file \"" + path + "\" was present but invalid!", ex);
diff --git a/luni/src/test/java/libcore/util/ZoneInfoDBTest.java b/luni/src/test/java/libcore/util/ZoneInfoDBTest.java
index 12ad0d72af..7fa46d52c3 100644
--- a/luni/src/test/java/libcore/util/ZoneInfoDBTest.java
+++ b/luni/src/test/java/libcore/util/ZoneInfoDBTest.java
@@ -29,36 +29,38 @@ public class ZoneInfoDBTest extends junit.framework.TestCase {
System.getenv("ANDROID_ROOT") + "/usr/share/zoneinfo/tzdata";
// An empty override file should fall back to the default file.
- public void testEmptyOverrideFile() throws Exception {
- ZoneInfoDB.TzData data = new ZoneInfoDB.TzData(TZDATA_IN_ROOT);
+ public void testLoadTzDataWithFallback_emptyOverrideFile() throws Exception {
+ ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzData(TZDATA_IN_ROOT);
String emptyFilePath = makeEmptyFile().getPath();
+
ZoneInfoDB.TzData dataWithEmptyOverride =
- new ZoneInfoDB.TzData(emptyFilePath, TZDATA_IN_ROOT);
+ ZoneInfoDB.TzData.loadTzDataWithFallback(emptyFilePath, TZDATA_IN_ROOT);
assertEquals(data.getVersion(), dataWithEmptyOverride.getVersion());
assertEquals(data.getAvailableIDs().length, dataWithEmptyOverride.getAvailableIDs().length);
}
// A corrupt override file should fall back to the default file.
- public void testCorruptOverrideFile() throws Exception {
- ZoneInfoDB.TzData data = new ZoneInfoDB.TzData(TZDATA_IN_ROOT);
+ public void testLoadTzDataWithFallback_corruptOverrideFile() throws Exception {
+ ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzData(TZDATA_IN_ROOT);
String corruptFilePath = makeCorruptFile().getPath();
+
ZoneInfoDB.TzData dataWithCorruptOverride =
- new ZoneInfoDB.TzData(corruptFilePath, TZDATA_IN_ROOT);
+ ZoneInfoDB.TzData.loadTzDataWithFallback(corruptFilePath, TZDATA_IN_ROOT);
assertEquals(data.getVersion(), dataWithCorruptOverride.getVersion());
assertEquals(data.getAvailableIDs().length, dataWithCorruptOverride.getAvailableIDs().length);
}
// Given no tzdata files we can use, we should fall back to built-in "GMT".
- public void testNoGoodFile() throws Exception {
+ public void testLoadTzDataWithFallback_noGoodFile() throws Exception {
String emptyFilePath = makeEmptyFile().getPath();
- ZoneInfoDB.TzData data = new ZoneInfoDB.TzData(emptyFilePath);
+ ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzDataWithFallback(emptyFilePath);
assertEquals("missing", data.getVersion());
assertEquals(1, data.getAvailableIDs().length);
assertEquals("GMT", data.getAvailableIDs()[0]);
}
// Given a valid override file, we should find ourselves using that.
- public void testGoodOverrideFile() throws Exception {
+ public void testLoadTzDataWithFallback_goodOverrideFile() throws Exception {
RandomAccessFile in = new RandomAccessFile(TZDATA_IN_ROOT, "r");
byte[] content = new byte[(int) in.length()];
in.readFully(content);
@@ -70,11 +72,11 @@ public class ZoneInfoDBTest extends junit.framework.TestCase {
content[10] = 'z';
in.close();
- ZoneInfoDB.TzData data = new ZoneInfoDB.TzData(TZDATA_IN_ROOT);
+ ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzData(TZDATA_IN_ROOT);
File goodFile = makeTemporaryFile(content);
try {
ZoneInfoDB.TzData dataWithOverride =
- new ZoneInfoDB.TzData(goodFile.getPath(), TZDATA_IN_ROOT);
+ ZoneInfoDB.TzData.loadTzDataWithFallback(goodFile.getPath(), TZDATA_IN_ROOT);
assertEquals("9999z", dataWithOverride.getVersion());
assertEquals(data.getAvailableIDs().length, dataWithOverride.getAvailableIDs().length);
} finally {
@@ -84,7 +86,7 @@ public class ZoneInfoDBTest extends junit.framework.TestCase {
// Confirms any caching that exists correctly handles TimeZone mutability.
public void testMakeTimeZone_timeZoneMutability() throws Exception {
- ZoneInfoDB.TzData data = new ZoneInfoDB.TzData(TZDATA_IN_ROOT);
+ ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzData(TZDATA_IN_ROOT);
String tzId = "Europe/London";
ZoneInfo first = data.makeTimeZone(tzId);
ZoneInfo second = data.makeTimeZone(tzId);
@@ -101,19 +103,19 @@ public class ZoneInfoDBTest extends junit.framework.TestCase {
}
public void testMakeTimeZone_notFound() throws Exception {
- ZoneInfoDB.TzData data = new ZoneInfoDB.TzData(TZDATA_IN_ROOT);
+ ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzData(TZDATA_IN_ROOT);
assertNull(data.makeTimeZone("THIS_TZ_DOES_NOT_EXIST"));
assertFalse(data.hasTimeZone("THIS_TZ_DOES_NOT_EXIST"));
}
public void testMakeTimeZone_found() throws Exception {
- ZoneInfoDB.TzData data = new ZoneInfoDB.TzData(TZDATA_IN_ROOT);
+ ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzData(TZDATA_IN_ROOT);
assertNotNull(data.makeTimeZone("Europe/London"));
assertTrue(data.hasTimeZone("Europe/London"));
}
public void testGetRulesVersion() throws Exception {
- ZoneInfoDB.TzData data = new ZoneInfoDB.TzData(TZDATA_IN_ROOT);
+ ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzData(TZDATA_IN_ROOT);
String rulesVersion = ZoneInfoDB.TzData.getRulesVersion(new File(TZDATA_IN_ROOT));
assertEquals(data.getVersion(), rulesVersion);