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 
Find(const int32_t userId,const std::string & bundleName)163 bool WorkQueue::Find(const int32_t userId, const std::string &bundleName)
164 {
165     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
166     auto iter = std::find_if(workList_.cbegin(), workList_.cend(),
167         [userId, &bundleName](const shared_ptr<WorkStatus> &workStatus) {
168             return workStatus->userId_ == userId && workStatus->bundleName_ == bundleName;
169         });
170     return iter != workList_.end();
171 }
172 
GetWorkToRunByPriority()173 shared_ptr<WorkStatus> WorkQueue::GetWorkToRunByPriority()
174 {
175     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
176     workList_.sort(WorkComp());
177     auto work = workList_.begin();
178     shared_ptr<WorkStatus> workStatus = nullptr;
179     while (work != workList_.end()) {
180         if ((*work)->GetStatus() == WorkStatus::CONDITION_READY) {
181             workStatus = *work;
182             workStatus->priority_++;
183             break;
184         }
185         work++;
186     }
187     return workStatus;
188 }
189 
CancelWork(shared_ptr<WorkStatus> workStatus)190 bool WorkQueue::CancelWork(shared_ptr<WorkStatus> workStatus)
191 {
192     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
193     workList_.remove(workStatus);
194     return true;
195 }
196 
GetWorkList()197 list<shared_ptr<WorkStatus>> WorkQueue::GetWorkList()
198 {
199     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
200     return workList_;
201 }
202 
RemoveUnReady()203 void WorkQueue::RemoveUnReady()
204 {
205     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
206     workList_.remove_if([](shared_ptr<WorkStatus> value) {
207         return (value->GetStatus() != WorkStatus::Status::CONDITION_READY);
208     });
209 }
210 
GetRunningCount()211 int32_t WorkQueue::GetRunningCount()
212 {
213     int32_t count = 0;
214     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
215     for (shared_ptr<WorkStatus> work : workList_) {
216         if (work->IsRunning()) {
217             count++;
218         }
219     }
220     return count;
221 }
222 
GetRunningWorks()223 std::list<std::shared_ptr<WorkInfo>> WorkQueue::GetRunningWorks()
224 {
225     std::list<std::shared_ptr<WorkInfo>> workInfo;
226     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
227     for (shared_ptr<WorkStatus> work : workList_) {
228         if (work->IsRunning()) {
229             auto info = std::make_shared<WorkInfo>();
230             info->SetElement(work->bundleName_, work->abilityName_);
231             info->RefreshUid(work->uid_);
232             workInfo.emplace_back(info);
233         }
234     }
235     return workInfo;
236 }
237 
GetDeepIdleWorks()238 std::list<std::shared_ptr<WorkStatus>> WorkQueue::GetDeepIdleWorks()
239 {
240     std::list<std::shared_ptr<WorkStatus>> works;
241     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
242     for (shared_ptr<WorkStatus> work : workList_) {
243         if (work->IsRunning() && work->workInfo_->GetDeepIdle() == WorkCondition::DeepIdle::DEEP_IDLE_IN) {
244             works.emplace_back(work);
245         }
246     }
247     return works;
248 }
249 
GetWorkIdStr(string & result)250 void WorkQueue::GetWorkIdStr(string& result)
251 {
252     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
253     for (auto it : workList_) {
254         result.append(it->workId_ + ", ");
255     }
256 }
257 
Dump(string & result)258 void WorkQueue::Dump(string& result)
259 {
260     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
261     for (auto it : workList_) {
262         it->Dump(result);
263     }
264 }
265 
ClearAll()266 void WorkQueue::ClearAll()
267 {
268     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
269     workList_.clear();
270 }
271 
operator ()(const shared_ptr<WorkStatus> w1,const shared_ptr<WorkStatus> w2)272 bool WorkComp::operator () (const shared_ptr<WorkStatus> w1, const shared_ptr<WorkStatus> w2)
273 {
274     return w1->priority_ < w2->priority_;
275 }
276 
SetMinIntervalByDump(int64_t interval)277 void WorkQueue::SetMinIntervalByDump(int64_t interval)
278 {
279     std::lock_guard<ffrt::recursive_mutex> lock(workListMutex_);
280     for (auto it : workList_) {
281         it->SetMinIntervalByDump(interval);
282     }
283 }
284 } // namespace WorkScheduler
285 } // namespace OHOS