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 "work_policy_manager.h"
17 
18 #include <string>
19 #include <hisysevent.h>
20 #include <if_system_ability_manager.h>
21 #include <ipc_skeleton.h>
22 #include <iservice_registry.h>
23 #include <system_ability_definition.h>
24 #include "parameters.h"
25 #include "policy/app_data_clear_listener.h"
26 #include "work_scheduler_service.h"
27 #include "work_event_handler.h"
28 #include "work_sched_hilog.h"
29 #include "work_sched_errors.h"
30 #include "work_sched_utils.h"
31 #include "watchdog.h"
32 #include "work_sched_data_manager.h"
33 
34 using namespace std;
35 using namespace OHOS::AppExecFwk;
36 using namespace OHOS::HiviewDFX;
37 
38 namespace OHOS {
39 namespace WorkScheduler {
40 namespace {
41 const int32_t MAX_RUNNING_COUNT = 3;
42 const int32_t STANDBY_MAX_RUNNING_COUNT = 2 * MAX_RUNNING_COUNT;
43 const uint32_t MAX_WORK_COUNT_PER_UID = 10;
44 const int32_t DELAY_TIME_LONG = 30000;
45 const int32_t DELAY_TIME_SHORT = 5000;
46 const uint32_t MAX_WATCHDOG_ID = 1000;
47 const uint32_t INIT_WATCHDOG_ID = 1;
48 const int32_t INIT_DUMP_SET_MEMORY = -1;
49 const int32_t WATCHDOG_TIME = 2 * 60 * 1000;
50 const int32_t MEDIUM_WATCHDOG_TIME = 10 * 60 * 1000;
51 const int32_t LONG_WATCHDOG_TIME = 20 * 60 * 1000;
52 const int32_t INIT_DUMP_SET_CPU = 0;
53 const int32_t INVALID_VALUE = -1;
54 const int32_t DUMP_SET_MAX_COUNT_LIMIT = 100;
55 static int32_t g_lastWatchdogTime = WATCHDOG_TIME;
56 }
57 
WorkPolicyManager(const std::shared_ptr<WorkSchedulerService> & wss)58 WorkPolicyManager::WorkPolicyManager(const std::shared_ptr<WorkSchedulerService>& wss) : wss_(wss)
59 {
60     conditionReadyQueue_ = std::make_shared<WorkQueue>();
61     watchdogId_ = INIT_WATCHDOG_ID;
62     dumpSetMemory_ = INIT_DUMP_SET_MEMORY;
63     watchdogTime_ = WATCHDOG_TIME;
64     dumpSetCpu_ = INIT_DUMP_SET_CPU;
65     dumpSetMaxRunningCount_ = INVALID_VALUE;
66 }
67 
Init(const std::shared_ptr<AppExecFwk::EventRunner> & runner)68 bool WorkPolicyManager::Init(const std::shared_ptr<AppExecFwk::EventRunner>& runner)
69 {
70     WS_HILOGD("Work policy manager init.");
71     if (wss_.expired()) {
72         WS_HILOGE("wss_ expired");
73         return false;
74     }
75     workConnManager_ = make_shared<WorkConnManager>();
76     handler_ = wss_.lock()->GetHandler();
77     if (handler_ == nullptr) {
78         WS_HILOGE("failed due to handler_ is nullptr");
79         return false;
80     }
81     watchdog_ = std::make_shared<Watchdog>(wss_.lock()->GetWorkPolicyManager(), runner);
82     return true;
83 }
84 
AddPolicyFilter(shared_ptr<IPolicyFilter> filter)85 void WorkPolicyManager::AddPolicyFilter(shared_ptr<IPolicyFilter> filter)
86 {
87     policyFilters_.emplace_back(filter);
88 }
89 
AddAppDataClearListener(std::shared_ptr<AppDataClearListener> listener)90 void WorkPolicyManager::AddAppDataClearListener(std::shared_ptr<AppDataClearListener> listener)
91 {
92     appDataClearListener_ = listener;
93     appDataClearListener_->Start();
94 }
95 
96 
GetConditionString(const shared_ptr<WorkStatus> workStatus)97 std::string WorkPolicyManager::GetConditionString(const shared_ptr<WorkStatus> workStatus)
98 {
99     string conditions = "";
100     if (workStatus->workInfo_->GetConditionMap()->count(WorkCondition::Type::NETWORK) > 0) {
101         conditions.append("NETWORK-");
102     }
103 
104     if (workStatus->workInfo_->GetConditionMap()->count(WorkCondition::Type::CHARGER) > 0) {
105         conditions.append("CHARGER-");
106     }
107 
108     if (workStatus->workInfo_->GetConditionMap()->count(WorkCondition::Type::BATTERY_STATUS) > 0) {
109         conditions.append("BATTERY_STATUS-");
110     }
111 
112     if (workStatus->workInfo_->GetConditionMap()->count(WorkCondition::Type::BATTERY_LEVEL) > 0) {
113         conditions.append("BATTERY_LEVEL-");
114     }
115 
116     if (workStatus->workInfo_->GetConditionMap()->count(WorkCondition::Type::STORAGE) > 0) {
117         conditions.append("STORAGE-");
118     }
119 
120     if (workStatus->workInfo_->GetConditionMap()->count(WorkCondition::Type::TIMER) > 0) {
121         conditions.append("TIMER-");
122     }
123 
124     if (workStatus->workInfo_->GetConditionMap()->count(WorkCondition::Type::DEEP_IDLE) > 0) {
125         conditions.append("DEEP_IDLE-");
126     }
127     conditions.pop_back();
128     return conditions;
129 }
130 
AddWork(shared_ptr<WorkStatus> workStatus,int32_t uid)131 int32_t WorkPolicyManager::AddWork(shared_ptr<WorkStatus> workStatus, int32_t uid)
132 {
133     WS_HILOGD("Add work");
134     std::lock_guard<ffrt::recursive_mutex> lock(uidMapMutex_);
135     if (uidQueueMap_.count(uid) > 0) {
136         if (uidQueueMap_.at(uid)->Contains(make_shared<string>(workStatus->workId_))) {
137             WS_HILOGD("Workid has been added, should remove first.");
138             return E_ADD_REPEAT_WORK_ERR;
139         } else if (uidQueueMap_.at(uid)->GetSize() >= MAX_WORK_COUNT_PER_UID) {
140             WS_HILOGE("each uid only can be added %{public}u works", MAX_WORK_COUNT_PER_UID);
141             return E_WORK_EXCEED_UPPER_LIMIT;
142         }
143         uidQueueMap_.at(uid)->Push(workStatus);
144     } else {
145         WS_HILOGD("uidQueue(%{public}d) not exists, create", uid);
146         uidQueueMap_.emplace(uid, make_shared<WorkQueue>());
147         uidQueueMap_.at(uid)->Push(workStatus);
148     }
149 
150     // Notify work add event to battery statistics
151     int32_t pid = IPCSkeleton::GetCallingPid();
152     string type = "Repeat";
153     if (!workStatus->workInfo_->IsRepeat()) {
154         type = "Not Repeat";
155     }
156 
157     HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::WORK_SCHEDULER,
158         "WORK_ADD", HiSysEvent::EventType::STATISTIC, "UID", uid, "PID", pid,
159         "NAME", workStatus->bundleName_, "WORKID", workStatus->workId_, "TRIGGER", GetConditionString(workStatus),
160         "TYPE", type, "INTERVAL", workStatus->workInfo_->GetTimeInterval());
161 
162     WS_HILOGI("push workStatus ID: %{public}s to uidQueue(%{public}d)", workStatus->workId_.c_str(), uid);
163     return ERR_OK;
164 }
165 
RemoveWork(shared_ptr<WorkStatus> workStatus,int32_t uid)166 bool WorkPolicyManager::RemoveWork(shared_ptr<WorkStatus> workStatus, int32_t uid)
167 {
168     WS_HILOGD("Remove work.");
169     bool ret = false;
170     std::lock_guard<ffrt::recursive_mutex> lock(uidMapMutex_);
171     if (uidQueueMap_.count(uid) > 0) {
172         WS_HILOGD("Remove workStatus ID: %{public}s form uidQueue(%{public}d)", workStatus->workId_.c_str(), uid);
173         ret = uidQueueMap_.at(uid)->Remove(workStatus);
174         if (uidQueueMap_.count(uid) <= 0) {
175             uidQueueMap_.erase(uid);
176         }
177     }
178     return ret;
179 }
180 
FindWorkStatus(WorkInfo & workInfo,int32_t uid)181 shared_ptr<WorkStatus> WorkPolicyManager::FindWorkStatus(WorkInfo& workInfo, int32_t uid)
182 {
183     WS_HILOGD("Find work status start.");
184     std::lock_guard<ffrt::recursive_mutex> lock(uidMapMutex_);
185     if (uidQueueMap_.count(uid) > 0) {
186         return uidQueueMap_.at(uid)->Find(WorkStatus::MakeWorkId(workInfo.GetWorkId(), uid));
187     }
188     return nullptr;
189 }
190 
RemoveFromUidQueue(std::shared_ptr<WorkStatus> workStatus,int32_t uid)191 void WorkPolicyManager::RemoveFromUidQueue(std::shared_ptr<WorkStatus> workStatus, int32_t uid)
192 {
193     std::lock_guard<ffrt::recursive_mutex> lock(uidMapMutex_);
194     if (uidQueueMap_.count(uid) > 0) {
195         uidQueueMap_.at(uid)->CancelWork(workStatus);
196         if (uidQueueMap_.at(uid)->GetSize() <= 0) {
197             uidQueueMap_.erase(uid);
198         }
199     }
200 }
201 
RemoveFromReadyQueue(std::shared_ptr<WorkStatus> workStatus)202 void WorkPolicyManager::RemoveFromReadyQueue(std::shared_ptr<WorkStatus> workStatus)
203 {
204     conditionReadyQueue_->RemoveUnReady();
205 }
206 
StopWork(std::shared_ptr<WorkStatus> workStatus,int32_t uid,const bool needCancel,bool isTimeOut)207 bool WorkPolicyManager::StopWork(std::shared_ptr<WorkStatus> workStatus, int32_t uid,
208     const bool needCancel, bool isTimeOut)
209 {
210     WS_HILOGD("enter");
211     bool hasCanceled = false;
212     if (workStatus->IsRunning()) {
213         workStatus->lastTimeout_ = isTimeOut;
214         workConnManager_->StopWork(workStatus, isTimeOut);
215         if (!workStatus->IsRepeating()) {
216             workStatus->MarkStatus(WorkStatus::Status::REMOVED);
217             RemoveFromUidQueue(workStatus, uid);
218             RemoveFromReadyQueue(workStatus);
219             hasCanceled = true;
220         } else {
221             workStatus->workStartTime_ = 0;
222             workStatus->workWatchDogTime_ = 0;
223             workStatus->duration_ = 0;
224             workStatus->MarkStatus(WorkStatus::Status::WAIT_CONDITION);
225         }
226     }
227 
228     if (!hasCanceled && needCancel) {
229         RemoveFromUidQueue(workStatus, uid);
230         RemoveFromReadyQueue(workStatus);
231         hasCanceled = true;
232     }
233     if (isTimeOut && (workStatus->GetStatus() == WorkStatus::Status::REMOVED)) {
234         WS_HILOGI("disconect %{public}s when timeout", workStatus->workId_.c_str());
235         workStatus->lastTimeout_ = isTimeOut;
236         workConnManager_->StopWork(workStatus, isTimeOut);
237     }
238     CheckWorkToRun();
239     return hasCanceled;
240 }
241 
StopAndClearWorks(int32_t uid)242 bool WorkPolicyManager::StopAndClearWorks(int32_t uid)
243 {
244     WS_HILOGD("enter");
245     std::lock_guard<ffrt::recursive_mutex> lock(uidMapMutex_);
246     if (uidQueueMap_.count(uid) > 0) {
247         auto queue = uidQueueMap_.at(uid);
248         for (auto it : queue->GetWorkList()) {
249             workConnManager_->StopWork(it, false);
250             it->MarkStatus(WorkStatus::Status::REMOVED);
251             RemoveFromReadyQueue(it);
252         }
253         queue->ClearAll();
254         uidQueueMap_.erase(uid);
255     }
256     CheckWorkToRun();
257     return true;
258 }
259 
IsLastWorkTimeout(int32_t workId,int32_t uid,bool & result)260 int32_t WorkPolicyManager::IsLastWorkTimeout(int32_t workId, int32_t uid, bool &result)
261 {
262     std::lock_guard<ffrt::recursive_mutex> lock(uidMapMutex_);
263     string workIdStr = WorkStatus::MakeWorkId(workId, uid);
264     if (uidQueueMap_.count(uid) > 0) {
265         shared_ptr<WorkStatus> workStatus = uidQueueMap_.at(uid)->Find(workIdStr);
266         if (workStatus != nullptr) {
267             return workStatus->IsLastWorkTimeout();
268         }
269     }
270     return E_WORK_NOT_EXIST_FAILED;
271 }
272 
OnConditionReady(shared_ptr<vector<shared_ptr<WorkStatus>>> workStatusVector)273 void WorkPolicyManager::OnConditionReady(shared_ptr<vector<shared_ptr<WorkStatus>>> workStatusVector)
274 {
275     WS_HILOGD("enter");
276     if (workStatusVector == nullptr) {
277         return;
278     }
279     AddToReadyQueue(workStatusVector);
280     CheckWorkToRun();
281 }
282 
AddToReadyQueue(shared_ptr<vector<shared_ptr<WorkStatus>>> workStatusVector)283 void WorkPolicyManager::AddToReadyQueue(shared_ptr<vector<shared_ptr<WorkStatus>>> workStatusVector)
284 {
285     conditionReadyQueue_->Push(workStatusVector);
286 }
287 
GetMaxRunningCount(std::string & policyName)288 int32_t WorkPolicyManager::GetMaxRunningCount(std::string& policyName)
289 {
290     int32_t currentMaxRunning = GetDumpSetMaxRunningCount();
291     if (currentMaxRunning > 0 && currentMaxRunning <= DUMP_SET_MAX_COUNT_LIMIT) {
292         return currentMaxRunning;
293     }
294     currentMaxRunning = MAX_RUNNING_COUNT;
295     for (auto policyFilter : policyFilters_) {
296         int32_t policyMaxRunning = policyFilter->GetPolicyMaxRunning();
297         if (policyMaxRunning < currentMaxRunning) {
298             currentMaxRunning = policyMaxRunning;
299             policyName = policyFilter->GetPolicyName();
300         }
301     }
302     return currentMaxRunning;
303 }
304 
GetRunningCount()305 int32_t WorkPolicyManager::GetRunningCount()
306 {
307     WS_HILOGD("enter");
308     std::lock_guard<ffrt::recursive_mutex> lock(uidMapMutex_);
309     int32_t count = 0;
310     auto it = uidQueueMap_.begin();
311     while (it != uidQueueMap_.end()) {
312         count += it->second->GetRunningCount();
313         it++;
314     }
315     return count;
316 }
317 
OnPolicyChanged(PolicyType policyType,shared_ptr<DetectorValue> detectorVal)318 void WorkPolicyManager::OnPolicyChanged(PolicyType policyType, shared_ptr<DetectorValue> detectorVal)
319 {
320     WS_HILOGD("enter");
321     if (wss_.expired()) {
322         WS_HILOGE("wss_ expired");
323         return;
324     }
325     auto service = wss_.lock();
326     if (!service) {
327         WS_HILOGE("service is null");
328         return;
329     }
330     switch (policyType) {
331         case PolicyType::USER_SWITCHED: {
332             service->InitPreinstalledWork();
333             break;
334         }
335         case PolicyType::APP_ADDED: {
336             if (!service->IsPreinstalledBundle(detectorVal->strVal)) {
337                 return;
338             }
339             service->InitPreinstalledWork();
340             break;
341         }
342         case PolicyType::APP_REMOVED: {
343             int32_t uid = detectorVal->intVal;
344             WorkStatus::ClearUidLastTimeMap(uid);
345             service->StopAndClearWorksByUid(detectorVal->intVal);
346             int32_t userId = WorkSchedUtils::GetUserIdByUid(uid);
347             DelayedSingleton<DataManager>::GetInstance()->ClearGroup(detectorVal->strVal, userId);
348             break;
349         }
350         default: {}
351     }
352     CheckWorkToRun();
353 }
354 
IsSpecialScene(std::shared_ptr<WorkStatus> topWork,int32_t runningCount)355 bool WorkPolicyManager::IsSpecialScene(std::shared_ptr<WorkStatus> topWork, int32_t runningCount)
356 {
357     if (OHOS::system::GetIntParameter("const.debuggable", 0) == 1 &&
358         topWork->bundleName_ == "com.huawei.hmos.hiviewx") {
359         return true;
360     }
361     if (DelayedSingleton<DataManager>::GetInstance()->GetDeviceSleep() &&
362         runningCount < STANDBY_MAX_RUNNING_COUNT &&
363         DelayedSingleton<DataManager>::GetInstance()->IsInDeviceStandyWhitelist(topWork->bundleName_)) {
364         WS_HILOGI("device is in standy mode, and work %{public}s is in whitelist, allow to run",
365             topWork->bundleName_.c_str());
366         return true;
367     }
368     return false;
369 }
370 
CheckWorkToRun()371 void WorkPolicyManager::CheckWorkToRun()
372 {
373     WS_HILOGD("Check work to run.");
374     if (wss_.lock() == nullptr) {
375         WS_HILOGE("wss_ expired");
376         return;
377     }
378     RemoveAllUnReady();
379     if (handler_ == nullptr) {
380         WS_HILOGE("handler lock() returns nullptr");
381         return;
382     }
383     handler_->RemoveEvent(WorkEventHandler::RETRIGGER_MSG);
384     shared_ptr<WorkStatus> topWork = GetWorkToRun();
385     if (topWork == nullptr) {
386         WS_HILOGD("no condition ready work not running, return.");
387         return;
388     }
389     std::string policyName;
390     int32_t runningCount = GetRunningCount();
391     int32_t allowRunningCount = GetMaxRunningCount(policyName);
392     if (runningCount < allowRunningCount || IsSpecialScene(topWork, runningCount)) {
393         WS_HILOGD("running count < max running count");
394         RealStartWork(topWork);
395         SendRetrigger(DELAY_TIME_SHORT);
396     } else {
397         WS_HILOGD("trigger delay: %{public}d", DELAY_TIME_LONG);
398         if (runningCount == MAX_RUNNING_COUNT) {
399             policyName = "OVER_LIMIT";
400         }
401 
402         if (!policyName.empty()) {
403             topWork->delayReason_= policyName;
404             WS_HILOGI("trigger delay, reason: %{public}s, bundleName: %{public}s, runningCount:%{public}d,"
405                 " allowRunningCount:%{public}d",
406                 policyName.c_str(), topWork->bundleName_.c_str(), runningCount, allowRunningCount);
407         }
408         SendRetrigger(DELAY_TIME_LONG);
409     }
410     WS_HILOGD("out");
411 }
412 
RemoveAllUnReady()413 void WorkPolicyManager::RemoveAllUnReady()
414 {
415     conditionReadyQueue_->RemoveUnReady();
416 }
417 
GetWorkToRun()418 std::shared_ptr<WorkStatus> WorkPolicyManager::GetWorkToRun()
419 {
420     shared_ptr<WorkStatus> topWork = conditionReadyQueue_->GetWorkToRunByPriority();
421     return topWork;
422 }
423 
RealStartWork(std::shared_ptr<WorkStatus> topWork)424 void WorkPolicyManager::RealStartWork(std::shared_ptr<WorkStatus> topWork)
425 {
426     WS_HILOGD("RealStartWork topWork ID: %{public}s", topWork->workId_.c_str());
427     if (wss_.expired()) {
428         WS_HILOGE("wss_ expired");
429         return;
430     }
431     UpdateWatchdogTime(wss_.lock(), topWork);
432     topWork->MarkStatus(WorkStatus::Status::RUNNING);
433     wss_.lock()->UpdateWorkBeforeRealStart(topWork);
434     RemoveFromReadyQueue(topWork);
435     bool ret = workConnManager_->StartWork(topWork);
436     if (ret) {
437         AddWatchdogForWork(topWork);
438         topWork->UpdateUidLastTimeMap();
439     } else {
440         if (!topWork->IsRepeating()) {
441             topWork->MarkStatus(WorkStatus::Status::REMOVED);
442             RemoveFromUidQueue(topWork, topWork->uid_);
443         } else {
444             topWork->MarkStatus(WorkStatus::Status::WAIT_CONDITION);
445         }
446     }
447 }
448 
UpdateWatchdogTime(const std::shared_ptr<WorkSchedulerService> & wmsptr,std::shared_ptr<WorkStatus> & topWork)449 void WorkPolicyManager::UpdateWatchdogTime(const std::shared_ptr<WorkSchedulerService> &wmsptr,
450     std::shared_ptr<WorkStatus> &topWork)
451 {
452     if (topWork->workInfo_->GetDeepIdle() == WorkCondition::DeepIdle::DEEP_IDLE_IN
453         && topWork->workInfo_->GetChargerType() != WorkCondition::Charger::CHARGING_UNKNOWN
454         && topWork->workInfo_->GetChargerType() != WorkCondition::Charger::CHARGING_UNPLUGGED) {
455         WS_HILOGD("deep idle and charger condition, update watchdog time:%{public}d", LONG_WATCHDOG_TIME);
456         SetWatchdogTime(LONG_WATCHDOG_TIME);
457         return;
458     }
459 
460     if (!wmsptr->CheckEffiResApplyInfo(topWork->uid_)) {
461         SetWatchdogTime(g_lastWatchdogTime);
462         return;
463     }
464     int32_t chargerStatus = 0;
465     auto iter = topWork->conditionMap_.find(WorkCondition::Type::CHARGER);
466     if (iter != topWork->conditionMap_.end() && iter->second) {
467         chargerStatus = topWork->conditionMap_.at(WorkCondition::Type::CHARGER)->enumVal;
468     } else {
469         WS_HILOGD("charger is in CHARGING_UNKNOWN status");
470         chargerStatus = static_cast<int32_t>(WorkCondition::Charger::CHARGING_UNKNOWN);
471     }
472     if (chargerStatus == static_cast<int32_t>(WorkCondition::Charger::CHARGING_UNPLUGGED)
473         || chargerStatus == static_cast<int32_t>(WorkCondition::Charger::CHARGING_UNKNOWN)) {
474         WS_HILOGD("charger is in CHARGING_UNKNOWN or CHARGING_UNPLUGGED status");
475         SetWatchdogTime(MEDIUM_WATCHDOG_TIME);
476     } else {
477         WS_HILOGD("charger is in CHARGING status");
478         SetWatchdogTime(LONG_WATCHDOG_TIME);
479     }
480 }
481 
AddWatchdogForWork(std::shared_ptr<WorkStatus> workStatus)482 void WorkPolicyManager::AddWatchdogForWork(std::shared_ptr<WorkStatus> workStatus)
483 {
484     uint32_t watchId = NewWatchdogId();
485     WS_HILOGI("AddWatchdog, watchId:%{public}u, bundleName:%{public}s, workId:%{public}s, watchdogTime:%{public}d",
486         watchId, workStatus->bundleName_.c_str(), workStatus->workId_.c_str(), watchdogTime_);
487     watchdog_->AddWatchdog(watchId, watchdogTime_);
488     workStatus->workStartTime_ = WorkSchedUtils::GetCurrentTimeMs();
489     workStatus->workWatchDogTime_ = static_cast<uint64_t>(watchdogTime_);
490     std::lock_guard<ffrt::mutex> lock(watchdogIdMapMutex_);
491     watchdogIdMap_.emplace(watchId, workStatus);
492 }
493 
SendRetrigger(int32_t delaytime)494 void WorkPolicyManager::SendRetrigger(int32_t delaytime)
495 {
496     WS_HILOGD("enter");
497     if (handler_ == nullptr) {
498         return;
499     }
500     WS_HILOGD("delay = %{public}d", delaytime);
501     handler_->SendEvent(InnerEvent::Get(WorkEventHandler::RETRIGGER_MSG, 0), delaytime);
502 }
503 
WatchdogTimeOut(uint32_t watchdogId)504 void WorkPolicyManager::WatchdogTimeOut(uint32_t watchdogId)
505 {
506     if (wss_.expired()) {
507         WS_HILOGE("wss_ expired");
508         return;
509     }
510     std::shared_ptr<WorkStatus> workStatus = GetWorkFromWatchdog(watchdogId);
511     if (workStatus == nullptr) {
512         WS_HILOGE("watchdog:%{public}u time out error, workStatus is nullptr", watchdogId);
513         return;
514     }
515     WS_HILOGI("WatchdogTimeOut, watchId:%{public}u, bundleName:%{public}s, workId:%{public}s",
516         watchdogId, workStatus->bundleName_.c_str(), workStatus->workId_.c_str());
517     wss_.lock()->WatchdogTimeOut(workStatus);
518     std::lock_guard<ffrt::mutex> lock(watchdogIdMapMutex_);
519     watchdogIdMap_.erase(watchdogId);
520 }
521 
GetWorkFromWatchdog(uint32_t id)522 std::shared_ptr<WorkStatus> WorkPolicyManager::GetWorkFromWatchdog(uint32_t id)
523 {
524     std::lock_guard<ffrt::mutex> lock(watchdogIdMapMutex_);
525     return watchdogIdMap_.count(id) > 0 ? watchdogIdMap_.at(id) : nullptr;
526 }
527 
ObtainAllWorks(int32_t & uid)528 list<shared_ptr<WorkInfo>> WorkPolicyManager::ObtainAllWorks(int32_t &uid)
529 {
530     WS_HILOGD("Wenter");
531     std::lock_guard<ffrt::recursive_mutex> lock(uidMapMutex_);
532     list<shared_ptr<WorkInfo>> allWorks;
533     if (uidQueueMap_.count(uid) > 0) {
534         auto queue = uidQueueMap_.at(uid);
535         auto allWorkStatus = queue->GetWorkList();
536         std::transform(allWorkStatus.begin(), allWorkStatus.end(), std::back_inserter(allWorks),
537             [](std::shared_ptr<WorkStatus> it) { return it->workInfo_; });
538     }
539     return allWorks;
540 }
541 
GetWorkStatus(int32_t & uid,int32_t & workId)542 shared_ptr<WorkInfo> WorkPolicyManager::GetWorkStatus(int32_t &uid, int32_t &workId)
543 {
544     WS_HILOGD("enter");
545     std::lock_guard<ffrt::recursive_mutex> lock(uidMapMutex_);
546     if (uidQueueMap_.count(uid) > 0) {
547         auto queue = uidQueueMap_.at(uid);
548         auto workStatus = queue->Find(string("u") + to_string(uid) + "_" + to_string(workId));
549         if (workStatus != nullptr) {
550             return workStatus->workInfo_;
551         }
552     }
553     return nullptr;
554 }
555 
GetAllWorkStatus(int32_t & uid)556 list<std::shared_ptr<WorkStatus>> WorkPolicyManager::GetAllWorkStatus(int32_t &uid)
557 {
558     WS_HILOGD("enter");
559     std::lock_guard<ffrt::recursive_mutex> lock(uidMapMutex_);
560     list<shared_ptr<WorkStatus>> allWorks;
561     if (uidQueueMap_.count(uid) > 0) {
562         allWorks = uidQueueMap_.at(uid)->GetWorkList();
563     }
564     return allWorks;
565 }
566 
GetAllRunningWorks()567 std::list<std::shared_ptr<WorkInfo>> WorkPolicyManager::GetAllRunningWorks()
568 {
569     WS_HILOGD("enter");
570     std::lock_guard<ffrt::recursive_mutex> lock(uidMapMutex_);
571     list<shared_ptr<WorkInfo>> allWorks;
572     auto it = uidQueueMap_.begin();
573     while (it != uidQueueMap_.end()) {
574         std::list<std::shared_ptr<WorkInfo>> workList = it->second->GetRunningWorks();
575         allWorks.insert(allWorks.end(), workList.begin(), workList.end());
576         it++;
577     }
578     return allWorks;
579 }
580 
DumpConditionReadyQueue(string & result)581 void WorkPolicyManager::DumpConditionReadyQueue(string& result)
582 {
583     conditionReadyQueue_->Dump(result);
584 }
585 
DumpUidQueueMap(string & result)586 void WorkPolicyManager::DumpUidQueueMap(string& result)
587 {
588     std::lock_guard<ffrt::recursive_mutex> lock(uidMapMutex_);
589     for (auto it : uidQueueMap_) {
590         result.append("uid: " + std::to_string(it.first) + ":\n");
591         it.second->Dump(result);
592     }
593 }
594 
Dump(string & result)595 void WorkPolicyManager::Dump(string& result)
596 {
597     WS_HILOGI("enter");
598     result.append("1. workPolicyManager conditionReadyQueue:\n");
599     DumpConditionReadyQueue(result);
600     result.append("\n");
601 
602     result.append("2. workPolicyManager uidQueueMap:\n");
603     DumpUidQueueMap(result);
604 
605     std::string policyName;
606     result.append("3. GetMaxRunningCount:");
607     result.append(to_string(GetMaxRunningCount(policyName))
608         + (policyName.empty() ? "" : " reason: " + policyName) + "\n");
609 }
610 
NewWatchdogId()611 uint32_t WorkPolicyManager::NewWatchdogId()
612 {
613     if (watchdogId_ == MAX_WATCHDOG_ID) {
614         watchdogId_ = INIT_WATCHDOG_ID;
615     }
616     return watchdogId_++;
617 }
618 
GetDumpSetMemory()619 int32_t WorkPolicyManager::GetDumpSetMemory()
620 {
621     return dumpSetMemory_;
622 }
623 
SetMemoryByDump(int32_t memory)624 void WorkPolicyManager::SetMemoryByDump(int32_t memory)
625 {
626     dumpSetMemory_ = memory;
627 }
628 
GetDumpSetCpuUsage()629 int32_t WorkPolicyManager::GetDumpSetCpuUsage()
630 {
631     return dumpSetCpu_;
632 }
633 
SetCpuUsageByDump(int32_t cpu)634 void WorkPolicyManager::SetCpuUsageByDump(int32_t cpu)
635 {
636     dumpSetCpu_ = cpu;
637 }
638 
GetDumpSetMaxRunningCount()639 int32_t WorkPolicyManager::GetDumpSetMaxRunningCount()
640 {
641     return dumpSetMaxRunningCount_;
642 }
643 
SetMaxRunningCountByDump(int32_t count)644 void WorkPolicyManager::SetMaxRunningCountByDump(int32_t count)
645 {
646     dumpSetMaxRunningCount_ = count;
647 }
648 
SetWatchdogTimeByDump(int32_t time)649 void WorkPolicyManager::SetWatchdogTimeByDump(int32_t time)
650 {
651     WS_HILOGD("Set watchdog time by dump to %{public}d", time);
652     watchdogTime_ = time == 0 ? WATCHDOG_TIME : time;
653     g_lastWatchdogTime = watchdogTime_;
654 }
655 
SetWatchdogTime(int32_t time)656 void WorkPolicyManager::SetWatchdogTime(int32_t time)
657 {
658     watchdogTime_ = time;
659 }
660 
GetWatchdogTime()661 int32_t WorkPolicyManager::WorkPolicyManager::GetWatchdogTime()
662 {
663     return watchdogTime_;
664 }
665 
DumpCheckIdeWorkToRun(const std::string & bundleName,const std::string & abilityName)666 void WorkPolicyManager::DumpCheckIdeWorkToRun(const std::string &bundleName, const std::string &abilityName)
667 {
668     std::lock_guard<ffrt::recursive_mutex> lock(ideDebugListMutex_);
669     ideDebugList = GetAllIdeWorkStatus(bundleName, abilityName);
670     if (ideDebugList.empty()) {
671         WS_HILOGE("ideDebugList is empty, please add one work");
672         return;
673     }
674     SendIdeWorkRetriggerEvent(0);
675 }
676 
TriggerIdeWork()677 void WorkPolicyManager::TriggerIdeWork()
678 {
679     std::lock_guard<ffrt::recursive_mutex> lock(ideDebugListMutex_);
680     if (ideDebugList.empty()) {
681         WS_HILOGI("ideDebugList has been empty, all the works have been done");
682         return;
683     }
684 
685     auto topWork = ideDebugList.front();
686     ideDebugList.pop_front();
687     if (topWork->IsRunning()) {
688         SendIdeWorkRetriggerEvent(g_lastWatchdogTime + DELAY_TIME_SHORT);
689         return;
690     }
691     topWork->MarkStatus(WorkStatus::Status::RUNNING);
692     bool ret = workConnManager_->StartWork(topWork);
693     if (ret) {
694         WS_HILOGI("TriggerIdeWork ok");
695         int time = watchdogTime_;
696         watchdogTime_ = g_lastWatchdogTime;
697         AddWatchdogForWork(topWork);
698         watchdogTime_ = time;
699     } else {
700         WS_HILOGE("TriggerIdeWork error");
701         ideDebugList.clear();
702         return;
703     }
704     SendIdeWorkRetriggerEvent(g_lastWatchdogTime + DELAY_TIME_SHORT);
705 }
706 
SendIdeWorkRetriggerEvent(int32_t delaytime)707 void WorkPolicyManager::SendIdeWorkRetriggerEvent(int32_t delaytime)
708 {
709     if (handler_ == nullptr) {
710         WS_HILOGE("handle is nullptr");
711         return;
712     }
713     handler_->SendEvent(InnerEvent::Get(WorkEventHandler::IDE_RETRIGGER_MSG, 0), delaytime);
714 }
715 
GetAllIdeWorkStatus(const std::string & bundleName,const std::string & abilityName)716 std::list<std::shared_ptr<WorkStatus>> WorkPolicyManager::GetAllIdeWorkStatus(const std::string &bundleName,
717     const std::string &abilityName)
718 {
719     int32_t currentAccountId = WorkSchedUtils::GetCurrentAccountId();
720     std::lock_guard<ffrt::recursive_mutex> lock(uidMapMutex_);
721     std::list<shared_ptr<WorkStatus>> allWorks;
722     auto it = uidQueueMap_.begin();
723     while (it != uidQueueMap_.end()) {
724         if (it->second->GetWorkList().empty()) {
725             it++;
726             continue;
727         }
728         bool isExist = false;
729         for (auto work : it->second->GetWorkList()) {
730             if (work->workInfo_->GetBundleName() == bundleName &&
731                 work->workInfo_->GetAbilityName() == abilityName &&
732                 (work->userId_ == 0 || work->userId_ == currentAccountId)) {
733                 allWorks.push_back(work);
734                 isExist = true;
735             }
736         }
737         if (isExist) {
738             return allWorks;
739         }
740         it++;
741     }
742     return allWorks;
743 }
744 
PauseRunningWorks(int32_t uid)745 int32_t WorkPolicyManager::PauseRunningWorks(int32_t uid)
746 {
747     WS_HILOGI("Pause Running Work Scheduler Work, uid:%{public}d", uid);
748     bool hasWorkWithUid = false;
749     std::lock_guard<ffrt::mutex> lock(watchdogIdMapMutex_);
750     for (auto it = watchdogIdMap_.begin(); it != watchdogIdMap_.end(); it++) {
751         auto workStatus = it->second;
752         if (workStatus->uid_ == uid && workStatus->IsRunning()) {
753             hasWorkWithUid = true;
754             if (workStatus->IsPaused()) {
755                 WS_HILOGE("Work has paused, bundleName:%{public}s, workId:%{public}s",
756                     workStatus->bundleName_.c_str(), workStatus->workId_.c_str());
757                 continue;
758             }
759             uint64_t oldWatchdogTime = workStatus->workWatchDogTime_;
760             uint64_t runningTime = WorkSchedUtils::GetCurrentTimeMs() - workStatus->workStartTime_;
761             uint64_t newWatchdogTime = oldWatchdogTime - runningTime;
762             if (newWatchdogTime > LONG_WATCHDOG_TIME) {
763                 WS_HILOGE("bundleName:%{public}s, workId:%{public}s, invalid watchdogtime: %{public}" PRIu64
764                     ",oldWatchdogTime:%{public}" PRIu64 ", runningTime:%{public}" PRIu64,
765                     workStatus->bundleName_.c_str(), workStatus->workId_.c_str(), newWatchdogTime, oldWatchdogTime,
766                     runningTime);
767                 newWatchdogTime = 0;
768             }
769             workStatus->duration_ += runningTime;
770             WS_HILOGI("PauseRunningWorks, watchId:%{public}u, bundleName:%{public}s, workId:%{public}s,"
771                 " oldWatchdogTime:%{public}" PRIu64 ", newWatchdogTime:%{public}" PRIu64 ", duration:%{public}" PRIu64,
772                 it->first, workStatus->bundleName_.c_str(), workStatus->workId_.c_str(),
773                 oldWatchdogTime, newWatchdogTime, workStatus->duration_);
774             workStatus->paused_ = true;
775             workStatus->workWatchDogTime_ = newWatchdogTime;
776             watchdog_->RemoveWatchdog(it->first);
777         }
778     }
779 
780     if (!hasWorkWithUid) {
781         WS_HILOGE("PauseRunningWorks fail, the uid:%{public}d has no matching work", uid);
782         return E_UID_NO_MATCHING_WORK_ERR;
783     }
784     return ERR_OK;
785 }
786 
ResumePausedWorks(int32_t uid)787 int32_t WorkPolicyManager::ResumePausedWorks(int32_t uid)
788 {
789     WS_HILOGI("Resume Paused Work Scheduler Work, uid:%{public}d", uid);
790     bool hasWorkWithUid = false;
791     std::lock_guard<ffrt::mutex> lock(watchdogIdMapMutex_);
792     for (auto it = watchdogIdMap_.begin(); it != watchdogIdMap_.end(); it++) {
793         auto workStatus = it->second;
794         if (workStatus->uid_ == uid && workStatus->IsRunning()) {
795             hasWorkWithUid = true;
796             if (!workStatus->IsPaused()) {
797                 WS_HILOGE("Work has resumed, bundleName:%{public}s, workId:%{public}s",
798                     workStatus->bundleName_.c_str(), workStatus->workId_.c_str());
799                 continue;
800             }
801             int32_t watchdogTime = static_cast<int32_t>(workStatus->workWatchDogTime_);
802             WS_HILOGI("ResumePausedWorks, watchId:%{public}u, bundleName:%{public}s, workId:%{public}s"
803                 " watchdogTime:%{public}d",
804                 it->first, workStatus->bundleName_.c_str(), workStatus->workId_.c_str(), watchdogTime);
805             workStatus->paused_ = false;
806             watchdog_->AddWatchdog(it->first, watchdogTime);
807             workStatus->workStartTime_ = WorkSchedUtils::GetCurrentTimeMs();
808         }
809     }
810 
811     if (!hasWorkWithUid) {
812         WS_HILOGE("ResumePausedWorks fail, the uid:%{public}d has no matching work", uid);
813         return E_UID_NO_MATCHING_WORK_ERR;
814     }
815     return ERR_OK;
816 }
817 
RemoveWatchDog(std::shared_ptr<WorkStatus> workStatus)818 void WorkPolicyManager::RemoveWatchDog(std::shared_ptr<WorkStatus> workStatus)
819 {
820     if (!workStatus || workStatus->workId_.empty()) {
821         WS_HILOGE("remove watchdog error, workStatus or workId is null");
822         return;
823     }
824 
825     std::lock_guard<ffrt::mutex> lock(watchdogIdMapMutex_);
826     uint32_t watchdogId = UINT32_MAX;
827     for (auto it = watchdogIdMap_.begin(); it != watchdogIdMap_.end(); it++) {
828         if (workStatus->workId_ == it->second->workId_) {
829             watchdog_->RemoveWatchdog(it->first);
830             watchdogId = it->first;
831             break;
832         }
833     }
834     if (watchdogId != UINT32_MAX) {
835         watchdogIdMap_.erase(watchdogId);
836     }
837 }
838 
GetDeepIdleWorks()839 std::list<std::shared_ptr<WorkStatus>> WorkPolicyManager::GetDeepIdleWorks()
840 {
841     std::list<shared_ptr<WorkStatus>> deepIdleWorkds;
842     std::lock_guard<ffrt::recursive_mutex> lock(uidMapMutex_);
843     auto it = uidQueueMap_.begin();
844     while (it != uidQueueMap_.end()) {
845         std::list<std::shared_ptr<WorkStatus>> workList = it->second->GetDeepIdleWorks();
846         if (workList.size() != 0) {
847             deepIdleWorkds.insert(deepIdleWorkds.end(), workList.begin(), workList.end());
848         }
849         it++;
850     }
851     return deepIdleWorkds;
852 }
853 
FindWork(int32_t uid)854 bool WorkPolicyManager::FindWork(int32_t uid)
855 {
856     std::lock_guard<ffrt::recursive_mutex> lock(uidMapMutex_);
857     auto iter = uidQueueMap_.find(uid);
858     return iter != uidQueueMap_.end() && iter->second->GetSize() > 0;
859 }
860 
FindWork(const int32_t userId,const std::string & bundleName)861 bool WorkPolicyManager::FindWork(const int32_t userId, const std::string &bundleName)
862 {
863     std::lock_guard<ffrt::recursive_mutex> lock(uidMapMutex_);
864     for (auto list : uidQueueMap_) {
865         if (list.second && list.second->Find(userId, bundleName)) {
866             return true;
867         }
868     }
869     return false;
870 }
871 } // namespace WorkScheduler
872 } // namespace OHOS