• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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_sched_errors.h"
20 #include "work_sched_utils.h"
21 #include "work_scheduler_service.h"
22 #include "work_sched_hilog.h"
23 #include "work_sched_errors.h"
24 #ifdef DEVICE_USAGE_STATISTICS_ENABLE
25 #include "bundle_active_client.h"
26 #include "bundle_active_group_map.h"
27 #endif
28 
29 using namespace std;
30 
31 namespace OHOS {
32 namespace WorkScheduler {
33 static const double ONE_SECOND = 1000.0;
34 static bool debugMode = false;
35 static const int64_t MIN_INTERVAL_DEFAULT = 2 * 60 * 60 * 1000;
36 std::map<int32_t, time_t> WorkStatus::s_uid_last_time_map;
37 const int32_t DEFAULT_PRIORITY = 100;
38 const int32_t ACTIVE_GROUP = 10;
39 std::mutex WorkStatus::s_uid_last_time_mutex;
40 
getCurrentTime()41 time_t getCurrentTime()
42 {
43     time_t result;
44     time(&result);
45     return result;
46 }
47 
getOppositeTime()48 time_t getOppositeTime()
49 {
50     time_t result;
51     sptr<MiscServices::TimeServiceClient> timer = MiscServices::TimeServiceClient::GetInstance();
52     result = static_cast<time_t>(timer->GetBootTimeMs());
53     return result;
54 }
55 
WorkStatus(WorkInfo & workInfo,int32_t uid)56 WorkStatus::WorkStatus(WorkInfo &workInfo, int32_t uid)
57 {
58     this->workInfo_ = make_shared<WorkInfo>(workInfo);
59     this->workId_ = MakeWorkId(workInfo.GetWorkId(), uid);
60     this->bundleName_ = workInfo.GetBundleName();
61     this->abilityName_ = workInfo.GetAbilityName();
62     this->baseTime_ = workInfo.GetBaseTime();
63     this->uid_ = uid;
64     this->userId_ = WorkSchedUtils::GetUserIdByUid(uid);
65     if (workInfo.GetConditionMap()->count(WorkCondition::Type::TIMER) > 0) {
66         auto workTimerCondition = workInfo.GetConditionMap()->at(WorkCondition::Type::TIMER);
67         shared_ptr<Condition> timeCondition = make_shared<Condition>();
68         timeCondition->uintVal = workTimerCondition->uintVal;
69         timeCondition->boolVal = workTimerCondition->boolVal;
70         if (!workTimerCondition->boolVal) {
71             timeCondition->intVal = workTimerCondition->intVal;
72         }
73         std::lock_guard<std::mutex> lock(conditionMapMutex_);
74         conditionMap_.emplace(WorkCondition::Type::TIMER, timeCondition);
75     }
76     this->persisted_ = workInfo.IsPersisted();
77     this->priority_ = DEFAULT_PRIORITY;
78     this->currentStatus_ = WAIT_CONDITION;
79     this->minInterval_ = MIN_INTERVAL_DEFAULT;
80     this->callbackFlag_ = false;
81 }
82 
~WorkStatus()83 WorkStatus::~WorkStatus() {}
84 
OnConditionChanged(WorkCondition::Type & type,shared_ptr<Condition> value)85 int32_t WorkStatus::OnConditionChanged(WorkCondition::Type &type, shared_ptr<Condition> value)
86 {
87     WS_HILOGD("Work status condition changed.");
88     if (workInfo_->GetConditionMap()->count(type) > 0
89         && type != WorkCondition::Type::TIMER
90         && type != WorkCondition::Type::GROUP) {
91         std::lock_guard<std::mutex> lock(conditionMapMutex_);
92         if (conditionMap_.count(type) > 0) {
93             conditionMap_.at(type) = value;
94         } else {
95             conditionMap_.emplace(type, value);
96         }
97     }
98     callbackFlag_ = false;
99     if (type == WorkCondition::Type::GROUP && value && value->boolVal) {
100         WS_HILOGD("Group changed, bundleName: %{public}s.", value->strVal.c_str());
101         callbackFlag_ = true;
102         if (value->intVal == userId_ && value->strVal == bundleName_) {
103             SetMinIntervalByGroup(value->enumVal);
104         } else {
105             return E_GROUP_CHANGE_NOT_MATCH_HAP;
106         }
107     }
108     if (type == WorkCondition::Type::STANDBY && value) {
109         isStandby_ = value->boolVal;
110     }
111     if (isStandby_ && !DelayedSpSingleton<WorkSchedulerService>::GetInstance()->CheckStandbyApplyInfo(bundleName_)) {
112         return E_GROUP_CHANGE_NOT_MATCH_HAP;
113     }
114     if (IsReady()) {
115         MarkStatus(Status::CONDITION_READY);
116     }
117     return ERR_OK;
118 }
119 
MakeWorkId(int32_t workId,int32_t uid)120 string WorkStatus::MakeWorkId(int32_t workId, int32_t uid)
121 {
122     return string("u") + to_string(uid) + "_" + to_string(workId);
123 }
124 
MarkTimeout()125 void WorkStatus::MarkTimeout()
126 {
127     lastTimeout_ = true;
128 }
129 
MarkStatus(Status status)130 void WorkStatus::MarkStatus(Status status)
131 {
132     currentStatus_ = status;
133 }
134 
MarkRound()135 void WorkStatus::MarkRound() {}
136 
UpdateTimerIfNeed()137 void WorkStatus::UpdateTimerIfNeed()
138 {
139     std::lock_guard<std::mutex> lock(conditionMapMutex_);
140     if (conditionMap_.count(WorkCondition::Type::TIMER) > 0) {
141         baseTime_ = getCurrentTime();
142         if (conditionMap_.at(WorkCondition::Type::TIMER)->boolVal) {
143             workInfo_->RequestBaseTime(baseTime_);
144             DelayedSpSingleton<WorkSchedulerService>::GetInstance()->RefreshPersistedWorks();
145             return;
146         }
147         int32_t cycleLeft = conditionMap_.at(WorkCondition::Type::TIMER)->intVal;
148         conditionMap_.at(WorkCondition::Type::TIMER)->intVal = cycleLeft - 1;
149         workInfo_->RequestBaseTimeAndCycle(baseTime_, cycleLeft - 1);
150         DelayedSpSingleton<WorkSchedulerService>::GetInstance()->RefreshPersistedWorks();
151     }
152 }
153 
NeedRemove()154 bool WorkStatus::NeedRemove()
155 {
156     std::lock_guard<std::mutex> lock(conditionMapMutex_);
157     if (conditionMap_.count(WorkCondition::Type::TIMER) <= 0) {
158         return true;
159     }
160     if (conditionMap_.at(WorkCondition::Type::TIMER)->boolVal) {
161         return false;
162     }
163     if (conditionMap_.at(WorkCondition::Type::TIMER)->intVal <= 0) {
164         return true;
165     }
166     return false;
167 }
168 
IsSameUser()169 bool WorkStatus::IsSameUser()
170 {
171     if (userId_ > 0 && !WorkSchedUtils::IsIdActive(userId_)) {
172         return false;
173     }
174     return true;
175 }
176 
IsReady()177 bool WorkStatus::IsReady()
178 {
179     WS_HILOGD("IsReady");
180     if (!IsSameUser()) {
181         WS_HILOGI("Not same user. WorkId:%{public}s", workId_.c_str());
182         return false;
183     }
184     if (IsRunning()) {
185         WS_HILOGI("Work is running");
186         return false;
187     }
188     auto workConditionMap = workInfo_->GetConditionMap();
189     std::lock_guard<std::mutex> lock(s_uid_last_time_mutex);
190     for (auto it : *workConditionMap) {
191         if (conditionMap_.count(it.first) <= 0) {
192             return false;
193         }
194         if (!IsBatteryAndNetworkReady(it.first) || !IsStorageAndChargerAndTimerReady(it.first)) {
195             return false;
196         }
197     }
198     if (DelayedSpSingleton<WorkSchedulerService>::GetInstance()->CheckEffiResApplyInfo(uid_)) {
199         return true;
200     }
201     if (!debugMode && ((!callbackFlag_ && !SetMinInterval()) || minInterval_ == -1)) {
202         WS_HILOGE("Work can't ready due to false group, forbidden group or unused group.");
203         return false;
204     }
205 
206     auto itMap = s_uid_last_time_map.find(uid_);
207     if (itMap == s_uid_last_time_map.end()) {
208         return true;
209     }
210     time_t lastTime = s_uid_last_time_map[uid_];
211     double del = difftime(getOppositeTime(), lastTime);
212     WS_HILOGD("CallbackFlag: %{public}d, minInterval = %{public}" PRId64 ", del = %{public}f",
213         callbackFlag_, minInterval_, del);
214     if (del < minInterval_) {
215         needRetrigger_ = true;
216         timeRetrigger_ = int(minInterval_ - del + ONE_SECOND);
217         return false;
218     }
219     return true;
220 }
221 
IsBatteryAndNetworkReady(WorkCondition::Type type)222 bool WorkStatus::IsBatteryAndNetworkReady(WorkCondition::Type type)
223 {
224     auto workConditionMap = workInfo_->GetConditionMap();
225     switch (type) {
226         case WorkCondition::Type::NETWORK: {
227             if (conditionMap_.at(type)->enumVal == WorkCondition::Network::NETWORK_UNKNOWN) {
228                 return false;
229             }
230             if (workConditionMap->at(type)->enumVal != WorkCondition::Network::NETWORK_TYPE_ANY &&
231                 workConditionMap->at(type)->enumVal != conditionMap_.at(type)->enumVal) {
232                 return false;
233             }
234             break;
235         }
236         case WorkCondition::Type::BATTERY_STATUS: {
237             int32_t batteryReq = workConditionMap->at(type)->enumVal;
238             if (batteryReq != WorkCondition::BatteryStatus::BATTERY_STATUS_LOW_OR_OKAY &&
239                 batteryReq != conditionMap_.at(type)->enumVal) {
240                 return false;
241             }
242             break;
243         }
244         case WorkCondition::Type::BATTERY_LEVEL: {
245             if (workConditionMap->at(type)->intVal > conditionMap_.at(type)->intVal) {
246                 return false;
247             }
248             break;
249         }
250         default:
251             break;
252     }
253     return true;
254 }
255 
IsStorageAndChargerAndTimerReady(WorkCondition::Type type)256 bool WorkStatus::IsStorageAndChargerAndTimerReady(WorkCondition::Type type)
257 {
258     auto workConditionMap = workInfo_->GetConditionMap();
259     switch (type) {
260         case WorkCondition::Type::STORAGE: {
261             if (workConditionMap->at(type)->enumVal != WorkCondition::Storage::STORAGE_LEVEL_LOW_OR_OKAY &&
262                 workConditionMap->at(type)->enumVal != conditionMap_.at(type)->enumVal) {
263                 return false;
264             }
265             break;
266         }
267         case WorkCondition::Type::CHARGER: {
268             auto conditionSet = workConditionMap->at(type);
269             auto conditionCurrent = conditionMap_.at(type);
270             if (conditionSet->boolVal) {
271                 if (conditionCurrent->enumVal != conditionSet->enumVal && conditionSet->enumVal !=
272                     static_cast<int32_t>(WorkCondition::Charger::CHARGING_PLUGGED_ANY)) {
273                     return false;
274                 }
275             } else {
276                 if (conditionCurrent->enumVal !=
277                     static_cast<int32_t>(WorkCondition::Charger::CHARGING_UNPLUGGED)) {
278                     return false;
279                 }
280             }
281             break;
282         }
283         case WorkCondition::Type::TIMER: {
284             uint32_t intervalTime = workConditionMap->at(WorkCondition::Type::TIMER)->uintVal;
285             time_t lastTime;
286             if (s_uid_last_time_map.find(uid_) == s_uid_last_time_map.end()) {
287                 lastTime = 0;
288             } else {
289                 lastTime = s_uid_last_time_map[uid_];
290             }
291             double currentdel = difftime(getCurrentTime(), baseTime_) * ONE_SECOND;
292             double oppositedel = difftime(getOppositeTime(), lastTime);
293             double del = currentdel > oppositedel ? currentdel : oppositedel;
294             WS_HILOGD("del time: %{public}lf, intervalTime: %{public}u", del, intervalTime);
295             WS_HILOGD("currentdel time: %{public}lf, oppositedel time: %{public}lf", currentdel, oppositedel);
296             if (del < intervalTime) {
297                 return false;
298             }
299             break;
300         }
301         default:
302             break;
303     }
304     return true;
305 }
306 
SetMinInterval()307 bool WorkStatus::SetMinInterval()
308 {
309 #ifdef DEVICE_USAGE_STATISTICS_ENABLE
310     int32_t group = 0;
311     if (workInfo_->IsCallBySystemApp()) {
312         WS_HILOGI("Is system app, default group is active.");
313         return SetMinIntervalByGroup(ACTIVE_GROUP);
314     }
315     int32_t errCode = DeviceUsageStats::BundleActiveClient::GetInstance().QueryAppGroup(group, bundleName_, userId_);
316     if (errCode != ERR_OK) {
317         WS_HILOGE("Query package group failed. userId = %{public}d, bundleName = %{public}s",
318             userId_, bundleName_.c_str());
319         return false;
320     }
321 #else
322     int32_t group = 10;
323 #endif
324     return SetMinIntervalByGroup(group);
325 }
326 
SetMinIntervalByGroup(int32_t group)327 bool WorkStatus::SetMinIntervalByGroup(int32_t group)
328 {
329     callbackFlag_ = true;
330 #ifdef DEVICE_USAGE_STATISTICS_ENABLE
331     auto itMap = DeviceUsageStats::DeviceUsageStatsGroupMap::groupIntervalMap_.find(group);
332     if (itMap != DeviceUsageStats::DeviceUsageStatsGroupMap::groupIntervalMap_.end()) {
333         minInterval_ = DeviceUsageStats::DeviceUsageStatsGroupMap::groupIntervalMap_[group];
334     } else {
335         minInterval_ = -1;
336     }
337 #else
338     minInterval_ = MIN_INTERVAL_DEFAULT;
339 #endif
340     WS_HILOGD("Set min interval to %{public}" PRId64 " by group %{public}d", minInterval_, group);
341     return true;
342 }
343 
SetMinIntervalByDump(int64_t interval)344 void WorkStatus::SetMinIntervalByDump(int64_t interval)
345 {
346     WS_HILOGD("Set min interval by dump to %{public}" PRId64 "", interval);
347     debugMode = interval == 0 ? false : true;
348     minInterval_ = interval == 0 ? minInterval_ : interval;
349 }
350 
GetMinInterval()351 int64_t WorkStatus::GetMinInterval()
352 {
353     return minInterval_;
354 }
355 
UpdateUidLastTimeMap()356 void WorkStatus::UpdateUidLastTimeMap()
357 {
358     std::lock_guard<std::mutex> lock(s_uid_last_time_mutex);
359     time_t lastTime = getOppositeTime();
360     s_uid_last_time_map[uid_] = lastTime;
361 }
362 
ClearUidLastTimeMap(int32_t uid)363 void WorkStatus::ClearUidLastTimeMap(int32_t uid)
364 {
365     std::lock_guard<std::mutex> lock(s_uid_last_time_mutex);
366     s_uid_last_time_map.erase(uid);
367 }
368 
IsRunning()369 bool WorkStatus::IsRunning()
370 {
371     return currentStatus_ == RUNNING;
372 }
373 
IsReadyStatus()374 bool WorkStatus::IsReadyStatus()
375 {
376     return currentStatus_ == CONDITION_READY;
377 }
378 
IsRemoved()379 bool WorkStatus::IsRemoved()
380 {
381     return currentStatus_ == REMOVED;
382 }
383 
IsLastWorkTimeout()384 bool WorkStatus::IsLastWorkTimeout()
385 {
386     return lastTimeout_;
387 }
388 
IsRepeating()389 bool WorkStatus::IsRepeating()
390 {
391     std::lock_guard<std::mutex> lock(conditionMapMutex_);
392     if (conditionMap_.count(WorkCondition::Type::TIMER) <= 0) {
393         return false;
394     }
395     if (conditionMap_.at(WorkCondition::Type::TIMER)->boolVal) {
396         return true;
397     } else {
398         return conditionMap_.at(WorkCondition::Type::TIMER)->intVal > 0;
399     }
400 }
401 
GetStatus()402 WorkStatus::Status WorkStatus::GetStatus()
403 {
404     return currentStatus_;
405 }
406 
Dump(string & result)407 void WorkStatus::Dump(string& result)
408 {
409     result.append("{\n");
410     result.append(string("\"workId\":") + workId_ + ",\n");
411     result.append(string("\"bundleName\":") + bundleName_ + ",\n");
412     result.append(string("\"status\":") + to_string(currentStatus_) + ",\n");
413     result.append(string("\"conditionMap\":{\n"));
414     std::lock_guard<std::mutex> lock(conditionMapMutex_);
415     if (conditionMap_.count(WorkCondition::Type::NETWORK) > 0) {
416         result.append(string("\"networkType\":") +
417             to_string(conditionMap_.at(WorkCondition::Type::NETWORK)->enumVal) + ",\n");
418     }
419     if (conditionMap_.count(WorkCondition::Type::CHARGER) > 0) {
420         result.append(string("\"isCharging\":") +
421             (conditionMap_.at(WorkCondition::Type::CHARGER)->boolVal ? "true" : "false") + ",\n");
422         result.append(string("\"chargerType\":") +
423             to_string(conditionMap_.at(WorkCondition::Type::CHARGER)->enumVal) + ",\n");
424     }
425     if (conditionMap_.count(WorkCondition::Type::BATTERY_LEVEL) > 0) {
426         result.append(string("\"batteryLevel\":") +
427             to_string(conditionMap_.at(WorkCondition::Type::BATTERY_LEVEL)->intVal) + ",\n");
428     }
429     if (conditionMap_.count(WorkCondition::Type::BATTERY_STATUS) > 0) {
430         result.append(string("\"batteryStatus\":") +
431             to_string(conditionMap_.at(WorkCondition::Type::BATTERY_STATUS)->enumVal) + ",\n");
432     }
433     if (conditionMap_.count(WorkCondition::Type::STORAGE) > 0) {
434         result.append(string("\"storageLevel\":") +
435             to_string(conditionMap_.at(WorkCondition::Type::STORAGE)->enumVal) + ",\n");
436     }
437     if (conditionMap_.count(WorkCondition::Type::TIMER) > 0) {
438         result.append(string("\"baseTime\":") + to_string(baseTime_) + ",\n");
439         if (conditionMap_.at(WorkCondition::Type::TIMER)->boolVal) {
440             result.append(string("\"isRepeat\": true,\n"));
441         } else {
442             result.append(string("\"cycleLeft\":") +
443                 to_string(conditionMap_.at(WorkCondition::Type::TIMER)->intVal) + ",\n");
444         }
445     }
446     result.append("},\n\"workInfo\":\n");
447     workInfo_->Dump(result);
448     result.append("}\n");
449     result.append("\n");
450 }
451 } // namespace WorkScheduler
452 } // namespace OHOS