1 /*
2 * Copyright (c) 2024 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 "alarm_timer_manager.h"
17
18 #include <array>
19 #include <cstdint>
20 #include <ctime>
21 #include <sys/time.h>
22 #include <cinttypes>
23 #include "ui_appearance_log.h"
24
25 namespace OHOS {
26 namespace ArkUi::UiAppearance {
27 constexpr int32_t DAY_TO_SECOND = 24 * 60 * 60;
28 constexpr int32_t DAY_TO_MINUTE = 24 * 60;
29 constexpr int32_t SECOND_TO_MILLI = 1000;
30 constexpr int32_t HOUR_TO_MINUTE = 60;
31 constexpr int32_t MINUTE_TO_SECOND = 60;
32 constexpr int32_t TIMER_TYPE_EXACT = 2 | 4;
33 constexpr int32_t START_INDEX = 0;
34 constexpr int32_t END_INDEX = 1;
35
SetScheduleTime(const uint64_t startTime,const uint64_t endTime,const uint32_t userId,const std::function<void ()> & startCallback,const std::function<void ()> & endCallback)36 ErrCode AlarmTimerManager::SetScheduleTime(const uint64_t startTime, const uint64_t endTime,
37 const uint32_t userId, const std::function<void()>& startCallback, const std::function<void()>& endCallback)
38 {
39 std::lock_guard<std::mutex> lock(timerMapMutex_);
40 if (!IsValidScheduleTime(startTime, endTime)) {
41 LOGE("userId:%{public}d, start %{public}" PRIu64 ", end %{public}" PRIu64, userId, startTime, endTime);
42 return ERR_INVALID_VALUE;
43 }
44 RecordInitialSetupTime(startTime, endTime, userId);
45 std::array<uint64_t, TRIGGER_ARRAY_SIZE> triggerTimeInterval = { 0, 0 };
46 SetTimerTriggerTime(startTime, endTime, triggerTimeInterval);
47 LOGI("userId: %{public}d, in %{public}" PRIu64 " %{public}" PRIu64 ", trigger %{public}" PRIu64 " %{public}" PRIu64,
48 userId, startTime, endTime, triggerTimeInterval[START_INDEX], triggerTimeInterval[END_INDEX]);
49 SetTimer(0, userId, triggerTimeInterval[START_INDEX], startCallback);
50 SetTimer(1, userId, triggerTimeInterval[END_INDEX], endCallback);
51 if (timerIdMap_[userId][START_INDEX] == 0 || timerIdMap_[userId][END_INDEX] == 0) {
52 LOGE("set timer fail, timerId: %{public}" PRIu64 " %{public}" PRIu64,
53 timerIdMap_[userId][START_INDEX], timerIdMap_[userId][END_INDEX]);
54 return ERR_INVALID_OPERATION;
55 }
56 LOGI("set timer success, timerId: %{public}" PRIu64 " %{public}" PRIu64,
57 timerIdMap_[userId][START_INDEX], timerIdMap_[userId][END_INDEX]);
58 return ERR_OK;
59 }
60
IsValidScheduleTime(const uint64_t startTime,const uint64_t endTime)61 bool AlarmTimerManager::IsValidScheduleTime(const uint64_t startTime, const uint64_t endTime)
62 {
63 if (startTime >= endTime) {
64 LOGE("startTime >= endTime");
65 return false;
66 }
67
68 if (startTime >= DAY_TO_MINUTE) {
69 LOGE("startTime >= DAY_TO_MINUTE");
70 return false;
71 }
72
73 if (endTime >= DAY_TO_MINUTE + startTime) {
74 LOGE("endTime >= DAY_TO_MINUTE + startTime");
75 return false;
76 }
77
78 return true;
79 }
80
SetTimerTriggerTime(const uint64_t startTime,const uint64_t endTime,std::array<uint64_t,TRIGGER_ARRAY_SIZE> & triggerTimeInterval)81 void AlarmTimerManager::SetTimerTriggerTime(const uint64_t startTime, const uint64_t endTime,
82 std::array<uint64_t, TRIGGER_ARRAY_SIZE>& triggerTimeInterval)
83 {
84 std::time_t timestamp = std::time(nullptr);
85 if (timestamp == static_cast<std::time_t>(-1)) {
86 LOGE("fail to get timestamp");
87 }
88 std::tm* nowTime = std::localtime(×tamp);
89 if (nowTime != nullptr) {
90 nowTime->tm_hour = 0;
91 nowTime->tm_min = 0;
92 nowTime->tm_sec = 0;
93 }
94 std::time_t nowZero = std::mktime(nowTime);
95 uint64_t curTimestamp = static_cast<uint64_t>(timestamp * SECOND_TO_MILLI);
96 uint64_t zeroTimestamp = static_cast<uint64_t>(nowZero * SECOND_TO_MILLI);
97 uint64_t startTimestamp = zeroTimestamp + startTime * MINUTE_TO_SECOND * SECOND_TO_MILLI;
98 uint64_t endTimestamp = zeroTimestamp + endTime * MINUTE_TO_SECOND * SECOND_TO_MILLI;
99
100 uint64_t step = DAY_TO_SECOND * SECOND_TO_MILLI;
101 if (curTimestamp <= startTimestamp) {
102 if (curTimestamp < endTimestamp - step) {
103 triggerTimeInterval = { startTimestamp, endTimestamp - step };
104 } else {
105 triggerTimeInterval = { startTimestamp, endTimestamp };
106 }
107 } else if (curTimestamp >= endTimestamp) {
108 triggerTimeInterval = { startTimestamp + step, endTimestamp + step };
109 } else {
110 triggerTimeInterval = { startTimestamp + step, endTimestamp };
111 }
112 }
113
Dump()114 void AlarmTimerManager::Dump()
115 {
116 std::lock_guard<std::mutex> lock(timerMapMutex_);
117 LOGD("timerIdMap size: %{public}zu", timerIdMap_.size());
118 for (const auto& it : timerIdMap_) {
119 LOGD("userId:%{public}d, start %{public}" PRIu64 ", end %{public}" PRIu64,
120 it.first, it.second[0], it.second[1]);
121 }
122 LOGD("initialSetupTimeMap size: %{public}zu", initialSetupTimeMap_.size());
123 for (const auto& it : initialSetupTimeMap_) {
124 LOGD("userId:%{public}d, start %{public}" PRIu64 ", end %{public}" PRIu64,
125 it.first, it.second[0], it.second[1]);
126 }
127 }
128
SetTimer(const int8_t index,const uint32_t userId,const uint64_t time,const std::function<void ()> & callback)129 void AlarmTimerManager::SetTimer(const int8_t index, const uint32_t userId, const uint64_t time,
130 const std::function<void()>& callback)
131 {
132 LOGD("SetTimer %{public}d %{public}d %{public}" PRIu64, index, userId, time);
133 if (timerIdMap_.find(userId) == timerIdMap_.end()) {
134 std::array<uint64_t, TRIGGER_ARRAY_SIZE> timerIds = { 0, 0 };
135 timerIdMap_[userId] = timerIds;
136 }
137
138 if (timerIdMap_[userId][index] > 0) {
139 timerIdMap_[userId][index] = UpdateTimer(timerIdMap_[userId][index], time, callback);
140 } else {
141 timerIdMap_[userId][index] = InitTimer(time, callback);
142 }
143 }
144
InitTimer(const uint64_t time,const std::function<void ()> & callback)145 uint64_t AlarmTimerManager::InitTimer(const uint64_t time, const std::function<void()>& callback)
146 {
147 auto timerInfo = std::make_shared<AlarmTimer>();
148 timerInfo->SetType(TIMER_TYPE_EXACT);
149 timerInfo->SetRepeat(true);
150 timerInfo->SetInterval(DAY_TO_SECOND * SECOND_TO_MILLI);
151 timerInfo->SetCallbackInfo(callback);
152 uint64_t id = static_cast<uint64_t>(MiscServices::TimeServiceClient::GetInstance()->CreateTimer(timerInfo));
153 if (id <= 0) {
154 LOGE("fail to create timer %{public}" PRIu64, id);
155 return 0;
156 }
157 bool ret = MiscServices::TimeServiceClient::GetInstance()->StartTimer(id, time);
158 if (!ret) {
159 LOGE("fail to StartTimer timer %{public}" PRIu64, id);
160 ClearTimer(id);
161 return 0;
162 }
163 return id;
164 }
165
ClearTimer(const uint64_t id)166 void AlarmTimerManager::ClearTimer(const uint64_t id)
167 {
168 if (id <= 0) {
169 LOGE("id <= 0: %{public}" PRIu64, id);
170 return;
171 }
172
173 bool ret = MiscServices::TimeServiceClient::GetInstance()->DestroyTimer(id);
174 if (!ret) {
175 LOGE("fail to DestroyTimer timer %{public}" PRIu64, id);
176 }
177 }
178
UpdateTimer(const uint64_t id,const uint64_t time,const std::function<void ()> & callback)179 uint64_t AlarmTimerManager::UpdateTimer(const uint64_t id, const uint64_t time,
180 const std::function<void()>& callback)
181 {
182 ClearTimer(id);
183 return InitTimer(time, callback);
184 }
185
ClearTimerByUserId(const uint64_t userId)186 void AlarmTimerManager::ClearTimerByUserId(const uint64_t userId)
187 {
188 std::lock_guard<std::mutex> lock(timerMapMutex_);
189 if (timerIdMap_.find(userId) == timerIdMap_.end()) {
190 LOGE("timerIdMap_ fail to find Timer: %{public}" PRIu64, userId);
191 return;
192 }
193
194 ClearTimer(timerIdMap_[userId][START_INDEX]);
195 ClearTimer(timerIdMap_[userId][END_INDEX]);
196 timerIdMap_.erase(userId);
197
198 if (initialSetupTimeMap_.find(userId) == initialSetupTimeMap_.end()) {
199 LOGE("initialSetupTimeMap_ fail to find Timer: %{public}" PRIu64, userId);
200 }
201 initialSetupTimeMap_.erase(userId);
202 }
203
IsWithinTimeInterval(const uint64_t startTime,const uint64_t endTime)204 bool AlarmTimerManager::IsWithinTimeInterval(const uint64_t startTime, const uint64_t endTime)
205 {
206 std::time_t timestamp = std::time(nullptr);
207 if (timestamp == static_cast<std::time_t>(-1)) {
208 LOGE("fail to get timestamp");
209 return false;
210 }
211 std::tm* nowTime = std::localtime(×tamp);
212 uint32_t totalMinutes{ 0 };
213 if (nowTime != nullptr) {
214 totalMinutes = static_cast<uint32_t>(nowTime->tm_hour * HOUR_TO_MINUTE + nowTime->tm_min);
215 }
216
217 if (endTime <= DAY_TO_MINUTE) {
218 return (startTime <= totalMinutes && totalMinutes < endTime);
219 } else {
220 if ((endTime - DAY_TO_MINUTE) <= totalMinutes && totalMinutes < startTime) {
221 return false;
222 }
223 return true;
224 }
225 }
226
RecordInitialSetupTime(const uint64_t startTime,const uint64_t endTime,const uint32_t userId)227 void AlarmTimerManager::RecordInitialSetupTime(const uint64_t startTime, const uint64_t endTime,
228 const uint32_t userId)
229 {
230 std::array<uint64_t, TRIGGER_ARRAY_SIZE> initialSetupTime = { startTime, endTime };
231 initialSetupTimeMap_[userId] = initialSetupTime;
232 }
233
RestartTimerByUserId(const uint64_t userId)234 bool AlarmTimerManager::RestartTimerByUserId(const uint64_t userId)
235 {
236 if (userId == 0) {
237 LOGE("userId == 0");
238 return false;
239 }
240
241 if (timerIdMap_.find(userId) == timerIdMap_.end()
242 || initialSetupTimeMap_.find(userId) == initialSetupTimeMap_.end()) {
243 LOGE("initialSetupTimeMap_ or timerIdMap_ fail to find Timer: %{public}" PRIu64, userId);
244 return false;
245 }
246
247 LOGI("RestartTimerByUserId userId: %{public}" PRIu64, userId);
248 std::array<uint64_t, TRIGGER_ARRAY_SIZE> triggerTimeInterval = { 0, 0 };
249 SetTimerTriggerTime(initialSetupTimeMap_[userId][START_INDEX],
250 initialSetupTimeMap_[userId][END_INDEX], triggerTimeInterval);
251
252 RestartTimerByTimerId(timerIdMap_[userId][START_INDEX], triggerTimeInterval[START_INDEX]);
253 RestartTimerByTimerId(timerIdMap_[userId][END_INDEX], triggerTimeInterval[END_INDEX]);
254
255 return true;
256 }
257
RestartTimerByTimerId(const uint64_t timerId,const uint64_t time)258 void AlarmTimerManager::RestartTimerByTimerId(const uint64_t timerId, const uint64_t time)
259 {
260 LOGI("RestartTimerByTimerId timerId: %{public}" PRIu64 " timer: %{public}" PRIu64, timerId, time);
261 MiscServices::TimeServiceClient::GetInstance()->StopTimer(timerId);
262 MiscServices::TimeServiceClient::GetInstance()->StartTimer(timerId, time);
263 }
264
RestartAllTimer()265 bool AlarmTimerManager::RestartAllTimer()
266 {
267 std::lock_guard<std::mutex> lock(timerMapMutex_);
268 bool res = true;
269 for (const auto& pair : timerIdMap_) {
270 uint64_t userId = pair.first;
271 if (userId == 0) {
272 LOGE("userId == 0: %{public}" PRIu64, userId);
273 continue;
274 }
275 res = res && RestartTimerByUserId(userId);
276 }
277
278 return res;
279 }
280 } // namespace ArkUi::UiAppearance
281 } // namespace OHOS
282