1 /*
2 * Copyright (c) 2021 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 "time_tick_monitor.h"
17
18 #include "db_errno.h"
19 #include "log_print.h"
20
21 namespace DistributedDB {
TimeTickMonitor()22 TimeTickMonitor::TimeTickMonitor()
23 : timeChangedNotifier_(nullptr),
24 runtimeCxt_(nullptr),
25 monitorTimerId_(0),
26 monitorCallback_(0),
27 lastMonotonicTime_(0),
28 lastSystemTime_(0),
29 isStarted_(false)
30 {
31 }
32
~TimeTickMonitor()33 TimeTickMonitor::~TimeTickMonitor()
34 {
35 StopTimeTickMonitor();
36 runtimeCxt_ = nullptr;
37 }
38
StartTimeTickMonitor()39 int TimeTickMonitor::StartTimeTickMonitor()
40 {
41 if (isStarted_) {
42 return E_OK;
43 }
44
45 int errCode = PrepareNotifierChain();
46 if (errCode != E_OK) {
47 return errCode;
48 }
49
50 lastMonotonicTime_ = GetMonotonicTime();
51 lastSystemTime_ = GetSysCurrentTime();
52 monitorCallback_ = [this](TimerId timerId) { return TimeTick(timerId); };
53 runtimeCxt_ = RuntimeContext::GetInstance();
54 monitorTimerId_ = 0;
55 errCode = runtimeCxt_->SetTimer(MONITOR_INTERVAL, monitorCallback_, nullptr, monitorTimerId_);
56 if (errCode != E_OK) {
57 return errCode;
58 }
59 isStarted_ = true;
60 return E_OK;
61 }
62
StopTimeTickMonitor()63 void TimeTickMonitor::StopTimeTickMonitor()
64 {
65 if (!isStarted_) {
66 return;
67 }
68
69 NotificationChain *notifier;
70 {
71 std::lock_guard<std::mutex> autoLock(timeTickMonitorLock_);
72 notifier = timeChangedNotifier_;
73 timeChangedNotifier_ = nullptr;
74 }
75 if (notifier != nullptr) {
76 notifier->UnRegisterEventType(TIME_CHANGE_EVENT);
77 RefObject::KillAndDecObjRef(notifier);
78 }
79 runtimeCxt_->RemoveTimer(monitorTimerId_, true);
80 isStarted_ = false;
81 }
82
RegisterTimeChangedLister(const TimeChangedAction & action,const TimeFinalizeAction & finalize,int & errCode)83 NotificationChain::Listener *TimeTickMonitor::RegisterTimeChangedLister(const TimeChangedAction &action,
84 const TimeFinalizeAction &finalize, int &errCode)
85 {
86 if (timeChangedNotifier_ == nullptr) {
87 errCode = -E_NOT_INIT;
88 return nullptr;
89 }
90
91 if (action == nullptr) {
92 errCode = -E_INVALID_ARGS;
93 return nullptr;
94 }
95
96 return timeChangedNotifier_->RegisterListener(TIME_CHANGE_EVENT, action, finalize, errCode);
97 }
98
PrepareNotifierChain()99 int TimeTickMonitor::PrepareNotifierChain()
100 {
101 std::lock_guard<std::mutex> autoLock(timeTickMonitorLock_);
102 if (timeChangedNotifier_ != nullptr) {
103 return E_OK;
104 }
105
106 timeChangedNotifier_ = new (std::nothrow) NotificationChain();
107 if (timeChangedNotifier_ == nullptr) {
108 return -E_OUT_OF_MEMORY;
109 }
110
111 int errCode = timeChangedNotifier_->RegisterEventType(TIME_CHANGE_EVENT);
112 if (errCode != E_OK) {
113 RefObject::KillAndDecObjRef(timeChangedNotifier_);
114 timeChangedNotifier_ = nullptr;
115 }
116 return errCode;
117 }
118
TimeTick(TimerId timerId)119 int TimeTickMonitor::TimeTick(TimerId timerId)
120 {
121 if (timerId != monitorTimerId_) {
122 return -E_INVALID_ARGS;
123 }
124
125 uint64_t monotonicTime = GetMonotonicTime();
126 uint64_t systemTime = GetSysCurrentTime();
127 int64_t monotonicOffset = static_cast<int64_t>(monotonicTime - lastMonotonicTime_);
128 int64_t systemOffset = static_cast<int64_t>(systemTime - lastSystemTime_);
129 lastMonotonicTime_ = monotonicTime;
130 lastSystemTime_ = systemTime;
131 int64_t changedOffset = systemOffset - monotonicOffset;
132 if (std::abs(changedOffset) > MAX_NOISE) {
133 LOGI("Local system time may be changed! changedOffset %ld", changedOffset);
134 RuntimeContext::GetInstance()->RecordAllTimeChange();
135 RuntimeContext::GetInstance()->ClearAllDeviceTimeInfo();
136 NotificationChain *notifier = nullptr;
137 {
138 std::lock_guard<std::mutex> autoLock(timeTickMonitorLock_);
139 notifier = timeChangedNotifier_;
140 RefObject::IncObjRef(notifier);
141 }
142 int ret = RuntimeContext::GetInstance()->ScheduleTask([notifier, changedOffset]() {
143 if (notifier == nullptr) {
144 return;
145 }
146 int64_t offset = changedOffset;
147 notifier->NotifyEvent(TIME_CHANGE_EVENT, &offset);
148 RefObject::DecObjRef(notifier);
149 });
150 if (ret != E_OK) {
151 LOGE("TimeTickMonitor ScheduleTask failed %d", ret);
152 }
153 timeChanged_ = true;
154 }
155 return E_OK;
156 }
157
GetSysCurrentTime()158 Timestamp TimeTickMonitor::GetSysCurrentTime()
159 {
160 uint64_t curTime = 0;
161 int errCode = OS::GetCurrentSysTimeInMicrosecond(curTime);
162 if (errCode != E_OK) {
163 LOGE("TimeTickMonitor:get system time failed!");
164 return INVALID_TIMESTAMP;
165 }
166 return curTime;
167 }
168
GetMonotonicTime()169 Timestamp TimeTickMonitor::GetMonotonicTime()
170 {
171 uint64_t time;
172 int errCode = OS::GetMonotonicRelativeTimeInMicrosecond(time);
173 if (errCode != E_OK) {
174 LOGE("GetMonotonicTime ERR! err = %d", errCode);
175 return INVALID_TIMESTAMP;
176 }
177 return time;
178 }
179
NotifyTimeChange(TimeOffset offset) const180 void TimeTickMonitor::NotifyTimeChange(TimeOffset offset) const
181 {
182 std::lock_guard<std::mutex> lock(timeTickMonitorLock_);
183 if (timeChangedNotifier_ == nullptr) {
184 LOGD("NotifyTimeChange fail, timeChangedNotifier_ is null.");
185 return;
186 }
187 timeChangedNotifier_->NotifyEvent(TIME_CHANGE_EVENT, static_cast<void *>(&offset));
188 }
189
EmptyListener() const190 bool TimeTickMonitor::EmptyListener() const
191 {
192 std::lock_guard<std::mutex> lock(timeTickMonitorLock_);
193 return timeChangedNotifier_->EmptyListener(TIME_CHANGE_EVENT);
194 }
195
IsTimeChanged() const196 bool TimeTickMonitor::IsTimeChanged() const
197 {
198 return timeChanged_;
199 }
200
SetTimeChanged(bool timeChange)201 void TimeTickMonitor::SetTimeChanged(bool timeChange)
202 {
203 timeChanged_ = timeChange;
204 }
205 } // namespace DistributedDB