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