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 #include <set>
16 #include "work_queue.h"
17 
18 #include "work_condition.h"
19 #include "work_sched_hilog.h"
20 #include "work_sched_errors.h"
21 #include "work_scheduler_service.h"
22 
23 using namespace std;
24 
25 namespace OHOS {
26 namespace WorkScheduler {
OnConditionChanged(WorkCondition::Type type, shared_ptr<DetectorValue> conditionVal)27 vector<shared_ptr<WorkStatus>> WorkQueue::OnConditionChanged(WorkCondition::Type type,
28     shared_ptr<DetectorValue> conditionVal)
29 {
30     shared_ptr<Condition> value = ParseCondition(type, conditionVal);
31     vector<shared_ptr<WorkStatus>> result;
32     std::set<int32_t> uidList;
33     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
34     workList_.sort(WorkComp());
35     for (auto it : workList_) {
36         if (it->OnConditionChanged(type, value) == E_GROUP_CHANGE_NOT_MATCH_HAP) {
37             continue;
38         }
39         if (uidList.count(it->uid_) > 0 && it->GetMinInterval() != 0 &&
40             !DelayedSingleton<WorkSchedulerService>::GetInstance()->CheckEffiResApplyInfo(it->uid_)) {
41             WS_HILOGI("One uid can start only one work, uid:%{public}d, bundleName:%{public}s",
42                 it->uid_, it->bundleName_.c_str());
43             continue;
44         }
45         if (it->IsReady()) {
46             result.emplace_back(it);
47             uidList.insert(it->uid_);
48         } else {
49             if (it->IsReadyStatus()) {
50                 it->MarkStatus(WorkStatus::Status::WAIT_CONDITION);
51             }
52         }
53         if (it->needRetrigger_) {
54             result.emplace_back(it);
55         }
56     }
57     return result;
58 }
59 
ParseCondition(WorkCondition::Type type, shared_ptr<DetectorValue> conditionVal)60 shared_ptr<Condition> WorkQueue::ParseCondition(WorkCondition::Type type,
61     shared_ptr<DetectorValue> conditionVal)
62 {
63     shared_ptr<Condition> value = make_shared<Condition>();
64     switch (type) {
65         case WorkCondition::Type::NETWORK:
66         // fall-through
67         case WorkCondition::Type::BATTERY_STATUS:
68         // fall-through
69         case WorkCondition::Type::STORAGE: {
70             value->enumVal = conditionVal->intVal;
71             break;
72         }
73         case WorkCondition::Type::CHARGER: {
74             value->enumVal = conditionVal->intVal;
75             value->boolVal = conditionVal->boolVal;
76             break;
77         }
78         case WorkCondition::Type::BATTERY_LEVEL: {
79             value->intVal = conditionVal->intVal;
80             break;
81         }
82         case WorkCondition::Type::TIMER: {
83             break;
84         }
85         case WorkCondition::Type::GROUP: {
86             value->enumVal = conditionVal->intVal;
87             value->intVal = conditionVal->timeVal;
88             value->boolVal = conditionVal->boolVal;
89             value->strVal = conditionVal->strVal;
90             break;
91         }
92         case WorkCondition::Type::DEEP_IDLE:
93         case WorkCondition::Type::STANDBY: {
94             value->boolVal = conditionVal->boolVal;
95             break;
96         }
97         default: {}
98     }
99     return value;
100 }
101 
Push(shared_ptr<vector<shared_ptr<WorkStatus>>> workStatusVector)102 void WorkQueue::Push(shared_ptr<vector<shared_ptr<WorkStatus>>> workStatusVector)
103 {
104     for (auto it : *workStatusVector) {
105         Push(it);
106     }
107     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
108     workList_.sort(WorkComp());
109 }
110 
Push(shared_ptr<WorkStatus> workStatus)111 void WorkQueue::Push(shared_ptr<WorkStatus> workStatus)
112 {
113     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
114     if (this->Contains(make_shared<string>(workStatus->workId_))) {
115         for (auto it : workList_) {
116             if (it->workId_.compare(workStatus->workId_) == 0) {
117                 return;
118             }
119         }
120         return;
121     }
122     workList_.push_back(workStatus);
123 }
124 
Remove(shared_ptr<WorkStatus> workStatus)125 bool WorkQueue::Remove(shared_ptr<WorkStatus> workStatus)
126 {
127     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
128     auto iter = std::find(workList_.cbegin(), workList_.cend(), workStatus);
129     if (iter != workList_.end()) {
130         workList_.remove(*iter);
131     }
132     return true;
133 }
134 
GetSize()135 uint32_t WorkQueue::GetSize()
136 {
137     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
138     return workList_.size();
139 }
140 
Contains(std::shared_ptr<std::string> workId)141 bool WorkQueue::Contains(std::shared_ptr<std::string> workId)
142 {
143     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
144     auto iter = std::find_if(workList_.cbegin(), workList_.cend(), [&workId]
145         (const shared_ptr<WorkStatus> &workStatus) { return workId->compare(workStatus->workId_) == 0; });
146     if (iter != workList_.end()) {
147         return true;
148     }
149     return false;
150 }
151 
Find(string workId)152 shared_ptr<WorkStatus> WorkQueue::Find(string workId)
153 {
154     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
155     auto iter = std::find_if(workList_.cbegin(), workList_.cend(),
156         [&workId](const shared_ptr<WorkStatus> &workStatus) { return workStatus->workId_ == workId; });
157     if (iter != workList_.end()) {
158         return *iter;
159     }
160     return nullptr;
161 }
162 
GetWorkToRunByPriority()163 shared_ptr<WorkStatus> WorkQueue::GetWorkToRunByPriority()
164 {
165     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
166     workList_.sort(WorkComp());
167     auto work = workList_.begin();
168     shared_ptr<WorkStatus> workStatus = nullptr;
169     while (work != workList_.end()) {
170         if ((*work)->GetStatus() == WorkStatus::CONDITION_READY) {
171             workStatus = *work;
172             workStatus->priority_++;
173             break;
174         }
175         work++;
176     }
177     return workStatus;
178 }
179 
CancelWork(shared_ptr<WorkStatus> workStatus)180 bool WorkQueue::CancelWork(shared_ptr<WorkStatus> workStatus)
181 {
182     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
183     workList_.remove(workStatus);
184     return true;
185 }
186 
GetWorkList()187 list<shared_ptr<WorkStatus>> WorkQueue::GetWorkList()
188 {
189     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
190     return workList_;
191 }
192 
RemoveUnReady()193 void WorkQueue::RemoveUnReady()
194 {
195     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
196     workList_.remove_if([](shared_ptr<WorkStatus> value) {
197         return (value->GetStatus() != WorkStatus::Status::CONDITION_READY);
198     });
199 }
200 
GetRunningCount()201 int32_t WorkQueue::GetRunningCount()
202 {
203     int32_t count = 0;
204     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
205     for (shared_ptr<WorkStatus> work : workList_) {
206         if (work->IsRunning()) {
207             count++;
208         }
209     }
210     return count;
211 }
212 
GetRunningWorks()213 std::list<std::shared_ptr<WorkInfo>> WorkQueue::GetRunningWorks()
214 {
215     std::list<std::shared_ptr<WorkInfo>> workInfo;
216     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
217     for (shared_ptr<WorkStatus> work : workList_) {
218         if (work->IsRunning()) {
219             auto info = std::make_shared<WorkInfo>();
220             info->SetElement(work->bundleName_, work->abilityName_);
221             info->RefreshUid(work->uid_);
222             workInfo.emplace_back(info);
223         }
224     }
225     return workInfo;
226 }
227 
GetDeepIdleWorks()228 std::list<std::shared_ptr<WorkStatus>> WorkQueue::GetDeepIdleWorks()
229 {
230     std::list<std::shared_ptr<WorkStatus>> works;
231     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
232     for (shared_ptr<WorkStatus> work : workList_) {
233         if (work->IsRunning() && work->workInfo_->GetDeepIdle() == WorkCondition::DeepIdle::DEEP_IDLE_IN) {
234             works.emplace_back(work);
235         }
236     }
237     return works;
238 }
239 
GetWorkIdStr(string& result)240 void WorkQueue::GetWorkIdStr(string& result)
241 {
242     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
243     for (auto it : workList_) {
244         result.append(it->workId_ + ", ");
245     }
246 }
247 
Dump(string& result)248 void WorkQueue::Dump(string& result)
249 {
250     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
251     for (auto it : workList_) {
252         it->Dump(result);
253     }
254 }
255 
ClearAll()256 void WorkQueue::ClearAll()
257 {
258     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
259     workList_.clear();
260 }
261 
operator ()(const shared_ptr<WorkStatus> w1, const shared_ptr<WorkStatus> w2)262 bool WorkComp::operator () (const shared_ptr<WorkStatus> w1, const shared_ptr<WorkStatus> w2)
263 {
264     return w1->priority_ < w2->priority_;
265 }
266 
SetMinIntervalByDump(int64_t interval)267 void WorkQueue::SetMinIntervalByDump(int64_t interval)
268 {
269     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
270     for (auto it : workList_) {
271         it->SetMinIntervalByDump(interval);
272     }
273 }
274 } // namespace WorkScheduler
275 } // namespace OHOS