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