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