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