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