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