1 /*
2 * Copyright (C) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "nitz_update.h"
17
18 #include <securec.h>
19
20 #include "common_event.h"
21 #include "common_event_manager.h"
22 #include "common_event_support.h"
23 #include "core_manager_inner.h"
24 #include "network_search_manager.h"
25 #ifdef ABILITY_POWER_SUPPORT
26 #include "power_mgr_client.h"
27 #endif
28 #include "setting_utils.h"
29 #include "string_ex.h"
30 #include "telephony_ext_wrapper.h"
31 #include "telephony_log_wrapper.h"
32 #include "time_service_client.h"
33 #include "zone_util.h"
34
35 #ifdef ABILITY_POWER_SUPPORT
36 using namespace OHOS::PowerMgr;
37 #endif
38 using namespace OHOS::AppExecFwk;
39 using namespace OHOS::EventFwk;
40 namespace OHOS {
41 namespace Telephony {
42 const int32_t MILLI_TO_BASE = 1000;
43 const int32_t NANO_TO_MILLI = 1000000;
44 const int32_t MAX_UPDATE_TIME = 5;
45 const int32_t TIME_STRING_SPLIT_NUM = 2;
46 const uint32_t TIME_SPLIT_NUM = 3;
47 const uint32_t TIMEZONE_SPLIT_NUM = 2;
48 const uint32_t YEAR_LENGTH_TWO = 2;
49 const uint32_t YEAR_LENGTH_FOUR = 4;
50 const uint32_t CST_YEAR = 1900;
51 constexpr int32_t QUARTER_TO_MILLISECOND = 15 * 60 * 1000;
52 const uint32_t LOCATION_DAY_OR_SEC = 2;
53 const uint32_t TIME_THRESHOLD = 3; // seconds
54 const int32_t SIM_SLOT_ID_0 = 0;
55 const int32_t SIM_SLOT_ID_1 = 1;
56 const std::string AUTO_TIME_OFF = "0";
57 const std::string AUTO_TIME_ZONE_OFF = "0";
58 const std::string PARAM_TIME_ZONE = "time-zone";
59 int64_t NitzUpdate::lastSystemTime_ = 0;
60 int32_t NitzUpdate::offset_ = 0;
61 int64_t NitzUpdate::lastNetworkTime_ = 0;
62 int64_t NitzUpdate::lastOffsetTime_ = 0;
63 std::string NitzUpdate::timeZone_;
64
NitzUpdate(const std::weak_ptr<NetworkSearchManager> & networkSearchManager,int32_t slotId)65 NitzUpdate::NitzUpdate(const std::weak_ptr<NetworkSearchManager> &networkSearchManager, int32_t slotId)
66 : networkSearchManager_(networkSearchManager), slotId_(slotId)
67 {}
68
ProcessNitzUpdate(const AppExecFwk::InnerEvent::Pointer & event)69 void NitzUpdate::ProcessNitzUpdate(const AppExecFwk::InnerEvent::Pointer &event)
70 {
71 if (event == nullptr) {
72 TELEPHONY_LOGE("NitzUpdate::ProcessNitzUpdate event is nullptr slotId:%{public}d", slotId_);
73 return;
74 }
75 std::shared_ptr<std::string> strTime = event->GetSharedObject<std::string>();
76 if (strTime == nullptr || strTime->empty()) {
77 TELEPHONY_LOGE("NitzUpdate::ProcessNitzUpdate is nullptr slotId:%{public}d", slotId_);
78 return;
79 }
80
81 int64_t now = OHOS::MiscServices::TimeServiceClient::GetInstance()->GetBootTimeMs();
82 if ((now / MILLI_TO_BASE - lastSystemTime_) < MAX_UPDATE_TIME) {
83 TELEPHONY_LOGI("NitzUpdate::ProcessNitzUpdate update time slotId:%{public}d", slotId_);
84 return;
85 }
86
87 TELEPHONY_LOGI(
88 "NitzUpdate::ProcessNitzUpdate get time:%{public}s slotId:%{public}d", strTime.get()->c_str(), slotId_);
89 NetworkTime networkTime = {0};
90 if (NitzParse(*strTime, networkTime)) {
91 ProcessTime(networkTime);
92 if (TELEPHONY_EXT_WRAPPER.updateTimeZoneOffsetExt_ != nullptr) {
93 TELEPHONY_EXT_WRAPPER.updateTimeZoneOffsetExt_(slotId_, networkTime.offset);
94 } else {
95 offset_ = networkTime.offset;
96 ProcessTimeZone();
97 }
98 }
99 }
100
NitzParse(std::string & nitzStr,NetworkTime & networkTime)101 bool NitzUpdate::NitzParse(std::string &nitzStr, NetworkTime &networkTime)
102 {
103 std::string split = ";";
104 std::vector<std::string> str;
105 SplitStr(nitzStr, split, str);
106 int32_t size = static_cast<int32_t>(str.size());
107 if (size != TIME_STRING_SPLIT_NUM) {
108 return false;
109 }
110 std::string nitzInfo = str[0];
111 std::istringstream time(str[1]);
112 time >> nitzRecvTime_;
113 std::string strSep = ",";
114 std::vector<std::string> strsRet;
115 SplitStr(nitzInfo, strSep, strsRet);
116 if (static_cast<uint32_t>(strsRet.size()) < static_cast<uint32_t>(TIMEZONE_SPLIT_NUM)) {
117 TELEPHONY_LOGE("NitzUpdate::NitzParse nitz string error slotId:%{public}d", slotId_);
118 return false;
119 }
120 std::string strDateSubs = strsRet[0];
121 std::string strTimeSubs = strsRet[1];
122 strsRet.clear();
123 strSep = "/";
124 SplitStr(strDateSubs, strSep, strsRet);
125 if (static_cast<uint32_t>(strsRet.size()) != static_cast<uint32_t>(TIME_SPLIT_NUM)) {
126 TELEPHONY_LOGE("NitzUpdate::NitzParse date string error slotId:%{public}d", slotId_);
127 return false;
128 }
129 std::string strYear = strsRet[0];
130 if (strYear.length() != YEAR_LENGTH_TWO && strYear.length() != YEAR_LENGTH_FOUR) {
131 TELEPHONY_LOGE("NitzUpdate::NitzParse year string length error slotId:%{public}d", slotId_);
132 return false;
133 }
134 if (strYear.length() == YEAR_LENGTH_TWO) {
135 strYear = "20" + strYear;
136 }
137 StrToInt(strYear, networkTime.year);
138 StrToInt(strsRet[1], networkTime.month);
139 StrToInt(strsRet[LOCATION_DAY_OR_SEC], networkTime.day);
140 if (!NitzTimeParse(strTimeSubs, networkTime)) {
141 return false;
142 }
143 return true;
144 }
145
NitzTimeParse(std::string & strTimeSubs,NetworkTime & networkTime)146 bool NitzUpdate::NitzTimeParse(std::string &strTimeSubs, NetworkTime &networkTime)
147 {
148 int32_t flag = 1;
149 std::string strSep = "+";
150 std::string::size_type posPositive = strTimeSubs.find(strSep);
151 strSep = "-";
152 std::string::size_type posNegative = strTimeSubs.find(strSep);
153 if (posPositive != std::string::npos) {
154 strSep = "+";
155 } else if (posNegative != std::string::npos) {
156 strSep = "-";
157 flag = -1;
158 } else {
159 TELEPHONY_LOGE("NitzUpdate::NitzParse timezone string error %{public}s slotId:%{public}d",
160 strTimeSubs.c_str(), slotId_);
161 return false;
162 }
163
164 std::vector<std::string> strsRet;
165 SplitStr(strTimeSubs, strSep, strsRet);
166 if (strsRet.size() != TIMEZONE_SPLIT_NUM) {
167 TELEPHONY_LOGE("NitzUpdate::NitzParse timezone error slotId:%{public}d", slotId_);
168 return false;
169 }
170 strTimeSubs = strsRet[0];
171 StrToInt(strsRet[1], networkTime.offset);
172 networkTime.offset = networkTime.offset * flag;
173
174 strSep = ":";
175 strsRet.clear();
176 SplitStr(strTimeSubs, strSep, strsRet);
177 if (strsRet.size() != TIME_SPLIT_NUM) {
178 TELEPHONY_LOGE("NitzUpdate::NitzParse timezone vector error slotId:%{public}d", slotId_);
179 return false;
180 }
181 StrToInt(strsRet[0], networkTime.hour);
182 StrToInt(strsRet[1], networkTime.minute);
183 StrToInt(strsRet[LOCATION_DAY_OR_SEC], networkTime.second);
184
185 return true;
186 }
187
ProcessTime(NetworkTime & networkTime)188 void NitzUpdate::ProcessTime(NetworkTime &networkTime)
189 {
190 if (networkTime.year < static_cast<int32_t>(CST_YEAR) || networkTime.month < 1) {
191 TELEPHONY_LOGE("NitzUpdate::ProcessTime time error slotId:%{public}d", slotId_);
192 return;
193 }
194 #ifdef ABILITY_POWER_SUPPORT
195 auto &powerMgrClient = PowerMgrClient::GetInstance();
196 auto runningLock = powerMgrClient.CreateRunningLock("runninglock", RunningLockType::RUNNINGLOCK_BACKGROUND_PHONE);
197 if (runningLock != nullptr) {
198 runningLock->Lock();
199 }
200 #endif
201 struct tm t;
202 (void)memset_s(&t, sizeof(t), 0, sizeof(t));
203 t.tm_year = networkTime.year - static_cast<int32_t>(CST_YEAR);
204 t.tm_mon = networkTime.month - 1;
205 t.tm_mday = networkTime.day;
206 t.tm_hour = networkTime.hour;
207 t.tm_min = networkTime.minute;
208 t.tm_sec = networkTime.second;
209 int64_t nitzTime = static_cast<int64_t>(timegm(&t));
210 int64_t currentTime = OHOS::MiscServices::TimeServiceClient::GetInstance()->GetBootTimeNs();
211 int64_t offset = (currentTime - nitzRecvTime_) / NANO_TO_MILLI;
212 if (offset < 0 || offset >= INT64_MAX) {
213 TELEPHONY_LOGE("NitzUpdate::ProcessTime offset invalid, slotId:%{public}d", slotId_);
214 return;
215 }
216 TELEPHONY_LOGI("slotId:%{public}d, currentTime:%{public}lld, offset:%{public}lld, nitzTime:%{public}lld",
217 slotId_, static_cast<long long>(currentTime), static_cast<long long>(offset), static_cast<long long>(nitzTime));
218 bool autoTime = IsAutoTime();
219 if (!autoTime) {
220 TELEPHONY_LOGI("NitzUpdate::ProcessTime not auto udpate time slotId:%{public}d", slotId_);
221 return;
222 }
223 SaveTime(nitzTime, offset);
224 #ifdef ABILITY_POWER_SUPPORT
225 if (runningLock != nullptr) {
226 runningLock->UnLock();
227 }
228 #endif
229 }
230
ProcessTimeZone()231 void NitzUpdate::ProcessTimeZone()
232 {
233 std::shared_ptr<NetworkSearchManager> nsm = networkSearchManager_.lock();
234 if (nsm == nullptr) {
235 TELEPHONY_LOGE("failed to get NetworkSearchManager slotId:%{public}d", slotId_);
236 return;
237 }
238 int32_t primarySlotId = INVALID_VALUE;
239 CoreManagerInner::GetInstance().GetPrimarySlotId(primarySlotId);
240 if (primarySlotId == INVALID_VALUE) {
241 TELEPHONY_LOGI("primarySlotId %{public}d is invalid slotId:%{public}d", primarySlotId, slotId_);
242 return;
243 }
244 std::u16string iso;
245 if (nsm->GetIsoCountryCodeForNetwork(primarySlotId, iso) != TELEPHONY_ERR_SUCCESS) {
246 TELEPHONY_LOGE("failed to get CountryCode slotId:%{public}d", primarySlotId);
247 return;
248 }
249 if (iso.empty()) {
250 int32_t otherSlotId = (primarySlotId == SIM_SLOT_ID_0) ? SIM_SLOT_ID_1 : SIM_SLOT_ID_0;
251 TELEPHONY_LOGI("primarySlotId = %{public}d, otherSlotId = %{public}d", primarySlotId, otherSlotId);
252 nsm->GetIsoCountryCodeForNetwork(otherSlotId, iso);
253 if (!iso.empty()) {
254 primarySlotId = otherSlotId;
255 }
256 }
257 std::string countryCode = Str16ToStr8(iso);
258 if (TELEPHONY_EXT_WRAPPER.updateCountryCodeExt_ != nullptr) {
259 TELEPHONY_EXT_WRAPPER.updateCountryCodeExt_(primarySlotId, countryCode.c_str());
260 } else {
261 UpdateCountryCode(countryCode);
262 }
263 }
264
UpdateCountryCode(std::string & countryCode)265 void NitzUpdate::UpdateCountryCode(std::string &countryCode)
266 {
267 if (countryCode.empty()) {
268 TELEPHONY_LOGE("NitzUpdate::UpdateCountryCode countryCode is null slotId:%{public}d", slotId_);
269 return;
270 }
271 if (!IsAutoTimeZone()) {
272 TELEPHONY_LOGI("NitzUpdate::UpdateCountryCode not auto udpate timezone slotId:%{public}d", slotId_);
273 return;
274 }
275 OHOS::Global::I18n::ZoneUtil util;
276 std::string timeZone = util.GetDefaultZone(countryCode.c_str());
277 if (timeZone.empty()) {
278 int32_t offset = QUARTER_TO_MILLISECOND * offset_;
279 timeZone = util.GetDefaultZone(countryCode.c_str(), offset);
280 }
281 if (timeZone.empty()) {
282 TELEPHONY_LOGE("failed to get zone slotId:%{public}d", slotId_);
283 return;
284 }
285 SaveTimeZone(timeZone);
286 }
287
SaveTimeZone(std::string & timeZone)288 void NitzUpdate::SaveTimeZone(std::string &timeZone)
289 {
290 std::string lastTimeZone = OHOS::MiscServices::TimeServiceClient::GetInstance()->GetTimeZone();
291 if (timeZone == lastTimeZone) {
292 TELEPHONY_LOGI("NitzUpdate::SaveTimeZone timezone[%{public}s] is the same as lastTimeZone slotId:%{public}d",
293 timeZone.c_str(), slotId_);
294 return;
295 }
296
297 timeZone_ = timeZone;
298 bool result = OHOS::MiscServices::TimeServiceClient::GetInstance()->SetTimeZone(timeZone);
299 TELEPHONY_LOGI("NitzUpdate::ProcessTimeZone result:%{public}d timezone:%{public}s slotId:%{public}d", result,
300 timeZone.c_str(), slotId_);
301
302 std::string param = PARAM_TIME_ZONE;
303 AAFwk::Want want;
304 want.SetAction(EventFwk::CommonEventSupport::COMMON_EVENT_NITZ_TIMEZONE_CHANGED);
305 want.SetParam(param, timeZone);
306 PublishCommonEvent(want);
307 }
308
SaveTime(int64_t networkTime,int64_t offset)309 void NitzUpdate::SaveTime(int64_t networkTime, int64_t offset)
310 {
311 TELEPHONY_LOGI("SaveTime networkTime:(%{public}" PRId64 ") slotId:%{public}d, offset:(%{public}" PRId64 ")",
312 networkTime, slotId_, offset);
313 #ifdef ABILITY_POWER_SUPPORT
314 auto &powerMgrClient = PowerMgrClient::GetInstance();
315 auto runningLock = powerMgrClient.CreateRunningLock("runninglock", RunningLockType::RUNNINGLOCK_BACKGROUND_PHONE);
316 if (runningLock != nullptr) {
317 runningLock->Lock();
318 }
319 #endif
320 bool result = OHOS::MiscServices::TimeServiceClient::GetInstance()->SetTime(networkTime * MILLI_TO_BASE + offset);
321 TELEPHONY_LOGI("NitzUpdate::ProcessTime result:%{public}d slotId:%{public}d", result, slotId_);
322 #ifdef ABILITY_POWER_SUPPORT
323 if (runningLock != nullptr) {
324 runningLock->UnLock();
325 }
326 #endif
327 std::string param = "time";
328 AAFwk::Want want;
329 want.SetAction(EventFwk::CommonEventSupport::COMMON_EVENT_NITZ_TIME_CHANGED);
330 want.SetParam(param, static_cast<int64_t>(networkTime));
331 PublishCommonEvent(want);
332 }
333
IsAutoTimeZone()334 bool NitzUpdate::IsAutoTimeZone()
335 {
336 std::shared_ptr<SettingUtils> settingHelper = SettingUtils::GetInstance();
337 if (settingHelper == nullptr) {
338 TELEPHONY_LOGI("settingHelper is null");
339 return false;
340 }
341 Uri uri(SettingUtils::NETWORK_SEARCH_SETTING_AUTO_TIMEZONE_URI);
342 std::string key = SettingUtils::SETTINGS_NETWORK_SEARCH_AUTO_TIMEZONE;
343 std::string value;
344 if (settingHelper->Query(uri, key, value) != TELEPHONY_SUCCESS) {
345 TELEPHONY_LOGI("Query %{public}s fail", key.c_str());
346 return false;
347 }
348 bool autoTimezone = true;
349 if (value == AUTO_TIME_ZONE_OFF) {
350 autoTimezone = false;
351 }
352 TELEPHONY_LOGI("NitzUpdate::IsAutoTimeZone autoTimezone:%{public}d slotId:%{public}d", autoTimezone, slotId_);
353 return autoTimezone;
354 }
355
IsAutoTime()356 bool NitzUpdate::IsAutoTime()
357 {
358 std::shared_ptr<SettingUtils> settingHelper = SettingUtils::GetInstance();
359 if (settingHelper == nullptr) {
360 TELEPHONY_LOGI("settingHelper is null");
361 return false;
362 }
363 Uri uri(SettingUtils::NETWORK_SEARCH_SETTING_AUTO_TIME_URI);
364 std::string key = SettingUtils::SETTINGS_NETWORK_SEARCH_AUTO_TIME;
365 std::string value = "";
366 if (settingHelper->Query(uri, key, value) != TELEPHONY_SUCCESS) {
367 TELEPHONY_LOGI("Query %{public}s fail", key.c_str());
368 return false;
369 }
370 bool autoTime = true;
371 if (value == AUTO_TIME_OFF) {
372 autoTime = false;
373 }
374 TELEPHONY_LOGI("NitzUpdate::IsAutoTime autoTime:%{public}d slotId:%{public}d", autoTime, slotId_);
375 return autoTime;
376 }
377
PublishCommonEvent(AAFwk::Want & want)378 void NitzUpdate::PublishCommonEvent(AAFwk::Want &want)
379 {
380 CommonEventData data;
381 data.SetWant(want);
382
383 bool stickty = true;
384 CommonEventPublishInfo publishInfo;
385 publishInfo.SetSticky(stickty);
386 bool publishResult = CommonEventManager::PublishCommonEvent(data, publishInfo, nullptr);
387 if (!publishResult) {
388 TELEPHONY_LOGE("NitzUpdate::PublishCommonEvent result:%{public}d slotId:%{public}d", publishResult, slotId_);
389 }
390 }
391
AutoTimeChange()392 void NitzUpdate::AutoTimeChange()
393 {
394 bool autoTime = IsAutoTime();
395 if (!autoTime) {
396 return;
397 }
398 TELEPHONY_LOGI("now update autoTime:%{public}d slotId:%{public}d", autoTime, slotId_);
399 int64_t time = OHOS::MiscServices::TimeServiceClient::GetInstance()->GetBootTimeMs();
400 time = time / MILLI_TO_BASE;
401 if (lastNetworkTime_ == 0 || lastSystemTime_ == 0 || time < lastSystemTime_) {
402 return;
403 }
404 SaveTime(lastNetworkTime_ + (time - lastSystemTime_), lastOffsetTime_);
405 }
406
AutoTimeZoneChange()407 void NitzUpdate::AutoTimeZoneChange()
408 {
409 bool autoTimezone = IsAutoTimeZone();
410 if (!autoTimezone) {
411 return;
412 }
413 TELEPHONY_LOGI("now update autoTimezone slotId:%{public}d, timeZone_:%{public}s", slotId_, timeZone_.c_str());
414 if (timeZone_.empty()) {
415 return;
416 }
417 SaveTimeZone(timeZone_);
418 }
419 } // namespace Telephony
420 } // namespace OHOS
421