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