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 <cinttypes>
17
18 #include "timer_proxy.h"
19
20 namespace OHOS {
21 namespace MiscServices {
22 using namespace std::chrono;
23 using namespace OHOS::AppExecFwk;
24
25 namespace {
26 constexpr int UID_PROXY_OFFSET = 32;
27 constexpr const char* NO_LOG_APP = "wifi_manager_service";
28 }
29
IMPLEMENT_SINGLE_INSTANCE(TimerProxy)30 IMPLEMENT_SINGLE_INSTANCE(TimerProxy)
31
32 uint64_t GetProxyKey(int uid, int pid)
33 {
34 uint64_t key = (static_cast<uint64_t>(uid) << UID_PROXY_OFFSET) | static_cast<uint64_t>(pid);
35 return key;
36 }
37
ParseProxyKey(uint64_t key)38 std::pair<int, int> ParseProxyKey(uint64_t key)
39 {
40 auto uid = static_cast<uint32_t>(key >> UID_PROXY_OFFSET);
41 auto pid = key & ((static_cast<uint64_t>(1) << UID_PROXY_OFFSET) - 1);
42 return std::make_pair(uid, pid);
43 }
44
CallbackAlarmIfNeed(const std::shared_ptr<TimerInfo> & alarm)45 int32_t TimerProxy::CallbackAlarmIfNeed(const std::shared_ptr<TimerInfo> &alarm)
46 {
47 if (alarm == nullptr) {
48 TIME_HILOGE(TIME_MODULE_SERVICE, "callback alarm is nullptr!");
49 return E_TIME_NULLPTR;
50 }
51 int32_t ret = alarm->callback(alarm->id);
52 if (alarm->bundleName != NO_LOG_APP || alarm->wakeup) {
53 TIME_SIMPLIFY_HILOGW(TIME_MODULE_SERVICE, "cb: %{public}" PRId64 " ret: %{public}d",
54 alarm->id, ret);
55 }
56 return ret;
57 }
58
ProxyTimer(int32_t uid,int pid,bool isProxy,bool needRetrigger,const std::chrono::steady_clock::time_point & now,std::function<void (std::shared_ptr<TimerInfo> & alarm,bool needRetrigger)> insertAlarmCallback)59 bool TimerProxy::ProxyTimer(int32_t uid, int pid, bool isProxy, bool needRetrigger,
60 const std::chrono::steady_clock::time_point &now,
61 std::function<void(std::shared_ptr<TimerInfo> &alarm, bool needRetrigger)> insertAlarmCallback)
62 {
63 TIME_HILOGD(TIME_MODULE_SERVICE, "start. pid=%{public}d, isProxy=%{public}u, needRetrigger=%{public}u",
64 pid, isProxy, needRetrigger);
65
66 std::lock_guard<std::mutex> lockProxy(proxyMutex_);
67 if (isProxy) {
68 UpdateProxyWhenElapsedForProxyTimers(uid, pid, now, insertAlarmCallback, needRetrigger);
69 return true;
70 }
71
72 if (!RestoreProxyWhenElapsedForProxyTimers(uid, pid, now, insertAlarmCallback, needRetrigger)) {
73 TIME_HILOGE(TIME_MODULE_SERVICE, "Pid: %{public}d doesn't exist in the proxy list" PRId64 "", pid);
74 return false;
75 }
76 return true;
77 }
78
AdjustTimer(bool isAdjust,uint32_t interval,const std::chrono::steady_clock::time_point & now,uint32_t delta,std::function<void (AdjustTimerCallback adjustTimer)> updateTimerDeliveries)79 bool TimerProxy::AdjustTimer(bool isAdjust, uint32_t interval,
80 const std::chrono::steady_clock::time_point &now, uint32_t delta,
81 std::function<void(AdjustTimerCallback adjustTimer)> updateTimerDeliveries)
82 {
83 std::lock_guard<std::mutex> lockProxy(adjustMutex_);
84 TIME_HILOGD(TIME_MODULE_SERVICE, "adjust timer state: %{public}d, interval: %{public}d, delta: %{public}d",
85 isAdjust, interval, delta);
86 auto callback = [=] (std::shared_ptr<TimerInfo> timer) {
87 if (timer == nullptr) {
88 TIME_HILOGE(TIME_MODULE_SERVICE, "adjust timer is nullptr!");
89 return false;
90 }
91 bool isOverdue = (now > timer->originWhenElapsed);
92 if (isAdjust && !isOverdue) {
93 return UpdateAdjustWhenElapsed(now, interval, delta, timer);
94 }
95 return RestoreAdjustWhenElapsed(timer);
96 };
97 updateTimerDeliveries(callback);
98 if (!isAdjust) {
99 adjustTimers_.clear();
100 }
101 return true;
102 }
103
UpdateAdjustWhenElapsed(const std::chrono::steady_clock::time_point & now,uint32_t interval,uint32_t delta,std::shared_ptr<TimerInfo> & timer)104 bool TimerProxy::UpdateAdjustWhenElapsed(const std::chrono::steady_clock::time_point &now,
105 uint32_t interval, uint32_t delta, std::shared_ptr<TimerInfo> &timer)
106 {
107 if (IsTimerExemption(timer)) {
108 TIME_HILOGD(TIME_MODULE_SERVICE, "adjust exemption timer bundleName: %{public}s",
109 timer->bundleName.c_str());
110 return false;
111 }
112 TIME_HILOGD(TIME_MODULE_SERVICE, "adjust single time id: %{public}" PRId64 ", "
113 "uid: %{public}d, bundleName: %{public}s",
114 timer->id, timer->uid, timer->bundleName.c_str());
115 adjustTimers_.insert(timer->id);
116 return timer->AdjustTimer(now, interval, delta);
117 }
118
RestoreAdjustWhenElapsed(std::shared_ptr<TimerInfo> & timer)119 bool TimerProxy::RestoreAdjustWhenElapsed(std::shared_ptr<TimerInfo> &timer)
120 {
121 if (adjustTimers_.find(timer->id) == adjustTimers_.end()) {
122 return false;
123 }
124 return timer->RestoreAdjustTimer();
125 }
126
SetTimerExemption(const std::unordered_set<std::string> & nameArr,bool isExemption)127 bool TimerProxy::SetTimerExemption(const std::unordered_set<std::string> &nameArr, bool isExemption)
128 {
129 std::lock_guard<std::mutex> lockProxy(adjustMutex_);
130 bool isChanged = false;
131 if (!isExemption) {
132 for (const auto &name : nameArr) {
133 adjustExemptionList_.erase(name);
134 }
135 return isChanged;
136 }
137 adjustExemptionList_.insert(nameArr.begin(), nameArr.end());
138 return isChanged;
139 }
140
IsTimerExemption(std::shared_ptr<TimerInfo> timer)141 bool TimerProxy::IsTimerExemption(std::shared_ptr<TimerInfo> timer)
142 {
143 auto key = timer->bundleName + "|" + timer->name;
144 TIME_HILOGD(TIME_MODULE_SERVICE, "key is: %{public}s", key.c_str());
145 if ((adjustExemptionList_.find(timer->bundleName) != adjustExemptionList_.end()
146 || adjustExemptionList_.find(key) != adjustExemptionList_.end())
147 && timer->windowLength == milliseconds::zero()) {
148 return true;
149 }
150 return false;
151 }
152
ResetAllProxy(const std::chrono::steady_clock::time_point & now,std::function<void (std::shared_ptr<TimerInfo> & alarm,bool needRetrigger)> insertAlarmCallback)153 bool TimerProxy::ResetAllProxy(const std::chrono::steady_clock::time_point &now,
154 std::function<void(std::shared_ptr<TimerInfo> &alarm, bool needRetrigger)> insertAlarmCallback)
155 {
156 TIME_HILOGD(TIME_MODULE_SERVICE, "start");
157 ResetAllProxyWhenElapsed(now, insertAlarmCallback);
158 return true;
159 }
160
EraseTimerFromProxyTimerMap(const uint64_t id,const int uid,const int pid)161 void TimerProxy::EraseTimerFromProxyTimerMap(const uint64_t id, const int uid, const int pid)
162 {
163 TIME_HILOGD(TIME_MODULE_SERVICE, "erase timer from proxy timer map, id=%{public}" PRId64 ", pid=%{public}u",
164 id, pid);
165 std::lock_guard<std::mutex> lock(proxyMutex_);
166 uint64_t key = GetProxyKey(uid, pid);
167 auto it = proxyTimers_.find(key);
168 if (it != proxyTimers_.end()) {
169 it->second.erase(std::remove_if(it->second.begin(), it->second.end(),
170 [id](uint64_t timerId) { return timerId == id; }), it->second.end());
171 }
172 }
173
EraseAlarmItem(const uint64_t id,std::unordered_map<uint64_t,std::shared_ptr<TimerInfo>> & idAlarmsMap)174 void TimerProxy::EraseAlarmItem(
175 const uint64_t id, std::unordered_map<uint64_t, std::shared_ptr<TimerInfo>> &idAlarmsMap)
176 {
177 auto itAlarms = idAlarmsMap.find(id);
178 if (itAlarms != idAlarmsMap.end()) {
179 TIME_HILOGD(TIME_MODULE_SERVICE, "timer already exists, id=%{public}" PRId64 "", id);
180 idAlarmsMap.erase(itAlarms);
181 }
182 }
183
CountUidTimerMapByUid(int32_t uid)184 int32_t TimerProxy::CountUidTimerMapByUid(int32_t uid)
185 {
186 std::lock_guard<std::mutex> lock(uidTimersMutex_);
187 auto it = uidTimersMap_.find(uid);
188 if (it == uidTimersMap_.end()) {
189 return 0;
190 }
191 return it->second.size();
192 }
193
RecordUidTimerMap(const std::shared_ptr<TimerInfo> & alarm,const bool isRebatched)194 void TimerProxy::RecordUidTimerMap(const std::shared_ptr<TimerInfo> &alarm, const bool isRebatched)
195 {
196 if (isRebatched) {
197 TIME_HILOGD(TIME_MODULE_SERVICE, "Record uid timer info map, isRebatched: %{public}d", isRebatched);
198 return;
199 }
200 if (alarm == nullptr) {
201 TIME_HILOGE(TIME_MODULE_SERVICE, "record uid timer map alarm is nullptr!");
202 return;
203 }
204
205 std::lock_guard<std::mutex> lock(uidTimersMutex_);
206 auto it = uidTimersMap_.find(alarm->uid);
207 if (it == uidTimersMap_.end()) {
208 std::unordered_map<uint64_t, std::shared_ptr<TimerInfo>> idAlarmsMap;
209 idAlarmsMap.insert(std::make_pair(alarm->id, alarm));
210 uidTimersMap_.insert(std::make_pair(alarm->uid, idAlarmsMap));
211 return;
212 }
213
214 EraseAlarmItem(alarm->id, it->second);
215 it->second.insert(std::make_pair(alarm->id, alarm));
216 }
217
RemoveUidTimerMap(const std::shared_ptr<TimerInfo> & alarm)218 void TimerProxy::RemoveUidTimerMap(const std::shared_ptr<TimerInfo> &alarm)
219 {
220 if (alarm == nullptr) {
221 TIME_HILOGE(TIME_MODULE_SERVICE, "remove uid timer map alarm is nullptr!");
222 return;
223 }
224
225 std::lock_guard<std::mutex> lock(uidTimersMutex_);
226 auto it = uidTimersMap_.find(alarm->uid);
227 if (it == uidTimersMap_.end()) {
228 return;
229 }
230
231 EraseAlarmItem(alarm->id, it->second);
232 if (it->second.empty()) {
233 uidTimersMap_.erase(it);
234 }
235 }
236
RemoveUidTimerMapLocked(const std::shared_ptr<TimerInfo> & alarm)237 void TimerProxy::RemoveUidTimerMapLocked(const std::shared_ptr<TimerInfo> &alarm)
238 {
239 if (alarm == nullptr) {
240 TIME_HILOGE(TIME_MODULE_SERVICE, "remove uid timer map alarm is nullptr!");
241 return;
242 }
243 auto it = uidTimersMap_.find(alarm->uid);
244 if (it == uidTimersMap_.end()) {
245 return;
246 }
247 EraseAlarmItem(alarm->id, it->second);
248 if (it->second.empty()) {
249 uidTimersMap_.erase(it);
250 }
251 }
252
RecordProxyTimerMap(const std::shared_ptr<TimerInfo> & alarm,bool isPid)253 void TimerProxy::RecordProxyTimerMap(const std::shared_ptr<TimerInfo> &alarm, bool isPid)
254 {
255 std::lock_guard<std::mutex> lock(proxyMutex_);
256 auto uid = alarm->uid;
257 auto pid = alarm->pid;
258 uint64_t key;
259 if (isPid) {
260 key = GetProxyKey(uid, pid);
261 } else {
262 key = GetProxyKey(uid, 0);
263 }
264 auto it = proxyTimers_.find(key);
265 if (it != proxyTimers_.end()) {
266 proxyTimers_[key].push_back(alarm->id);
267 } else {
268 proxyTimers_.insert(std::make_pair(key, std::vector<uint64_t>{alarm->id}));
269 }
270 }
271
RemoveUidTimerMap(const uint64_t id)272 void TimerProxy::RemoveUidTimerMap(const uint64_t id)
273 {
274 std::lock_guard<std::mutex> lock(uidTimersMutex_);
275 for (auto itUidsTimer = uidTimersMap_.begin(); itUidsTimer!= uidTimersMap_.end(); ++itUidsTimer) {
276 for (auto itTimerId = itUidsTimer->second.begin(); itTimerId!= itUidsTimer->second.end(); ++itTimerId) {
277 if (itTimerId->first != id) {
278 continue;
279 }
280
281 itUidsTimer->second.erase(itTimerId);
282 if (itUidsTimer->second.empty()) {
283 uidTimersMap_.erase(itUidsTimer);
284 }
285 return;
286 }
287 }
288 }
289
IsProxy(const int32_t uid,const int32_t pid)290 bool TimerProxy::IsProxy(const int32_t uid, const int32_t pid)
291 {
292 std::lock_guard<std::mutex> lock(proxyMutex_);
293 uint64_t key = GetProxyKey(uid, pid);
294 auto it = proxyTimers_.find(key);
295 if (it == proxyTimers_.end()) {
296 return false;
297 }
298 return true;
299 }
300
301 // needs to acquire the lock `proxyMutex_` before calling this method
IsProxyLocked(const int32_t uid,const int32_t pid)302 bool TimerProxy::IsProxyLocked(const int32_t uid, const int32_t pid)
303 {
304 uint64_t key = GetProxyKey(uid, pid);
305 auto it = proxyTimers_.find(key);
306 if (it == proxyTimers_.end()) {
307 return false;
308 }
309 return true;
310 }
311
UpdateProxyWhenElapsedForProxyTimers(int32_t uid,int pid,const std::chrono::steady_clock::time_point & now,std::function<void (std::shared_ptr<TimerInfo> & alarm,bool needRetrigger)> insertAlarmCallback,bool needRetrigger)312 void TimerProxy::UpdateProxyWhenElapsedForProxyTimers(int32_t uid, int pid,
313 const std::chrono::steady_clock::time_point &now,
314 std::function<void(std::shared_ptr<TimerInfo> &alarm, bool needRetrigger)> insertAlarmCallback,
315 bool needRetrigger)
316 {
317 uint64_t key = GetProxyKey(uid, pid);
318 auto it = proxyTimers_.find(key);
319 if (it != proxyTimers_.end()) {
320 TIME_HILOGD(TIME_MODULE_SERVICE, "uid:%{public}d pid: %{public}d is already proxy", uid, pid);
321 return;
322 }
323 std::lock_guard<std::mutex> lockUidTimers(uidTimersMutex_);
324 std::vector<uint64_t> timerList;
325 auto itUidTimersMap = uidTimersMap_.find(uid);
326 if (itUidTimersMap == uidTimersMap_.end()) {
327 TIME_HILOGD(TIME_MODULE_SERVICE, "uid: %{public}d in map not found", uid);
328 proxyTimers_[key] = timerList;
329 return;
330 }
331
332 for (auto itTimerInfo = itUidTimersMap->second.begin(); itTimerInfo!= itUidTimersMap->second.end();
333 ++itTimerInfo) {
334 if (pid == 0 || pid == itTimerInfo->second->pid) {
335 if (!needRetrigger) {
336 insertAlarmCallback(itTimerInfo->second, false);
337 break;
338 }
339 itTimerInfo->second->ProxyTimer(now, milliseconds(proxyDelayTime_));
340 TIME_HILOGD(TIME_MODULE_SERVICE, "Update proxy WhenElapsed for proxy pid map. "
341 "pid= %{public}d, id=%{public}" PRId64 ", timer whenElapsed=%{public}lld, now=%{public}lld",
342 itTimerInfo->second->pid, itTimerInfo->second->id,
343 itTimerInfo->second->whenElapsed.time_since_epoch().count(),
344 now.time_since_epoch().count());
345 insertAlarmCallback(itTimerInfo->second, true);
346 timerList.push_back(itTimerInfo->first);
347 }
348 }
349 proxyTimers_[key] = timerList;
350 }
351
RestoreProxyWhenElapsed(const int uid,const int pid,const std::chrono::steady_clock::time_point & now,std::function<void (std::shared_ptr<TimerInfo> & alarm,bool needRetrigger)> insertAlarmCallback,bool needRetrigger)352 bool TimerProxy::RestoreProxyWhenElapsed(const int uid, const int pid,
353 const std::chrono::steady_clock::time_point &now,
354 std::function<void(std::shared_ptr<TimerInfo> &alarm, bool needRetrigger)> insertAlarmCallback,
355 bool needRetrigger)
356 {
357 uint64_t key = GetProxyKey(uid, pid);
358 auto itProxy = proxyTimers_.find(key);
359 if (itProxy == proxyTimers_.end()) {
360 TIME_HILOGD(TIME_MODULE_SERVICE, "uid:%{public}d pid:%{public}d not in proxy", uid, pid);
361 return false;
362 }
363 std::lock_guard<std::mutex> lockPidTimers(uidTimersMutex_);
364 auto itTimer = uidTimersMap_.find(uid);
365 if (uidTimersMap_.find(uid) == uidTimersMap_.end()) {
366 TIME_HILOGD(TIME_MODULE_SERVICE, "uid:%{public}d timer info not found, erase proxy map", uid);
367 return true;
368 }
369
370 for (auto elem : itProxy->second) {
371 auto itTimerInfo = itTimer->second.find(elem);
372 if (itTimerInfo == itTimer->second.end()) {
373 continue;
374 }
375 itTimerInfo->second->RestoreProxyTimer();
376 TIME_HILOGD(TIME_MODULE_SERVICE, "Restore proxy WhenElapsed by pid"
377 "pid= %{public}d, id=%{public}" PRId64 ", timer whenElapsed=%{public}lld, now=%{public}lld",
378 itTimerInfo->second->pid, itTimerInfo->second->id,
379 itTimerInfo->second->whenElapsed.time_since_epoch().count(),
380 now.time_since_epoch().count());
381 insertAlarmCallback(itTimerInfo->second, needRetrigger);
382 }
383 return true;
384 }
385
RestoreProxyWhenElapsedForProxyTimers(const int uid,const int pid,const std::chrono::steady_clock::time_point & now,std::function<void (std::shared_ptr<TimerInfo> & alarm,bool needRetrigger)> insertAlarmCallback,bool needRetrigger)386 bool TimerProxy::RestoreProxyWhenElapsedForProxyTimers(const int uid, const int pid,
387 const std::chrono::steady_clock::time_point &now,
388 std::function<void(std::shared_ptr<TimerInfo> &alarm, bool needRetrigger)> insertAlarmCallback,
389 bool needRetrigger)
390 {
391 uint64_t key = GetProxyKey(uid, pid);
392 bool ret = RestoreProxyWhenElapsed(uid, pid, now, insertAlarmCallback, needRetrigger);
393 if (ret) {
394 proxyTimers_.erase(key);
395 }
396 return ret;
397 }
398
ResetAllProxyWhenElapsed(const std::chrono::steady_clock::time_point & now,std::function<void (std::shared_ptr<TimerInfo> & alarm,bool needRetrigger)> insertAlarmCallback)399 void TimerProxy::ResetAllProxyWhenElapsed(const std::chrono::steady_clock::time_point &now,
400 std::function<void(std::shared_ptr<TimerInfo> &alarm, bool needRetrigger)> insertAlarmCallback)
401 {
402 std::lock_guard<std::mutex> lockProxy(proxyMutex_);
403 for (auto it = proxyTimers_.begin(); it != proxyTimers_.end(); ++it) {
404 auto resPair = ParseProxyKey(it->first);
405 RestoreProxyWhenElapsed(resPair.first, resPair.second, now, insertAlarmCallback, true);
406 }
407 proxyTimers_.clear();
408 }
409
410 #ifdef HIDUMPER_ENABLE
ShowProxyTimerInfo(int fd,const int64_t now)411 bool TimerProxy::ShowProxyTimerInfo(int fd, const int64_t now)
412 {
413 TIME_HILOGD(TIME_MODULE_SERVICE, "start");
414 std::lock_guard<std::mutex> lockPidProxy(proxyMutex_);
415 dprintf(fd, "current time %lld\n", now);
416 for (auto itProxyPids = proxyTimers_.begin(); itProxyPids != proxyTimers_.end(); ++itProxyPids) {
417 auto resPair = ParseProxyKey(itProxyPids->first);
418 dprintf(fd, " - proxy uid = %lu pid = %lu\n", resPair.first, resPair.second);
419 for (auto elem : itProxyPids->second) {
420 dprintf(fd, " * save timer id = %llu\n", elem);
421 }
422 }
423 TIME_HILOGD(TIME_MODULE_SERVICE, "end");
424 return true;
425 }
426
ShowUidTimerMapInfo(int fd,const int64_t now)427 bool TimerProxy::ShowUidTimerMapInfo(int fd, const int64_t now)
428 {
429 TIME_HILOGD(TIME_MODULE_SERVICE, "start");
430 std::lock_guard<std::mutex> lockProxy(uidTimersMutex_);
431 dprintf(fd, "current time %lld\n", now);
432 for (auto itTimerInfoMap = uidTimersMap_.begin(); itTimerInfoMap != uidTimersMap_.end(); ++itTimerInfoMap) {
433 dprintf(fd, " - uid = %lu\n", itTimerInfoMap->first);
434 for (auto itTimerInfo = itTimerInfoMap->second.begin(); itTimerInfo != itTimerInfoMap->second.end();
435 ++itTimerInfo) {
436 dprintf(fd, " * timer id = %llu\n", itTimerInfo->second->id);
437 dprintf(fd, " * timer whenElapsed = %lld\n", itTimerInfo->second->whenElapsed.time_since_epoch().count());
438 }
439 }
440 TIME_HILOGD(TIME_MODULE_SERVICE, "end");
441 return true;
442 }
443
ShowAdjustTimerInfo(int fd)444 void TimerProxy::ShowAdjustTimerInfo(int fd)
445 {
446 std::lock_guard<std::mutex> lockProxy(adjustMutex_);
447 dprintf(fd, "show adjust timer");
448 for (auto timerId : adjustTimers_) {
449 dprintf(fd, " * timer id = %lu\n", timerId);
450 }
451 }
452
ShowProxyDelayTime(int fd)453 bool TimerProxy::ShowProxyDelayTime(int fd)
454 {
455 TIME_HILOGD(TIME_MODULE_SERVICE, "start");
456 dprintf(fd, "proxy delay time: %lld ms\n", proxyDelayTime_);
457 TIME_HILOGD(TIME_MODULE_SERVICE, "end");
458 return true;
459 }
460 #endif
461
GetProxyDelayTime() const462 int64_t TimerProxy::GetProxyDelayTime() const
463 {
464 return proxyDelayTime_;
465 }
466 } // MiscServices
467 } // OHOS
468