1 /*
2  * Copyright (c) 2022-2023 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 "timer_manager.h"
17 
18 #include <numeric>
19 
20 #include <sys/timerfd.h>
21 
22 #include "devicestatus_define.h"
23 #include "fi_log.h"
24 #include "include/util.h"
25 
26 #undef LOG_TAG
27 #define LOG_TAG "TimerManager"
28 
29 namespace OHOS {
30 namespace Msdp {
31 namespace DeviceStatus {
32 namespace {
33 constexpr int32_t MIN_DELAY { -1 };
34 constexpr int32_t NONEXISTENT_ID { -1 };
35 constexpr int32_t MIN_INTERVAL { 50 };
36 constexpr int32_t TIME_CONVERSION { 1000 };
37 constexpr int32_t MAX_INTERVAL_MS { 10000 };
38 constexpr size_t MAX_TIMER_COUNT { 64 };
39 } // namespace
40 
OnInit(IContext * context)41 int32_t TimerManager::OnInit(IContext *context)
42 {
43     CHKPR(context, RET_ERR);
44     context_ = context;
45 
46     timerFd_ = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
47     if (timerFd_ < 0) {
48         FI_HILOGE("timerfd_create failed");
49         return RET_ERR;
50     }
51     return RET_OK;
52 }
53 
Init(IContext * context)54 int32_t TimerManager::Init(IContext *context)
55 {
56     CHKPR(context, RET_ERR);
57     return context->GetDelegateTasks().PostSyncTask([this, context] {
58         return this->OnInit(context);
59     });
60 }
61 
OnAddTimer(int32_t intervalMs,int32_t repeatCount,std::function<void ()> callback)62 int32_t TimerManager::OnAddTimer(int32_t intervalMs, int32_t repeatCount, std::function<void()> callback)
63 {
64     int32_t timerId = AddTimerInternal(intervalMs, repeatCount, callback);
65     ArmTimer();
66     return timerId;
67 }
68 
AddTimer(int32_t intervalMs,int32_t repeatCount,std::function<void ()> callback)69 int32_t TimerManager::AddTimer(int32_t intervalMs, int32_t repeatCount, std::function<void()> callback)
70 {
71     CALL_DEBUG_ENTER;
72     CHKPR(context_, RET_ERR);
73     return context_->GetDelegateTasks().PostSyncTask([this, intervalMs, repeatCount, callback] {
74         return this->OnAddTimer(intervalMs, repeatCount, callback);
75     });
76 }
77 
OnRemoveTimer(int32_t timerId)78 int32_t TimerManager::OnRemoveTimer(int32_t timerId)
79 {
80     int32_t ret = RemoveTimerInternal(timerId);
81     if (ret == RET_OK) {
82         ArmTimer();
83     }
84     return ret;
85 }
86 
RemoveTimer(int32_t timerId)87 int32_t TimerManager::RemoveTimer(int32_t timerId)
88 {
89     CALL_DEBUG_ENTER;
90     CHKPR(context_, RET_ERR);
91     return context_->GetDelegateTasks().PostSyncTask([this, timerId] {
92         return this->OnRemoveTimer(timerId);
93     });
94 }
95 
OnResetTimer(int32_t timerId)96 int32_t TimerManager::OnResetTimer(int32_t timerId)
97 {
98     int32_t ret = ResetTimerInternal(timerId);
99     ArmTimer();
100     return ret;
101 }
102 
ResetTimer(int32_t timerId)103 int32_t TimerManager::ResetTimer(int32_t timerId)
104 {
105     CALL_INFO_TRACE;
106     CHKPR(context_, RET_ERR);
107     return context_->GetDelegateTasks().PostSyncTask([this, timerId] {
108         return this->OnResetTimer(timerId);
109     });
110 }
111 
OnIsExist(int32_t timerId) const112 bool TimerManager::OnIsExist(int32_t timerId) const
113 {
114     for (auto iter = timers_.begin(); iter != timers_.end(); ++iter) {
115         if ((*iter)->id == timerId) {
116             return true;
117         }
118     }
119     return false;
120 }
121 
IsExist(int32_t timerId) const122 bool TimerManager::IsExist(int32_t timerId) const
123 {
124     CHKPR(context_, false);
125     std::packaged_task<bool(int32_t)> task { [this](int32_t timerId) {
126         return this->OnIsExist(timerId);
127     } };
128     auto fu = task.get_future();
129 
130     int32_t ret = context_->GetDelegateTasks().PostSyncTask([this, &task, timerId] {
131         return this->RunIsExist(std::ref(task), timerId);
132     });
133     if (ret != RET_OK) {
134         FI_HILOGE("Post task failed");
135         return false;
136     }
137     return fu.get();
138 }
139 
OnProcessTimers()140 int32_t TimerManager::OnProcessTimers()
141 {
142     ProcessTimersInternal();
143     ArmTimer();
144     return RET_OK;
145 }
146 
ProcessTimers()147 void TimerManager::ProcessTimers()
148 {
149     CALL_DEBUG_ENTER;
150     CHKPV(context_);
151     context_->GetDelegateTasks().PostAsyncTask([this] {
152         return this->OnProcessTimers();
153     });
154 }
155 
RunIsExist(std::packaged_task<bool (int32_t)> & task,int32_t timerId) const156 int32_t TimerManager::RunIsExist(std::packaged_task<bool(int32_t)> &task, int32_t timerId) const
157 {
158     task(timerId);
159     return RET_OK;
160 }
161 
TakeNextTimerId()162 int32_t TimerManager::TakeNextTimerId()
163 {
164     uint64_t timerSlot = std::accumulate(timers_.cbegin(), timers_.cend(), uint64_t(0U),
165         [] (uint64_t s, const auto &timer) {
166             return (s |= (uint64_t(1U) << timer->id));
167         });
168     for (size_t tmpCount = 0; tmpCount < MAX_TIMER_COUNT; ++tmpCount) {
169         if ((timerSlot & (uint64_t(1U) << tmpCount)) == 0) {
170             return tmpCount;
171         }
172     }
173     return NONEXISTENT_ID;
174 }
175 
AddTimerInternal(int32_t intervalMs,int32_t repeatCount,std::function<void ()> callback)176 int32_t TimerManager::AddTimerInternal(int32_t intervalMs, int32_t repeatCount, std::function<void()> callback)
177 {
178     CALL_DEBUG_ENTER;
179     if (intervalMs < MIN_INTERVAL) {
180         intervalMs = MIN_INTERVAL;
181     } else if (intervalMs > MAX_INTERVAL_MS) {
182         intervalMs = MAX_INTERVAL_MS;
183     }
184     if (!callback) {
185         return NONEXISTENT_ID;
186     }
187     int32_t nextTimerId = TakeNextTimerId();
188     if (nextTimerId < 0) {
189         return NONEXISTENT_ID;
190     }
191     auto timer = std::make_unique<TimerItem>();
192     timer->id = nextTimerId;
193     timer->repeatCount = repeatCount;
194     timer->intervalMs = intervalMs;
195     timer->callbackCount = 0;
196     int64_t nowTime = GetMillisTime();
197     if (!AddInt64(nowTime, timer->intervalMs, timer->nextCallTime)) {
198         FI_HILOGE("The addition of nextCallTime in TimerItem overflows");
199         return NONEXISTENT_ID;
200     }
201     timer->callback = callback;
202     InsertTimerInternal(timer);
203     return nextTimerId;
204 }
205 
RemoveTimerInternal(int32_t timerId)206 int32_t TimerManager::RemoveTimerInternal(int32_t timerId)
207 {
208     for (auto iter = timers_.begin(); iter != timers_.end(); ++iter) {
209         if ((*iter)->id == timerId) {
210             timers_.erase(iter);
211             return RET_OK;
212         }
213     }
214     return RET_ERR;
215 }
216 
ResetTimerInternal(int32_t timerId)217 int32_t TimerManager::ResetTimerInternal(int32_t timerId)
218 {
219     for (auto iter = timers_.begin(); iter!= timers_.end(); ++iter) {
220         if ((*iter)->id == timerId) {
221             auto timer = std::move(*iter);
222             timers_.erase(iter);
223             int64_t nowTime = GetMillisTime();
224             if (!AddInt64(nowTime, timer->intervalMs, timer->nextCallTime)) {
225                 FI_HILOGE("The addition of nextCallTime in TimerItem overflows");
226                 return RET_ERR;
227             }
228             timer->callbackCount = 0;
229             InsertTimerInternal(timer);
230             return RET_OK;
231         }
232     }
233     return RET_ERR;
234 }
235 
InsertTimerInternal(std::unique_ptr<TimerItem> & timer)236 void TimerManager::InsertTimerInternal(std::unique_ptr<TimerItem> &timer)
237 {
238     for (auto iter = timers_.begin(); iter != timers_.end(); ++iter) {
239         if ((*iter)->nextCallTime > timer->nextCallTime) {
240             timers_.insert(iter, std::move(timer));
241             return;
242         }
243     }
244     timers_.push_back(std::move(timer));
245 }
246 
CalcNextDelayInternal()247 int64_t TimerManager::CalcNextDelayInternal()
248 {
249     int64_t delayTime = MIN_DELAY;
250     if (!timers_.empty()) {
251         int64_t nowTime = GetMillisTime();
252         const auto &items = *timers_.begin();
253         if (nowTime >= items->nextCallTime) {
254             delayTime = 0;
255         } else {
256             delayTime = items->nextCallTime - nowTime;
257         }
258     }
259     return delayTime;
260 }
261 
ProcessTimersInternal()262 void TimerManager::ProcessTimersInternal()
263 {
264     if (timers_.empty()) {
265         return;
266     }
267     int64_t presentTime = GetMillisTime();
268     for (;;) {
269         auto tIter = timers_.begin();
270         if (tIter == timers_.end()) {
271             break;
272         }
273         if ((*tIter)->nextCallTime > presentTime) {
274             break;
275         }
276         auto currentTimer = std::move(*tIter);
277         timers_.erase(tIter);
278         ++currentTimer->callbackCount;
279         if ((currentTimer->repeatCount >= 1) && (currentTimer->callbackCount >= currentTimer->repeatCount)) {
280             currentTimer->callback();
281             continue;
282         }
283         if (!AddInt64(currentTimer->nextCallTime, currentTimer->intervalMs, currentTimer->nextCallTime)) {
284             FI_HILOGE("The addition of nextCallTime in TimerItem overflows");
285             return;
286         }
287         auto callback = currentTimer->callback;
288         InsertTimerInternal(currentTimer);
289         callback();
290     }
291 }
292 
ArmTimer()293 int32_t TimerManager::ArmTimer()
294 {
295     CALL_DEBUG_ENTER;
296     if (timerFd_ < 0) {
297         FI_HILOGE("TimerManager is not initialized");
298         return RET_ERR;
299     }
300     struct itimerspec tspec {};
301     int64_t expire = CalcNextDelayInternal();
302     FI_HILOGI("The next expire %{public}" PRId64, expire);
303 
304     if (expire == 0) {
305         expire = 1;
306     }
307     if (expire > 0) {
308         tspec.it_value.tv_sec = expire / TIME_CONVERSION;
309         tspec.it_value.tv_nsec = (expire % TIME_CONVERSION) * TIME_CONVERSION * TIME_CONVERSION;
310     }
311 
312     if (timerfd_settime(timerFd_, 0, &tspec, NULL) != 0) {
313         FI_HILOGE("Timer: the timerfd_settime is error");
314         return RET_ERR;
315     }
316     return RET_OK;
317 }
318 } // namespace DeviceStatus
319 } // namespace Msdp
320 } // namespace OHOS
321