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 <chrono>
16 #include <thread>
17 #include <cinttypes>
18 #include <ctime>
19 #include <string>
20 #include <fstream>
21 #include <mutex>
22 #include <unistd.h>
23
24 #include "ntp_trusted_time.h"
25 #include "time_common.h"
26 #include "json/json.h"
27 #include "time_service.h"
28 #include "nitz_subscriber.h"
29 #include "time_zone_info.h"
30 #include "net_conn_callback_observer.h"
31 #include "net_specifier.h"
32 #include "net_conn_client.h"
33 #include "ntp_update_time.h"
34
35 using namespace std::chrono;
36 using namespace OHOS::NetManagerStandard;
37
38 namespace OHOS {
39 namespace MiscServices {
40 namespace {
41 constexpr uint64_t NANO_TO_MILLISECOND = 1000000;
42 constexpr uint64_t DAY_TO_MILLISECOND = 86400000;
43 const std::string AUTOTIME_FILE_PATH = "/data/misc/zoneinfo/autotime.json";
44 const std::string NETWORK_TIME_STATUS_ON = "ON";
45 const std::string NETWORK_TIME_STATUS_OFF = "OFF";
46 const std::string NTP_CN_SERVER = "ntp.aliyun.com";
47 const int64_t INVALID_TIMES = -1;
48 }
49
NtpUpdateTime()50 NtpUpdateTime::NtpUpdateTime() : nitzUpdateTimeMili_(0) {};
~NtpUpdateTime()51 NtpUpdateTime::~NtpUpdateTime() {};
52
Init()53 void NtpUpdateTime::Init()
54 {
55 TIME_HILOGD(TIME_MODULE_SERVICE, "Ntp Update Time start.");
56 SubscriberNITZTimeChangeCommonEvent();
57 if (!GetAutoTimeInfoFromFile(autoTimeInfo_)) {
58 autoTimeInfo_.lastUpdateTime = INVALID_TIMES;
59 autoTimeInfo_.NTP_SERVER = NTP_CN_SERVER;
60 autoTimeInfo_.status = NETWORK_TIME_STATUS_ON;
61 if (!SaveAutoTimeInfoToFile(autoTimeInfo_)) {
62 TIME_HILOGE(TIME_MODULE_SERVICE, "end, SaveAutoTimeInfoToFile failed.");
63 return;
64 }
65 if (!GetAutoTimeInfoFromFile(autoTimeInfo_)) {
66 TIME_HILOGE(TIME_MODULE_SERVICE, "end, GetAutoTimeInfoFromFile failed.");
67 return;
68 }
69 }
70
71 std::thread th = std::thread([this]() {
72 constexpr int RETRY_MAX_TIMES = 100;
73 int retryCount = 0;
74 constexpr int RETRY_TIME_INTERVAL_MILLISECOND = 1 * 1000 * 1000; // retry after 2 second
75 do {
76 if (this->MonitorNetwork() == NET_CONN_SUCCESS) {
77 break;
78 }
79 retryCount++;
80 usleep(RETRY_TIME_INTERVAL_MILLISECOND);
81 } while (retryCount < RETRY_MAX_TIMES);
82 });
83 th.detach();
84
85 int32_t timerType = ITimerManager::TimerType::ELAPSED_REALTIME;
86 auto callback = [this](uint64_t id) {
87 this->RefreshNetworkTimeByTimer(id);
88 };
89 timerId_ = TimeService::GetInstance()->CreateTimer(timerType, 0, DAY_TO_MILLISECOND, 0, callback);
90 TIME_HILOGD(TIME_MODULE_SERVICE, "Ntp update timerId: %{public}" PRId64 "", timerId_);
91 RefreshNextTriggerTime();
92 TIME_HILOGD(TIME_MODULE_SERVICE, "Ntp update triggertime: %{public}" PRId64 "", nextTriggerTime_);
93 TimeService::GetInstance()->StartTimer(timerId_, nextTriggerTime_);
94 }
95
MonitorNetwork()96 int32_t NtpUpdateTime::MonitorNetwork()
97 {
98 // observer net connection
99 TIME_HILOGD(TIME_MODULE_SERVICE, "NtpUpdateTime::MonitorNetwork");
100 NetSpecifier netSpecifier;
101 NetAllCapabilities netAllCapabilities;
102 netAllCapabilities.netCaps_.insert(NetManagerStandard::NetCap::NET_CAPABILITY_INTERNET);
103 netSpecifier.netCapabilities_ = netAllCapabilities;
104 sptr<NetSpecifier> specifier = new(std::nothrow) NetSpecifier(netSpecifier);
105 if (specifier == nullptr) {
106 TIME_HILOGD(TIME_MODULE_SERVICE, "new operator error.specifier is nullptr");
107 return NET_CONN_ERR_INPUT_NULL_PTR;
108 }
109 sptr<NetConnCallbackObserver> observer = new(std::nothrow) NetConnCallbackObserver();
110 if (observer == nullptr) {
111 TIME_HILOGD(TIME_MODULE_SERVICE, "new operator error.observer is nullptr");
112 return NET_CONN_ERR_INPUT_NULL_PTR;
113 }
114 int nRet = DelayedSingleton<NetConnClient>::GetInstance()->RegisterNetConnCallback(specifier, observer, 0);
115 TIME_HILOGD(TIME_MODULE_SERVICE, "RegisterNetConnCallback retcode= %{public}d", nRet);
116
117 return nRet;
118 }
119
SubscriberNITZTimeChangeCommonEvent()120 void NtpUpdateTime::SubscriberNITZTimeChangeCommonEvent()
121 {
122 // Broadcast subscription
123 MatchingSkills matchingSkills;
124 matchingSkills.AddEvent(CommonEventSupport::COMMON_EVENT_NITZ_TIME_UPDATED);
125 CommonEventSubscribeInfo subscriberInfo(matchingSkills);
126 std::shared_ptr<NITZSubscriber> subscriberPtr =
127 std::make_shared<NITZSubscriber>(subscriberInfo);
128 if (subscriberPtr != nullptr) {
129 bool subscribeResult = CommonEventManager::SubscribeCommonEvent(subscriberPtr);
130 if (!subscribeResult) {
131 TIME_HILOGE(TIME_MODULE_SERVICE, "SubscribeCommonEvent failed");
132 }
133 }
134 }
135
RefreshNetworkTimeByTimer(const uint64_t timerId)136 void NtpUpdateTime::RefreshNetworkTimeByTimer(const uint64_t timerId)
137 {
138 if (!(CheckStatus())) {
139 TIME_HILOGD(TIME_MODULE_SERVICE, "Network time status off.");
140 return;
141 }
142
143 SetSystemTime();
144 SaveAutoTimeInfoToFile(autoTimeInfo_);
145 TIME_HILOGD(TIME_MODULE_SERVICE, "Ntp update triggertime: %{public}" PRId64 "", nextTriggerTime_);
146 }
147
UpdateNITZSetTime()148 void NtpUpdateTime::UpdateNITZSetTime()
149 {
150 auto BootTimeNano = steady_clock::now().time_since_epoch().count();
151 auto BootTimeMilli = BootTimeNano / NANO_TO_MILLISECOND;
152 TIME_HILOGD(TIME_MODULE_SERVICE, "nitz time changed.");
153 nitzUpdateTimeMili_ = BootTimeMilli;
154 }
155
SetSystemTime()156 void NtpUpdateTime::SetSystemTime()
157 {
158 TIME_HILOGD(TIME_MODULE_SERVICE, "start.");
159 if (IsNITZTimeInvalid()) {
160 TIME_HILOGD(TIME_MODULE_SERVICE, "NITZ Time is valid.");
161 return;
162 }
163 if (!DelayedSingleton<NtpTrustedTime>::GetInstance()->ForceRefresh(autoTimeInfo_.NTP_SERVER)) {
164 TIME_HILOGE(TIME_MODULE_SERVICE, "get ntp time failed.");
165 return;
166 }
167 int64_t currentTime = DelayedSingleton<NtpTrustedTime>::GetInstance()->CurrentTimeMillis();
168 if (currentTime == INVALID_TIMES) {
169 TIME_HILOGD(TIME_MODULE_SERVICE, "Ntp update time failed");
170 return;
171 }
172 if (currentTime <= 0) {
173 TIME_HILOGD(TIME_MODULE_SERVICE, "current time invalid.");
174 return;
175 }
176 TIME_HILOGD(TIME_MODULE_SERVICE, "Ntp UTC Time: %{public}" PRId64 "", currentTime);
177 auto timeOffsetMs = DelayedSingleton<TimeZoneInfo>::GetInstance()->GetCurrentOffsetMs();
178 currentTime = currentTime + timeOffsetMs;
179 TIME_HILOGD(TIME_MODULE_SERVICE, "Ntp UTC+TIMEZONE tTime: %{public}" PRId64 "", currentTime);
180
181 TimeService::GetInstance()->SetTime(currentTime);
182 autoTimeInfo_.lastUpdateTime = currentTime;
183 TIME_HILOGD(TIME_MODULE_SERVICE, "Ntp update currentTime: %{public}" PRId64 "", currentTime);
184 TIME_HILOGD(TIME_MODULE_SERVICE, "end.");
185 }
186
RefreshNextTriggerTime()187 void NtpUpdateTime::RefreshNextTriggerTime()
188 {
189 auto BootTimeNano = steady_clock::now().time_since_epoch().count();
190 auto BootTimeMilli = BootTimeNano / NANO_TO_MILLISECOND;
191 nextTriggerTime_ = BootTimeMilli + DAY_TO_MILLISECOND;
192 }
193
UpdateStatusOff()194 void NtpUpdateTime::UpdateStatusOff()
195 {
196 TIME_HILOGD(TIME_MODULE_SERVICE, "start");
197 autoTimeInfo_.lastUpdateTime = INVALID_TIMES;
198 autoTimeInfo_.NTP_SERVER = NTP_CN_SERVER;
199 autoTimeInfo_.status = NETWORK_TIME_STATUS_OFF;
200 if (!SaveAutoTimeInfoToFile(autoTimeInfo_)) {
201 TIME_HILOGE(TIME_MODULE_SERVICE, "end, SaveAutoTimeInfoToFile failed.");
202 }
203 TIME_HILOGD(TIME_MODULE_SERVICE, "end");
204 }
205
UpdateStatusOn()206 void NtpUpdateTime::UpdateStatusOn()
207 {
208 TIME_HILOGD(TIME_MODULE_SERVICE, "start");
209 if (CheckStatus()) {
210 TIME_HILOGD(TIME_MODULE_SERVICE, "network update time status is already on.");
211 return;
212 }
213 SetSystemTime();
214 autoTimeInfo_.status = NETWORK_TIME_STATUS_ON;
215 if (!SaveAutoTimeInfoToFile(autoTimeInfo_)) {
216 TIME_HILOGE(TIME_MODULE_SERVICE, "end, SaveAutoTimeInfoToFile failed.");
217 }
218 TIME_HILOGD(TIME_MODULE_SERVICE, "end");
219 }
220
CheckStatus()221 bool NtpUpdateTime::CheckStatus()
222 {
223 return autoTimeInfo_.status == NETWORK_TIME_STATUS_ON;
224 }
225
IsNITZTimeInvalid()226 bool NtpUpdateTime::IsNITZTimeInvalid()
227 {
228 if (nitzUpdateTimeMili_ == 0) {
229 return false;
230 }
231 auto BootTimeNano = steady_clock::now().time_since_epoch().count();
232 auto BootTimeMilli = BootTimeNano / NANO_TO_MILLISECOND;
233 return (BootTimeMilli - nitzUpdateTimeMili_) < DAY_TO_MILLISECOND;
234 }
235
StartTimer()236 void NtpUpdateTime::StartTimer()
237 {
238 TimeService::GetInstance()->StartTimer(timerId_, nextTriggerTime_);
239 }
240
Stop()241 void NtpUpdateTime::Stop()
242 {
243 TIME_HILOGD(TIME_MODULE_SERVICE, "start.");
244 TimeService::GetInstance()->DestroyTimer(timerId_);
245 }
246
GetAutoTimeInfoFromFile(autoTimeInfo & info)247 bool NtpUpdateTime::GetAutoTimeInfoFromFile(autoTimeInfo &info)
248 {
249 Json::Value jsonValue;
250 std::ifstream ifs;
251 ifs.open(AUTOTIME_FILE_PATH);
252 Json::CharReaderBuilder builder;
253 builder["collectComments"] = true;
254 JSONCPP_STRING errs;
255 if (!parseFromStream(builder, ifs, &jsonValue, &errs)) {
256 ifs.close();
257 TIME_HILOGE(TIME_MODULE_SERVICE, "Read file failed %{public}s.", errs.c_str());
258 return false;
259 }
260 info.status = jsonValue["status"].asString();
261 info.NTP_SERVER = jsonValue["ntpServer"].asString();
262 info.lastUpdateTime = jsonValue["lastUpdateTime"].asInt64();
263 TIME_HILOGD(TIME_MODULE_SERVICE, "Read file %{public}s.", info.status.c_str());
264 TIME_HILOGD(TIME_MODULE_SERVICE, "Read file %{public}s.", info.NTP_SERVER.c_str());
265 TIME_HILOGD(TIME_MODULE_SERVICE, "Read file %{public}" PRId64 "", info.lastUpdateTime);
266 ifs.close();
267 return true;
268 }
269
SaveAutoTimeInfoToFile(autoTimeInfo & info)270 bool NtpUpdateTime::SaveAutoTimeInfoToFile(autoTimeInfo &info)
271 {
272 Json::Value jsonValue;
273 std::ofstream ofs;
274 ofs.open(AUTOTIME_FILE_PATH);
275 jsonValue["status"] = info.status;
276 jsonValue["ntpServer"] = info.NTP_SERVER;
277 jsonValue["lastUpdateTime"] = info.lastUpdateTime;
278 Json::StreamWriterBuilder builder;
279 const std::string json_file = Json::writeString(builder, jsonValue);
280 ofs << json_file;
281 ofs.close();
282 TIME_HILOGD(TIME_MODULE_SERVICE, "Write file %{public}s.", info.status.c_str());
283 TIME_HILOGD(TIME_MODULE_SERVICE, "Write file %{public}s.", info.NTP_SERVER.c_str());
284 TIME_HILOGD(TIME_MODULE_SERVICE, "Write file %{public}" PRId64 "", info.lastUpdateTime);
285 return true;
286 }
287 } // MiscServices
288 } // OHOS