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