• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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