• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 #include "ntp_update_time.h"
16 
17 #include "init_param.h"
18 #include "ntp_trusted_time.h"
19 #include "parameters.h"
20 #include "time_system_ability.h"
21 
22 using namespace std::chrono;
23 
24 namespace OHOS {
25 namespace MiscServices {
26 namespace {
27 constexpr int64_t NANO_TO_MILLISECOND = 1000000;
28 constexpr int64_t TWO_SECOND_TO_MILLISECOND = 2000;
29 constexpr int64_t HALF_DAY_TO_MILLISECOND = 43200000;
30 constexpr const char* NTP_SERVER_SYSTEM_PARAMETER = "persist.time.ntpserver";
31 constexpr const char* NTP_SERVER_SPECIFIC_SYSTEM_PARAMETER = "persist.time.ntpserver_specific";
32 constexpr uint32_t NTP_MAX_SIZE = 5;
33 constexpr const char* AUTO_TIME_SYSTEM_PARAMETER = "persist.time.auto_time";
34 constexpr const char* AUTO_TIME_STATUS_ON = "ON";
35 constexpr const char* AUTO_TIME_STATUS_OFF = "OFF";
36 constexpr int64_t ONE_HOUR = 3600000;
37 constexpr const char* DEFAULT_NTP_SERVER = "1.cn.pool.ntp.org";
38 constexpr int32_t RETRY_TIMES = 2;
39 } // namespace
40 
41 AutoTimeInfo NtpUpdateTime::autoTimeInfo_{};
42 std::mutex NtpUpdateTime::requestMutex_;
43 
NtpUpdateTime()44 NtpUpdateTime::NtpUpdateTime() : timerId_(0), nitzUpdateTimeMilli_(0), nextTriggerTime_(0), lastNITZUpdateTime_(0){};
45 
GetInstance()46 NtpUpdateTime& NtpUpdateTime::GetInstance()
47 {
48     static NtpUpdateTime instance;
49     return instance;
50 }
51 
Init()52 void NtpUpdateTime::Init()
53 {
54     TIME_HILOGD(TIME_MODULE_SERVICE, "Ntp Update Time start");
55     std::string ntpServer = system::GetParameter(NTP_SERVER_SYSTEM_PARAMETER, DEFAULT_NTP_SERVER);
56     std::string ntpServerSpec = system::GetParameter(NTP_SERVER_SPECIFIC_SYSTEM_PARAMETER, "");
57     std::string autoTime = system::GetParameter(AUTO_TIME_SYSTEM_PARAMETER, "ON");
58     if ((ntpServer.empty() && ntpServerSpec.empty()) || autoTime.empty()) {
59         TIME_HILOGW(TIME_MODULE_SERVICE, "No found parameter from system parameter");
60         return;
61     }
62     RegisterSystemParameterListener();
63     autoTimeInfo_.ntpServer = ntpServer;
64     autoTimeInfo_.ntpServerSpec = ntpServerSpec;
65     autoTimeInfo_.status = autoTime;
66     auto callback = [this](uint64_t id) -> int32_t {
67         this->RefreshNetworkTimeByTimer(id);
68         return E_TIME_OK;
69     };
70     TimerPara timerPara{};
71     timerPara.timerType = static_cast<int>(ITimerManager::TimerType::ELAPSED_REALTIME);
72     timerPara.windowLength = 0;
73     timerPara.interval = HALF_DAY_TO_MILLISECOND;
74     timerPara.flag = 0;
75     TimeSystemAbility::GetInstance()->CreateTimer(timerPara, callback, timerId_);
76     RefreshNextTriggerTime();
77     TimeSystemAbility::GetInstance()->StartTimer(timerId_, nextTriggerTime_);
78     TIME_HILOGI(TIME_MODULE_SERVICE, "ntp update timerId: %{public}" PRIu64 "triggertime: %{public}" PRId64 "",
79                 timerId_, nextTriggerTime_);
80 }
81 
RefreshNetworkTimeByTimer(uint64_t timerId)82 void NtpUpdateTime::RefreshNetworkTimeByTimer(uint64_t timerId)
83 {
84     TIME_HILOGI(TIME_MODULE_SERVICE, "The timer is up");
85     if (!CheckStatus()) {
86         TIME_HILOGI(TIME_MODULE_SERVICE, "Auto Sync Switch Off");
87         return;
88     }
89 
90     auto setSystemTime = [this]() { this->SetSystemTime(); };
91     std::thread thread(setSystemTime);
92     thread.detach();
93     TIME_HILOGD(TIME_MODULE_SERVICE, "Ntp next triggertime: %{public}" PRId64 "", nextTriggerTime_);
94 }
95 
UpdateNITZSetTime()96 void NtpUpdateTime::UpdateNITZSetTime()
97 {
98     auto bootTimeNano = steady_clock::now().time_since_epoch().count();
99     auto bootTimeMilli = bootTimeNano / NANO_TO_MILLISECOND;
100     if (TimeUtils::GetBootTimeMs(lastNITZUpdateTime_) != ERR_OK) {
101         TIME_HILOGE(TIME_MODULE_SERVICE, "get boot time fail");
102     }
103     TIME_HILOGD(TIME_MODULE_SERVICE, "nitz time changed");
104     nitzUpdateTimeMilli_ = static_cast<uint64_t>(bootTimeMilli);
105 }
106 
SplitNtpAddrs(const std::string & ntpStr)107 std::vector<std::string> NtpUpdateTime::SplitNtpAddrs(const std::string &ntpStr)
108 {
109     std::vector<std::string> ntpList;
110     size_t start = 0;
111     do {
112         if (ntpList.size() == NTP_MAX_SIZE) {
113             break;
114         }
115         size_t end = ntpStr.find(',', start);
116         if (end < start) {
117             break;
118         }
119         std::string temp = ntpStr.substr(start, end - start);
120         if (temp.empty()) {
121             ++start;
122             continue;
123         }
124         if (end == std::string::npos) {
125             ntpList.emplace_back(temp);
126             break;
127         }
128         ntpList.emplace_back(temp);
129         start = end + 1;
130     } while (start < ntpStr.size());
131     return ntpList;
132 }
133 
IsInUpdateInterval()134 bool NtpUpdateTime::IsInUpdateInterval()
135 {
136     // Determine the time interval between two NTP requests sent.
137     int64_t curBootTime = 0;
138     TimeUtils::GetBootTimeMs(curBootTime);
139     auto lastBootTime = NtpTrustedTime::GetInstance().ElapsedRealtimeMillis();
140     // If the time <= ONE_HOUR, do not send NTP requests.
141     if ((lastBootTime > 0) && (curBootTime - lastBootTime <= ONE_HOUR)) {
142         TIME_HILOGI(TIME_MODULE_SERVICE,
143             "ntp updated bootTime: %{public}" PRId64 ", lastBootTime: %{public}" PRId64 "",
144             curBootTime, lastBootTime);
145         return true;
146     }
147     return false;
148 }
149 
GetNtpTimeInner()150 NtpRefreshCode NtpUpdateTime::GetNtpTimeInner()
151 {
152     if (IsInUpdateInterval()) {
153         return NO_NEED_REFRESH;
154     }
155 
156     std::vector<std::string> ntpSpecList = SplitNtpAddrs(autoTimeInfo_.ntpServerSpec);
157     std::vector<std::string> ntpList = SplitNtpAddrs(autoTimeInfo_.ntpServer);
158     ntpSpecList.insert(ntpSpecList.end(), ntpList.begin(), ntpList.end());
159     for (int i = 0; i < RETRY_TIMES; i++) {
160         for (size_t j = 0; j < ntpSpecList.size(); j++) {
161             TIME_HILOGI(TIME_MODULE_SERVICE, "ntpServer is : %{public}s", ntpSpecList[j].c_str());
162             if (NtpTrustedTime::GetInstance().ForceRefresh(ntpSpecList[j])) {
163                 return REFRESH_SUCCESS;
164             }
165         }
166     }
167     return REFRESH_FAILED;
168 }
169 
GetRealTimeInner(int64_t & time)170 bool NtpUpdateTime::GetRealTimeInner(int64_t &time)
171 {
172     time = NtpTrustedTime::GetInstance().CurrentTimeMillis();
173     if (time <= 0) {
174         TIME_HILOGE(TIME_MODULE_SERVICE, "current time is invalid: %{public}" PRId64 "", time);
175         return false;
176     }
177     return true;
178 }
179 
GetRealTime(int64_t & time)180 bool NtpUpdateTime::GetRealTime(int64_t &time)
181 {
182     return GetRealTimeInner(time);
183 }
184 
CheckNeedSetTime(NtpRefreshCode code,int64_t time)185 bool NtpUpdateTime::CheckNeedSetTime(NtpRefreshCode code, int64_t time)
186 {
187     if (code == NO_NEED_REFRESH) {
188         int64_t currentWallTime = 0;
189         if (TimeUtils::GetWallTimeMs(currentWallTime) != ERR_OK) {
190             TIME_HILOGE(TIME_MODULE_SERVICE, "get walltime fail");
191             return false;
192         }
193 
194         if (std::abs(currentWallTime - time) < TWO_SECOND_TO_MILLISECOND) {
195             TIME_HILOGW(TIME_MODULE_SERVICE, "no need to refresh time");
196             return false;
197         }
198     }
199     return true;
200 }
201 
GetNtpTime(int64_t & time)202 bool NtpUpdateTime::GetNtpTime(int64_t &time)
203 {
204     std::lock_guard<std::mutex> autoLock(requestMutex_);
205 
206     auto ret = GetNtpTimeInner();
207     if (ret == REFRESH_FAILED) {
208         TIME_HILOGE(TIME_MODULE_SERVICE, "get ntp time failed");
209         return false;
210     }
211 
212     if (!GetRealTimeInner(time)) {
213         return false;
214     }
215 
216     if (autoTimeInfo_.status == AUTO_TIME_STATUS_ON && CheckNeedSetTime(ret, time)) {
217         TimeSystemAbility::GetInstance()->SetTimeInner(time);
218     }
219     return true;
220 }
221 
SetSystemTime()222 void NtpUpdateTime::SetSystemTime()
223 {
224     if (autoTimeInfo_.status != AUTO_TIME_STATUS_ON) {
225         TIME_HILOGI(TIME_MODULE_SERVICE, "auto sync switch off");
226         return;
227     }
228 
229     if (!requestMutex_.try_lock()) {
230         TIME_HILOGW(TIME_MODULE_SERVICE, "The NTP request is in progress");
231         return;
232     }
233 
234     auto ret = GetNtpTimeInner();
235     if (ret == REFRESH_FAILED) {
236         TIME_HILOGE(TIME_MODULE_SERVICE, "get ntp time failed");
237         requestMutex_.unlock();
238         return;
239     }
240 
241     int64_t currentTime = NtpTrustedTime::GetInstance().CurrentTimeMillis();
242     if (currentTime <= 0) {
243         TIME_HILOGE(TIME_MODULE_SERVICE, "current time is invalid: %{public}" PRIu64 "", currentTime);
244         requestMutex_.unlock();
245         return;
246     }
247     if (!CheckNeedSetTime(ret, currentTime)) {
248         requestMutex_.unlock();
249         return;
250     }
251 
252     TimeSystemAbility::GetInstance()->SetTimeInner(currentTime);
253     requestMutex_.unlock();
254 }
255 
RefreshNextTriggerTime()256 void NtpUpdateTime::RefreshNextTriggerTime()
257 {
258     auto bootTimeNano = steady_clock::now().time_since_epoch().count();
259     auto bootTimeMilli = bootTimeNano / NANO_TO_MILLISECOND;
260     nextTriggerTime_ = static_cast<uint64_t>(bootTimeMilli + HALF_DAY_TO_MILLISECOND);
261 }
262 
CheckStatus()263 bool NtpUpdateTime::CheckStatus()
264 {
265     return autoTimeInfo_.status == AUTO_TIME_STATUS_ON;
266 }
267 
IsValidNITZTime()268 bool NtpUpdateTime::IsValidNITZTime()
269 {
270     if (nitzUpdateTimeMilli_ == 0) {
271         return false;
272     }
273     int64_t bootTimeNano = static_cast<int64_t>(steady_clock::now().time_since_epoch().count());
274     int64_t bootTimeMilli = bootTimeNano / NANO_TO_MILLISECOND;
275     TIME_HILOGI(TIME_MODULE_SERVICE, "nitz update time: %{public}" PRIu64 " currentTime: %{public}" PRId64 "",
276         nitzUpdateTimeMilli_, bootTimeMilli);
277     return (bootTimeMilli - static_cast<int64_t>(nitzUpdateTimeMilli_)) < HALF_DAY_TO_MILLISECOND;
278 }
279 
StartTimer()280 void NtpUpdateTime::StartTimer()
281 {
282     TimeSystemAbility::GetInstance()->StartTimer(timerId_, nextTriggerTime_);
283 }
284 
Stop()285 void NtpUpdateTime::Stop()
286 {
287     TIME_HILOGD(TIME_MODULE_SERVICE, "start");
288     TimeSystemAbility::GetInstance()->DestroyTimer(timerId_);
289 }
290 
RegisterSystemParameterListener()291 void NtpUpdateTime::RegisterSystemParameterListener()
292 {
293     TIME_HILOGD(TIME_MODULE_SERVICE, "register system parameter modify lister");
294     auto specificNtpResult = SystemWatchParameter(NTP_SERVER_SPECIFIC_SYSTEM_PARAMETER,
295                                                   ChangeNtpServerCallback, nullptr);
296     if (specificNtpResult != E_TIME_OK) {
297         TIME_HILOGE(TIME_MODULE_SERVICE, "register specific ntp server lister fail: %{public}d", specificNtpResult);
298     }
299 
300     auto netResult = SystemWatchParameter(NTP_SERVER_SYSTEM_PARAMETER, ChangeNtpServerCallback, nullptr);
301     if (netResult != E_TIME_OK) {
302         TIME_HILOGE(TIME_MODULE_SERVICE, "register ntp server lister fail: %{public}d", netResult);
303     }
304 
305     auto switchResult = SystemWatchParameter(AUTO_TIME_SYSTEM_PARAMETER, ChangeAutoTimeCallback, nullptr);
306     if (switchResult != E_TIME_OK) {
307         TIME_HILOGE(TIME_MODULE_SERVICE, "register auto sync switch lister fail: %{public}d", switchResult);
308     }
309 }
310 
ChangeNtpServerCallback(const char * key,const char * value,void * context)311 void NtpUpdateTime::ChangeNtpServerCallback(const char *key, const char *value, void *context)
312 {
313     TIME_HILOGI(TIME_MODULE_SERVICE, "Ntp server changed");
314     std::string ntpServer = system::GetParameter(NTP_SERVER_SYSTEM_PARAMETER, DEFAULT_NTP_SERVER);
315     std::string ntpServerSpec = system::GetParameter(NTP_SERVER_SPECIFIC_SYSTEM_PARAMETER, "");
316     if (ntpServer.empty() && ntpServerSpec.empty()) {
317         TIME_HILOGW(TIME_MODULE_SERVICE, "No found ntp server from system parameter");
318         return;
319     }
320     autoTimeInfo_.ntpServer = ntpServer;
321     autoTimeInfo_.ntpServerSpec = ntpServerSpec;
322     SetSystemTime();
323 }
324 
ChangeAutoTimeCallback(const char * key,const char * value,void * context)325 void NtpUpdateTime::ChangeAutoTimeCallback(const char *key, const char *value, void *context)
326 {
327     TIME_HILOGI(TIME_MODULE_SERVICE, "Auto sync switch changed");
328     if (key == nullptr || value == nullptr) {
329         TIME_HILOGE(TIME_MODULE_SERVICE, "key or value is nullptr");
330         return;
331     }
332     if (std::string(AUTO_TIME_SYSTEM_PARAMETER).compare(key) != 0) {
333         TIME_HILOGE(TIME_MODULE_SERVICE, "incorrect key:%{public}s", key);
334         return;
335     }
336 
337     if (std::string(AUTO_TIME_STATUS_ON).compare(value) != 0 && std::string(AUTO_TIME_STATUS_OFF).compare(value) != 0) {
338         TIME_HILOGE(TIME_MODULE_SERVICE, "incorrect value:%{public}s", value);
339         return;
340     }
341     autoTimeInfo_.status = std::string(value);
342     SetSystemTime();
343 }
344 
GetNITZUpdateTime()345 uint64_t NtpUpdateTime::GetNITZUpdateTime()
346 {
347     return static_cast<uint64_t>(lastNITZUpdateTime_);
348 }
349 } // namespace MiscServices
350 } // namespace OHOS