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