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