xref: /aosp_15_r20/external/icu/libandroidicuinit/IcuRegistration.cpp (revision 0e209d3975ff4a8c132096b14b0e9364a753506e)
1*0e209d39SAndroid Build Coastguard Worker /*
2*0e209d39SAndroid Build Coastguard Worker  * Copyright (C) 2019 The Android Open Source Project
3*0e209d39SAndroid Build Coastguard Worker  *
4*0e209d39SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*0e209d39SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*0e209d39SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*0e209d39SAndroid Build Coastguard Worker  *
8*0e209d39SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*0e209d39SAndroid Build Coastguard Worker  *
10*0e209d39SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*0e209d39SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*0e209d39SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*0e209d39SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*0e209d39SAndroid Build Coastguard Worker  * limitations under the License.
15*0e209d39SAndroid Build Coastguard Worker  */
16*0e209d39SAndroid Build Coastguard Worker 
17*0e209d39SAndroid Build Coastguard Worker #include "IcuRegistration.h"
18*0e209d39SAndroid Build Coastguard Worker 
19*0e209d39SAndroid Build Coastguard Worker #include <sys/mman.h>
20*0e209d39SAndroid Build Coastguard Worker #include <sys/stat.h>
21*0e209d39SAndroid Build Coastguard Worker #include <sys/types.h>
22*0e209d39SAndroid Build Coastguard Worker #include <errno.h>
23*0e209d39SAndroid Build Coastguard Worker #include <fcntl.h>
24*0e209d39SAndroid Build Coastguard Worker #include <string.h>
25*0e209d39SAndroid Build Coastguard Worker #include <unistd.h>
26*0e209d39SAndroid Build Coastguard Worker 
27*0e209d39SAndroid Build Coastguard Worker #include <unicode/putil.h>
28*0e209d39SAndroid Build Coastguard Worker #include <unicode/udata.h>
29*0e209d39SAndroid Build Coastguard Worker #include <unicode/utypes.h>
30*0e209d39SAndroid Build Coastguard Worker 
31*0e209d39SAndroid Build Coastguard Worker #if !defined(__ANDROID__) || defined(NO_ANDROID_LIBLOG)
PriorityToLevel(char priority)32*0e209d39SAndroid Build Coastguard Worker static int PriorityToLevel(char priority) {
33*0e209d39SAndroid Build Coastguard Worker   // Priority is just the array index of priority in kPriorities.
34*0e209d39SAndroid Build Coastguard Worker   static const char* kPriorities = "VDIWEF";
35*0e209d39SAndroid Build Coastguard Worker   static const int kLogSuppress = sizeof(kPriorities);
36*0e209d39SAndroid Build Coastguard Worker   const char* matching_priority = strchr(kPriorities, toupper(priority));
37*0e209d39SAndroid Build Coastguard Worker   return (matching_priority != nullptr) ? matching_priority - kPriorities : kLogSuppress;
38*0e209d39SAndroid Build Coastguard Worker }
39*0e209d39SAndroid Build Coastguard Worker 
GetHostLogLevel()40*0e209d39SAndroid Build Coastguard Worker static int GetHostLogLevel() {
41*0e209d39SAndroid Build Coastguard Worker   const char* log_tags = getenv("ANDROID_LOG_TAGS");
42*0e209d39SAndroid Build Coastguard Worker   if (log_tags == nullptr) {
43*0e209d39SAndroid Build Coastguard Worker     return 0;
44*0e209d39SAndroid Build Coastguard Worker   }
45*0e209d39SAndroid Build Coastguard Worker   // Find the wildcard prefix if present in ANDROID_LOG_TAGS.
46*0e209d39SAndroid Build Coastguard Worker   static constexpr const char kLogWildcardPrefix[] = "*:";
47*0e209d39SAndroid Build Coastguard Worker   static constexpr size_t kLogWildcardPrefixLength = sizeof(kLogWildcardPrefix) - 1;
48*0e209d39SAndroid Build Coastguard Worker   const char* wildcard_start = strstr(log_tags, kLogWildcardPrefix);
49*0e209d39SAndroid Build Coastguard Worker   if (wildcard_start == nullptr) {
50*0e209d39SAndroid Build Coastguard Worker     return 0;
51*0e209d39SAndroid Build Coastguard Worker   }
52*0e209d39SAndroid Build Coastguard Worker   // Priority is based on the character after the wildcard prefix.
53*0e209d39SAndroid Build Coastguard Worker   char priority = *(wildcard_start + kLogWildcardPrefixLength);
54*0e209d39SAndroid Build Coastguard Worker   return PriorityToLevel(priority);
55*0e209d39SAndroid Build Coastguard Worker }
56*0e209d39SAndroid Build Coastguard Worker 
AIcuHostShouldLog(char priority)57*0e209d39SAndroid Build Coastguard Worker bool AIcuHostShouldLog(char priority) {
58*0e209d39SAndroid Build Coastguard Worker   static int g_LogLevel = GetHostLogLevel();
59*0e209d39SAndroid Build Coastguard Worker   return PriorityToLevel(priority) >= g_LogLevel;
60*0e209d39SAndroid Build Coastguard Worker }
61*0e209d39SAndroid Build Coastguard Worker #endif  // !defined(__ANDROID__) || defined(NO_ANDROID_LIBLOG)
62*0e209d39SAndroid Build Coastguard Worker 
63*0e209d39SAndroid Build Coastguard Worker namespace androidicuinit {
64*0e209d39SAndroid Build Coastguard Worker namespace impl {
65*0e209d39SAndroid Build Coastguard Worker 
66*0e209d39SAndroid Build Coastguard Worker #if !defined(__ANDROID__) || defined(NO_ANDROID_LIBLOG)
67*0e209d39SAndroid Build Coastguard Worker // http://b/171371690 Avoid dependency on liblog and libbase on host
68*0e209d39SAndroid Build Coastguard Worker // Simplified version of android::base::unique_fd for host.
69*0e209d39SAndroid Build Coastguard Worker class simple_unique_fd final {
70*0e209d39SAndroid Build Coastguard Worker  public:
simple_unique_fd(int fd)71*0e209d39SAndroid Build Coastguard Worker   simple_unique_fd(int fd) {
72*0e209d39SAndroid Build Coastguard Worker     reset(fd);
73*0e209d39SAndroid Build Coastguard Worker   }
~simple_unique_fd()74*0e209d39SAndroid Build Coastguard Worker   ~simple_unique_fd() {
75*0e209d39SAndroid Build Coastguard Worker     reset();
76*0e209d39SAndroid Build Coastguard Worker   }
get()77*0e209d39SAndroid Build Coastguard Worker   int get() {
78*0e209d39SAndroid Build Coastguard Worker     return fd_;
79*0e209d39SAndroid Build Coastguard Worker   }
80*0e209d39SAndroid Build Coastguard Worker 
81*0e209d39SAndroid Build Coastguard Worker  private:
82*0e209d39SAndroid Build Coastguard Worker   int fd_ = -1;
reset(int new_fd=-1)83*0e209d39SAndroid Build Coastguard Worker   void reset(int new_fd = -1) {
84*0e209d39SAndroid Build Coastguard Worker     if (fd_ != -1) {
85*0e209d39SAndroid Build Coastguard Worker       close(fd_);
86*0e209d39SAndroid Build Coastguard Worker     }
87*0e209d39SAndroid Build Coastguard Worker     fd_ = new_fd;
88*0e209d39SAndroid Build Coastguard Worker   }
89*0e209d39SAndroid Build Coastguard Worker   // Disable copy constructor and assignment operator
90*0e209d39SAndroid Build Coastguard Worker   simple_unique_fd(const simple_unique_fd&) = delete;
91*0e209d39SAndroid Build Coastguard Worker   void operator=(const simple_unique_fd&) = delete;
92*0e209d39SAndroid Build Coastguard Worker 
93*0e209d39SAndroid Build Coastguard Worker };
94*0e209d39SAndroid Build Coastguard Worker 
95*0e209d39SAndroid Build Coastguard Worker   // A copy of TEMP_FAILURE_RETRY from android-base/macros.h
96*0e209d39SAndroid Build Coastguard Worker   // bionic and glibc both have TEMP_FAILURE_RETRY, but eg Mac OS' libc doesn't.
97*0e209d39SAndroid Build Coastguard Worker   #ifndef TEMP_FAILURE_RETRY
98*0e209d39SAndroid Build Coastguard Worker     #define TEMP_FAILURE_RETRY(exp)            \
99*0e209d39SAndroid Build Coastguard Worker       ({                                       \
100*0e209d39SAndroid Build Coastguard Worker         decltype(exp) _rc;                     \
101*0e209d39SAndroid Build Coastguard Worker         do {                                   \
102*0e209d39SAndroid Build Coastguard Worker           _rc = (exp);                         \
103*0e209d39SAndroid Build Coastguard Worker         } while (_rc == -1 && errno == EINTR); \
104*0e209d39SAndroid Build Coastguard Worker         _rc;                                   \
105*0e209d39SAndroid Build Coastguard Worker       })
106*0e209d39SAndroid Build Coastguard Worker   #endif
107*0e209d39SAndroid Build Coastguard Worker #endif // !defined(__ANDROID__) || defined(NO_ANDROID_LIBLOG)
108*0e209d39SAndroid Build Coastguard Worker 
109*0e209d39SAndroid Build Coastguard Worker // http://b/171371690 Avoid dependency on liblog and libbase on host
110*0e209d39SAndroid Build Coastguard Worker #if defined(__ANDROID__) && !defined(NO_ANDROID_LIBLOG)
111*0e209d39SAndroid Build Coastguard Worker   typedef android::base::unique_fd aicu_unique_fd;
112*0e209d39SAndroid Build Coastguard Worker #else
113*0e209d39SAndroid Build Coastguard Worker   typedef simple_unique_fd aicu_unique_fd;
114*0e209d39SAndroid Build Coastguard Worker #endif
115*0e209d39SAndroid Build Coastguard Worker 
116*0e209d39SAndroid Build Coastguard Worker // Map in ICU data at the path, returning null to print error if it failed.
Create(const std::string & path)117*0e209d39SAndroid Build Coastguard Worker std::unique_ptr<IcuDataMap> IcuDataMap::Create(const std::string& path) {
118*0e209d39SAndroid Build Coastguard Worker   std::unique_ptr<IcuDataMap> map(new IcuDataMap(path));
119*0e209d39SAndroid Build Coastguard Worker 
120*0e209d39SAndroid Build Coastguard Worker   if (!map->TryMap()) {
121*0e209d39SAndroid Build Coastguard Worker     // madvise or ICU could fail but mmap still succeeds.
122*0e209d39SAndroid Build Coastguard Worker     // Destructor will take care of cleaning up a partial init.
123*0e209d39SAndroid Build Coastguard Worker     return nullptr;
124*0e209d39SAndroid Build Coastguard Worker   }
125*0e209d39SAndroid Build Coastguard Worker 
126*0e209d39SAndroid Build Coastguard Worker   return map;
127*0e209d39SAndroid Build Coastguard Worker }
128*0e209d39SAndroid Build Coastguard Worker 
129*0e209d39SAndroid Build Coastguard Worker // Unmap the ICU data.
~IcuDataMap()130*0e209d39SAndroid Build Coastguard Worker IcuDataMap::~IcuDataMap() { TryUnmap(); }
131*0e209d39SAndroid Build Coastguard Worker 
TryMap()132*0e209d39SAndroid Build Coastguard Worker bool IcuDataMap::TryMap() {
133*0e209d39SAndroid Build Coastguard Worker   // Open the file and get its length.
134*0e209d39SAndroid Build Coastguard Worker   aicu_unique_fd fd(TEMP_FAILURE_RETRY(open(path_.c_str(), O_RDONLY)));
135*0e209d39SAndroid Build Coastguard Worker 
136*0e209d39SAndroid Build Coastguard Worker   if (fd.get() == -1) {
137*0e209d39SAndroid Build Coastguard Worker     AICU_LOGE("Couldn't open '%s': %s", path_.c_str(), strerror(errno));
138*0e209d39SAndroid Build Coastguard Worker     return false;
139*0e209d39SAndroid Build Coastguard Worker   }
140*0e209d39SAndroid Build Coastguard Worker 
141*0e209d39SAndroid Build Coastguard Worker   struct stat sb;
142*0e209d39SAndroid Build Coastguard Worker   if (fstat(fd.get(), &sb) == -1) {
143*0e209d39SAndroid Build Coastguard Worker     AICU_LOGE("Couldn't stat '%s': %s", path_.c_str(), strerror(errno));
144*0e209d39SAndroid Build Coastguard Worker     return false;
145*0e209d39SAndroid Build Coastguard Worker   }
146*0e209d39SAndroid Build Coastguard Worker 
147*0e209d39SAndroid Build Coastguard Worker   data_length_ = sb.st_size;
148*0e209d39SAndroid Build Coastguard Worker 
149*0e209d39SAndroid Build Coastguard Worker   // Map it.
150*0e209d39SAndroid Build Coastguard Worker   data_ =
151*0e209d39SAndroid Build Coastguard Worker       mmap(NULL, data_length_, PROT_READ, MAP_SHARED, fd.get(), 0 /* offset */);
152*0e209d39SAndroid Build Coastguard Worker   if (data_ == MAP_FAILED) {
153*0e209d39SAndroid Build Coastguard Worker     AICU_LOGE("Couldn't mmap '%s': %s", path_.c_str(), strerror(errno));
154*0e209d39SAndroid Build Coastguard Worker     return false;
155*0e209d39SAndroid Build Coastguard Worker   }
156*0e209d39SAndroid Build Coastguard Worker 
157*0e209d39SAndroid Build Coastguard Worker   // Tell the kernel that accesses are likely to be random rather than
158*0e209d39SAndroid Build Coastguard Worker   // sequential.
159*0e209d39SAndroid Build Coastguard Worker   if (madvise(data_, data_length_, MADV_RANDOM) == -1) {
160*0e209d39SAndroid Build Coastguard Worker     AICU_LOGE("Couldn't madvise(MADV_RANDOM) '%s': %s", path_.c_str(),
161*0e209d39SAndroid Build Coastguard Worker           strerror(errno));
162*0e209d39SAndroid Build Coastguard Worker     return false;
163*0e209d39SAndroid Build Coastguard Worker   }
164*0e209d39SAndroid Build Coastguard Worker 
165*0e209d39SAndroid Build Coastguard Worker   UErrorCode status = U_ZERO_ERROR;
166*0e209d39SAndroid Build Coastguard Worker 
167*0e209d39SAndroid Build Coastguard Worker   // Tell ICU to use our memory-mapped data.
168*0e209d39SAndroid Build Coastguard Worker   udata_setCommonData(data_, &status);
169*0e209d39SAndroid Build Coastguard Worker   if (status != U_ZERO_ERROR) {
170*0e209d39SAndroid Build Coastguard Worker     AICU_LOGE("Couldn't initialize ICU (udata_setCommonData): %s (%s)",
171*0e209d39SAndroid Build Coastguard Worker           u_errorName(status), path_.c_str());
172*0e209d39SAndroid Build Coastguard Worker     return false;
173*0e209d39SAndroid Build Coastguard Worker   }
174*0e209d39SAndroid Build Coastguard Worker 
175*0e209d39SAndroid Build Coastguard Worker   return true;
176*0e209d39SAndroid Build Coastguard Worker }
177*0e209d39SAndroid Build Coastguard Worker 
TryUnmap()178*0e209d39SAndroid Build Coastguard Worker bool IcuDataMap::TryUnmap() {
179*0e209d39SAndroid Build Coastguard Worker   // Don't need to do opposite of udata_setCommonData,
180*0e209d39SAndroid Build Coastguard Worker   // u_cleanup (performed in IcuRegistration::~IcuRegistration()) takes care of
181*0e209d39SAndroid Build Coastguard Worker   // it.
182*0e209d39SAndroid Build Coastguard Worker 
183*0e209d39SAndroid Build Coastguard Worker   // Don't need to opposite of madvise, munmap will take care of it.
184*0e209d39SAndroid Build Coastguard Worker 
185*0e209d39SAndroid Build Coastguard Worker   if (data_ != nullptr && data_ != MAP_FAILED) {
186*0e209d39SAndroid Build Coastguard Worker     if (munmap(data_, data_length_) == -1) {
187*0e209d39SAndroid Build Coastguard Worker       AICU_LOGE("Couldn't munmap '%s': %s", path_.c_str(), strerror(errno));
188*0e209d39SAndroid Build Coastguard Worker       return false;
189*0e209d39SAndroid Build Coastguard Worker     }
190*0e209d39SAndroid Build Coastguard Worker   }
191*0e209d39SAndroid Build Coastguard Worker 
192*0e209d39SAndroid Build Coastguard Worker   // Don't need to close the file, it was closed automatically during TryMap.
193*0e209d39SAndroid Build Coastguard Worker   return true;
194*0e209d39SAndroid Build Coastguard Worker }
195*0e209d39SAndroid Build Coastguard Worker 
196*0e209d39SAndroid Build Coastguard Worker }  // namespace impl
197*0e209d39SAndroid Build Coastguard Worker 
198*0e209d39SAndroid Build Coastguard Worker // A pointer to the instance used by Register and Deregister. Since this code
199*0e209d39SAndroid Build Coastguard Worker // is currently included in a static library this doesn't prevent duplicate
200*0e209d39SAndroid Build Coastguard Worker // initialization calls.
201*0e209d39SAndroid Build Coastguard Worker static std::unique_ptr<IcuRegistration> gIcuRegistration;
202*0e209d39SAndroid Build Coastguard Worker 
Register()203*0e209d39SAndroid Build Coastguard Worker void IcuRegistration::Register() {
204*0e209d39SAndroid Build Coastguard Worker   CHECK(gIcuRegistration.get() == nullptr);
205*0e209d39SAndroid Build Coastguard Worker 
206*0e209d39SAndroid Build Coastguard Worker   gIcuRegistration.reset(new IcuRegistration());
207*0e209d39SAndroid Build Coastguard Worker }
208*0e209d39SAndroid Build Coastguard Worker 
Deregister()209*0e209d39SAndroid Build Coastguard Worker void IcuRegistration::Deregister() {
210*0e209d39SAndroid Build Coastguard Worker   gIcuRegistration.reset();
211*0e209d39SAndroid Build Coastguard Worker }
212*0e209d39SAndroid Build Coastguard Worker 
213*0e209d39SAndroid Build Coastguard Worker // Init ICU, configuring it and loading the data files.
IcuRegistration()214*0e209d39SAndroid Build Coastguard Worker IcuRegistration::IcuRegistration() {
215*0e209d39SAndroid Build Coastguard Worker   // Check the timezone override file exists from a mounted APEX file.
216*0e209d39SAndroid Build Coastguard Worker   // If it does, map it so we use its data in preference to later ones.
217*0e209d39SAndroid Build Coastguard Worker   // However, I18N apex is not expected to have the time zone data resources.
218*0e209d39SAndroid Build Coastguard Worker   // http://b/171542040
219*0e209d39SAndroid Build Coastguard Worker   std::string tzIcuDataPath = getTimeZoneModulePath();
220*0e209d39SAndroid Build Coastguard Worker   if (pathExists(tzIcuDataPath)) {
221*0e209d39SAndroid Build Coastguard Worker     UErrorCode status = U_ZERO_ERROR;
222*0e209d39SAndroid Build Coastguard Worker     u_setTimeZoneFilesDirectory(tzIcuDataPath.c_str(), &status);
223*0e209d39SAndroid Build Coastguard Worker     if (U_SUCCESS(status)) {
224*0e209d39SAndroid Build Coastguard Worker       AICU_LOGD("u_setTimeZoneFilesDirectory(\"%s\") succeeded. ", tzIcuDataPath.c_str());
225*0e209d39SAndroid Build Coastguard Worker     } else {
226*0e209d39SAndroid Build Coastguard Worker       AICU_LOGE("u_setTimeZoneFilesDirectory(\"%s\") failed: %s",
227*0e209d39SAndroid Build Coastguard Worker           tzIcuDataPath.c_str(), u_errorName(status));
228*0e209d39SAndroid Build Coastguard Worker     }
229*0e209d39SAndroid Build Coastguard Worker   } else {
230*0e209d39SAndroid Build Coastguard Worker     AICU_LOGE("IcuRegistration: no time zone files were found. %s does not exist.",
231*0e209d39SAndroid Build Coastguard Worker         tzIcuDataPath.c_str());
232*0e209d39SAndroid Build Coastguard Worker   }
233*0e209d39SAndroid Build Coastguard Worker 
234*0e209d39SAndroid Build Coastguard Worker   // Use the ICU data files that shipped with the i18n module for everything
235*0e209d39SAndroid Build Coastguard Worker   // else.
236*0e209d39SAndroid Build Coastguard Worker   std::string i18nModulePath = getI18nModulePath();
237*0e209d39SAndroid Build Coastguard Worker   icu_datamap_from_i18n_module_ = impl::IcuDataMap::Create(i18nModulePath);
238*0e209d39SAndroid Build Coastguard Worker   if (icu_datamap_from_i18n_module_ == nullptr) {
239*0e209d39SAndroid Build Coastguard Worker     // IcuDataMap::Create() will log on error so there is no need to log here.
240*0e209d39SAndroid Build Coastguard Worker     abort();
241*0e209d39SAndroid Build Coastguard Worker   }
242*0e209d39SAndroid Build Coastguard Worker   AICU_LOGD("I18n APEX ICU file found: %s", i18nModulePath.c_str());
243*0e209d39SAndroid Build Coastguard Worker }
244*0e209d39SAndroid Build Coastguard Worker 
245*0e209d39SAndroid Build Coastguard Worker // De-init ICU, unloading the data files. Do the opposite of the above function.
~IcuRegistration()246*0e209d39SAndroid Build Coastguard Worker IcuRegistration::~IcuRegistration() {
247*0e209d39SAndroid Build Coastguard Worker   // Unmap ICU data files.
248*0e209d39SAndroid Build Coastguard Worker   icu_datamap_from_i18n_module_.reset();
249*0e209d39SAndroid Build Coastguard Worker   icu_datamap_from_tz_module_.reset();
250*0e209d39SAndroid Build Coastguard Worker }
251*0e209d39SAndroid Build Coastguard Worker 
pathExists(const std::string & path)252*0e209d39SAndroid Build Coastguard Worker bool IcuRegistration::pathExists(const std::string& path) {
253*0e209d39SAndroid Build Coastguard Worker   struct stat sb;
254*0e209d39SAndroid Build Coastguard Worker   return stat(path.c_str(), &sb) == 0;
255*0e209d39SAndroid Build Coastguard Worker }
256*0e209d39SAndroid Build Coastguard Worker 
257*0e209d39SAndroid Build Coastguard Worker // Identical to TzDataSetVersion#CURRENT_MAJOR_FORMAT_VERSION.
258*0e209d39SAndroid Build Coastguard Worker // LINT.IfChange
259*0e209d39SAndroid Build Coastguard Worker static const std::string CURRENT_MAJOR_FORMAT_VERSION = "8";
260*0e209d39SAndroid Build Coastguard Worker // LINT.ThenChange(external/icu/android_icu4j/libcore_bridge/src/java/com/android/i18n/timezone/TzDataSetVersion.java)
261*0e209d39SAndroid Build Coastguard Worker 
getTimeZoneModulePath()262*0e209d39SAndroid Build Coastguard Worker std::string IcuRegistration::getTimeZoneModulePath() {
263*0e209d39SAndroid Build Coastguard Worker   const char* tzdataModulePathPrefix = getenv("ANDROID_TZDATA_ROOT");
264*0e209d39SAndroid Build Coastguard Worker   if (tzdataModulePathPrefix == NULL) {
265*0e209d39SAndroid Build Coastguard Worker     AICU_LOGE("ANDROID_TZDATA_ROOT environment variable not set");
266*0e209d39SAndroid Build Coastguard Worker     abort();
267*0e209d39SAndroid Build Coastguard Worker   }
268*0e209d39SAndroid Build Coastguard Worker 
269*0e209d39SAndroid Build Coastguard Worker   std::string tzdataModulePath;
270*0e209d39SAndroid Build Coastguard Worker   tzdataModulePath = tzdataModulePathPrefix;
271*0e209d39SAndroid Build Coastguard Worker   tzdataModulePath += "/etc/tz/versioned/" + CURRENT_MAJOR_FORMAT_VERSION + "/icu";
272*0e209d39SAndroid Build Coastguard Worker   return tzdataModulePath;
273*0e209d39SAndroid Build Coastguard Worker }
274*0e209d39SAndroid Build Coastguard Worker 
getI18nModulePath()275*0e209d39SAndroid Build Coastguard Worker std::string IcuRegistration::getI18nModulePath() {
276*0e209d39SAndroid Build Coastguard Worker   const char* i18nModulePathPrefix = getenv("ANDROID_I18N_ROOT");
277*0e209d39SAndroid Build Coastguard Worker   if (i18nModulePathPrefix == NULL) {
278*0e209d39SAndroid Build Coastguard Worker     AICU_LOGE("ANDROID_I18N_ROOT environment variable not set");
279*0e209d39SAndroid Build Coastguard Worker     abort();
280*0e209d39SAndroid Build Coastguard Worker   }
281*0e209d39SAndroid Build Coastguard Worker 
282*0e209d39SAndroid Build Coastguard Worker   std::string i18nModulePath;
283*0e209d39SAndroid Build Coastguard Worker   i18nModulePath = i18nModulePathPrefix;
284*0e209d39SAndroid Build Coastguard Worker   i18nModulePath += "/etc/icu/" U_ICUDATA_NAME ".dat";
285*0e209d39SAndroid Build Coastguard Worker   return i18nModulePath;
286*0e209d39SAndroid Build Coastguard Worker }
287*0e209d39SAndroid Build Coastguard Worker 
288*0e209d39SAndroid Build Coastguard Worker }  // namespace androidicuinit
289*0e209d39SAndroid Build Coastguard Worker 
android_icu_register()290*0e209d39SAndroid Build Coastguard Worker void android_icu_register() {
291*0e209d39SAndroid Build Coastguard Worker   androidicuinit::IcuRegistration::Register();
292*0e209d39SAndroid Build Coastguard Worker }
293*0e209d39SAndroid Build Coastguard Worker 
android_icu_deregister()294*0e209d39SAndroid Build Coastguard Worker void android_icu_deregister() {
295*0e209d39SAndroid Build Coastguard Worker   androidicuinit::IcuRegistration::Deregister();
296*0e209d39SAndroid Build Coastguard Worker }
297*0e209d39SAndroid Build Coastguard Worker 
android_icu_is_registered()298*0e209d39SAndroid Build Coastguard Worker bool android_icu_is_registered() {
299*0e209d39SAndroid Build Coastguard Worker   return androidicuinit::gIcuRegistration.get() != nullptr;
300*0e209d39SAndroid Build Coastguard Worker }
301