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