1 /*
2 * Copyright (C) 2023-2023 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 <string>
17 #include <cinttypes>
18
19 #include "timer_proxy.h"
20 #include "time_hilog.h"
21
22 namespace OHOS {
23 namespace MiscServices {
24 using namespace std::chrono;
25 using namespace OHOS::AppExecFwk;
26
27 namespace {
28 constexpr int MILLI_TO_SECOND = 1000;
29 /* ms for 3 days */
30 constexpr int64_t PROXY_DELAY_TIME_IN_MILLI = 3 * 24 * 60 * 60 * 1000;
31 }
32
IMPLEMENT_SINGLE_INSTANCE(TimerProxy)33 IMPLEMENT_SINGLE_INSTANCE(TimerProxy)
34
35 void TimerProxy::RemoveProxy(uint64_t timerNumber, int32_t uid)
36 {
37 std::lock_guard<std::mutex> lock(proxyMutex_);
38 auto itMap = proxyMap_.find(uid);
39 if (itMap != proxyMap_.end()) {
40 auto alarms = itMap->second;
41 for (auto itAlarm = alarms.begin(); itAlarm != alarms.end();) {
42 if ((*itAlarm)->id == timerNumber) {
43 alarms.erase(itAlarm);
44 }
45 itAlarm++;
46 }
47 if (alarms.empty()) {
48 proxyMap_.erase(uid);
49 }
50 }
51 }
52
CallbackAlarmIfNeed(const std::shared_ptr<TimerInfo> & alarm)53 void TimerProxy::CallbackAlarmIfNeed(const std::shared_ptr<TimerInfo> &alarm)
54 {
55 if (alarm == nullptr) {
56 TIME_HILOGE(TIME_MODULE_SERVICE, "callback alarm is nullptr!");
57 return;
58 }
59
60 int uid = alarm->uid;
61 std::lock_guard<std::mutex> lock(proxyMutex_);
62 auto it = proxyUids_.find(uid);
63 if (it == proxyUids_.end()) {
64 alarm->callback(alarm->id);
65 TIME_HILOGI(TIME_MODULE_SERVICE, "Trigger id: %{public}" PRId64 "", alarm->id);
66 return;
67 }
68
69 TIME_HILOGD(TIME_MODULE_SERVICE, "Alarm is proxy!");
70 auto itMap = proxyMap_.find(uid);
71 if (itMap == proxyMap_.end()) {
72 std::vector<std::shared_ptr<TimerInfo>> timeInfoVec;
73 timeInfoVec.push_back(alarm);
74 proxyMap_[uid] = timeInfoVec;
75 } else {
76 std::vector<std::shared_ptr<TimerInfo>> timeInfoVec = itMap->second;
77 timeInfoVec.push_back(alarm);
78 proxyMap_[uid] = timeInfoVec;
79 }
80 }
81
ProxyTimer(int32_t uid,bool isProxy,bool needRetrigger,const std::chrono::steady_clock::time_point & now,std::function<void (std::shared_ptr<TimerInfo> & alarm)> insertAlarmCallback)82 bool TimerProxy::ProxyTimer(int32_t uid, bool isProxy, bool needRetrigger,
83 const std::chrono::steady_clock::time_point &now,
84 std::function<void(std::shared_ptr<TimerInfo> &alarm)> insertAlarmCallback)
85 {
86 TIME_HILOGD(TIME_MODULE_SERVICE, "start. uid=%{public}d, isProxy=%{public}u, needRetrigger=%{public}u",
87 uid, isProxy, needRetrigger);
88 if (isProxy) {
89 UpdateProxyWhenElapsedForProxyUidMap(uid, now, insertAlarmCallback);
90 return true;
91 }
92 if (!RestoreProxyWhenElapsedForProxyUidMap(uid, now, insertAlarmCallback)) {
93 TIME_HILOGE(TIME_MODULE_SERVICE, "Uid: %{public}d doesn't exist in the proxy list." PRId64 "", uid);
94 return false;
95 }
96
97 if (!needRetrigger) {
98 TIME_HILOGI(TIME_MODULE_SERVICE, "ProxyTimer doesn't need retrigger, clear all callbacks!");
99 proxyMap_.erase(uid);
100 return true;
101 }
102 auto itMap = proxyMap_.find(uid);
103 if (itMap != proxyMap_.end()) {
104 auto timeInfoVec = itMap->second;
105 for (const auto& alarm : timeInfoVec) {
106 if (!alarm->callback) {
107 TIME_HILOGE(TIME_MODULE_SERVICE, "ProxyTimer Callback is nullptr!");
108 continue;
109 }
110 alarm->callback(alarm->id);
111 TIME_HILOGD(TIME_MODULE_SERVICE, "Shut down proxy, proxyUid: %{public}d, alarmId: %{public}" PRId64 "",
112 uid, alarm->id);
113 }
114 timeInfoVec.clear();
115 proxyMap_.erase(uid);
116 }
117 return true;
118 }
119
ResetProxyMaps()120 void TimerProxy::ResetProxyMaps()
121 {
122 std::lock_guard<std::mutex> lock(proxyMutex_);
123 for (auto it = proxyMap_.begin(); it != proxyMap_.end(); it++) {
124 auto timeInfoVec = it->second;
125 for (const auto& alarm : timeInfoVec) {
126 if (!alarm->callback) {
127 TIME_HILOGE(TIME_MODULE_SERVICE, "Callback is nullptr!");
128 continue;
129 }
130 alarm->callback(alarm->id);
131 TIME_HILOGD(TIME_MODULE_SERVICE, "Reset all proxy, proxyUid: %{public}d, alarmId: %{public}" PRId64 "",
132 it->first, alarm->id);
133 }
134 timeInfoVec.clear();
135 }
136 proxyMap_.clear();
137 }
138
ResetAllProxy(const std::chrono::steady_clock::time_point & now,std::function<void (std::shared_ptr<TimerInfo> & alarm)> insertAlarmCallback)139 bool TimerProxy::ResetAllProxy(const std::chrono::steady_clock::time_point &now,
140 std::function<void(std::shared_ptr<TimerInfo> &alarm)> insertAlarmCallback)
141 {
142 TIME_HILOGD(TIME_MODULE_SERVICE, "start");
143 ResetProxyMaps();
144 ResetAllProxyWhenElapsed(now, insertAlarmCallback);
145 return true;
146 }
147
EraseTimerFromProxyUidMap(const uint64_t id,const uint32_t uid)148 void TimerProxy::EraseTimerFromProxyUidMap(const uint64_t id, const uint32_t uid)
149 {
150 TIME_HILOGD(TIME_MODULE_SERVICE, "erase timer from proxy timer map, id=%{public}" PRId64 ", uid=%{public}u",
151 id, uid);
152 std::lock_guard<std::mutex> lock(proxyMutex_);
153 auto it = proxyUids_.find(uid);
154 if (it != proxyUids_.end()) {
155 it->second.erase(id);
156 }
157 }
158
EraseAlarmItem(const uint64_t id,std::unordered_map<uint64_t,std::shared_ptr<TimerInfo>> & idAlarmsMap)159 void TimerProxy::EraseAlarmItem(
160 const uint64_t id, std::unordered_map<uint64_t, std::shared_ptr<TimerInfo>> &idAlarmsMap)
161 {
162 auto itAlarms = idAlarmsMap.find(id);
163 if (itAlarms != idAlarmsMap.end()) {
164 TIME_HILOGD(TIME_MODULE_SERVICE, "timer already exists, id=%{public}" PRId64 "", id);
165 idAlarmsMap.erase(itAlarms);
166 }
167 }
168
RecordUidTimerMap(const std::shared_ptr<TimerInfo> & alarm,const bool isRebatched)169 void TimerProxy::RecordUidTimerMap(const std::shared_ptr<TimerInfo> &alarm, const bool isRebatched)
170 {
171 if (isRebatched) {
172 TIME_HILOGD(TIME_MODULE_SERVICE, "Record uid timer info map, isRebatched: %{public}d", isRebatched);
173 return;
174 }
175 if (alarm == nullptr) {
176 TIME_HILOGE(TIME_MODULE_SERVICE, "record uid timer map alarm is nullptr!");
177 return;
178 }
179
180 std::lock_guard<std::mutex> lock(uidTimersMutex_);
181 auto it = uidTimersMap_.find(alarm->uid);
182 if (it == uidTimersMap_.end()) {
183 std::unordered_map<uint64_t, std::shared_ptr<TimerInfo>> idAlarmsMap;
184 idAlarmsMap.insert(std::make_pair(alarm->id, alarm));
185 uidTimersMap_.insert(std::make_pair(alarm->uid, idAlarmsMap));
186 return;
187 }
188
189 EraseAlarmItem(alarm->id, it->second);
190 it->second.insert(std::make_pair(alarm->id, alarm));
191 }
192
RemoveUidTimerMap(const std::shared_ptr<TimerInfo> & alarm)193 void TimerProxy::RemoveUidTimerMap(const std::shared_ptr<TimerInfo> &alarm)
194 {
195 if (alarm == nullptr) {
196 TIME_HILOGE(TIME_MODULE_SERVICE, "remove uid timer map alarm is nullptr!");
197 return;
198 }
199
200 std::lock_guard<std::mutex> lock(uidTimersMutex_);
201 auto it = uidTimersMap_.find(alarm->uid);
202 if (it == uidTimersMap_.end()) {
203 return;
204 }
205
206 EraseAlarmItem(alarm->id, it->second);
207 if (it->second.empty()) {
208 uidTimersMap_.erase(it);
209 }
210 }
211
RemoveUidTimerMap(const uint64_t id)212 void TimerProxy::RemoveUidTimerMap(const uint64_t id)
213 {
214 std::lock_guard<std::mutex> lock(uidTimersMutex_);
215 for (auto itUidsTimer = uidTimersMap_.begin(); itUidsTimer!= uidTimersMap_.end(); ++itUidsTimer) {
216 for (auto itTimerId = itUidsTimer->second.begin(); itTimerId!= itUidsTimer->second.end(); ++itTimerId) {
217 if (itTimerId->first != id) {
218 continue;
219 }
220
221 itUidsTimer->second.erase(itTimerId);
222 if (itUidsTimer->second.empty()) {
223 uidTimersMap_.erase(itUidsTimer);
224 }
225 return;
226 }
227 }
228 }
229
IsUidProxy(const int32_t uid)230 bool TimerProxy::IsUidProxy(const int32_t uid)
231 {
232 std::lock_guard<std::mutex> lock(proxyMutex_);
233 auto it = proxyUids_.find(uid);
234 if (it == proxyUids_.end()) {
235 return false;
236 }
237 return true;
238 }
239
UpdateProxyWhenElapsedForProxyUidMap(const int32_t uid,const std::chrono::steady_clock::time_point & now,std::function<void (std::shared_ptr<TimerInfo> & alarm)> insertAlarmCallback)240 void TimerProxy::UpdateProxyWhenElapsedForProxyUidMap(const int32_t uid,
241 const std::chrono::steady_clock::time_point &now,
242 std::function<void(std::shared_ptr<TimerInfo> &alarm)> insertAlarmCallback)
243 {
244 std::lock_guard<std::mutex> lockProxy(proxyMutex_);
245 auto it = proxyUids_.find(uid);
246 if (it != proxyUids_.end()) {
247 TIME_HILOGI(TIME_MODULE_SERVICE, "uid is already proxy, uid: %{public}d", uid);
248 return;
249 }
250
251 std::lock_guard<std::mutex> lockUidTimers(uidTimersMutex_);
252 if (uidTimersMap_.find(uid) == uidTimersMap_.end()) {
253 TIME_HILOGI(TIME_MODULE_SERVICE, "uid timer info map not found, uid: %{public}d", uid);
254 std::unordered_map<uint64_t, std::chrono::steady_clock::time_point> timePointMap {};
255 proxyUids_.insert(std::make_pair(uid, timePointMap));
256 return;
257 }
258
259 std::unordered_map<uint64_t, std::chrono::steady_clock::time_point> timePointMap {};
260 for (auto itUidTimersMap = uidTimersMap_.at(uid).begin(); itUidTimersMap!= uidTimersMap_.at(uid).end();
261 ++itUidTimersMap) {
262 timePointMap.insert(std::make_pair(itUidTimersMap->first, itUidTimersMap->second->whenElapsed));
263 itUidTimersMap->second->UpdateWhenElapsed(now, milliseconds(proxyDelayTime_));
264 TIME_HILOGD(TIME_MODULE_SERVICE, "Update proxy WhenElapsed for proxy uid map. "
265 "uid= %{public}d, id=%{public}" PRId64 ", timer whenElapsed=%{public}lld, now=%{public}lld",
266 itUidTimersMap->second->uid, itUidTimersMap->second->id,
267 itUidTimersMap->second->whenElapsed.time_since_epoch().count(),
268 now.time_since_epoch().count());
269 insertAlarmCallback(itUidTimersMap->second);
270 }
271 proxyUids_.insert(std::make_pair(uid, timePointMap));
272 }
273
RestoreProxyWhenElapsedByUid(const int32_t uid,const std::chrono::steady_clock::time_point & now,std::function<void (std::shared_ptr<TimerInfo> & alarm)> insertAlarmCallback)274 bool TimerProxy::RestoreProxyWhenElapsedByUid(const int32_t uid,
275 const std::chrono::steady_clock::time_point &now,
276 std::function<void(std::shared_ptr<TimerInfo> &alarm)> insertAlarmCallback)
277 {
278 auto it = proxyUids_.find(uid);
279 if (it == proxyUids_.end()) {
280 TIME_HILOGI(TIME_MODULE_SERVICE, "Uid: %{public}d doesn't exist in the proxy list.", uid);
281 return false;
282 }
283
284 std::lock_guard<std::mutex> lockUidTimers(uidTimersMutex_);
285 if (uidTimersMap_.find(uid) == uidTimersMap_.end()) {
286 TIME_HILOGI(TIME_MODULE_SERVICE, "uid timer info map not found, just erase proxy map. uid: %{public}d", uid);
287 return true;
288 }
289
290 for (auto itProxyUids = proxyUids_.at(uid).begin(); itProxyUids != proxyUids_.at(uid).end(); ++itProxyUids) {
291 auto itTimerInfo = uidTimersMap_.at(uid).find(itProxyUids->first);
292 if (itTimerInfo == uidTimersMap_.at(uid).end()) {
293 continue;
294 }
295 if (itProxyUids->second > now + milliseconds(MILLI_TO_SECOND)) {
296 itTimerInfo->second->UpdateWhenElapsed(itProxyUids->second, milliseconds(0));
297 } else {
298 itTimerInfo->second->UpdateWhenElapsed(now, milliseconds(MILLI_TO_SECOND));
299 }
300 TIME_HILOGD(TIME_MODULE_SERVICE, "Restore proxy WhenElapsed by uid. "
301 "uid= %{public}d, id=%{public}" PRId64 ", timer whenElapsed=%{public}lld, now=%{public}lld",
302 itTimerInfo->second->uid, itTimerInfo->second->id,
303 itTimerInfo->second->whenElapsed.time_since_epoch().count(),
304 now.time_since_epoch().count());
305 insertAlarmCallback(itTimerInfo->second);
306 }
307
308 return true;
309 }
310
RestoreProxyWhenElapsedForProxyUidMap(const int32_t uid,const std::chrono::steady_clock::time_point & now,std::function<void (std::shared_ptr<TimerInfo> & alarm)> insertAlarmCallback)311 bool TimerProxy::RestoreProxyWhenElapsedForProxyUidMap(const int32_t uid,
312 const std::chrono::steady_clock::time_point &now,
313 std::function<void(std::shared_ptr<TimerInfo> &alarm)> insertAlarmCallback)
314 {
315 std::lock_guard<std::mutex> lockProxy(proxyMutex_);
316 bool ret = RestoreProxyWhenElapsedByUid(uid, now, insertAlarmCallback);
317 if (ret) {
318 proxyUids_.erase(uid);
319 }
320 return ret;
321 }
322
ResetAllProxyWhenElapsed(const std::chrono::steady_clock::time_point & now,std::function<void (std::shared_ptr<TimerInfo> & alarm)> insertAlarmCallback)323 void TimerProxy::ResetAllProxyWhenElapsed(const std::chrono::steady_clock::time_point &now,
324 std::function<void(std::shared_ptr<TimerInfo> &alarm)> insertAlarmCallback)
325 {
326 std::lock_guard<std::mutex> lockProxy(proxyMutex_);
327 for (auto it = proxyUids_.begin(); it != proxyUids_.end(); ++it) {
328 RestoreProxyWhenElapsedByUid(it->first, now, insertAlarmCallback);
329 }
330 proxyUids_.clear();
331 }
332
ShowProxyTimerInfo(int fd,const int64_t now)333 bool TimerProxy::ShowProxyTimerInfo(int fd, const int64_t now)
334 {
335 TIME_HILOGD(TIME_MODULE_SERVICE, "start.");
336 std::lock_guard<std::mutex> lockProxy(proxyMutex_);
337 dprintf(fd, "current time %lld\n", now);
338 for (auto itProxyUids = proxyUids_.begin(); itProxyUids != proxyUids_.end(); ++itProxyUids) {
339 dprintf(fd, " - proxy uid = %lu\n", itProxyUids->first);
340 for (auto itTimerIdMap = itProxyUids->second.begin(); itTimerIdMap != itProxyUids->second.end();
341 ++itTimerIdMap) {
342 dprintf(fd, " * save timer id = %llu\n", itTimerIdMap->first);
343 dprintf(fd, " * save timer whenElapsed = %lld\n", itTimerIdMap->second.time_since_epoch().count());
344 }
345 }
346 TIME_HILOGD(TIME_MODULE_SERVICE, "end.");
347 return true;
348 }
349
ShowUidTimerMapInfo(int fd,const int64_t now)350 bool TimerProxy::ShowUidTimerMapInfo(int fd, const int64_t now)
351 {
352 TIME_HILOGD(TIME_MODULE_SERVICE, "start.");
353 std::lock_guard<std::mutex> lockProxy(uidTimersMutex_);
354 dprintf(fd, "current time %lld\n", now);
355 for (auto itTimerInfoMap = uidTimersMap_.begin(); itTimerInfoMap != uidTimersMap_.end(); ++itTimerInfoMap) {
356 dprintf(fd, " - uid = %lu\n", itTimerInfoMap->first);
357 for (auto itTimerInfo = itTimerInfoMap->second.begin(); itTimerInfo != itTimerInfoMap->second.end();
358 ++itTimerInfo) {
359 dprintf(fd, " * timer id = %llu\n", itTimerInfo->second->id);
360 dprintf(fd, " * timer whenElapsed = %lld\n", itTimerInfo->second->whenElapsed.time_since_epoch().count());
361 }
362 }
363 TIME_HILOGD(TIME_MODULE_SERVICE, "end.");
364 return true;
365 }
366
SetProxyDelayTime(int fd,const int64_t proxyDelayTime)367 bool TimerProxy::SetProxyDelayTime(int fd, const int64_t proxyDelayTime)
368 {
369 TIME_HILOGD(TIME_MODULE_SERVICE, "start.");
370 if (proxyDelayTime < 0) {
371 dprintf(fd, "set proxy delay time err: %lld\n", proxyDelayTime);
372 TIME_HILOGD(TIME_MODULE_SERVICE, "err.");
373 return true;
374 }
375
376 if (proxyDelayTime == 0) {
377 proxyDelayTime_ = PROXY_DELAY_TIME_IN_MILLI;
378 } else {
379 proxyDelayTime_ = proxyDelayTime;
380 }
381 dprintf(fd, "proxy delay time is set to %lld ms\n", proxyDelayTime_);
382
383 TIME_HILOGD(TIME_MODULE_SERVICE, "end.");
384 return true;
385 }
386
ShowProxyDelayTime(int fd)387 bool TimerProxy::ShowProxyDelayTime(int fd)
388 {
389 TIME_HILOGD(TIME_MODULE_SERVICE, "start.");
390 dprintf(fd, "proxy delay time: %lld ms\n", proxyDelayTime_);
391 TIME_HILOGD(TIME_MODULE_SERVICE, "end.");
392 return true;
393 }
394
GetProxyDelayTime() const395 int64_t TimerProxy::GetProxyDelayTime() const
396 {
397 return proxyDelayTime_;
398 }
399 } // MiscServices
400 } // OHOS