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