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 <hisysevent.h>
16 #include <ipc_skeleton.h>
17
18 #include "work_queue_manager.h"
19 #include "work_scheduler_service.h"
20 #include "work_sched_hilog.h"
21 #include "work_sched_utils.h"
22
23 using namespace std;
24
25 namespace OHOS {
26 namespace WorkScheduler {
27 const uint32_t TIME_CYCLE = 10 * 60 * 1000; // 10min
28 static int32_t g_timeRetrigger = INT32_MAX;
29
WorkQueueManager(const std::shared_ptr<WorkSchedulerService> & wss)30 WorkQueueManager::WorkQueueManager(const std::shared_ptr<WorkSchedulerService>& wss) : wss_(wss)
31 {
32 timeCycle_ = TIME_CYCLE;
33 }
34
Init()35 bool WorkQueueManager::Init()
36 {
37 return true;
38 }
39
AddListener(WorkCondition::Type type,shared_ptr<IConditionListener> listener)40 bool WorkQueueManager::AddListener(WorkCondition::Type type, shared_ptr<IConditionListener> listener)
41 {
42 std::lock_guard<ffrt::mutex> lock(mutex_);
43 if (listenerMap_.count(type) > 0) {
44 return false;
45 }
46 listenerMap_.emplace(type, listener);
47 return true;
48 }
49
AddWork(shared_ptr<WorkStatus> workStatus)50 bool WorkQueueManager::AddWork(shared_ptr<WorkStatus> workStatus)
51 {
52 if (!workStatus || !workStatus->workInfo_ || !workStatus->workInfo_->GetConditionMap()) {
53 return false;
54 }
55 WS_HILOGD("workStatus ID: %{public}s", workStatus->workId_.c_str());
56 std::lock_guard<ffrt::mutex> lock(mutex_);
57 auto map = workStatus->workInfo_->GetConditionMap();
58 for (auto it : *map) {
59 if (queueMap_.count(it.first) == 0) {
60 queueMap_.emplace(it.first, make_shared<WorkQueue>());
61 if (it.first != WorkCondition::Type::BATTERY_LEVEL && listenerMap_.count(it.first) != 0) {
62 listenerMap_.at(it.first)->Start();
63 }
64 }
65 queueMap_.at(it.first)->Push(workStatus);
66 }
67 if (WorkSchedUtils::IsSystemApp()) {
68 WS_HILOGI("Is system app, default group is active.");
69 workStatus->workInfo_->SetCallBySystemApp(true);
70 }
71 return true;
72 }
73
RemoveWork(shared_ptr<WorkStatus> workStatus)74 bool WorkQueueManager::RemoveWork(shared_ptr<WorkStatus> workStatus)
75 {
76 std::lock_guard<ffrt::mutex> lock(mutex_);
77 WS_HILOGD("workStatus ID: %{public}s", workStatus->workId_.c_str());
78 auto map = workStatus->workInfo_->GetConditionMap();
79 for (auto it : *map) {
80 if (queueMap_.count(it.first) > 0) {
81 queueMap_.at(it.first)->Remove(workStatus);
82 }
83 if (queueMap_.count(it.first) == 0) {
84 listenerMap_.at(it.first)->Stop();
85 }
86 }
87 return true;
88 }
89
CancelWork(shared_ptr<WorkStatus> workStatus)90 bool WorkQueueManager::CancelWork(shared_ptr<WorkStatus> workStatus)
91 {
92 std::lock_guard<ffrt::mutex> lock(mutex_);
93 WS_HILOGD("workStatus ID: %{public}s", workStatus->workId_.c_str());
94 for (auto it : queueMap_) {
95 it.second->CancelWork(workStatus);
96 if (queueMap_.count(it.first) == 0) {
97 if (it.first == WorkCondition::Type::BATTERY_LEVEL) {
98 continue;
99 }
100 listenerMap_.at(it.first)->Stop();
101 }
102 }
103 // Notify work remove event to battery statistics
104 int32_t pid = IPCSkeleton::GetCallingPid();
105 HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::WORK_SCHEDULER,
106 "WORK_REMOVE", HiviewDFX::HiSysEvent::EventType::STATISTIC, "UID", workStatus->uid_,
107 "PID", pid, "NAME", workStatus->bundleName_, "WORKID", workStatus->workId_);
108 return true;
109 }
110
GetReayQueue(WorkCondition::Type conditionType,shared_ptr<DetectorValue> conditionVal)111 vector<shared_ptr<WorkStatus>> WorkQueueManager::GetReayQueue(WorkCondition::Type conditionType,
112 shared_ptr<DetectorValue> conditionVal)
113 {
114 vector<shared_ptr<WorkStatus>> result;
115 std::lock_guard<ffrt::mutex> lock(mutex_);
116 if (conditionType != WorkCondition::Type::GROUP && queueMap_.count(conditionType) > 0) {
117 shared_ptr<WorkQueue> workQueue = queueMap_.at(conditionType);
118 result = workQueue->OnConditionChanged(conditionType, conditionVal);
119 }
120 if (conditionType == WorkCondition::Type::GROUP || conditionType == WorkCondition::Type::STANDBY) {
121 for (auto it : queueMap_) {
122 shared_ptr<WorkQueue> workQueue = it.second;
123 auto works = workQueue->OnConditionChanged(conditionType, conditionVal);
124 PushWork(works, result);
125 }
126 }
127 bool hasStop = false;
128 auto it = result.begin();
129 while (it != result.end()) {
130 if (!(*it)->needRetrigger_) {
131 ++it;
132 continue;
133 }
134 if (conditionType != WorkCondition::Type::TIMER
135 && conditionType != WorkCondition::Type::GROUP) {
136 WS_HILOGI("Need retrigger, start group listener, bundleName:%{public}s, workId:%{public}s",
137 (*it)->bundleName_.c_str(), (*it)->workId_.c_str());
138 SetTimeRetrigger((*it)->timeRetrigger_);
139 if (!hasStop) {
140 listenerMap_.at(WorkCondition::Type::GROUP)->Stop();
141 hasStop = true;
142 }
143 listenerMap_.at(WorkCondition::Type::GROUP)->Start();
144 }
145 (*it)->needRetrigger_ = false;
146 (*it)->timeRetrigger_ = INT32_MAX;
147 it = result.erase(it);
148 }
149 PrintWorkStatus(conditionType);
150 return result;
151 }
152
PrintWorkStatus(WorkCondition::Type conditionType)153 void WorkQueueManager::PrintWorkStatus(WorkCondition::Type conditionType)
154 {
155 if (conditionType == WorkCondition::Type::GROUP || conditionType == WorkCondition::Type::STANDBY) {
156 PrintAllWorkStatus(conditionType);
157 return;
158 }
159 if (queueMap_.count(conditionType) > 0) {
160 shared_ptr<WorkQueue> workQueue = queueMap_.at(conditionType);
161 auto workList = workQueue->GetWorkList();
162 for (auto work : workList) {
163 work->ToString(conditionType);
164 }
165 }
166 }
167
PrintAllWorkStatus(WorkCondition::Type conditionType)168 void WorkQueueManager::PrintAllWorkStatus(WorkCondition::Type conditionType)
169 {
170 std::set<std::string> allWorkIds;
171 for (auto it : queueMap_) {
172 shared_ptr<WorkQueue> workQueue = it.second;
173 auto workList = workQueue->GetWorkList();
174 for (auto work : workList) {
175 if (allWorkIds.count(work->workId_) != 0) {
176 continue;
177 }
178 allWorkIds.insert(work->workId_);
179 work->ToString(conditionType);
180 }
181 }
182 }
183
PushWork(vector<shared_ptr<WorkStatus>> & works,vector<shared_ptr<WorkStatus>> & result)184 void WorkQueueManager::PushWork(vector<shared_ptr<WorkStatus>> &works, vector<shared_ptr<WorkStatus>> &result)
185 {
186 for (const auto &work : works) {
187 auto iter = std::find_if(result.begin(), result.end(),
188 [&](const auto &existingWork) {
189 return existingWork->workId_ == work->workId_;
190 });
191 if (iter != result.end()) {
192 WS_HILOGE("WorkId:%{public}s existing, bundleName:%{public}s",
193 work->workId_.c_str(), work->bundleName_.c_str());
194 continue;
195 }
196 result.push_back(work);
197 }
198 }
199
OnConditionChanged(WorkCondition::Type conditionType,shared_ptr<DetectorValue> conditionVal)200 void WorkQueueManager::OnConditionChanged(WorkCondition::Type conditionType,
201 shared_ptr<DetectorValue> conditionVal)
202 {
203 auto service = wss_.lock();
204 if (!service) {
205 WS_HILOGE("service is null");
206 return;
207 }
208 auto task = [weak = weak_from_this(), service, conditionType, conditionVal]() {
209 auto strong = weak.lock();
210 if (!strong) {
211 WS_HILOGE("strong is null");
212 return;
213 }
214 vector<shared_ptr<WorkStatus>> readyWorkVector = strong->GetReayQueue(conditionType, conditionVal);
215 if (readyWorkVector.size() == 0) {
216 return;
217 }
218 for (auto it : readyWorkVector) {
219 it->MarkStatus(WorkStatus::Status::CONDITION_READY);
220 }
221 service->OnConditionReady(make_shared<vector<shared_ptr<WorkStatus>>>(readyWorkVector));
222 };
223 auto handler = service->GetHandler();
224 if (!handler) {
225 WS_HILOGE("handler is null");
226 return;
227 }
228 handler->PostTask(task);
229 }
230
StopAndClearWorks(list<shared_ptr<WorkStatus>> workList)231 bool WorkQueueManager::StopAndClearWorks(list<shared_ptr<WorkStatus>> workList)
232 {
233 for (auto &it : workList) {
234 CancelWork(it);
235 }
236 return true;
237 }
238
Dump(string & result)239 void WorkQueueManager::Dump(string& result)
240 {
241 std::lock_guard<ffrt::mutex> lock(mutex_);
242 string conditionType[] = {"network", "charger", "battery_status", "battery_level",
243 "storage", "timer", "group", "deepIdle", "standby", "unknown"};
244 uint32_t size = sizeof(conditionType);
245 for (auto it : queueMap_) {
246 if (it.first < size) {
247 result.append(conditionType[it.first]);
248 } else {
249 result.append(conditionType[size - 1]);
250 }
251 result.append(" : ");
252 result.append("[");
253 string workIdStr;
254 it.second->GetWorkIdStr(workIdStr);
255 result.append(workIdStr);
256 result.append("]\n");
257 }
258 }
259
SetTimeCycle(uint32_t time)260 void WorkQueueManager::SetTimeCycle(uint32_t time)
261 {
262 timeCycle_ = time;
263 listenerMap_.at(WorkCondition::Type::TIMER)->Stop();
264 listenerMap_.at(WorkCondition::Type::TIMER)->Start();
265 }
266
GetTimeCycle()267 uint32_t WorkQueueManager::GetTimeCycle()
268 {
269 return timeCycle_;
270 }
271
SetTimeRetrigger(int32_t time)272 void WorkQueueManager::SetTimeRetrigger(int32_t time)
273 {
274 g_timeRetrigger = time;
275 }
276
GetTimeRetrigger()277 int32_t WorkQueueManager::GetTimeRetrigger()
278 {
279 return g_timeRetrigger;
280 }
281
SetMinIntervalByDump(int64_t interval)282 void WorkQueueManager::SetMinIntervalByDump(int64_t interval)
283 {
284 for (auto it : queueMap_) {
285 it.second->SetMinIntervalByDump(interval);
286 }
287 }
288 } // namespace WorkScheduler
289 } // namespace OHOS