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