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