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