1 /*
2  * Copyright (c) 2022 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 "bg_efficiency_resources_mgr.h"
17 #include "background_task_mgr_service.h"
18 
19 #include <set>
20 #include <algorithm>
21 #include <vector>
22 
23 #include "event_runner.h"
24 #include "system_ability_definition.h"
25 #include "iservice_registry.h"
26 #include "bgtaskmgr_inner_errors.h"
27 
28 #include "resource_type.h"
29 #include "time_provider.h"
30 #include "bundle_manager_helper.h"
31 #include "efficiency_resource_log.h"
32 #include "tokenid_kit.h"
33 #include "extension_ability_info.h"
34 #include "hitrace_meter.h"
35 
36 namespace OHOS {
37 namespace BackgroundTaskMgr {
38 namespace {
39     const std::string DUMP_PARAM_LIST_ALL = "--all";
40     const std::string DUMP_PARAM_RESET_ALL = "--reset_all";
41     const std::string DUMP_PARAM_RESET_APP = "--resetapp";
42     const std::string DUMP_PARAM_RESET_PROC = "--resetproc";
43     const int32_t MAX_DUMP_PARAM_NUMS = 4;
44     const uint32_t APP_MGR_READY = 1;
45     const uint32_t BUNDLE_MGR_READY = 2;
46     const uint32_t ALL_DEPENDS_READY = 3;
47     const uint32_t FREEZE_ALL_RESOURCES = 0;
48     const uint32_t MAX_RESOURCES_TYPE_NUM = ResourceTypeName.size();
49     const uint32_t MAX_RESOURCE_MASK = (1 << ResourceTypeName.size()) - 1;
50 }
BgEfficiencyResourcesMgr()51 BgEfficiencyResourcesMgr::BgEfficiencyResourcesMgr() {}
52 
~BgEfficiencyResourcesMgr()53 BgEfficiencyResourcesMgr::~BgEfficiencyResourcesMgr() {}
54 
Init(const std::shared_ptr<AppExecFwk::EventRunner> & runner)55 bool BgEfficiencyResourcesMgr::Init(const std::shared_ptr<AppExecFwk::EventRunner>& runner)
56 {
57     subscriberMgr_ = DelayedSingleton<ResourcesSubscriberMgr>::GetInstance();
58     if (runner == nullptr) {
59         BGTASK_LOGE("efficiency resources mgr runner create failed!");
60         return false;
61     }
62     handler_ = std::make_shared<AppExecFwk::EventHandler>(runner);
63     if (!handler_) {
64         BGTASK_LOGE("efficiency resources mgr handler create failed!");
65         return false;
66     }
67     BGTASK_LOGI("efficiency resources mgr finish Init");
68     return true;
69 }
70 
InitNecessaryState()71 void BgEfficiencyResourcesMgr::InitNecessaryState()
72 {
73     if (isSysReady_.load()) {
74         return;
75     }
76     HandlePersistenceData();
77     BGTASK_LOGD("app resource record size: %{public}d, process  resource record size:  %{public}d!",
78         static_cast<int32_t>(appResourceApplyMap_.size()), static_cast<int32_t>(procResourceApplyMap_.size()));
79     isSysReady_.store(true);
80     DelayedSingleton<BackgroundTaskMgrService>::GetInstance()->SetReady(
81         ServiceReadyState::EFFICIENCY_RESOURCES_SERVICE_READY);
82     BGTASK_LOGI("SetReady EFFICIENCY_RESOURCES_SERVICE_READY");
83 }
84 
OnAddSystemAbility(int32_t systemAbilityId,const std::string & deviceId)85 void BgEfficiencyResourcesMgr::OnAddSystemAbility(int32_t systemAbilityId, const std::string& deviceId)
86 {
87     BGTASK_LOGI("add system ability, systemAbilityId : %{public}d", systemAbilityId);
88     std::lock_guard<std::mutex> lock(sysAbilityLock_);
89     switch (systemAbilityId) {
90         case APP_MGR_SERVICE_ID:
91             BGTASK_LOGI("app mgr service is ready!");
92             dependsReady_ |= APP_MGR_READY;
93             break;
94         case BUNDLE_MGR_SERVICE_SYS_ABILITY_ID:
95             BGTASK_LOGI("bundle mgr service is ready!");
96             dependsReady_ |= BUNDLE_MGR_READY;
97             break;
98         default:
99             break;
100     }
101     if (dependsReady_ == ALL_DEPENDS_READY) {
102         BGTASK_LOGI("necessary system service has been satisfied!");
103         auto task = [weak = weak_from_this()]() {
104             auto self = weak.lock();
105             if (!self) {
106                 BGTASK_LOGE("weak.lock return null");
107                 return;
108             }
109             self->InitNecessaryState();
110         };
111         handler_->PostSyncTask(task);
112     }
113 }
114 
OnRemoveSystemAbility(int32_t systemAbilityId,const std::string & deviceId)115 void BgEfficiencyResourcesMgr::OnRemoveSystemAbility(int32_t systemAbilityId, const std::string& deviceId)
116 {
117     BGTASK_LOGI("remove system ability, systemAbilityId : %{public}d", systemAbilityId);
118     std::lock_guard<std::mutex> lock(sysAbilityLock_);
119     switch (systemAbilityId) {
120         case APP_MGR_SERVICE_ID:
121             BGTASK_LOGI("app mgr service is removed!");
122             dependsReady_ &= (~APP_MGR_READY);
123             break;
124         case BUNDLE_MGR_SERVICE_SYS_ABILITY_ID:
125             BGTASK_LOGI("bundle mgr service is removed!");
126             dependsReady_ &= (~BUNDLE_MGR_READY);
127             break;
128         default:
129             break;
130     }
131     if (dependsReady_ != ALL_DEPENDS_READY) {
132         BGTASK_LOGI("necessary system service has been unsatisfied");
133         isSysReady_.store(false);
134     }
135 }
136 
HandlePersistenceData()137 void BgEfficiencyResourcesMgr::HandlePersistenceData()
138 {
139     BGTASK_LOGD("ResourceRecordStorage service restart, restore data");
140 
141     if (appMgrClient_ == nullptr) {
142         appMgrClient_ = std::make_unique<AppExecFwk::AppMgrClient>();
143         if (!appMgrClient_ || appMgrClient_->ConnectAppMgrService() != ERR_OK) {
144             BGTASK_LOGW("ResourceRecordStorage connect to app mgr service failed");
145             DelayedSingleton<DataStorageHelper>::GetInstance()->RefreshResourceRecord(
146                 appResourceApplyMap_, procResourceApplyMap_);
147             return;
148         }
149     }
150     std::vector<AppExecFwk::RunningProcessInfo> allAppProcessInfos;
151     appMgrClient_->GetAllRunningProcesses(allAppProcessInfos);
152     BGTASK_LOGI("start to recovery delayed task of apps and processes");
153     DelayedSingleton<DataStorageHelper>::GetInstance()->RestoreResourceRecord(
154         appResourceApplyMap_, procResourceApplyMap_);
155     CheckPersistenceData(allAppProcessInfos);
156     RecoverDelayedTask(true, procResourceApplyMap_);
157     RecoverDelayedTask(false, appResourceApplyMap_);
158     DelayedSingleton<DataStorageHelper>::GetInstance()->RefreshResourceRecord(
159         appResourceApplyMap_, procResourceApplyMap_);
160 }
161 
EraseRecordIf(ResourceRecordMap & infoMap,const std::function<bool (ResourceRecordPair)> & fun)162 void BgEfficiencyResourcesMgr::EraseRecordIf(ResourceRecordMap &infoMap,
163     const std::function<bool(ResourceRecordPair)> &fun)
164 {
165     for (auto iter = infoMap.begin(); iter != infoMap.end();) {
166         if (fun(*iter)) {
167             iter = infoMap.erase(iter);
168         } else {
169             iter++;
170         }
171     }
172 }
173 
CheckPersistenceData(const std::vector<AppExecFwk::RunningProcessInfo> & allProcesses)174 void BgEfficiencyResourcesMgr::CheckPersistenceData(const std::vector<AppExecFwk::RunningProcessInfo> &allProcesses)
175 {
176     BGTASK_LOGI("efficiency resources check existing uid and pid");
177     std::set<int32_t> runningUid;
178     std::set<int32_t> runningPid;
179     std::for_each(allProcesses.begin(), allProcesses.end(), [&runningUid, &runningPid](const auto &iter) {
180         runningUid.emplace(iter.uid_);
181         runningPid.emplace(iter.pid_);
182     });
183     auto removeUid = [&runningUid](const auto &iter) {
184         std::shared_ptr<ResourceApplicationRecord> record = iter.second;
185         if ((record->GetResourceNumber() & ResourceType::WORK_SCHEDULER) != 0 ||
186             (record->GetResourceNumber() & ResourceType::TIMER) != 0) {
187                 return false;
188             }
189         return runningUid.find(iter.first) == runningUid.end();
190     };
191     EraseRecordIf(appResourceApplyMap_, removeUid);
192     auto removePid = [&runningPid](const auto &iter)  { return runningPid.find(iter.first) == runningPid.end(); };
193     EraseRecordIf(procResourceApplyMap_, removePid);
194 }
195 
RecoverDelayedTask(bool isProcess,ResourceRecordMap & infoMap)196 __attribute__((no_sanitize("cfi"))) void BgEfficiencyResourcesMgr::RecoverDelayedTask(bool isProcess,
197     ResourceRecordMap& infoMap)
198 {
199     BGTASK_LOGD("start to recovery delayed task");
200     const auto &mgr = shared_from_this();
201     for (auto iter = infoMap.begin(); iter != infoMap.end(); iter ++) {
202         auto &resourceList = iter->second->resourceUnitList_;
203         int32_t mapKey = iter->first;
204         for (auto resourceIter = resourceList.begin(); resourceIter != resourceList.end(); resourceIter++) {
205             if (resourceIter->isPersist_) {
206                 continue;
207             }
208             auto task = [mgr, mapKey, isProcess] () {
209                 mgr->ResetTimeOutResource(mapKey, isProcess);
210             };
211             int32_t timeOut = static_cast<int32_t>(resourceIter->endTime_ - TimeProvider::GetCurrentTime());
212             handler_->PostTask(task, std::max(0, timeOut));
213         }
214     }
215 }
216 
RemoveAppRecord(int32_t uid,const std::string & bundleName,bool resetAll)217 ErrCode BgEfficiencyResourcesMgr::RemoveAppRecord(int32_t uid, const std::string &bundleName, bool resetAll)
218 {
219     if (!isSysReady_.load()) {
220         BGTASK_LOGW("Efficiency resources manager is not ready, RemoveAppRecord failed");
221         return ERR_BGTASK_SYS_NOT_READY;
222     }
223     BGTASK_LOGD("app died, uid: %{public}d, bundleName: %{public}s", uid, bundleName.c_str());
224     handler_->PostTask([this, uid, bundleName, resetAll]() {
225         int resourceNumber = resetAll ? MAX_RESOURCE_MASK : (MAX_RESOURCE_MASK ^ ResourceType::WORK_SCHEDULER ^
226             ResourceType::TIMER);
227         std::shared_ptr<ResourceCallbackInfo> callbackInfo = std::make_shared<ResourceCallbackInfo>(uid,
228             0, resourceNumber, bundleName);
229         this->ResetEfficiencyResourcesInner(callbackInfo, false);
230     });
231     return ERR_OK;
232 }
233 
RemoveProcessRecord(int32_t uid,int32_t pid,const std::string & bundleName)234 ErrCode BgEfficiencyResourcesMgr::RemoveProcessRecord(int32_t uid, int32_t pid, const std::string &bundleName)
235 {
236     if (!isSysReady_.load()) {
237         BGTASK_LOGW("Efficiency resources manager is not ready, remove process record failed");
238         return ERR_BGTASK_SYS_NOT_READY;
239     }
240     BGTASK_LOGD("process died, uid: %{public}d, pid: %{public}d, bundleName: %{public}s",
241         uid, pid, bundleName.c_str());
242     handler_->PostTask([this, uid, pid, bundleName]() {
243         std::shared_ptr<ResourceCallbackInfo> callbackInfo = std::make_shared<ResourceCallbackInfo>(uid,
244             pid, MAX_RESOURCE_MASK ^ ResourceType::WORK_SCHEDULER ^ ResourceType::TIMER, bundleName);
245         this->ResetEfficiencyResourcesInner(callbackInfo, true);
246     });
247     return ERR_OK;
248 }
249 
CheckAlivedApp(int32_t uid)250 bool BgEfficiencyResourcesMgr::CheckAlivedApp(int32_t uid)
251 {
252     BGTASK_LOGD("start check app alive or not");
253     if (!appMgrClient_ || appMgrClient_->ConnectAppMgrService() != ERR_OK) {
254         BGTASK_LOGE("ResourceRecordStorage connect to app mgr service failed");
255         return true;
256     }
257     std::vector<AppExecFwk::RunningProcessInfo> allAppProcessInfos {};
258     appMgrClient_->GetAllRunningProcesses(allAppProcessInfos);
259     for (const auto &info : allAppProcessInfos) {
260         if (info.uid_ == uid) {
261             return true;
262         }
263     }
264     return false;
265 }
266 
Clear()267 void BgEfficiencyResourcesMgr::Clear()
268 {
269 }
270 
CheckResourceInfo(const sptr<EfficiencyResourceInfo> & resourceInfo)271 bool CheckResourceInfo(const sptr<EfficiencyResourceInfo> &resourceInfo)
272 {
273     if (!resourceInfo) {
274         BGTASK_LOGE("apply efficiency resource request params is null!");
275         return false;
276     }
277     if (resourceInfo->GetResourceNumber() == 0 || resourceInfo->GetResourceNumber() > MAX_RESOURCE_MASK
278         || (resourceInfo->IsApply() && !resourceInfo->IsPersist() && resourceInfo->GetTimeOut() == 0)) {
279         BGTASK_LOGE("efficiency resources params invalid!");
280         return false;
281     }
282     return true;
283 }
284 
IsServiceExtensionType(const pid_t pid)285 bool BgEfficiencyResourcesMgr::IsServiceExtensionType(const pid_t pid)
286 {
287     if (!appMgrClient_ || appMgrClient_->ConnectAppMgrService() != ERR_OK) {
288         BGTASK_LOGE("ApplyEfficiencyResources connect to app mgr service failed");
289         return false;
290     }
291 
292     int32_t proId = static_cast<int32_t>(pid);
293     std::vector<AppExecFwk::RunningProcessInfo> allRunningProcessInfos;
294     appMgrClient_->GetAllRunningProcesses(allRunningProcessInfos);
295     for (const auto &info : allRunningProcessInfos) {
296         if (info.pid_ == proId && info.extensionType_ == OHOS::AppExecFwk::ExtensionAbilityType::SERVICE) {
297             return true;
298         }
299     }
300     return false;
301 }
302 
ApplyEfficiencyResources(const sptr<EfficiencyResourceInfo> & resourceInfo)303 ErrCode BgEfficiencyResourcesMgr::ApplyEfficiencyResources(
304     const sptr<EfficiencyResourceInfo> &resourceInfo)
305 {
306     HitraceScoped traceScoped(HITRACE_TAG_OHOS,
307         "BackgroundTaskManager::EfficiencyResource::Service::ApplyEfficiencyResources");
308 
309     BGTASK_LOGD("start bgtaskefficiency");
310     if (!isSysReady_.load()) {
311         BGTASK_LOGW("Efficiency resources manager is not ready");
312         return ERR_BGTASK_SYS_NOT_READY;
313     }
314 
315     if (!CheckResourceInfo(resourceInfo)) {
316         return ERR_BGTASK_RESOURCES_EXCEEDS_MAX;
317     }
318 
319     auto uid = IPCSkeleton::GetCallingUid();
320     auto pid = IPCSkeleton::GetCallingPid();
321     std::string bundleName = "";
322     if (!IsCallingInfoLegal(uid, pid, bundleName)) {
323         BGTASK_LOGI("apply efficiency resources failed, calling info is illegal");
324         return ERR_BGTASK_INVALID_PID_OR_UID;
325     }
326 
327     uint64_t tokenId = IPCSkeleton::GetCallingFullTokenID();
328     if (!BundleManagerHelper::GetInstance()->IsSystemApp(tokenId) && !IsServiceExtensionType(pid)) {
329         BGTASK_LOGE("apply efficiency resources failed, %{public}s is not system app and service extension type",
330             bundleName.c_str());
331         return ERR_BGTASK_NOT_SYSTEM_APP;
332     }
333 
334     auto exemptedResourceType = GetExemptedResourceType(resourceInfo->GetResourceNumber(), uid, bundleName);
335     resourceInfo->SetResourceNumber(exemptedResourceType);
336     if (exemptedResourceType == 0) {
337         BGTASK_LOGE("apply efficiency resources failed, no permitted resource type");
338         return ERR_BGTASK_PERMISSION_DENIED;
339     }
340     ApplyResourceForPkgAndProc(uid, pid, bundleName, resourceInfo);
341     return ERR_OK;
342 }
343 
ApplyResourceForPkgAndProc(int32_t uid,int32_t pid,const std::string & bundleName,const sptr<EfficiencyResourceInfo> & resourceInfo)344 void BgEfficiencyResourcesMgr::ApplyResourceForPkgAndProc(int32_t uid, int32_t pid, const std::string &bundleName,
345     const sptr<EfficiencyResourceInfo> &resourceInfo)
346 {
347     if (!resourceInfo->IsProcess()) {
348         SendResourceApplyTask(uid, pid, bundleName, resourceInfo);
349         return;
350     }
351     // Only cpu can apply for process
352     if ((resourceInfo->GetResourceNumber() & ResourceType::CPU) !=0) {
353         sptr<EfficiencyResourceInfo> procResourceInfo = new (std::nothrow) EfficiencyResourceInfo(*resourceInfo);
354         procResourceInfo->SetResourceNumber(ResourceType::CPU);
355         SendResourceApplyTask(uid, pid, bundleName, procResourceInfo);
356     }
357     int resourceNumber = resourceInfo->GetResourceNumber() & (~ResourceType::CPU);
358     if (resourceNumber != 0) {
359         sptr<EfficiencyResourceInfo> appResourceInfo = new (std::nothrow) EfficiencyResourceInfo(*resourceInfo);
360         appResourceInfo->SetResourceNumber(resourceNumber);
361         appResourceInfo->SetProcess(false);
362         SendResourceApplyTask(uid, pid, bundleName, appResourceInfo);
363     }
364 }
365 
SendResourceApplyTask(int32_t uid,int32_t pid,const std::string & bundleName,const sptr<EfficiencyResourceInfo> & resourceInfo)366 void BgEfficiencyResourcesMgr::SendResourceApplyTask(int32_t uid, int32_t pid, const std::string &bundleName,
367     const sptr<EfficiencyResourceInfo> &resourceInfo)
368 {
369     std::shared_ptr<ResourceCallbackInfo> callbackInfo = std::make_shared<ResourceCallbackInfo>(uid,
370         pid, resourceInfo->GetResourceNumber(), bundleName);
371     if (resourceInfo->IsApply()) {
372         handler_->PostTask([this, callbackInfo, resourceInfo]() {
373             this->ApplyEfficiencyResourcesInner(callbackInfo, resourceInfo);
374         });
375     } else {
376         handler_->PostTask([this, callbackInfo, resourceInfo]() {
377             this->ResetEfficiencyResourcesInner(callbackInfo, resourceInfo->IsProcess());
378         });
379     }
380 }
381 
ApplyEfficiencyResourcesInner(std::shared_ptr<ResourceCallbackInfo> callbackInfo,const sptr<EfficiencyResourceInfo> & resourceInfo)382 void BgEfficiencyResourcesMgr::ApplyEfficiencyResourcesInner(std::shared_ptr<ResourceCallbackInfo>
383     callbackInfo, const sptr<EfficiencyResourceInfo> &resourceInfo)
384 {
385     BGTASK_LOGI("apply efficiency resources, uid:%{public}d, pid %{public}d, resource number: %{public}u,"\
386         "isPersist: %{public}d, timeOut: %{public}u, isProcess: %{public}d", callbackInfo->GetUid(),
387         callbackInfo->GetPid(), resourceInfo->GetResourceNumber(), resourceInfo->IsPersist(),
388         resourceInfo->GetTimeOut(), resourceInfo->IsProcess());
389     int32_t mapKey = resourceInfo->IsProcess() ? callbackInfo->GetPid() : callbackInfo->GetUid();
390     auto &infoMap = resourceInfo->IsProcess() ? procResourceApplyMap_ : appResourceApplyMap_;
391     uint32_t preResourceNumber = 0;
392     auto iter = infoMap.find(mapKey);
393     if (iter == infoMap.end()) {
394         infoMap.emplace(mapKey, std::make_shared<ResourceApplicationRecord>(callbackInfo->GetUid(),
395             callbackInfo->GetPid(), callbackInfo->GetResourceNumber(), callbackInfo->GetBundleName()));
396         iter = infoMap.find(mapKey);
397     } else {
398         preResourceNumber = iter->second->resourceNumber_;
399         iter->second->resourceNumber_ |= callbackInfo->GetResourceNumber();
400     }
401     BGTASK_LOGD("start to update resources end time");
402     UpdateResourcesEndtime(callbackInfo, iter->second, resourceInfo);
403     uint32_t diffResourceNumber = iter->second->resourceNumber_ ^ (preResourceNumber & iter->second->resourceNumber_);
404     if (diffResourceNumber == 0) {
405         BGTASK_LOGD("after update end time, diff between resourcesNumbers is zero");
406         DelayedSingleton<DataStorageHelper>::GetInstance()->RefreshResourceRecord(
407             appResourceApplyMap_, procResourceApplyMap_);
408         return;
409     }
410 
411     callbackInfo->SetResourceNumber(diffResourceNumber);
412     BGTASK_LOGD("after update end time, callbackInfo resource number is %{public}u,"\
413         " uid: %{public}d, bundle name: %{public}s", callbackInfo->GetResourceNumber(),
414         callbackInfo->GetUid(), callbackInfo->GetBundleName().c_str());
415     if (resourceInfo->IsProcess()) {
416         subscriberMgr_->OnResourceChanged(callbackInfo, EfficiencyResourcesEventType::RESOURCE_APPLY);
417     } else {
418         subscriberMgr_->OnResourceChanged(callbackInfo, EfficiencyResourcesEventType::APP_RESOURCE_APPLY);
419     }
420     DelayedSingleton<DataStorageHelper>::GetInstance()->RefreshResourceRecord(
421         appResourceApplyMap_, procResourceApplyMap_);
422 }
423 
UpdateResourcesEndtime(const std::shared_ptr<ResourceCallbackInfo> & callbackInfo,std::shared_ptr<ResourceApplicationRecord> & record,const sptr<EfficiencyResourceInfo> & resourceInfo)424 __attribute__((no_sanitize("cfi"))) void BgEfficiencyResourcesMgr::UpdateResourcesEndtime(
425     const std::shared_ptr<ResourceCallbackInfo> &callbackInfo, std::shared_ptr<ResourceApplicationRecord> &record,
426     const sptr<EfficiencyResourceInfo> &resourceInfo)
427 {
428     for (uint32_t resourceIndex = 0; resourceIndex < MAX_RESOURCES_TYPE_NUM; ++resourceIndex) {
429         if ((callbackInfo->GetResourceNumber() & (1 << resourceIndex)) == 0) {
430             continue;
431         }
432         auto task = [resourceIndex](const auto &it) {
433             return it.resourceIndex_ == resourceIndex;
434         };
435         auto resourceUnitIter = std::find_if(record->resourceUnitList_.begin(),
436             record->resourceUnitList_.end(), task);
437         int64_t endtime = TimeProvider::GetCurrentTime() + static_cast<int64_t>(resourceInfo->GetTimeOut());
438         if (resourceUnitIter == record->resourceUnitList_.end()) {
439             if (resourceInfo->IsPersist()) {
440                 endtime = 0;
441             }
442             record->resourceUnitList_.emplace_back(PersistTime {resourceIndex, resourceInfo->IsPersist(),
443                 endtime, resourceInfo->GetReason()});
444         } else {
445             resourceUnitIter->reason_ = resourceInfo->GetReason();
446             resourceUnitIter->isPersist_ = resourceUnitIter->isPersist_ || resourceInfo->IsPersist();
447             if (resourceUnitIter->isPersist_) {
448                 resourceUnitIter->endTime_ = 0;
449             } else {
450                 resourceUnitIter->endTime_ = std::max(resourceUnitIter->endTime_,
451                     endtime);
452             }
453         }
454     }
455     BGTASK_LOGD("update end time of resource");
456     if (resourceInfo->IsPersist()) {
457         return;
458     }
459     const bool isProcess = resourceInfo->IsProcess();
460     int32_t mapKey = isProcess ? callbackInfo->GetPid() : callbackInfo->GetUid();
461     const auto& mgr = shared_from_this();
462     auto task = [mgr, mapKey, isProcess] () {
463         mgr->ResetTimeOutResource(mapKey, isProcess);
464     };
465     handler_->PostTask(task, resourceInfo->GetTimeOut());
466 }
467 
ResetTimeOutResource(int32_t mapKey,bool isProcess)468 void BgEfficiencyResourcesMgr::ResetTimeOutResource(int32_t mapKey, bool isProcess)
469 {
470     BGTASK_LOGD("ResetTimeOutResource reset efficiency rsources, mapkey: %{public}d",
471         mapKey);
472     auto &infoMap = isProcess ? procResourceApplyMap_ : appResourceApplyMap_;
473     auto type = isProcess ? EfficiencyResourcesEventType::RESOURCE_RESET :
474         EfficiencyResourcesEventType::APP_RESOURCE_RESET;
475     auto iter = infoMap.find(mapKey);
476     if (iter == infoMap.end()) {
477         BGTASK_LOGI("efficiency resource does not exist");
478         return;
479     }
480     auto &resourceRecord = iter->second;
481     uint32_t eraseBit = 0;
482     for (auto recordIter = resourceRecord->resourceUnitList_.begin();
483         recordIter != resourceRecord->resourceUnitList_.end(); ++recordIter) {
484         if (recordIter->isPersist_) {
485             continue;
486         }
487         auto endTime = recordIter->endTime_;
488         if (TimeProvider::GetCurrentTime() >= endTime) {
489             eraseBit |= 1 << recordIter->resourceIndex_;
490         }
491     }
492     BGTASK_LOGD("ResetTimeOutResource eraseBit: %{public}u, resourceNumber: %{public}u, result: %{public}u",
493         eraseBit, resourceRecord->resourceNumber_, resourceRecord->resourceNumber_ ^ eraseBit);
494     if (eraseBit == 0) {
495         BGTASK_LOGD("try to reset time out resources, but find nothing to reset");
496         return;
497     }
498     resourceRecord->resourceNumber_ ^= eraseBit;
499     RemoveListRecord(resourceRecord->resourceUnitList_, eraseBit);
500     auto callbackInfo = std::make_shared<ResourceCallbackInfo>(resourceRecord->uid_, resourceRecord->pid_, eraseBit,
501         resourceRecord->bundleName_);
502     BGTASK_LOGI("after reset time out resources, callbackInfo resource number is %{public}u,"\
503         " uid: %{public}d, bundle name: %{public}s", callbackInfo->GetResourceNumber(),
504         callbackInfo->GetUid(), callbackInfo->GetBundleName().c_str());
505     subscriberMgr_->OnResourceChanged(callbackInfo, type);
506     if (resourceRecord->resourceNumber_ == 0) {
507         infoMap.erase(iter);
508     }
509 }
510 
ResetAllEfficiencyResources()511 ErrCode BgEfficiencyResourcesMgr::ResetAllEfficiencyResources()
512 {
513     HitraceScoped traceScoped(HITRACE_TAG_OHOS,
514         "BackgroundTaskManager::EfficiencyResource::Service::ResetAllEfficiencyResources");
515     BGTASK_LOGD("start to reset all efficiency resources");
516     if (!isSysReady_.load()) {
517         BGTASK_LOGW("efficiency resources manager is not ready");
518         return ERR_BGTASK_SYS_NOT_READY;
519     }
520 
521     auto uid = IPCSkeleton::GetCallingUid();
522     auto pid = IPCSkeleton::GetCallingPid();
523     std::string bundleName = "";
524     if (!IsCallingInfoLegal(uid, pid, bundleName)) {
525         BGTASK_LOGE("reset efficiency resources failed, calling info is illegal");
526         return ERR_BGTASK_INVALID_PID_OR_UID;
527     }
528     uint64_t tokenId = IPCSkeleton::GetCallingFullTokenID();
529     if (!BundleManagerHelper::GetInstance()->IsSystemApp(tokenId) && !IsServiceExtensionType(pid)) {
530         BGTASK_LOGE("reset efficiency resources failed, %{public}s is not system app and service extension type",
531             bundleName.c_str());
532         return ERR_BGTASK_NOT_SYSTEM_APP;
533     }
534 
535     auto exemptedResourceType = GetExemptedResourceType(MAX_RESOURCE_MASK, uid, bundleName);
536     if (exemptedResourceType == 0) {
537         BGTASK_LOGE("reset efficiency resources failed, no permitted resource type");
538         return ERR_BGTASK_PERMISSION_DENIED;
539     }
540 
541     handler_->PostTask([this, exemptedResourceType, uid, pid, bundleName]() {
542         std::shared_ptr<ResourceCallbackInfo> callbackInfo = std::make_shared<ResourceCallbackInfo>(uid,
543             pid, exemptedResourceType, bundleName);
544         this->ResetEfficiencyResourcesInner(callbackInfo, false);
545     });
546     return ERR_OK;
547 }
548 
RemoveRelativeProcessRecord(int32_t uid,uint32_t resourceNumber)549 void BgEfficiencyResourcesMgr::RemoveRelativeProcessRecord(int32_t uid, uint32_t resourceNumber)
550 {
551     for (auto iter = procResourceApplyMap_.begin(); iter != procResourceApplyMap_.end(); iter++) {
552         if (iter->second->uid_ == uid && (resourceNumber & iter->second->resourceNumber_) != 0) {
553             uint32_t eraseBit = (resourceNumber & iter->second->resourceNumber_);
554             std::shared_ptr<ResourceCallbackInfo> callbackInfo = std::make_shared<ResourceCallbackInfo>(uid,
555                 iter->second->pid_, eraseBit, iter->second->bundleName_);
556             handler_->PostTask([this, callbackInfo]() {
557                 this->ResetEfficiencyResourcesInner(callbackInfo, true);
558             });
559         }
560     }
561 }
562 
ResetEfficiencyResourcesInner(const std::shared_ptr<ResourceCallbackInfo> & callbackInfo,bool isProcess)563 void BgEfficiencyResourcesMgr::ResetEfficiencyResourcesInner(
564     const std::shared_ptr<ResourceCallbackInfo> &callbackInfo, bool isProcess)
565 {
566     HitraceScoped traceScoped(HITRACE_TAG_OHOS,
567         "BackgroundTaskManager::EfficiencyResource::Service::ResetEfficiencyResourcesInner");
568 
569     BGTASK_LOGD("reset efficiency resources inner,  uid:%{public}d, pid %{public}d,"\
570         " resource number: %{public}u, isProcess: %{public}d", callbackInfo->GetUid(),
571         callbackInfo->GetPid(), callbackInfo->GetResourceNumber(), isProcess);
572     if (isProcess) {
573         RemoveTargetResourceRecord(procResourceApplyMap_, callbackInfo->GetPid(),
574             callbackInfo->GetResourceNumber(), EfficiencyResourcesEventType::RESOURCE_RESET);
575     } else {
576         RemoveTargetResourceRecord(appResourceApplyMap_, callbackInfo->GetUid(),
577             callbackInfo->GetResourceNumber(), EfficiencyResourcesEventType::APP_RESOURCE_RESET);
578         RemoveRelativeProcessRecord(callbackInfo->GetUid(), callbackInfo->GetResourceNumber());
579     }
580     DelayedSingleton<DataStorageHelper>::GetInstance()->RefreshResourceRecord(
581         appResourceApplyMap_, procResourceApplyMap_);
582 }
583 
IsCallingInfoLegal(int32_t uid,int32_t pid,std::string & bundleName)584 bool BgEfficiencyResourcesMgr::IsCallingInfoLegal(int32_t uid, int32_t pid, std::string &bundleName)
585 {
586     if (uid < 0 || pid < 0) {
587         BGTASK_LOGE("pid or uid is invalid");
588         return false;
589     }
590     bundleName = BundleManagerHelper::GetInstance()->GetClientBundleName(uid);
591     return true;
592 }
593 
AddSubscriber(const sptr<IBackgroundTaskSubscriber> & subscriber)594 ErrCode BgEfficiencyResourcesMgr::AddSubscriber(const sptr<IBackgroundTaskSubscriber> &subscriber)
595 {
596     BGTASK_LOGD("add subscriber to efficiency resources succeed");
597     handler_->PostSyncTask([this, &subscriber]() {
598         subscriberMgr_->AddSubscriber(subscriber);
599     });
600     return ERR_OK;
601 }
602 
RemoveSubscriber(const sptr<IBackgroundTaskSubscriber> & subscriber)603 ErrCode BgEfficiencyResourcesMgr::RemoveSubscriber(const sptr<IBackgroundTaskSubscriber> &subscriber)
604 {
605     BGTASK_LOGD("remove subscriber to efficiency resources succeed");
606     ErrCode result {};
607     handler_->PostSyncTask([this, &result, &subscriber]() {
608         result = subscriberMgr_->RemoveSubscriber(subscriber);
609     });
610     return result;
611 }
612 
ShellDump(const std::vector<std::string> & dumpOption,std::vector<std::string> & dumpInfo)613 ErrCode BgEfficiencyResourcesMgr::ShellDump(const std::vector<std::string> &dumpOption,
614     std::vector<std::string> &dumpInfo)
615 {
616     if (!isSysReady_.load()) {
617         BGTASK_LOGE("manager is not ready");
618         return ERR_BGTASK_SYS_NOT_READY;
619     }
620     handler_->PostSyncTask([&]() {
621         this->ShellDumpInner(dumpOption, dumpInfo);
622     });
623     return ERR_OK;
624 }
625 
ShellDumpInner(const std::vector<std::string> & dumpOption,std::vector<std::string> & dumpInfo)626 ErrCode BgEfficiencyResourcesMgr::ShellDumpInner(const std::vector<std::string> &dumpOption,
627     std::vector<std::string> &dumpInfo)
628 {
629     if (dumpOption[1] == DUMP_PARAM_LIST_ALL) {
630         DumpAllApplicationInfo(dumpInfo);
631     } else if (dumpOption[1] == DUMP_PARAM_RESET_ALL) {
632         DumpResetAllResource(dumpInfo);
633     } else if (dumpOption[1] == DUMP_PARAM_RESET_APP) {
634         DumpResetResource(dumpOption, true, false);
635     } else if (dumpOption[1] == DUMP_PARAM_RESET_PROC) {
636         DumpResetResource(dumpOption, false, false);
637     }
638     DelayedSingleton<DataStorageHelper>::GetInstance()->RefreshResourceRecord(
639         appResourceApplyMap_, procResourceApplyMap_);
640     return ERR_OK;
641 }
642 
DumpAllApplicationInfo(std::vector<std::string> & dumpInfo)643 void BgEfficiencyResourcesMgr::DumpAllApplicationInfo(std::vector<std::string> &dumpInfo)
644 {
645     std::stringstream stream;
646     if (appResourceApplyMap_.empty() && procResourceApplyMap_.empty()) {
647         dumpInfo.emplace_back("No running efficiency resources\n");
648         return;
649     }
650     DumpApplicationInfoMap(appResourceApplyMap_, dumpInfo, stream, "app efficiency resource: \n");
651     DumpApplicationInfoMap(procResourceApplyMap_, dumpInfo, stream, "process efficiency resource: \n");
652 }
653 
DumpApplicationInfoMap(std::unordered_map<int32_t,std::shared_ptr<ResourceApplicationRecord>> & infoMap,std::vector<std::string> & dumpInfo,std::stringstream & stream,const char * headInfo)654 void BgEfficiencyResourcesMgr::DumpApplicationInfoMap(std::unordered_map<int32_t,
655     std::shared_ptr<ResourceApplicationRecord>> &infoMap, std::vector<std::string> &dumpInfo,
656     std::stringstream &stream, const char *headInfo)
657 {
658     uint32_t index = 1;
659     stream << headInfo << "\n";
660     for (auto iter = infoMap.begin(); iter != infoMap.end(); iter++) {
661         stream << "No." << index << "\n";
662         stream << "\tefficiencyResourceKey: " << iter->first << "\n";
663         stream << "\tefficiencyResourceValue:" << "\n";
664         stream << "\t\tbundleName: " << iter->second->GetBundleName() << "\n";
665         stream << "\t\tuid: " << iter->second->GetUid() << "\n";
666         stream << "\t\tpid: " << iter->second->GetPid() << "\n";
667         stream << "\t\tresourceNumber: " << iter->second->GetResourceNumber() << "\n";
668         int64_t curTime = TimeProvider::GetCurrentTime();
669         auto &resourceUnitList = iter->second->resourceUnitList_;
670         for (auto unitIter = resourceUnitList.begin();
671             unitIter != resourceUnitList.end(); ++unitIter) {
672             stream << "\t\t\tresource type: " << ResourceTypeName[unitIter->resourceIndex_] << "\n";
673             stream << "\t\t\tisPersist: " << (unitIter->isPersist_ ? "true" : "false") << "\n";
674             if (!unitIter->isPersist_) {
675                 stream << "\t\t\tremainTime: " << unitIter->endTime_ - curTime << "\n";
676             }
677             stream << "\t\t\treason: " << unitIter->reason_ << "\n";
678         }
679         stream << "\n";
680         dumpInfo.emplace_back(stream.str());
681         stream.str("");
682         stream.clear();
683         index++;
684     }
685 }
686 
DumpResetAllResource(const std::vector<std::string> & dumpOption)687 void BgEfficiencyResourcesMgr::DumpResetAllResource(const std::vector<std::string> &dumpOption)
688 {
689     DumpResetResource(dumpOption, true, true);
690     DumpResetResource(dumpOption, false, true);
691 }
692 
DumpResetResource(const std::vector<std::string> & dumpOption,bool cleanApp,bool cleanAll)693 void BgEfficiencyResourcesMgr::DumpResetResource(const std::vector<std::string> &dumpOption,
694     bool cleanApp, bool cleanAll)
695 {
696     auto &infoMap = cleanApp ? appResourceApplyMap_ : procResourceApplyMap_;
697     auto type = cleanApp ? EfficiencyResourcesEventType::APP_RESOURCE_RESET
698         : EfficiencyResourcesEventType::RESOURCE_RESET;
699 
700     if (cleanAll) {
701         for (auto iter = infoMap.begin(); iter != infoMap.end(); ++iter) {
702             std::shared_ptr<ResourceCallbackInfo> callbackInfo = std::make_shared<ResourceCallbackInfo>
703                 (iter->second->GetUid(), iter->second->GetPid(), iter->second->GetResourceNumber(),
704                 iter->second->GetBundleName());
705             subscriberMgr_->OnResourceChanged(callbackInfo, type);
706         }
707         infoMap.clear();
708     } else {
709         if (dumpOption.size() < MAX_DUMP_PARAM_NUMS) {
710             BGTASK_LOGW("invalid dump param");
711             return;
712         }
713         int32_t mapKey = std::atoi(dumpOption[2].c_str());
714         uint32_t cleanResource = static_cast<uint32_t>(std::atoi(dumpOption[3].c_str()));
715         RemoveTargetResourceRecord(infoMap, mapKey, cleanResource, type);
716     }
717 }
718 
RemoveTargetResourceRecord(std::unordered_map<int32_t,std::shared_ptr<ResourceApplicationRecord>> & infoMap,int32_t mapKey,uint32_t cleanResource,EfficiencyResourcesEventType type)719 bool BgEfficiencyResourcesMgr::RemoveTargetResourceRecord(std::unordered_map<int32_t,
720     std::shared_ptr<ResourceApplicationRecord>> &infoMap, int32_t mapKey, uint32_t cleanResource,
721     EfficiencyResourcesEventType type)
722 {
723     BGTASK_LOGD("resource record key: %{public}d, resource record size(): %{public}d",
724         mapKey, static_cast<int32_t>(infoMap.size()));
725     auto iter = infoMap.find(mapKey);
726     if (iter == infoMap.end() || (iter->second->resourceNumber_ & cleanResource) == 0) {
727         BGTASK_LOGD("remove single resource record failure, no matched task: %{public}d", mapKey);
728         return false;
729     }
730     uint32_t eraseBit = (iter->second->resourceNumber_ & cleanResource);
731     iter->second->resourceNumber_ ^= eraseBit;
732     RemoveListRecord(iter->second->resourceUnitList_, eraseBit);
733     auto callbackInfo = std::make_shared<ResourceCallbackInfo>(iter->second->GetUid(),
734         iter->second->GetPid(), eraseBit, iter->second->GetBundleName());
735     BGTASK_LOGI("remove record from info map, mapkey %{public}d, uid: %{public}d, bundle name: %{public}s"
736         "erasebit %{public}d", mapKey, callbackInfo->GetUid(), callbackInfo->GetBundleName().c_str(), eraseBit);
737     subscriberMgr_->OnResourceChanged(callbackInfo, type);
738     if (iter->second->resourceNumber_ == 0) {
739         infoMap.erase(iter);
740     }
741     return true;
742 }
743 
RemoveListRecord(std::list<PersistTime> & resourceUnitList,uint32_t eraseBit)744 void BgEfficiencyResourcesMgr::RemoveListRecord(std::list<PersistTime> &resourceUnitList, uint32_t eraseBit)
745 {
746     BGTASK_LOGD("start remove record from list, eraseBit: %{public}d", eraseBit);
747     if (eraseBit == 0) {
748         return;
749     }
750     for (auto it = resourceUnitList.begin(); it != resourceUnitList.end();) {
751         if (((1 << it->resourceIndex_) & eraseBit) != 0) {
752             it = resourceUnitList.erase(it);
753         } else {
754             ++it;
755         }
756     }
757 }
758 
GetEfficiencyResourcesInfos(std::vector<std::shared_ptr<ResourceCallbackInfo>> & appList,std::vector<std::shared_ptr<ResourceCallbackInfo>> & procList)759 ErrCode BgEfficiencyResourcesMgr::GetEfficiencyResourcesInfos(std::vector<std::shared_ptr<
760     ResourceCallbackInfo>> &appList, std::vector<std::shared_ptr<ResourceCallbackInfo>> &procList)
761 {
762     handler_->PostSyncTask([this, &appList, &procList]() {
763         this->GetEfficiencyResourcesInfosInner(appResourceApplyMap_, appList);
764         this->GetEfficiencyResourcesInfosInner(procResourceApplyMap_, procList);
765         }, AppExecFwk::EventQueue::Priority::HIGH);
766 
767     return ERR_OK;
768 }
769 
GetEfficiencyResourcesInfosInner(const ResourceRecordMap & infoMap,std::vector<std::shared_ptr<ResourceCallbackInfo>> & list)770 void BgEfficiencyResourcesMgr::GetEfficiencyResourcesInfosInner(const ResourceRecordMap &infoMap,
771     std::vector<std::shared_ptr<ResourceCallbackInfo>> &list)
772 {
773     if (infoMap.empty()) {
774         return;
775     }
776     BGTASK_LOGD("get efficiency resources info inner function, resources record size(): %{public}d ",
777         static_cast<int32_t>(infoMap.size()));
778     for (auto &record : infoMap) {
779         auto appInfo = std::make_shared<ResourceCallbackInfo>(record.second->uid_, record.second->pid_,
780             record.second->resourceNumber_, record.second->bundleName_);
781         list.push_back(appInfo);
782     }
783 }
784 
GetExemptedResourceType(uint32_t resourceNumber,const int32_t uid,const std::string & bundleName)785 uint32_t BgEfficiencyResourcesMgr::GetExemptedResourceType(uint32_t resourceNumber, const int32_t uid,
786     const std::string &bundleName)
787 {
788     const std::vector<int32_t>& resourcesApply = QueryRunningResourcesApply(uid, bundleName);
789 
790     uint32_t exemptedResources = 0;
791     if (resourcesApply.empty()) {
792         return exemptedResources;
793     }
794 
795     // application is permitted to use all type of resources if FREEZE_ALL_RESOURCES in resourceApply
796     if (std::find(resourcesApply.begin(), resourcesApply.end(), FREEZE_ALL_RESOURCES) != resourcesApply.end()) {
797         return resourceNumber;
798     }
799 
800     // traverse resourcesApply and get exempted resource type
801     for (const auto resourceType : resourcesApply) {
802         if (resourceType < 0 || resourceType > static_cast<int32_t>(MAX_RESOURCES_TYPE_NUM)) {
803             continue;
804         }
805         // (1 << (resourceType - 1)) map number in resourceApply to resourceType defined in resource_type.h
806         exemptedResources |= (1 << (resourceType - 1));
807     }
808     exemptedResources &= resourceNumber;
809     BGTASK_LOGD("after filter, uid: %{public}d, bundleName: %{public}s, origin resource number: %{public}u, return "\
810         "resource number: %{public}u", uid, bundleName.c_str(), resourceNumber, exemptedResources);
811 
812     return exemptedResources;
813 }
814 
815 // meaning of number in resourcesApply list: 0 - all type of resources, 1 - cpu, 2 - COMMON_EVENT, 3 - TIMER,
816 // 4 - WORK_SCHEDULER, 5 - BLUETOOTH, 6 - GPS, 7 - AUDIO, 8 - RUNNING_LOCK, 9 - SENSOR
QueryRunningResourcesApply(const int32_t uid,const std::string & bundleName)817 std::vector<int32_t> BgEfficiencyResourcesMgr::QueryRunningResourcesApply(const int32_t uid,
818     const std::string &bundleName)
819 {
820     AppExecFwk::ApplicationInfo applicationInfo;
821     if (!BundleManagerHelper::GetInstance()->GetApplicationInfo(bundleName,
822         AppExecFwk::ApplicationFlag::GET_BASIC_APPLICATION_INFO, GetUserIdByUid(uid), applicationInfo)) {
823         BGTASK_LOGE("failed to get applicationInfo from AppExecFwk, bundleName is %{public}s", bundleName.c_str());
824         return {};
825     }
826     BGTASK_LOGD("size of applicationInfo.resourcesApply is %{public}d",
827         static_cast<int32_t>(applicationInfo.resourcesApply.size()));
828     return applicationInfo.resourcesApply;
829 }
830 
GetUserIdByUid(int32_t uid)831 int32_t BgEfficiencyResourcesMgr::GetUserIdByUid(int32_t uid)
832 {
833     const int32_t BASE_USER_RANGE = 200000;
834     return uid / BASE_USER_RANGE;
835 }
836 }  // namespace BackgroundTaskMgr
837 }  // namespace OHOS
838