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