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(&timestamp);
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(&timestamp);
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