• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_status.h"
17 
18 #include "time_service_client.h"
19 #include "work_datashare_helper.h"
20 #include "work_sched_errors.h"
21 #include "work_sched_utils.h"
22 #include "work_scheduler_service.h"
23 #include "work_sched_hilog.h"
24 #include "work_sched_errors.h"
25 #ifdef DEVICE_USAGE_STATISTICS_ENABLE
26 #include "bundle_active_client.h"
27 #include "bundle_active_group_map.h"
28 #endif
29 #include "parameters.h"
30 #include "work_sched_data_manager.h"
31 #include "work_sched_config.h"
32 #include "work_sched_constants.h"
33 #include <unordered_map>
34 #include <cinttypes>
35 
36 using namespace std;
37 
38 namespace OHOS {
39 namespace WorkScheduler {
40 static const double ONE_SECOND = 1000.0;
41 static bool g_groupDebugMode = false;
42 static const int64_t MIN_INTERVAL_DEFAULT = 2 * 60 * 60 * 1000;
43 std::map<int32_t, time_t> WorkStatus::s_uid_last_time_map;
44 const int32_t DEFAULT_PRIORITY = 10000;
45 const int32_t HIGH_PRIORITY = 0;
46 const int32_t ACTIVE_GROUP = 10;
47 const string SWITCH_ON = "1";
48 const string DELIMITER = ",";
49 ffrt::mutex WorkStatus::s_uid_last_time_mutex;
50 
51 std::unordered_map<WorkCondition::Type, std::string> COND_TYPE_STRING_MAP = {
52     {WorkCondition::Type::NETWORK, "NETWORK"},
53     {WorkCondition::Type::CHARGER, "CHARGER"},
54     {WorkCondition::Type::BATTERY_STATUS, "BATTERY_STATUS"},
55     {WorkCondition::Type::BATTERY_LEVEL, "BATTERY_LEVEL"},
56     {WorkCondition::Type::STORAGE, "STORAGE"},
57     {WorkCondition::Type::TIMER, "TIMER"},
58     {WorkCondition::Type::GROUP, "GROUP"},
59     {WorkCondition::Type::DEEP_IDLE, "DEEP_IDLE"},
60     {WorkCondition::Type::STANDBY, "STANDBY"}
61 };
62 
getCurrentTime()63 time_t getCurrentTime()
64 {
65     time_t result;
66     time(&result);
67     return result;
68 }
69 
getOppositeTime()70 time_t getOppositeTime()
71 {
72     time_t result;
73     sptr<MiscServices::TimeServiceClient> timer = MiscServices::TimeServiceClient::GetInstance();
74     result = static_cast<time_t>(timer->GetBootTimeMs());
75     return result;
76 }
77 
WorkStatus(WorkInfo & workInfo,int32_t uid)78 WorkStatus::WorkStatus(WorkInfo &workInfo, int32_t uid)
79 {
80     this->workInfo_ = make_shared<WorkInfo>(workInfo);
81     this->workId_ = MakeWorkId(workInfo.GetWorkId(), uid);
82     this->bundleName_ = workInfo.GetBundleName();
83     this->abilityName_ = workInfo.GetAbilityName();
84     this->baseTime_ = workInfo.GetBaseTime();
85     this->uid_ = uid;
86     this->userId_ = WorkSchedUtils::GetUserIdByUid(uid);
87     if (workInfo.GetConditionMap()->count(WorkCondition::Type::TIMER) > 0) {
88         auto workTimerCondition = workInfo.GetConditionMap()->at(WorkCondition::Type::TIMER);
89         shared_ptr<Condition> timeCondition = make_shared<Condition>();
90         timeCondition->uintVal = workTimerCondition->uintVal;
91         timeCondition->boolVal = workTimerCondition->boolVal;
92         if (!workTimerCondition->boolVal) {
93             timeCondition->intVal = workTimerCondition->intVal;
94         }
95         std::lock_guard<ffrt::mutex> lock(conditionMapMutex_);
96         conditionMap_.emplace(WorkCondition::Type::TIMER, timeCondition);
97     }
98     this->persisted_ = workInfo.IsPersisted();
99     this->priority_ = GetPriority();
100     this->currentStatus_ = WAIT_CONDITION;
101     this->minInterval_ = MIN_INTERVAL_DEFAULT;
102     this->groupChanged_ = false;
103 }
104 
~WorkStatus()105 WorkStatus::~WorkStatus() {}
106 
OnConditionChanged(WorkCondition::Type & type,shared_ptr<Condition> value)107 int32_t WorkStatus::OnConditionChanged(WorkCondition::Type &type, shared_ptr<Condition> value)
108 {
109     conditionStatus_.clear();
110     if (workInfo_->GetConditionMap()->count(type) > 0 &&
111         type != WorkCondition::Type::TIMER &&
112         type != WorkCondition::Type::GROUP) {
113         std::lock_guard<ffrt::mutex> lock(conditionMapMutex_);
114         if (conditionMap_.count(type) > 0 &&
115             type >= WorkCondition::Type::NETWORK &&
116             type <= WorkCondition::Type::UNKNOWN) {
117             conditionMap_.at(type) = value;
118         } else {
119             conditionMap_.emplace(type, value);
120         }
121     }
122     if (workInfo_->IsSA()) {
123         if (IsSAReady()) {
124             MarkStatus(Status::CONDITION_READY);
125         }
126         return ERR_OK;
127     }
128     groupChanged_ = false;
129     if (type == WorkCondition::Type::GROUP && value && value->boolVal) {
130         WS_HILOGD("Group changed, bundleName: %{public}s.", value->strVal.c_str());
131         groupChanged_ = true;
132         if (value->intVal == userId_ && value->strVal == bundleName_) {
133             SetMinIntervalByGroup(value->enumVal);
134         } else {
135             return E_GROUP_CHANGE_NOT_MATCH_HAP;
136         }
137     }
138     if (!IsStandbyExemption()) {
139         HasTimeout();
140         return E_GROUP_CHANGE_NOT_MATCH_HAP;
141     }
142     if (IsReady()) {
143         MarkStatus(Status::CONDITION_READY);
144     }
145     return ERR_OK;
146 }
147 
MakeWorkId(int32_t workId,int32_t uid)148 string WorkStatus::MakeWorkId(int32_t workId, int32_t uid)
149 {
150     return string("u") + to_string(uid) + "_" + to_string(workId);
151 }
152 
MarkTimeout()153 void WorkStatus::MarkTimeout()
154 {
155     lastTimeout_ = true;
156 }
157 
MarkStatus(Status status)158 void WorkStatus::MarkStatus(Status status)
159 {
160     currentStatus_ = status;
161 }
162 
MarkRound()163 void WorkStatus::MarkRound() {}
164 
UpdateTimerIfNeed()165 void WorkStatus::UpdateTimerIfNeed()
166 {
167     std::lock_guard<ffrt::mutex> lock(conditionMapMutex_);
168     if (conditionMap_.count(WorkCondition::Type::TIMER) > 0) {
169         baseTime_ = getCurrentTime();
170         if (conditionMap_.at(WorkCondition::Type::TIMER)->boolVal) {
171             workInfo_->RequestBaseTime(baseTime_);
172             DelayedSingleton<WorkSchedulerService>::GetInstance()->RefreshPersistedWorks();
173             return;
174         }
175         int32_t cycleLeft = conditionMap_.at(WorkCondition::Type::TIMER)->intVal;
176         conditionMap_.at(WorkCondition::Type::TIMER)->intVal = cycleLeft - 1;
177         workInfo_->RequestBaseTimeAndCycle(baseTime_, cycleLeft - 1);
178         DelayedSingleton<WorkSchedulerService>::GetInstance()->RefreshPersistedWorks();
179     }
180 }
181 
NeedRemove()182 bool WorkStatus::NeedRemove()
183 {
184     std::lock_guard<ffrt::mutex> lock(conditionMapMutex_);
185     if (conditionMap_.count(WorkCondition::Type::TIMER) <= 0) {
186         return true;
187     }
188     if (conditionMap_.at(WorkCondition::Type::TIMER)->boolVal) {
189         return false;
190     }
191     if (conditionMap_.at(WorkCondition::Type::TIMER)->intVal <= 0) {
192         return true;
193     }
194     return false;
195 }
196 
IsSameUser()197 bool WorkStatus::IsSameUser()
198 {
199     if (userId_ > 0 && !WorkSchedUtils::IsIdActive(userId_)) {
200         return false;
201     }
202     return true;
203 }
204 
IsUriKeySwitchOn()205 bool WorkStatus::IsUriKeySwitchOn()
206 {
207     if (!workInfo_->IsPreinstalled()) {
208         return true;
209     }
210     if (workInfo_->GetUriKey().empty()) {
211         WS_HILOGE("key is empty %{public}s", workId_.c_str());
212         return false;
213     }
214     string key = workInfo_->GetUriKey();
215     string value;
216     (void)WorkDatashareHelper::GetInstance().GetStringValue(key, value);
217     if (value == SWITCH_ON) {
218         return true;
219     }
220     WS_HILOGE("workid %{public}s key %{public}s, value is 0", workId_.c_str(), key.c_str());
221     return false;
222 }
223 
IsReady()224 bool WorkStatus::IsReady()
225 {
226     conditionStatus_.clear();
227     if (!IsSameUser()) {
228         conditionStatus_ += DELIMITER + "notSameUser";
229         return false;
230     }
231     if (IsRunning()) {
232         HasTimeout();
233         conditionStatus_ += DELIMITER + "running";
234         return false;
235     }
236     if (!IsConditionReady()) {
237         return false;
238     }
239     if (!IsUriKeySwitchOn()) {
240         conditionStatus_ += DELIMITER + "uriKeyOFF";
241         return false;
242     }
243     if (DelayedSingleton<WorkSchedulerService>::GetInstance()->CheckEffiResApplyInfo(uid_)) {
244         conditionStatus_ += DELIMITER + "effiResWhitelist";
245         return true;
246     }
247     if (!g_groupDebugMode && ((!groupChanged_ && !SetMinInterval()) || minInterval_ == -1)) {
248         WS_HILOGE("Work can't ready due to false group, forbidden group or unused group, bundleName:%{public}s, "
249             "minInterval:%{public}" PRId64 ", workId:%{public}s", bundleName_.c_str(), minInterval_, workId_.c_str());
250         return false;
251     }
252     if (s_uid_last_time_map.find(uid_) == s_uid_last_time_map.end()) {
253         conditionStatus_ += DELIMITER + "firstTrigger";
254         return true;
255     }
256     double del = difftime(getOppositeTime(), s_uid_last_time_map[uid_]);
257     if (del < minInterval_) {
258         conditionStatus_ += DELIMITER + COND_TYPE_STRING_MAP[WorkCondition::Type::GROUP] + "&" + NOT_OK + "(" +
259             to_string(static_cast<long>(del)) + ":" + to_string(minInterval_) + ")";
260         needRetrigger_ = true;
261         timeRetrigger_ = int(minInterval_ - del + ONE_SECOND);
262         return false;
263     }
264     WS_HILOGI("All condition ready, bundleName:%{public}s, abilityName:%{public}s, workId:%{public}s, "
265         "groupChanged:%{public}d, minInterval:%{public}" PRId64 ", del = %{public}f",
266         bundleName_.c_str(), abilityName_.c_str(), workId_.c_str(), groupChanged_, minInterval_, del);
267     return true;
268 }
269 
IsSAReady()270 bool WorkStatus::IsSAReady()
271 {
272     conditionStatus_.clear();
273     if (!IsConditionReady()) {
274         return false;
275     }
276     WS_HILOGI("All condition ready, saId:%{public}d, workId:%{public}s", workInfo_->GetSaId(), workId_.c_str());
277     return true;
278 }
279 
IsConditionReady()280 bool WorkStatus::IsConditionReady()
281 {
282     auto workConditionMap = workInfo_->GetConditionMap();
283     std::lock_guard<ffrt::mutex> lock(s_uid_last_time_mutex);
284     bool isReady = true;
285     for (auto it : *workConditionMap) {
286         if (conditionMap_.count(it.first) <= 0) {
287             conditionStatus_ += DELIMITER + COND_TYPE_STRING_MAP[it.first] + "&" + NOT_OK;
288             isReady = false;
289             break;
290         }
291         if (!IsBatteryAndNetworkReady(it.first) || !IsStorageReady(it.first) ||
292             !IsChargerReady(it.first) || !IsNapReady(it.first)) {
293             conditionStatus_ += DELIMITER + COND_TYPE_STRING_MAP[it.first] + "&" + NOT_OK;
294             isReady = false;
295             break;
296         }
297         if (!IsTimerReady(it.first)) {
298             isReady = false;
299             break;
300         }
301         conditionStatus_ += DELIMITER + COND_TYPE_STRING_MAP[it.first] + "&" + OK;
302     }
303     return isReady;
304 }
305 
IsBatteryAndNetworkReady(WorkCondition::Type type)306 bool WorkStatus::IsBatteryAndNetworkReady(WorkCondition::Type type)
307 {
308     auto workConditionMap = workInfo_->GetConditionMap();
309     switch (type) {
310         case WorkCondition::Type::NETWORK: {
311             if (conditionMap_.at(type)->enumVal == WorkCondition::Network::NETWORK_UNKNOWN) {
312                 return false;
313             }
314             if (workConditionMap->at(type)->enumVal != WorkCondition::Network::NETWORK_TYPE_ANY &&
315                 workConditionMap->at(type)->enumVal != conditionMap_.at(type)->enumVal) {
316                 return false;
317             }
318             break;
319         }
320         case WorkCondition::Type::BATTERY_STATUS: {
321             int32_t batteryReq = workConditionMap->at(type)->enumVal;
322             if (batteryReq != WorkCondition::BatteryStatus::BATTERY_STATUS_LOW_OR_OKAY &&
323                 batteryReq != conditionMap_.at(type)->enumVal) {
324                 return false;
325             }
326             break;
327         }
328         case WorkCondition::Type::BATTERY_LEVEL: {
329             if (workConditionMap->at(type)->intVal > conditionMap_.at(type)->intVal) {
330                 return false;
331             }
332             break;
333         }
334         default:
335             break;
336     }
337     return true;
338 }
339 
IsChargerReady(WorkCondition::Type type)340 bool WorkStatus::IsChargerReady(WorkCondition::Type type)
341 {
342     if (type != WorkCondition::Type::CHARGER) {
343         return true;
344     }
345     auto conditionSet = workInfo_->GetConditionMap()->at(WorkCondition::Type::CHARGER);
346     auto conditionCurrent = conditionMap_.at(WorkCondition::Type::CHARGER);
347     if (conditionSet->boolVal != conditionCurrent->boolVal) {
348         return false;
349     }
350     if (conditionSet->boolVal) {
351         if (conditionCurrent->enumVal != conditionSet->enumVal && conditionSet->enumVal !=
352             static_cast<int32_t>(WorkCondition::Charger::CHARGING_PLUGGED_ANY)) {
353             return false;
354         }
355     } else {
356         if (conditionCurrent->enumVal != static_cast<int32_t>(WorkCondition::Charger::CHARGING_UNPLUGGED)) {
357             return false;
358         }
359     }
360     return true;
361 }
362 
IsStorageReady(WorkCondition::Type type)363 bool WorkStatus::IsStorageReady(WorkCondition::Type type)
364 {
365     if (type != WorkCondition::Type::STORAGE) {
366         return true;
367     }
368     auto workConditionMap = workInfo_->GetConditionMap();
369     if (workConditionMap->at(type)->enumVal != WorkCondition::Storage::STORAGE_LEVEL_LOW_OR_OKAY &&
370         workConditionMap->at(type)->enumVal != conditionMap_.at(type)->enumVal) {
371         return false;
372     }
373     return true;
374 }
375 
IsStandbyExemption()376 bool WorkStatus::IsStandbyExemption()
377 {
378     auto dataManager = DelayedSingleton<DataManager>::GetInstance();
379     if (dataManager->IsInDeviceStandyRestrictlist(bundleName_)) {
380         WS_HILOGD("%{public}s is in restrict list.", bundleName_.c_str());
381         return false;
382     }
383     if (dataManager->GetDeviceSleep()) {
384         return dataManager->IsInDeviceStandyWhitelist(bundleName_);
385     }
386     return true;
387 }
388 
IsTimerReady(WorkCondition::Type type)389 bool WorkStatus::IsTimerReady(WorkCondition::Type type)
390 {
391     if (type != WorkCondition::Type::TIMER) {
392         return true;
393     }
394     auto workConditionMap = workInfo_->GetConditionMap();
395     uint32_t intervalTime = workConditionMap->at(WorkCondition::Type::TIMER)->uintVal;
396     time_t lastTime;
397     if (s_uid_last_time_map.find(uid_) == s_uid_last_time_map.end()) {
398         lastTime = 0;
399     } else {
400         lastTime = s_uid_last_time_map[uid_];
401     }
402     double currentdel = difftime(getCurrentTime(), baseTime_) * ONE_SECOND;
403     double oppositedel = difftime(getOppositeTime(), lastTime);
404     double del = currentdel > oppositedel ? currentdel : oppositedel;
405     if (del < intervalTime) {
406         conditionStatus_ += DELIMITER + COND_TYPE_STRING_MAP[type] + "&" + NOT_OK + "(" +
407             to_string(static_cast<long>(del)) + ":" + to_string(intervalTime) + ")";
408         return false;
409     }
410     return true;
411 }
412 
IsNapReady(WorkCondition::Type type)413 bool WorkStatus::IsNapReady(WorkCondition::Type type)
414 {
415     if (type != WorkCondition::Type::DEEP_IDLE) {
416         return true;
417     }
418     auto conditionSet = workInfo_->GetConditionMap()->at(WorkCondition::Type::DEEP_IDLE);
419     auto conditionCurrent = conditionMap_.at(WorkCondition::Type::DEEP_IDLE);
420     if (conditionSet->boolVal != conditionCurrent->boolVal) {
421         return false;
422     }
423     return true;
424 }
425 
SetMinInterval()426 bool WorkStatus::SetMinInterval()
427 {
428 #ifdef DEVICE_USAGE_STATISTICS_ENABLE
429     int32_t group = 0;
430     if (workInfo_->IsCallBySystemApp()) {
431         WS_HILOGD("system app %{public}s, default group is active.", bundleName_.c_str());
432         return SetMinIntervalByGroup(ACTIVE_GROUP);
433     }
434     bool res = DelayedSingleton<DataManager>::GetInstance()->FindGroup(bundleName_, userId_, group);
435     if (!res) {
436         WS_HILOGI("no cache find, bundleName:%{public}s", bundleName_.c_str());
437         auto errCode = DeviceUsageStats::BundleActiveClient::GetInstance().QueryAppGroup(group, bundleName_, userId_);
438         if (errCode != ERR_OK) {
439             WS_HILOGE("query package group failed. userId = %{public}d, bundleName = %{public}s",
440                 userId_, bundleName_.c_str());
441             group = ACTIVE_GROUP;
442         }
443         DelayedSingleton<DataManager>::GetInstance()->AddGroup(bundleName_, userId_, group);
444     }
445 #else
446     int32_t group = ACTIVE_GROUP;
447 #endif
448     return SetMinIntervalByGroup(group);
449 }
450 
SetMinIntervalByGroup(int32_t group)451 bool WorkStatus::SetMinIntervalByGroup(int32_t group)
452 {
453     groupChanged_ = true;
454 
455 #ifdef DEVICE_USAGE_STATISTICS_ENABLE
456     int32_t newGroup = group;
457     if (DelayedSingleton<WorkSchedulerConfig>::GetInstance()->IsInActiveGroupWhitelist(bundleName_) &&
458         group > DeviceUsageStats::DeviceUsageStatsGroupConst::ACTIVE_GROUP_FIXED) {
459         newGroup = DeviceUsageStats::DeviceUsageStatsGroupConst::ACTIVE_GROUP_FIXED;
460     }
461     auto itMap = DeviceUsageStats::DeviceUsageStatsGroupMap::groupIntervalMap_.find(newGroup);
462     if (itMap != DeviceUsageStats::DeviceUsageStatsGroupMap::groupIntervalMap_.end()) {
463         minInterval_ = DeviceUsageStats::DeviceUsageStatsGroupMap::groupIntervalMap_[newGroup];
464     } else {
465         WS_HILOGE("query package group interval failed. group:%{public}d, bundleName:%{public}s",
466             newGroup, bundleName_.c_str());
467         minInterval_ = -1;
468     }
469 #else
470     minInterval_ = MIN_INTERVAL_DEFAULT;
471 #endif
472     WS_HILOGD("set min interval to %{public}" PRId64 " by group %{public}d", minInterval_, group);
473     return true;
474 }
475 
SetMinIntervalByDump(int64_t interval)476 void WorkStatus::SetMinIntervalByDump(int64_t interval)
477 {
478     WS_HILOGD("set min interval by dump to %{public}" PRId64 "", interval);
479     g_groupDebugMode = interval == 0 ? false : true;
480     minInterval_ = interval == 0 ? minInterval_ : interval;
481 }
482 
GetMinInterval()483 int64_t WorkStatus::GetMinInterval()
484 {
485     return minInterval_;
486 }
487 
UpdateUidLastTimeMap()488 void WorkStatus::UpdateUidLastTimeMap()
489 {
490     std::lock_guard<ffrt::mutex> lock(s_uid_last_time_mutex);
491     time_t lastTime = getOppositeTime();
492     s_uid_last_time_map[uid_] = lastTime;
493 }
494 
ClearUidLastTimeMap(int32_t uid)495 void WorkStatus::ClearUidLastTimeMap(int32_t uid)
496 {
497     std::lock_guard<ffrt::mutex> lock(s_uid_last_time_mutex);
498     s_uid_last_time_map.erase(uid);
499 }
500 
IsRunning()501 bool WorkStatus::IsRunning()
502 {
503     return currentStatus_ == RUNNING;
504 }
505 
IsPaused()506 bool WorkStatus::IsPaused()
507 {
508     return paused_;
509 }
510 
IsReadyStatus()511 bool WorkStatus::IsReadyStatus()
512 {
513     return currentStatus_ == CONDITION_READY;
514 }
515 
IsRemoved()516 bool WorkStatus::IsRemoved()
517 {
518     return currentStatus_ == REMOVED;
519 }
520 
IsLastWorkTimeout()521 bool WorkStatus::IsLastWorkTimeout()
522 {
523     return lastTimeout_;
524 }
525 
IsRepeating()526 bool WorkStatus::IsRepeating()
527 {
528     std::lock_guard<ffrt::mutex> lock(conditionMapMutex_);
529     if (conditionMap_.count(WorkCondition::Type::TIMER) <= 0) {
530         return false;
531     }
532     if (conditionMap_.at(WorkCondition::Type::TIMER)->boolVal) {
533         return true;
534     } else {
535         return conditionMap_.at(WorkCondition::Type::TIMER)->intVal > 0;
536     }
537 }
538 
GetStatus()539 WorkStatus::Status WorkStatus::GetStatus()
540 {
541     return currentStatus_;
542 }
543 
GetPriority()544 int WorkStatus::GetPriority()
545 {
546     if ((OHOS::system::GetIntParameter("const.debuggable", 0) == 1) &&
547         DelayedSingleton<WorkSchedulerService>::GetInstance()->IsExemptionBundle(bundleName_)) {
548         return HIGH_PRIORITY;
549     }
550     return DEFAULT_PRIORITY;
551 }
552 
Dump(string & result)553 void WorkStatus::Dump(string& result)
554 {
555     result.append("{\n");
556     result.append(string("\"workId\":") + workId_ + ",\n");
557     result.append(string("\"isSA\":") + (workInfo_->IsSA() ? "true" : "false") + ",\n");
558     if (workInfo_->IsSA()) {
559         result.append(string("\"SAId\":") + to_string(workInfo_->GetSaId()) + ",\n");
560         result.append(string("\"resident\":") + (workInfo_->IsResidentSa() ? "true" : "false") + ",\n");
561     } else {
562         result.append(string("\"bundleName\":") + bundleName_ + ",\n");
563     }
564     result.append(string("\"status\":") + to_string(currentStatus_) + ",\n");
565     result.append(string("\"paused\":") + (paused_ ? "true" : "false") + ",\n");
566     result.append(string("\"priority\":") + to_string(priority_) + ",\n");
567     result.append(string("\"conditionMap\":{\n"));
568     DumpCondition(result);
569     result.append("},\n\"workInfo\":\n");
570     workInfo_->Dump(result);
571     result.append("}\n");
572     result.append("\n");
573 }
574 
DumpCondition(string & result)575 void WorkStatus::DumpCondition(string& result)
576 {
577     std::lock_guard<ffrt::mutex> lock(conditionMapMutex_);
578     if (conditionMap_.count(WorkCondition::Type::NETWORK) > 0) {
579         result.append(string("\"networkType\":") +
580             to_string(conditionMap_.at(WorkCondition::Type::NETWORK)->enumVal) + ",\n");
581     }
582     if (conditionMap_.count(WorkCondition::Type::CHARGER) > 0) {
583         result.append(string("\"isCharging\":") +
584             (conditionMap_.at(WorkCondition::Type::CHARGER)->boolVal ? "true" : "false") + ",\n");
585         result.append(string("\"chargerType\":") +
586             to_string(conditionMap_.at(WorkCondition::Type::CHARGER)->enumVal) + ",\n");
587     }
588     if (conditionMap_.count(WorkCondition::Type::BATTERY_LEVEL) > 0) {
589         result.append(string("\"batteryLevel\":") +
590             to_string(conditionMap_.at(WorkCondition::Type::BATTERY_LEVEL)->intVal) + ",\n");
591     }
592     if (conditionMap_.count(WorkCondition::Type::BATTERY_STATUS) > 0) {
593         result.append(string("\"batteryStatus\":") +
594             to_string(conditionMap_.at(WorkCondition::Type::BATTERY_STATUS)->enumVal) + ",\n");
595     }
596     if (conditionMap_.count(WorkCondition::Type::STORAGE) > 0) {
597         result.append(string("\"storageLevel\":") +
598             to_string(conditionMap_.at(WorkCondition::Type::STORAGE)->enumVal) + ",\n");
599     }
600     if (conditionMap_.count(WorkCondition::Type::TIMER) > 0) {
601         result.append(string("\"baseTime\":") + to_string(baseTime_) + ",\n");
602         if (conditionMap_.at(WorkCondition::Type::TIMER)->boolVal) {
603             result.append(string("\"isRepeat\": true,\n"));
604         } else {
605             result.append(string("\"cycleLeft\":") +
606                 to_string(conditionMap_.at(WorkCondition::Type::TIMER)->intVal) + ",\n");
607         }
608     }
609     if (conditionMap_.count(WorkCondition::Type::DEEP_IDLE) > 0) {
610         result.append(string("\"isDeepIdle\":") +
611             to_string(conditionMap_.at(WorkCondition::Type::DEEP_IDLE)->boolVal) + ",\n");
612     }
613 }
614 
ToString(WorkCondition::Type type)615 void WorkStatus::ToString(WorkCondition::Type type)
616 {
617     auto dataManager = DelayedSingleton<DataManager>::GetInstance();
618     if (dataManager->GetDeviceSleep()) {
619         if (dataManager->IsInDeviceStandyWhitelist(bundleName_)) {
620             conditionStatus_ += DELIMITER + COND_TYPE_STRING_MAP[WorkCondition::Type::STANDBY] + "&" + OK;
621         } else {
622             conditionStatus_ += DELIMITER + COND_TYPE_STRING_MAP[WorkCondition::Type::STANDBY] + "&" + NOT_OK;
623         }
624     }
625     if (type != WorkCondition::Type::GROUP && conditionStatus_.empty()) {
626         WS_HILOGE("%{public}s, condition is empty", COND_TYPE_STRING_MAP[type].c_str());
627         return;
628     }
629     if (workInfo_->IsSA()) {
630         WS_HILOGI("%{public}s,%{public}s%{public}s", COND_TYPE_STRING_MAP[type].c_str(),
631             workId_.c_str(), conditionStatus_.c_str());
632     } else {
633         WS_HILOGI("%{public}s,%{public}s_%{public}s%{public}s", COND_TYPE_STRING_MAP[type].c_str(),
634             bundleName_.c_str(), workId_.c_str(), conditionStatus_.c_str());
635     }
636 }
637 
HasTimeout()638 void WorkStatus::HasTimeout()
639 {
640     if (!IsRunning() || IsPaused()) {
641         return;
642     }
643 
644     if (workWatchDogTime_ > LONG_WATCHDOG_TIME) {
645         WS_HILOGE("invalid watchdogtime, bundleName:%{public}s, workId:%{public}s, watchdogtime:%{public}" PRIu64
646             " workStartTime:%{public}" PRIu64, bundleName_.c_str(), workId_.c_str(), workWatchDogTime_, workStartTime_);
647         workWatchDogTime_ = 0;
648         timeout_.store(true);
649         return;
650     }
651 
652     uint64_t runningTime = WorkSchedUtils::GetCurrentTimeMs() - workStartTime_;
653     if (runningTime > (workWatchDogTime_ + WATCHDOG_TIMEOUT_THRESHOLD_MS)) {
654         WS_HILOGE("invalid running time, bundleName:%{public}s, workId:%{public}s, watchdogtime:%{public}" PRIu64
655             " workStartTime:%{public}" PRIu64 " runningTime:%{public}" PRIu64, bundleName_.c_str(), workId_.c_str(),
656             workWatchDogTime_, workStartTime_, runningTime);
657         workWatchDogTime_ = 0;
658         timeout_.store(true);
659     }
660 }
661 
SetTimeout(bool timeout)662 void WorkStatus::SetTimeout(bool timeout)
663 {
664     timeout_.store(timeout);
665 }
666 
IsTimeout()667 bool WorkStatus::IsTimeout()
668 {
669     return timeout_.load();
670 }
671 } // namespace WorkScheduler
672 } // namespace OHOS