1 /*
2  * Copyright (c) 2021-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 
16 #include "timer_manager.h"
17 
18 #undef MMI_LOG_TAG
19 #define MMI_LOG_TAG "TimerManager"
20 #undef MMI_LOG_DOMAIN
21 #define MMI_LOG_DOMAIN MMI_LOG_SERVER
22 
23 namespace OHOS {
24 namespace MMI {
25 namespace {
26 constexpr int32_t MIN_DELAY { -1 };
27 constexpr int32_t MIN_INTERVAL { 36 };
28 constexpr int32_t MAX_INTERVAL_MS { 10000 };
29 constexpr int32_t MAX_TIMER_COUNT { 64 };
30 constexpr int32_t NONEXISTENT_ID { -1 };
31 } // namespace
32 
TimerManager()33 TimerManager::TimerManager() {}
~TimerManager()34 TimerManager::~TimerManager() {}
35 
AddTimer(int32_t intervalMs,int32_t repeatCount,std::function<void ()> callback)36 int32_t TimerManager::AddTimer(int32_t intervalMs, int32_t repeatCount, std::function<void()> callback)
37 {
38     return AddTimerInternal(intervalMs, repeatCount, callback);
39 }
40 
RemoveTimer(int32_t timerId)41 int32_t TimerManager::RemoveTimer(int32_t timerId)
42 {
43     return RemoveTimerInternal(timerId);
44 }
45 
ResetTimer(int32_t timerId)46 int32_t TimerManager::ResetTimer(int32_t timerId)
47 {
48     return ResetTimerInternal(timerId);
49 }
50 
IsExist(int32_t timerId)51 bool TimerManager::IsExist(int32_t timerId)
52 {
53     return IsExistInternal(timerId);
54 }
55 
CalcNextDelay()56 int32_t TimerManager::CalcNextDelay()
57 {
58     return CalcNextDelayInternal();
59 }
60 
ProcessTimers()61 void TimerManager::ProcessTimers()
62 {
63     ProcessTimersInternal();
64 }
65 
TakeNextTimerId()66 int32_t TimerManager::TakeNextTimerId()
67 {
68     uint64_t timerSlot = 0;
69     uint64_t one = 1;
70     std::lock_guard<std::recursive_mutex> lock(timerMutex_);
71     for (const auto &timer : timers_) {
72         timerSlot |= (one << timer->id);
73     }
74 
75     for (int32_t i = 0; i < MAX_TIMER_COUNT; i++) {
76         if ((timerSlot & (one << i)) == 0) {
77             return i;
78         }
79     }
80     return NONEXISTENT_ID;
81 }
82 
AddTimerInternal(int32_t intervalMs,int32_t repeatCount,std::function<void ()> callback)83 int32_t TimerManager::AddTimerInternal(int32_t intervalMs, int32_t repeatCount, std::function<void()> callback)
84 {
85     if (intervalMs < MIN_INTERVAL) {
86         intervalMs = MIN_INTERVAL;
87     } else if (intervalMs > MAX_INTERVAL_MS) {
88         intervalMs = MAX_INTERVAL_MS;
89     }
90     if (!callback) {
91         return NONEXISTENT_ID;
92     }
93     int32_t timerId = TakeNextTimerId();
94     if (timerId < 0) {
95         return NONEXISTENT_ID;
96     }
97     auto timer = std::make_unique<TimerItem>();
98     timer->id = timerId;
99     timer->intervalMs = intervalMs;
100     timer->repeatCount = repeatCount;
101     timer->callbackCount = 0;
102     auto nowTime = GetMillisTime();
103     if (!AddInt64(nowTime, timer->intervalMs, timer->nextCallTime)) {
104         MMI_HILOGE("The addition of nextCallTime in TimerItem overflows");
105         return NONEXISTENT_ID;
106     }
107     timer->callback = callback;
108     InsertTimerInternal(timer);
109     return timerId;
110 }
111 
RemoveTimerInternal(int32_t timerId)112 int32_t TimerManager::RemoveTimerInternal(int32_t timerId)
113 {
114     std::lock_guard<std::recursive_mutex> lock(timerMutex_);
115     for (auto it = timers_.begin(); it != timers_.end(); ++it) {
116         if ((*it)->id == timerId) {
117             timers_.erase(it);
118             return RET_OK;
119         }
120     }
121     return RET_ERR;
122 }
123 
ResetTimerInternal(int32_t timerId)124 int32_t TimerManager::ResetTimerInternal(int32_t timerId)
125 {
126     std::lock_guard<std::recursive_mutex> lock(timerMutex_);
127     for (auto it = timers_.begin(); it != timers_.end(); ++it) {
128         if ((*it)->id == timerId) {
129             auto timer = std::move(*it);
130             timers_.erase(it);
131             auto nowTime = GetMillisTime();
132             if (!AddInt64(nowTime, timer->intervalMs, timer->nextCallTime)) {
133                 MMI_HILOGE("The addition of nextCallTime in TimerItem overflows");
134                 return RET_ERR;
135             }
136             timer->callbackCount = 0;
137             InsertTimerInternal(timer);
138             return RET_OK;
139         }
140     }
141     return RET_ERR;
142 }
143 
IsExistInternal(int32_t timerId)144 bool TimerManager::IsExistInternal(int32_t timerId)
145 {
146     std::lock_guard<std::recursive_mutex> lock(timerMutex_);
147     for (auto it = timers_.begin(); it != timers_.end(); ++it) {
148         if ((*it)->id == timerId) {
149             return true;
150         }
151     }
152     return false;
153 }
154 
InsertTimerInternal(std::unique_ptr<TimerItem> & timer)155 void TimerManager::InsertTimerInternal(std::unique_ptr<TimerItem>& timer)
156 {
157     std::lock_guard<std::recursive_mutex> lock(timerMutex_);
158     for (auto it = timers_.begin(); it != timers_.end(); ++it) {
159         if ((*it)->nextCallTime > timer->nextCallTime) {
160             timers_.insert(it, std::move(timer));
161             return;
162         }
163     }
164     timers_.push_back(std::move(timer));
165 }
166 
CalcNextDelayInternal()167 int32_t TimerManager::CalcNextDelayInternal()
168 {
169     auto delay = MIN_DELAY;
170     std::lock_guard<std::recursive_mutex> lock(timerMutex_);
171     if (!timers_.empty()) {
172         auto nowTime = GetMillisTime();
173         const auto& item = *timers_.begin();
174         if (nowTime >= item->nextCallTime) {
175             delay = 0;
176         } else {
177             delay = item->nextCallTime - nowTime;
178         }
179     }
180     return delay;
181 }
182 
ProcessTimersInternal()183 void TimerManager::ProcessTimersInternal()
184 {
185     std::lock_guard<std::recursive_mutex> lock(timerMutex_);
186     if (timers_.empty()) {
187         return;
188     }
189     auto nowTime = GetMillisTime();
190     for (;;) {
191         auto it = timers_.begin();
192         if (it == timers_.end()) {
193             break;
194         }
195         if ((*it)->nextCallTime > nowTime) {
196             break;
197         }
198         auto curTimer = std::move(*it);
199         timers_.erase(it);
200         ++curTimer->callbackCount;
201         if ((curTimer->repeatCount >= 1) && (curTimer->callbackCount >= curTimer->repeatCount)) {
202             curTimer->callback();
203             continue;
204         }
205         if (!AddInt64(curTimer->nextCallTime, curTimer->intervalMs, curTimer->nextCallTime)) {
206             MMI_HILOGE("The addition of nextCallTime in TimerItem overflows");
207             return;
208         }
209         auto callback = curTimer->callback;
210         InsertTimerInternal(curTimer);
211         callback();
212     }
213 }
214 } // namespace MMI
215 } // namespace OHOS
216