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