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 "decision_maker.h"
17 
18 #include <climits>
19 
20 #include "bg_transient_task_mgr.h"
21 #include "bgtask_common.h"
22 #include "transient_task_log.h"
23 #include "time_provider.h"
24 #include "iservice_registry.h"
25 #include "system_ability_definition.h"
26 #include "hisysevent.h"
27 #include "parameters.h"
28 #include "data_storage_helper.h"
29 #include "bgtask_config.h"
30 
31 using namespace std;
32 
33 namespace OHOS {
34 namespace BackgroundTaskMgr {
35 namespace {
36     const std::string SUSPEND_MANAGER_CONFIG_FILE = "/etc/efficiency_manager/suspend_manager_config.json";
37 }
DecisionMaker(const shared_ptr<TimerManager> & timerManager,const shared_ptr<DeviceInfoManager> & device)38 DecisionMaker::DecisionMaker(const shared_ptr<TimerManager>& timerManager, const shared_ptr<DeviceInfoManager>& device)
39 {
40     lock_guard<mutex> lock(lock_);
41     timerManager_ = timerManager;
42     deviceInfoManager_ = device;
43 
44     if (!GetAppMgrProxy()) {
45         BGTASK_LOGE("GetAppMgrProxy failed");
46         return;
47     }
48 }
49 
~DecisionMaker()50 DecisionMaker::~DecisionMaker()
51 {
52     lock_guard<mutex> lock(lock_);
53     if (appMgrProxy_ && observer_) {
54         appMgrProxy_->UnregisterApplicationStateObserver(iface_cast<AppExecFwk::IApplicationStateObserver>(observer_));
55     }
56     appMgrProxy_ = nullptr;
57     observer_ = nullptr;
58     recipient_ = nullptr;
59 }
60 
GetAppMgrProxy()61 bool DecisionMaker::GetAppMgrProxy()
62 {
63     if (appMgrProxy_ != nullptr) {
64         return true;
65     }
66 
67     sptr<ISystemAbilityManager> systemAbilityManager =
68         SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
69     if (systemAbilityManager == nullptr) {
70         BGTASK_LOGE("GetSystemAbilityManager failed.");
71         return false;
72     }
73 
74     sptr<IRemoteObject> remoteObject =
75         systemAbilityManager->GetSystemAbility(APP_MGR_SERVICE_ID);
76     if (remoteObject == nullptr) {
77         BGTASK_LOGE("GetSystemAbility failed.");
78         return false;
79     }
80 
81     appMgrProxy_ = iface_cast<AppExecFwk::IAppMgr>(remoteObject);
82     if ((appMgrProxy_ == nullptr) || (appMgrProxy_->AsObject() == nullptr)) {
83         BGTASK_LOGE("iface_cast remoteObject failed.");
84         return false;
85     }
86     observer_ = new (std::nothrow) ApplicationStateObserver(*this);
87     if (observer_ == nullptr) {
88         return false;
89     }
90     appMgrProxy_->RegisterApplicationStateObserver(iface_cast<AppExecFwk::IApplicationStateObserver>(observer_));
91 
92     recipient_ = new (std::nothrow) AppMgrDeathRecipient(*this);
93     if (recipient_ == nullptr) {
94         return false;
95     }
96     appMgrProxy_->AsObject()->AddDeathRecipient(recipient_);
97     return true;
98 }
99 
ResetAppMgrProxy()100 void DecisionMaker::ResetAppMgrProxy()
101 {
102     if ((appMgrProxy_ != nullptr) && (appMgrProxy_->AsObject() != nullptr)) {
103         appMgrProxy_->AsObject()->RemoveDeathRecipient(recipient_);
104     }
105     appMgrProxy_ = nullptr;
106 }
107 
OnRemoteDied(const wptr<IRemoteObject> & remote)108 void DecisionMaker::AppMgrDeathRecipient::OnRemoteDied(const wptr<IRemoteObject> &remote)
109 {
110     lock_guard<mutex> lock(decisionMaker_.lock_);
111     decisionMaker_.ResetAppMgrProxy();
112     decisionMaker_.GetAppMgrProxy();
113 }
114 
OnForegroundApplicationChanged(const AppExecFwk::AppStateData & appStateData)115 void DecisionMaker::ApplicationStateObserver::OnForegroundApplicationChanged(
116     const AppExecFwk::AppStateData &appStateData)
117 {
118     lock_guard<mutex> lock(decisionMaker_.lock_);
119 
120     auto key = std::make_shared<KeyInfo>(appStateData.bundleName, appStateData.uid);
121     if (appStateData.state == static_cast<int32_t>(AppExecFwk::ApplicationState::APP_STATE_FOREGROUND) ||
122         appStateData.state == static_cast<int32_t>(AppExecFwk::ApplicationState::APP_STATE_FOCUS)) {
123         auto it = decisionMaker_.pkgDelaySuspendInfoMap_.find(key);
124         if (it != decisionMaker_.pkgDelaySuspendInfoMap_.end()) {
125             auto pkgInfo = it->second;
126             pkgInfo->StopAccountingAll();
127         }
128         auto itBg = decisionMaker_.pkgBgDurationMap_.find(key);
129         if (itBg != decisionMaker_.pkgBgDurationMap_.end()) {
130             decisionMaker_.pkgBgDurationMap_.erase(itBg);
131         }
132     } else if (appStateData.state == static_cast<int32_t>(AppExecFwk::ApplicationState::APP_STATE_BACKGROUND)) {
133         decisionMaker_.pkgBgDurationMap_[key] = TimeProvider::GetCurrentTime();
134         auto it = decisionMaker_.pkgDelaySuspendInfoMap_.find(key);
135         if (it == decisionMaker_.pkgDelaySuspendInfoMap_.end()) {
136             return;
137         }
138         auto pkgInfo = it->second;
139         if (decisionMaker_.CanStartAccountingLocked(pkgInfo)) {
140             pkgInfo->StartAccounting();
141         }
142     }
143 }
144 
GetAllowRequestTime()145 int DecisionMaker::GetAllowRequestTime()
146 {
147     static int time = 0;
148 
149     if (time != 0) {
150         return time;
151     }
152     if (!DelayedSingleton<DataStorageHelper>::GetInstance()->ParseFastSuspendDozeTime(
153         SUSPEND_MANAGER_CONFIG_FILE, time)) {
154         time = ALLOW_REQUEST_TIME_BG;
155     }
156     BGTASK_LOGI("time = %{public}d", time);
157     return time;
158 }
159 
CheckQuotaTime(const std::shared_ptr<PkgDelaySuspendInfo> & pkgInfo,const std::string & name,int32_t uid,const std::shared_ptr<KeyInfo> & key,bool & needSetTime)160 ErrCode DecisionMaker::CheckQuotaTime(const std::shared_ptr<PkgDelaySuspendInfo>& pkgInfo, const std::string &name,
161     int32_t uid, const std::shared_ptr<KeyInfo>& key, bool &needSetTime)
162 {
163     ErrCode ret = pkgInfo->IsAllowRequest();
164     if (ret == ERR_BGTASK_TIME_INSUFFICIENT) {
165         bool isExemptedApp = DelayedSingleton<BgtaskConfig>::GetInstance()->
166             IsTransientTaskExemptedQuatoApp(name);
167         BGTASK_LOGI("pkgname %{public}s has no quota time, isExemptedApp %{public}d", name.c_str(), isExemptedApp);
168         if (isExemptedApp) {
169             needSetTime = true;
170             return ERR_OK;
171         } else {
172             return ERR_BGTASK_TIME_INSUFFICIENT;
173         }
174     }
175     if (ret != ERR_OK) {
176         BGTASK_LOGE("Request not allow by its info");
177         return ret;
178     }
179     return ERR_OK;
180 }
181 
Decide(const std::shared_ptr<KeyInfo> & key,const std::shared_ptr<DelaySuspendInfoEx> & delayInfo)182 ErrCode DecisionMaker::Decide(const std::shared_ptr<KeyInfo>& key, const std::shared_ptr<DelaySuspendInfoEx>& delayInfo)
183 {
184     lock_guard<mutex> lock(lock_);
185     if (key == nullptr || delayInfo == nullptr) {
186         BGTASK_LOGE("Invalid key or delayInfo");
187         return ERR_BGTASK_NO_MEMORY;
188     }
189 
190     ResetDayQuotaLocked();
191     auto findBgDurationIt = pkgBgDurationMap_.find(key);
192     if (findBgDurationIt != pkgBgDurationMap_.end()) {
193         if (TimeProvider::GetCurrentTime() - findBgDurationIt->second > GetAllowRequestTime()) {
194             BGTASK_LOGI("Request not allow after entering background for a valid duration, %{public}s",
195                 key->ToString().c_str());
196             return ERR_BGTASK_NOT_IN_PRESET_TIME;
197         }
198     }
199     const string &name = key->GetPkg();
200     int32_t uid = key->GetUid();
201     auto findInfoIt = pkgDelaySuspendInfoMap_.find(key);
202     if (findInfoIt == pkgDelaySuspendInfoMap_.end()) {
203         pkgDelaySuspendInfoMap_[key] = make_shared<PkgDelaySuspendInfo>(name, uid, timerManager_);
204     }
205     auto pkgInfo = pkgDelaySuspendInfoMap_[key];
206     bool needSetTime = false;
207     ErrCode ret = CheckQuotaTime(pkgInfo, name, uid, key, needSetTime);
208     if (ret != ERR_OK) {
209         return ret;
210     }
211     delayInfo->SetRequestId(NewDelaySuspendRequestId());
212     pkgInfo->AddRequest(delayInfo, GetDelayTime(), needSetTime);
213     auto appInfo = make_shared<TransientTaskAppInfo>(name, uid, key->GetPid());
214     DelayedSingleton<BgTransientTaskMgr>::GetInstance()
215         ->HandleTransientTaskSuscriberTask(appInfo, TransientTaskEventType::TASK_START);
216     if (pkgInfo->GetRequestSize() == 1) {
217         suspendController_.RequestSuspendDelay(key);
218         auto info = make_shared<TransientTaskAppInfo>(name, uid);
219         DelayedSingleton<BgTransientTaskMgr>::GetInstance()
220         ->HandleTransientTaskSuscriberTask(info, TransientTaskEventType::APP_TASK_START);
221     }
222     if (CanStartAccountingLocked(pkgInfo)) {
223         pkgInfo->StartAccounting(delayInfo->GetRequestId());
224     }
225     HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::BACKGROUND_TASK, "TRANSIENT_TASK_APPLY",
226         HiviewDFX::HiSysEvent::EventType::STATISTIC, "APP_UID", key->GetUid(), "APP_PID", key->GetPid(),
227         "APP_NAME", key->GetPkg(), "TASKID", delayInfo->GetRequestId(), "VALUE", delayInfo->GetActualDelayTime());
228     return ERR_OK;
229 }
230 
PauseTransientTaskTimeForInner(int32_t uid,const std::string & name)231 ErrCode DecisionMaker::PauseTransientTaskTimeForInner(int32_t uid, const std::string &name)
232 {
233     lock_guard<mutex> lock(lock_);
234     auto key = std::make_shared<KeyInfo>(name, uid);
235     auto itBg = pkgBgDurationMap_.find(key);
236     if (itBg == pkgBgDurationMap_.end()) {
237         BGTASK_LOGE("pkgname: %{public}s, uid: %{public}d is foreground applicaion.", name.c_str(), uid);
238         return ERR_BGTASK_FOREGROUND;
239     }
240     auto it = pkgDelaySuspendInfoMap_.find(key);
241     if (it == pkgDelaySuspendInfoMap_.end()) {
242         BGTASK_LOGE("pkgname: %{public}s, uid: %{public}d not request transient task.", name.c_str(), uid);
243         return ERR_BGTASK_NOREQUEST_TASK;
244     }
245     auto pkgInfo = it->second;
246     pkgInfo->StopAccountingAll();
247     return ERR_OK;
248 }
249 
StartTransientTaskTimeForInner(int32_t uid,const std::string & name)250 ErrCode DecisionMaker::StartTransientTaskTimeForInner(int32_t uid, const std::string &name)
251 {
252     lock_guard<mutex> lock(lock_);
253     auto key = std::make_shared<KeyInfo>(name, uid);
254     auto itBg = pkgBgDurationMap_.find(key);
255     if (itBg == pkgBgDurationMap_.end()) {
256         BGTASK_LOGE("pkgname: %{public}s, uid: %{public}d is foreground applicaion.", name.c_str(), uid);
257         return ERR_BGTASK_FOREGROUND;
258     }
259     auto it = pkgDelaySuspendInfoMap_.find(key);
260     if (it == pkgDelaySuspendInfoMap_.end()) {
261         BGTASK_LOGE("pkgname: %{public}s, uid: %{public}d not request transient task.", name.c_str(), uid);
262         return ERR_BGTASK_NOREQUEST_TASK;
263     }
264     auto pkgInfo = it->second;
265     if (CanStartAccountingLocked(pkgInfo)) {
266         pkgInfo->StartAccounting();
267     } else {
268         BGTASK_LOGE("pkgname: %{public}s, uid: %{public}d can't can startAccountingLocked.", name.c_str(), uid);
269         return ERR_BGTASK_FOREGROUND;
270     }
271     return ERR_OK;
272 }
273 
RemoveRequest(const std::shared_ptr<KeyInfo> & key,const int32_t requestId)274 void DecisionMaker::RemoveRequest(const std::shared_ptr<KeyInfo>& key, const int32_t requestId)
275 {
276     lock_guard<mutex> lock(lock_);
277     if (key == nullptr) {
278         BGTASK_LOGE("Invalid key");
279         return;
280     }
281 
282     auto findInfoIt = pkgDelaySuspendInfoMap_.find(key);
283     if (findInfoIt != pkgDelaySuspendInfoMap_.end()) {
284         auto pkgInfo = findInfoIt->second;
285         pkgInfo->RemoveRequest(requestId);
286         auto appInfo = make_shared<TransientTaskAppInfo>(key->GetPkg(), key->GetUid(), key->GetPid());
287         DelayedSingleton<BgTransientTaskMgr>::GetInstance()
288             ->HandleTransientTaskSuscriberTask(appInfo, TransientTaskEventType::TASK_END);
289         if (pkgInfo->IsRequestEmpty()) {
290             suspendController_.CancelSuspendDelay(key);
291             auto info = make_shared<TransientTaskAppInfo>(key->GetPkg(), key->GetUid());
292             DelayedSingleton<BgTransientTaskMgr>::GetInstance()
293                 ->HandleTransientTaskSuscriberTask(info, TransientTaskEventType::APP_TASK_END);
294         }
295         BGTASK_LOGD("Remove requestId: %{public}d", requestId);
296         HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::BACKGROUND_TASK, "TRANSIENT_TASK_CANCEL",
297             HiviewDFX::HiSysEvent::EventType::STATISTIC, "APP_UID", key->GetUid(), "APP_PID", key->GetPid(),
298             "APP_NAME", key->GetPkg(), "TASKID", requestId);
299     }
300 }
301 
GetRemainingDelayTime(const std::shared_ptr<KeyInfo> & key,const int32_t requestId)302 int32_t DecisionMaker::GetRemainingDelayTime(const std::shared_ptr<KeyInfo>& key, const int32_t requestId)
303 {
304     lock_guard<mutex> lock(lock_);
305     if (key == nullptr) {
306         BGTASK_LOGE("GetRemainingDelayTime, key is null.");
307         return -1;
308     }
309 
310     auto it = pkgDelaySuspendInfoMap_.find(key);
311     if (it != pkgDelaySuspendInfoMap_.end()) {
312         auto pkgInfo = it->second;
313         return pkgInfo->GetRemainDelayTime(requestId);
314     }
315     return -1;
316 }
317 
GetQuota(const std::shared_ptr<KeyInfo> & key)318 int32_t DecisionMaker::GetQuota(const std::shared_ptr<KeyInfo>& key)
319 {
320     lock_guard<mutex> lock(lock_);
321     if (key == nullptr) {
322         BGTASK_LOGE("GetQuota, key is null.");
323         return -1;
324     }
325 
326     auto it = pkgDelaySuspendInfoMap_.find(key);
327     if (it != pkgDelaySuspendInfoMap_.end()) {
328         auto pkgInfo = it->second;
329         pkgInfo->UpdateQuota();
330         return pkgInfo->GetQuota();
331     }
332     return INIT_QUOTA;
333 }
334 
IsFrontApp(const string & pkgName,int32_t uid)335 bool DecisionMaker::IsFrontApp(const string& pkgName, int32_t uid)
336 {
337     lock_guard<mutex> lock(lock_);
338     if (!GetAppMgrProxy()) {
339         BGTASK_LOGE("GetAppMgrProxy failed");
340         return false;
341     }
342     vector<AppExecFwk::AppStateData> fgAppList;
343     appMgrProxy_->GetForegroundApplications(fgAppList);
344     for (auto fgApp : fgAppList) {
345         if (fgApp.bundleName == pkgName && fgApp.uid == uid) {
346             return true;
347         }
348     }
349     return false;
350 }
351 
CanStartAccountingLocked(const std::shared_ptr<PkgDelaySuspendInfo> & pkgInfo)352 bool DecisionMaker::CanStartAccountingLocked(const std::shared_ptr<PkgDelaySuspendInfo>& pkgInfo)
353 {
354     if (!deviceInfoManager_->IsScreenOn()) {
355         return true;
356     }
357 
358     if (!GetAppMgrProxy()) {
359         BGTASK_LOGE("GetAppMgrProxy failed");
360         return false;
361     }
362     vector<AppExecFwk::AppStateData> fgAppList;
363     appMgrProxy_->GetForegroundApplications(fgAppList);
364     for (auto fgApp : fgAppList) {
365         if (fgApp.bundleName == pkgInfo->GetPkg() && fgApp.uid == pkgInfo->GetUid()) {
366             return false;
367         }
368     }
369     return true;
370 }
371 
GetDelayTime()372 int32_t DecisionMaker::GetDelayTime()
373 {
374     return deviceInfoManager_->IsLowPowerMode() ? DELAY_TIME_LOW_POWER : DELAY_TIME_NORMAL;
375 }
376 
NewDelaySuspendRequestId()377 int32_t DecisionMaker::NewDelaySuspendRequestId()
378 {
379     if (requestId_ == INT_MAX) {
380         requestId_ = initRequestId_;
381     }
382     return requestId_++;
383 }
384 
ResetDayQuotaLocked()385 void DecisionMaker::ResetDayQuotaLocked()
386 {
387     int64_t currentTime = TimeProvider::GetCurrentTime();
388     if (!IsAfterOneDay(lastRequestTime_, currentTime)) {
389         return;
390     }
391     for (auto iter = pkgDelaySuspendInfoMap_.begin(); iter != pkgDelaySuspendInfoMap_.end();) {
392         auto pkgInfo = iter->second;
393         if (pkgInfo->IsRequestEmpty()) {
394             iter = pkgDelaySuspendInfoMap_.erase(iter);
395         } else {
396             pkgInfo->UpdateQuota(true);
397             iter++;
398         }
399     }
400     lastRequestTime_ = currentTime;
401 }
402 
IsAfterOneDay(int64_t lastRequestTime,int64_t currentTime)403 bool DecisionMaker::IsAfterOneDay(int64_t lastRequestTime, int64_t currentTime)
404 {
405     if (currentTime - lastRequestTime > QUOTA_UPDATE) {
406         return true;
407     }
408     return false;
409 }
410 
OnInputEvent(const EventInfo & eventInfo)411 void DecisionMaker::OnInputEvent(const EventInfo& eventInfo)
412 {
413     if (!eventInfo.GetEventId()) {
414         return;
415     }
416 
417     switch (eventInfo.GetEventId()) {
418         case EVENT_SCREEN_ON:
419             HandleScreenOn();
420             break;
421         case EVENT_SCREEN_OFF:
422             HandleScreenOff();
423             break;
424         default:
425             break;
426     }
427 }
428 
HandleScreenOn()429 void DecisionMaker::HandleScreenOn()
430 {
431     lock_guard<mutex> lock(lock_);
432     if (!GetAppMgrProxy()) {
433         BGTASK_LOGE("GetAppMgrProxy failed");
434         return;
435     }
436     vector<AppExecFwk::AppStateData> fgAppList;
437     appMgrProxy_->GetForegroundApplications(fgAppList);
438     for (auto fgApp : fgAppList) {
439         auto key = std::make_shared<KeyInfo>(fgApp.bundleName, fgApp.uid);
440         auto it = pkgDelaySuspendInfoMap_.find(key);
441         if (it != pkgDelaySuspendInfoMap_.end()) {
442             auto pkgInfo = it->second;
443             pkgInfo->StopAccountingAll();
444         }
445     }
446 }
447 
HandleScreenOff()448 void DecisionMaker::HandleScreenOff()
449 {
450     lock_guard<mutex> lock(lock_);
451     std::set<int32_t> &transientPauseUid = DelayedSingleton<BgTransientTaskMgr>::GetInstance()
452         ->GetTransientPauseUid();
453     for (const auto &p : pkgDelaySuspendInfoMap_) {
454         auto pkgInfo = p.second;
455         auto findUid = [&pkgInfo](const auto &target) {
456             return pkgInfo->GetUid() == target;
457         };
458         auto findUidIter = find_if(transientPauseUid.begin(), transientPauseUid.end(), findUid);
459         if (findUidIter != transientPauseUid.end()) {
460             BGTASK_LOGD("transient task freeze, not can start.");
461             continue;
462         }
463         if (CanStartAccountingLocked(pkgInfo)) {
464             pkgInfo->StartAccounting();
465         }
466     }
467 }
468 }  // namespace BackgroundTaskMgr
469 }  // namespace OHOS