1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package libcore.timezone; 18 19 import java.util.ArrayList; 20 import java.util.List; 21 22 /** 23 * Utility methods associated with finding updateable time zone data files. 24 * 25 * @hide 26 */ 27 @libcore.api.CorePlatformApi 28 public final class TimeZoneDataFiles { 29 private static final String ANDROID_ROOT_ENV = "ANDROID_ROOT"; 30 private static final String ANDROID_RUNTIME_ROOT_ENV = "ANDROID_RUNTIME_ROOT"; 31 private static final String ANDROID_TZDATA_ROOT_ENV = "ANDROID_TZDATA_ROOT"; 32 private static final String ANDROID_DATA_ENV = "ANDROID_DATA"; 33 TimeZoneDataFiles()34 private TimeZoneDataFiles() {} 35 36 /** 37 * Returns time zone file paths for the specified file name in an array in the order they 38 * should be tried. See {@link #generateIcuDataPath()} for ICU files instead. 39 * <ul> 40 * <li>[0] - the location of the file in the /data partition (may not exist).</li> 41 * <li>[1] - the location of the file from the time zone module under /apex (may not exist). 42 * </li> 43 * <li>[2] - the location of the file from the runtime module under /apex (should exist).</li> 44 * </ul> 45 * <li>[3] - the location of the file in the /system partition (should exist).</li> 46 */ 47 // VisibleForTesting getTimeZoneFilePaths(String fileName)48 public static String[] getTimeZoneFilePaths(String fileName) { 49 return new String[] { 50 getDataTimeZoneFile(fileName), 51 getTimeZoneModuleFile("tz/" + fileName), 52 getRuntimeModuleFile("tz/" + fileName), 53 getSystemTimeZoneFile(fileName) 54 }; 55 } 56 57 // Remove from CorePlatformApi when all users in platform code are removed. http://b/123398797 58 @libcore.api.CorePlatformApi getDataTimeZoneRootDir()59 public static String getDataTimeZoneRootDir() { 60 return System.getenv(ANDROID_DATA_ENV) + "/misc/zoneinfo/"; 61 } 62 63 @libcore.api.CorePlatformApi getDataTimeZoneFile(String fileName)64 public static String getDataTimeZoneFile(String fileName) { 65 return getDataTimeZoneRootDir() + "current/" + fileName; 66 } 67 getTimeZoneModuleFile(String fileName)68 public static String getTimeZoneModuleFile(String fileName) { 69 return System.getenv(ANDROID_TZDATA_ROOT_ENV) + "/etc/" + fileName; 70 } 71 72 // Remove from CorePlatformApi when all users in platform code are removed. http://b/123398797 73 @libcore.api.CorePlatformApi getRuntimeModuleTzVersionFile()74 public static String getRuntimeModuleTzVersionFile() { 75 return getRuntimeModuleFile("tz/" + TzDataSetVersion.DEFAULT_FILE_NAME); 76 } 77 getRuntimeModuleFile(String fileName)78 public static String getRuntimeModuleFile(String fileName) { 79 return System.getenv(ANDROID_RUNTIME_ROOT_ENV) + "/etc/" + fileName; 80 } 81 getSystemTimeZoneFile(String fileName)82 public static String getSystemTimeZoneFile(String fileName) { 83 return getEnvironmentPath(ANDROID_ROOT_ENV, "/usr/share/zoneinfo/" + fileName); 84 } 85 getSystemIcuFile(String fileName)86 public static String getSystemIcuFile(String fileName) { 87 return getEnvironmentPath(ANDROID_ROOT_ENV, "/usr/icu/" + fileName); 88 } 89 generateIcuDataPath()90 public static String generateIcuDataPath() { 91 List<String> paths = new ArrayList<>(3); 92 93 // ICU should first look in ANDROID_DATA. This is used for (optional) time zone data 94 // delivered by APK (https://source.android.com/devices/tech/config/timezone-rules) 95 String dataIcuDataPath = 96 getEnvironmentPath(ANDROID_DATA_ENV, "/misc/zoneinfo/current/icu/"); 97 if (dataIcuDataPath != null) { 98 paths.add(dataIcuDataPath); 99 } 100 101 // ICU should then look for a mounted time zone module file in /apex. This is used for 102 // (optional) time zone data that can be updated with an APEX file. 103 String timeZoneModuleIcuDataPath = getTimeZoneModuleFile("icu/"); 104 if (timeZoneModuleIcuDataPath != null) { 105 paths.add(timeZoneModuleIcuDataPath); 106 } 107 108 // ICU should always look in the runtime module path as this is where most of the data 109 // can be found. 110 String runtimeModuleIcuDataPath = getRuntimeModuleFile("icu/"); 111 if (runtimeModuleIcuDataPath != null) { 112 paths.add(runtimeModuleIcuDataPath); 113 } 114 return String.join(":", paths); 115 } 116 117 /** 118 * Creates a path by combining the value of an environment variable with a relative path. 119 * Returns {@code null} if the environment variable is not set. 120 */ getEnvironmentPath(String environmentVariable, String path)121 private static String getEnvironmentPath(String environmentVariable, String path) { 122 String variable = System.getenv(environmentVariable); 123 if (variable == null) { 124 return null; 125 } 126 return variable + path; 127 } 128 } 129