• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&timestamp);
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(&timestamp);
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