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 MAX_UPDATE_TIME = 5;
44 const uint32_t TIME_SPLIT_NUM = 3;
45 const uint32_t TIMEZONE_SPLIT_NUM = 2;
46 const uint32_t YEAR_LENGTH_TWO = 2;
47 const uint32_t YEAR_LENGTH_FOUR = 4;
48 const uint32_t CST_YEAR = 1900;
49 constexpr int32_t QUARTER_TO_MILLISECOND = 15 * 60 * 1000;
50 const uint32_t LOCATION_DAY_OR_SEC = 2;
51 const uint32_t TIME_THRESHOLD = 3; // seconds
52 const int32_t SIM_SLOT_ID_0 = 0;
53 const int32_t SIM_SLOT_ID_1 = 1;
54 const std::string AUTO_TIME_OFF = "0";
55 const std::string AUTO_TIME_ZONE_OFF = "0";
56 const std::string PARAM_TIME_ZONE = "time-zone";
57 int64_t NitzUpdate::lastSystemTime_ = 0;
58 int32_t NitzUpdate::offset_ = 0;
59 int64_t NitzUpdate::lastNetworkTime_ = 0;
60 std::string NitzUpdate::timeZone_;
61 
NitzUpdate(const std::weak_ptr<NetworkSearchManager> & networkSearchManager,int32_t slotId)62 NitzUpdate::NitzUpdate(const std::weak_ptr<NetworkSearchManager> &networkSearchManager, int32_t slotId)
63     : networkSearchManager_(networkSearchManager), slotId_(slotId)
64 {}
65 
ProcessNitzUpdate(const AppExecFwk::InnerEvent::Pointer & event)66 void NitzUpdate::ProcessNitzUpdate(const AppExecFwk::InnerEvent::Pointer &event)
67 {
68     if (event == nullptr) {
69         TELEPHONY_LOGE("NitzUpdate::ProcessNitzUpdate event is nullptr slotId:%{public}d", slotId_);
70         return;
71     }
72     std::shared_ptr<std::string> strTime = event->GetSharedObject<std::string>();
73     if (strTime == nullptr || strTime->empty()) {
74         TELEPHONY_LOGE("NitzUpdate::ProcessNitzUpdate is nullptr slotId:%{public}d", slotId_);
75         return;
76     }
77 
78     int64_t now = OHOS::MiscServices::TimeServiceClient::GetInstance()->GetBootTimeMs();
79     if ((now / MILLI_TO_BASE - lastSystemTime_) < MAX_UPDATE_TIME) {
80         TELEPHONY_LOGI("NitzUpdate::ProcessNitzUpdate update time slotId:%{public}d", slotId_);
81         return;
82     }
83 
84     TELEPHONY_LOGI(
85         "NitzUpdate::ProcessNitzUpdate get time:%{public}s slotId:%{public}d", strTime.get()->c_str(), slotId_);
86     NetworkTime networkTime = {0};
87     if (NitzParse(*strTime, networkTime)) {
88         ProcessTime(networkTime);
89         if (TELEPHONY_EXT_WRAPPER.updateTimeZoneOffsetExt_ != nullptr) {
90             TELEPHONY_EXT_WRAPPER.updateTimeZoneOffsetExt_(slotId_, networkTime.offset);
91         } else {
92             offset_ = networkTime.offset;
93             ProcessTimeZone();
94         }
95     }
96 }
97 
NitzParse(std::string & nitzStr,NetworkTime & networkTime)98 bool NitzUpdate::NitzParse(std::string &nitzStr, NetworkTime &networkTime)
99 {
100     std::string strSep = ",";
101     std::vector<std::string> strsRet;
102     SplitStr(nitzStr, strSep, strsRet);
103     if (static_cast<uint32_t>(strsRet.size()) < static_cast<uint32_t>(TIMEZONE_SPLIT_NUM)) {
104         TELEPHONY_LOGE("NitzUpdate::NitzParse nitz string error slotId:%{public}d", slotId_);
105         return false;
106     }
107     std::string strDateSubs = strsRet[0];
108     std::string strTimeSubs = strsRet[1];
109     strsRet.clear();
110     strSep = "/";
111     SplitStr(strDateSubs, strSep, strsRet);
112     if (static_cast<uint32_t>(strsRet.size()) != static_cast<uint32_t>(TIME_SPLIT_NUM)) {
113         TELEPHONY_LOGE("NitzUpdate::NitzParse date string error slotId:%{public}d", slotId_);
114         return false;
115     }
116     std::string strYear = strsRet[0];
117     if (strYear.length() != YEAR_LENGTH_TWO && strYear.length() != YEAR_LENGTH_FOUR) {
118         TELEPHONY_LOGE("NitzUpdate::NitzParse year string length error slotId:%{public}d", slotId_);
119         return false;
120     }
121     if (strYear.length() == YEAR_LENGTH_TWO) {
122         strYear = "20" + strYear;
123     }
124     StrToInt(strYear, networkTime.year);
125     StrToInt(strsRet[1], networkTime.month);
126     StrToInt(strsRet[LOCATION_DAY_OR_SEC], networkTime.day);
127     if (!NitzTimeParse(strTimeSubs, networkTime)) {
128         return false;
129     }
130     return true;
131 }
132 
NitzTimeParse(std::string & strTimeSubs,NetworkTime & networkTime)133 bool NitzUpdate::NitzTimeParse(std::string &strTimeSubs, NetworkTime &networkTime)
134 {
135     int32_t flag = 1;
136     std::string strSep = "+";
137     std::string::size_type posPositive = strTimeSubs.find(strSep);
138     strSep = "-";
139     std::string::size_type posNegative = strTimeSubs.find(strSep);
140     if (posPositive != std::string::npos) {
141         strSep = "+";
142     } else if (posNegative != std::string::npos) {
143         strSep = "-";
144         flag = -1;
145     } else {
146         TELEPHONY_LOGE("NitzUpdate::NitzParse timezone string error %{public}s slotId:%{public}d",
147             strTimeSubs.c_str(), slotId_);
148         return false;
149     }
150 
151     std::vector<std::string> strsRet;
152     SplitStr(strTimeSubs, strSep, strsRet);
153     if (strsRet.size() != TIMEZONE_SPLIT_NUM) {
154         TELEPHONY_LOGE("NitzUpdate::NitzParse timezone error slotId:%{public}d", slotId_);
155         return false;
156     }
157     strTimeSubs = strsRet[0];
158     StrToInt(strsRet[1], networkTime.offset);
159     networkTime.offset = networkTime.offset * flag;
160 
161     strSep = ":";
162     strsRet.clear();
163     SplitStr(strTimeSubs, strSep, strsRet);
164     if (strsRet.size() != TIME_SPLIT_NUM) {
165         TELEPHONY_LOGE("NitzUpdate::NitzParse timezone vector error slotId:%{public}d", slotId_);
166         return false;
167     }
168     StrToInt(strsRet[0], networkTime.hour);
169     StrToInt(strsRet[1], networkTime.minute);
170     StrToInt(strsRet[LOCATION_DAY_OR_SEC], networkTime.second);
171 
172     return true;
173 }
174 
ProcessTime(NetworkTime & networkTime)175 void NitzUpdate::ProcessTime(NetworkTime &networkTime)
176 {
177     if (networkTime.year < static_cast<int32_t>(CST_YEAR) || networkTime.month < 1) {
178         TELEPHONY_LOGE("NitzUpdate::ProcessTime time error slotId:%{public}d", slotId_);
179         return;
180     }
181 #ifdef ABILITY_POWER_SUPPORT
182     auto &powerMgrClient = PowerMgrClient::GetInstance();
183     auto runningLock = powerMgrClient.CreateRunningLock("runninglock", RunningLockType::RUNNINGLOCK_BACKGROUND_PHONE);
184     if (runningLock != nullptr) {
185         runningLock->Lock();
186     }
187 #endif
188     struct tm t;
189     (void)memset_s(&t, sizeof(t), 0, sizeof(t));
190     t.tm_year = networkTime.year - static_cast<int32_t>(CST_YEAR);
191     t.tm_mon = networkTime.month - 1;
192     t.tm_mday = networkTime.day;
193     t.tm_hour = networkTime.hour;
194     t.tm_min = networkTime.minute;
195     t.tm_sec = networkTime.second;
196 
197     if (!IsValidTime(static_cast<int64_t>(timegm(&t)))) {
198         TELEPHONY_LOGE("NitzUpdate::ProcessTime invalid time, slotId:%{public}d", slotId_);
199         return;
200     }
201     bool autoTime = IsAutoTime();
202     if (!autoTime) {
203         TELEPHONY_LOGI("NitzUpdate::ProcessTime not auto udpate time slotId:%{public}d", slotId_);
204         return;
205     }
206     SaveTime(static_cast<int64_t>(timegm(&t)));
207 #ifdef ABILITY_POWER_SUPPORT
208     if (runningLock != nullptr) {
209         runningLock->UnLock();
210     }
211 #endif
212 }
213 
IsValidTime(int64_t networkTime)214 bool NitzUpdate::IsValidTime(int64_t networkTime)
215 {
216     int64_t currentSystemTime = OHOS::MiscServices::TimeServiceClient::GetInstance()->GetBootTimeMs();
217     if (currentSystemTime <= 0) {
218         TELEPHONY_LOGE("NitzUpdate::IsInvalidTime current system time is invalid");
219         return false;
220     }
221     currentSystemTime = currentSystemTime / MILLI_TO_BASE;
222     if (lastSystemTime_ == 0 && lastNetworkTime_ == 0) {
223         lastSystemTime_ = currentSystemTime;
224         lastNetworkTime_ = networkTime;
225         return true;
226     }
227 
228     // The difference between the two NITZ times and the elapsed time should be within the threshold
229     int64_t networkTimeInterval = networkTime - lastNetworkTime_;
230     int64_t systemElapsedTime = currentSystemTime - lastSystemTime_;
231     if (abs(networkTimeInterval - systemElapsedTime) > TIME_THRESHOLD) {
232         TELEPHONY_LOGE(
233             "NitzUpdate::IsInvalidTime The gap between the network time interval and the system elapsed time interval "
234             "is large and will not be processed, slotId:%{public}d", slotId_);
235         return false;
236     }
237 
238     lastSystemTime_ = currentSystemTime;
239     lastNetworkTime_ = networkTime;
240 
241     return true;
242 }
243 
ProcessTimeZone()244 void NitzUpdate::ProcessTimeZone()
245 {
246     std::shared_ptr<NetworkSearchManager> nsm = networkSearchManager_.lock();
247     if (nsm == nullptr) {
248         TELEPHONY_LOGE("failed to get NetworkSearchManager slotId:%{public}d", slotId_);
249         return;
250     }
251     int32_t primarySlotId = INVALID_VALUE;
252     CoreManagerInner::GetInstance().GetPrimarySlotId(primarySlotId);
253     if (primarySlotId == INVALID_VALUE) {
254         TELEPHONY_LOGI("primarySlotId %{public}d is invalid slotId:%{public}d", primarySlotId, slotId_);
255         return;
256     }
257     std::u16string iso;
258     if (nsm->GetIsoCountryCodeForNetwork(primarySlotId, iso) != TELEPHONY_ERR_SUCCESS) {
259         TELEPHONY_LOGE("failed to get CountryCode slotId:%{public}d", primarySlotId);
260         return;
261     }
262     if (iso.empty()) {
263         int32_t otherSlotId = (primarySlotId == SIM_SLOT_ID_0) ? SIM_SLOT_ID_1 : SIM_SLOT_ID_0;
264         TELEPHONY_LOGI("primarySlotId = %{public}d, otherSlotId = %{public}d", primarySlotId, otherSlotId);
265         nsm->GetIsoCountryCodeForNetwork(otherSlotId, iso);
266         if (!iso.empty()) {
267             primarySlotId = otherSlotId;
268         }
269     }
270     std::string countryCode = Str16ToStr8(iso);
271     if (TELEPHONY_EXT_WRAPPER.updateCountryCodeExt_ != nullptr) {
272         TELEPHONY_EXT_WRAPPER.updateCountryCodeExt_(primarySlotId, countryCode.c_str());
273     } else {
274         UpdateCountryCode(countryCode);
275     }
276 }
277 
UpdateCountryCode(std::string & countryCode)278 void NitzUpdate::UpdateCountryCode(std::string &countryCode)
279 {
280     if (countryCode.empty()) {
281         TELEPHONY_LOGE("NitzUpdate::UpdateCountryCode countryCode is null slotId:%{public}d", slotId_);
282         return;
283     }
284     if (!IsAutoTimeZone()) {
285         TELEPHONY_LOGI("NitzUpdate::UpdateCountryCode not auto udpate timezone slotId:%{public}d", slotId_);
286         return;
287     }
288     OHOS::Global::I18n::ZoneUtil util;
289     std::string timeZone = util.GetDefaultZone(countryCode.c_str());
290     if (timeZone.empty()) {
291         int32_t offset = QUARTER_TO_MILLISECOND * offset_;
292         timeZone = util.GetDefaultZone(countryCode.c_str(), offset);
293     }
294     if (timeZone.empty()) {
295         TELEPHONY_LOGE("failed to get zone slotId:%{public}d", slotId_);
296         return;
297     }
298     SaveTimeZone(timeZone);
299 }
300 
SaveTimeZone(std::string & timeZone)301 void NitzUpdate::SaveTimeZone(std::string &timeZone)
302 {
303     std::string lastTimeZone = OHOS::MiscServices::TimeServiceClient::GetInstance()->GetTimeZone();
304     if (timeZone == lastTimeZone) {
305         TELEPHONY_LOGI("NitzUpdate::SaveTimeZone timezone[%{public}s] is the same as lastTimeZone slotId:%{public}d",
306             timeZone.c_str(), slotId_);
307         return;
308     }
309 
310     timeZone_ = timeZone;
311     bool result = OHOS::MiscServices::TimeServiceClient::GetInstance()->SetTimeZone(timeZone);
312     TELEPHONY_LOGI("NitzUpdate::ProcessTimeZone result:%{public}d timezone:%{public}s slotId:%{public}d", result,
313         timeZone.c_str(), slotId_);
314 
315     std::string param = PARAM_TIME_ZONE;
316     AAFwk::Want want;
317     want.SetAction(EventFwk::CommonEventSupport::COMMON_EVENT_NITZ_TIMEZONE_CHANGED);
318     want.SetParam(param, timeZone);
319     PublishCommonEvent(want);
320 }
321 
SaveTime(int64_t networkTime)322 void NitzUpdate::SaveTime(int64_t networkTime)
323 {
324     TELEPHONY_LOGI("NitzUpdate::SaveTime networkTime:(%{public}" PRId64 ") slotId:%{public}d", networkTime, slotId_);
325 #ifdef ABILITY_POWER_SUPPORT
326     auto &powerMgrClient = PowerMgrClient::GetInstance();
327     auto runningLock = powerMgrClient.CreateRunningLock("runninglock", RunningLockType::RUNNINGLOCK_BACKGROUND_PHONE);
328     if (runningLock != nullptr) {
329         runningLock->Lock();
330     }
331 #endif
332     bool result = OHOS::MiscServices::TimeServiceClient::GetInstance()->SetTime(networkTime * MILLI_TO_BASE);
333     TELEPHONY_LOGI("NitzUpdate::ProcessTime result:%{public}d slotId:%{public}d", result, slotId_);
334 #ifdef ABILITY_POWER_SUPPORT
335     if (runningLock != nullptr) {
336         runningLock->UnLock();
337     }
338 #endif
339     std::string param = "time";
340     AAFwk::Want want;
341     want.SetAction(EventFwk::CommonEventSupport::COMMON_EVENT_NITZ_TIME_CHANGED);
342     want.SetParam(param, static_cast<int64_t>(networkTime));
343     PublishCommonEvent(want);
344 }
345 
IsAutoTimeZone()346 bool NitzUpdate::IsAutoTimeZone()
347 {
348     std::shared_ptr<SettingUtils> settingHelper = SettingUtils::GetInstance();
349     if (settingHelper == nullptr) {
350         TELEPHONY_LOGI("settingHelper is null");
351         return false;
352     }
353     Uri uri(SettingUtils::NETWORK_SEARCH_SETTING_AUTO_TIMEZONE_URI);
354     std::string key = SettingUtils::SETTINGS_NETWORK_SEARCH_AUTO_TIMEZONE;
355     std::string value;
356     if (settingHelper->Query(uri, key, value) != TELEPHONY_SUCCESS) {
357         TELEPHONY_LOGI("Query %{public}s fail", key.c_str());
358         return false;
359     }
360     bool autoTimezone = true;
361     if (value == AUTO_TIME_ZONE_OFF) {
362         autoTimezone = false;
363     }
364     TELEPHONY_LOGI("NitzUpdate::IsAutoTimeZone autoTimezone:%{public}d slotId:%{public}d", autoTimezone, slotId_);
365     return autoTimezone;
366 }
367 
IsAutoTime()368 bool NitzUpdate::IsAutoTime()
369 {
370     std::shared_ptr<SettingUtils> settingHelper = SettingUtils::GetInstance();
371     if (settingHelper == nullptr) {
372         TELEPHONY_LOGI("settingHelper is null");
373         return false;
374     }
375     Uri uri(SettingUtils::NETWORK_SEARCH_SETTING_AUTO_TIME_URI);
376     std::string key = SettingUtils::SETTINGS_NETWORK_SEARCH_AUTO_TIME;
377     std::string value = "";
378     if (settingHelper->Query(uri, key, value) != TELEPHONY_SUCCESS) {
379         TELEPHONY_LOGI("Query %{public}s fail", key.c_str());
380         return false;
381     }
382     bool autoTime = true;
383     if (value == AUTO_TIME_OFF) {
384         autoTime = false;
385     }
386     TELEPHONY_LOGI("NitzUpdate::IsAutoTime autoTime:%{public}d slotId:%{public}d", autoTime, slotId_);
387     return autoTime;
388 }
389 
PublishCommonEvent(AAFwk::Want & want)390 void NitzUpdate::PublishCommonEvent(AAFwk::Want &want)
391 {
392     CommonEventData data;
393     data.SetWant(want);
394 
395     bool stickty = true;
396     CommonEventPublishInfo publishInfo;
397     publishInfo.SetSticky(stickty);
398     bool publishResult = CommonEventManager::PublishCommonEvent(data, publishInfo, nullptr);
399     if (!publishResult) {
400         TELEPHONY_LOGE("NitzUpdate::PublishCommonEvent result:%{public}d slotId:%{public}d", publishResult, slotId_);
401     }
402 }
403 
AutoTimeChange()404 void NitzUpdate::AutoTimeChange()
405 {
406     bool autoTime = IsAutoTime();
407     if (!autoTime) {
408         return;
409     }
410     TELEPHONY_LOGI("now update autoTime:%{public}d slotId:%{public}d", autoTime, slotId_);
411     int64_t time = OHOS::MiscServices::TimeServiceClient::GetInstance()->GetBootTimeMs();
412     time = time / MILLI_TO_BASE;
413     if (lastNetworkTime_ == 0 || lastSystemTime_ == 0 || time < lastSystemTime_) {
414         return;
415     }
416     SaveTime(lastNetworkTime_ + (time - lastSystemTime_));
417 }
418 
AutoTimeZoneChange()419 void NitzUpdate::AutoTimeZoneChange()
420 {
421     bool autoTimezone = IsAutoTimeZone();
422     if (!autoTimezone) {
423         return;
424     }
425     TELEPHONY_LOGI("now update autoTimezone slotId:%{public}d, timeZone_:%{public}s", slotId_, timeZone_.c_str());
426     if (timeZone_.empty()) {
427         return;
428     }
429     SaveTimeZone(timeZone_);
430 }
431 } // namespace Telephony
432 } // namespace OHOS
433