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