1 /*
2 * Copyright (C) 2023 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 "tel_event_queue.h"
17
18 #include "tel_event_handler.h"
19 #include "telephony_log_wrapper.h"
20
21 namespace OHOS {
22 namespace Telephony {
23 namespace {
24 enum class TelPriority : uint32_t { IMMEDIATE = 0, HIGH, LOW };
25 }
26
TelEventQueue(const std::string & name)27 TelEventQueue::TelEventQueue(const std::string &name) : name_(name)
28 {
29 TELEPHONY_LOGI("%{public}s create", name_.c_str());
30 name_ = std::string(name_.c_str());
31 queue_ = std::make_shared<ffrt::queue>(name_.c_str());
32 }
33
~TelEventQueue()34 TelEventQueue::~TelEventQueue()
35 {
36 TELEPHONY_LOGI("%{public}s destroy", name_.c_str());
37 RemoveAllEvents();
38 ClearCurrentTask(true);
39 if (!queue_) {
40 return;
41 }
42 if (!curTask_) {
43 return;
44 }
45 TELEPHONY_LOGD("%{public}s need to wait", name_.c_str());
46 queue_->wait(curTask_);
47 curTask_ = ffrt::task_handle();
48 queue_ = nullptr;
49 }
50
GetCurHandleTime()51 AppExecFwk::InnerEvent::TimePoint TelEventQueue::GetCurHandleTime()
52 {
53 std::lock_guard<std::mutex> lock(memberCtx_);
54 return curHandleTime_;
55 }
56
SetCurHandleTime(AppExecFwk::InnerEvent::TimePoint handleTime)57 void TelEventQueue::SetCurHandleTime(AppExecFwk::InnerEvent::TimePoint handleTime)
58 {
59 std::lock_guard<std::mutex> lock(memberCtx_);
60 curHandleTime_ = handleTime;
61 }
62
Submit(AppExecFwk::InnerEvent::Pointer & event,AppExecFwk::EventQueue::Priority priority)63 void TelEventQueue::Submit(AppExecFwk::InnerEvent::Pointer &event, AppExecFwk::EventQueue::Priority priority)
64 {
65 InsertEventsInner(event, priority);
66 if (GetHandleTime() < GetCurHandleTime()) {
67 GetNextQueueId();
68 ClearCurrentTask(false);
69 SubmitInner(queueId_.load());
70 }
71 }
72
ToTelPriority(AppExecFwk::EventQueue::Priority priority)73 uint32_t TelEventQueue::ToTelPriority(AppExecFwk::EventQueue::Priority priority)
74 {
75 if (priority == AppExecFwk::EventQueue::Priority::IMMEDIATE) {
76 return static_cast<uint32_t>(TelPriority::IMMEDIATE);
77 }
78 if (priority == AppExecFwk::EventQueue::Priority::HIGH) {
79 return static_cast<uint32_t>(TelPriority::HIGH);
80 }
81 return static_cast<uint32_t>(TelPriority::LOW);
82 }
83
InsertEventsInner(AppExecFwk::InnerEvent::Pointer & event,AppExecFwk::EventQueue::Priority priority)84 void TelEventQueue::InsertEventsInner(AppExecFwk::InnerEvent::Pointer &event, AppExecFwk::EventQueue::Priority priority)
85 {
86 if (event == nullptr) {
87 return;
88 }
89 std::unique_lock<std::mutex> lock(eventCtx_);
90 auto &events = eventLists_[ToTelPriority(priority)].events;
91 auto f = [](const AppExecFwk::InnerEvent::Pointer &first, const AppExecFwk::InnerEvent::Pointer &second) {
92 if (!first || !second) {
93 return false;
94 }
95 return first->GetHandleTime() < second->GetHandleTime();
96 };
97 auto it = std::upper_bound(events.begin(), events.end(), event, f);
98 auto innerEventId = event->GetInnerEventId();
99 events.insert(it, std::move(event));
100 TELEPHONY_LOGD(
101 "%{public}s InsertEventsInner eventId %{public}d finish", name_.c_str(), static_cast<int32_t>(innerEventId));
102 }
103
ClearCurrentTask(bool isNeedEnd)104 void TelEventQueue::ClearCurrentTask(bool isNeedEnd)
105 {
106 std::lock_guard<std::mutex> lock(taskCtx_);
107 if (!curTask_ || !queue_) {
108 return;
109 }
110 queue_->cancel(curTask_);
111 if (isNeedEnd) {
112 GetNextQueueId();
113 return;
114 }
115 curTask_ = ffrt::task_handle();
116 TELEPHONY_LOGD("%{public}s cancel current task", name_.c_str());
117 }
118
SubmitInner(int32_t queueId)119 void TelEventQueue::SubmitInner(int32_t queueId)
120 {
121 if (!queue_) {
122 TELEPHONY_LOGE("%{public}s queue is nullptr", name_.c_str());
123 return;
124 }
125 auto handleTime = GetHandleTime();
126 if (handleTime == AppExecFwk::InnerEvent::TimePoint::max()) {
127 TELEPHONY_LOGD("%{public}s SubmitInner has no task", name_.c_str());
128 return;
129 }
130 int64_t delayTime = 0;
131 AppExecFwk::InnerEvent::TimePoint now = AppExecFwk::InnerEvent::Clock::now();
132 if (handleTime > now) {
133 delayTime = std::chrono::duration_cast<std::chrono::microseconds>(handleTime - now).count();
134 }
135 SubmitToFFRT(queueId, handleTime, delayTime);
136 }
137
GetNextQueueId()138 int32_t TelEventQueue::GetNextQueueId()
139 {
140 if (queueId_ >= INT32_MAX) {
141 queueId_ = 1;
142 }
143 return queueId_++;
144 }
145
SubmitToFFRT(int32_t queueId,AppExecFwk::InnerEvent::TimePoint handleTime,int64_t delayTime)146 void TelEventQueue::SubmitToFFRT(int32_t queueId, AppExecFwk::InnerEvent::TimePoint handleTime, int64_t delayTime)
147 {
148 std::lock_guard<std::mutex> lock(taskCtx_);
149 if (queueId != queueId_.load()) {
150 TELEPHONY_LOGD("%{public}s task no need to submit", name_.c_str());
151 SetCurHandleTime(AppExecFwk::InnerEvent::TimePoint::max());
152 return;
153 }
154 SetCurHandleTime(handleTime);
155 curTask_ = queue_->submit_h(
156 [this, queueId = queueId]() {
157 bool isNeedSubmit = true;
158 auto event = PopEvent(queueId, isNeedSubmit);
159 std::shared_ptr<TelEventHandler> handler = nullptr;
160 if (event) {
161 handler = std::static_pointer_cast<TelEventHandler>(event->GetOwner());
162 }
163 if (event && handler) {
164 TELEPHONY_LOGD("%{public}s ProcessEvent eventId %{public}d", name_.c_str(),
165 static_cast<uint32_t>(event->GetInnerEventId()));
166 handler->ProcessEvent(event);
167 }
168 if (!isNeedSubmit) {
169 TELEPHONY_LOGD("%{public}s task no need to submit", name_.c_str());
170 return;
171 }
172 SubmitInner(queueId);
173 },
174 ffrt::task_attr().delay(delayTime));
175 }
176
RemoveEvent(uint32_t innerEventId)177 void TelEventQueue::RemoveEvent(uint32_t innerEventId)
178 {
179 std::lock_guard<std::mutex> lock(eventCtx_);
180 auto filter = [innerEventId](const AppExecFwk::InnerEvent::Pointer &p) {
181 if (p == nullptr) {
182 return false;
183 }
184 return p->GetInnerEventId() == innerEventId;
185 };
186 for (uint32_t i = 0; i < EVENT_QUEUE_NUM; ++i) {
187 eventLists_[i].events.remove_if(filter);
188 }
189 if (IsEmpty()) {
190 SetCurHandleTime(AppExecFwk::InnerEvent::TimePoint::max());
191 }
192 TELEPHONY_LOGD("%{public}s remove eventId %{public}d finish", name_.c_str(), innerEventId);
193 }
194
HasInnerEvent(uint32_t innerEventId)195 bool TelEventQueue::HasInnerEvent(uint32_t innerEventId)
196 {
197 std::lock_guard<std::mutex> lock(eventCtx_);
198 auto filter = [innerEventId](
199 const AppExecFwk::InnerEvent::Pointer &p) { return p->GetInnerEventId() == innerEventId; };
200 for (uint32_t i = 0; i < EVENT_QUEUE_NUM; ++i) {
201 std::list<AppExecFwk::InnerEvent::Pointer>::iterator iter =
202 std::find_if(eventLists_[i].events.begin(), eventLists_[i].events.end(), filter);
203 if (iter != eventLists_[i].events.end()) {
204 return true;
205 }
206 }
207 return false;
208 }
209
RemoveAllEvents()210 void TelEventQueue::RemoveAllEvents()
211 {
212 std::lock_guard<std::mutex> lock(eventCtx_);
213 for (uint32_t i = 0; i < EVENT_QUEUE_NUM; ++i) {
214 eventLists_[i].events.clear();
215 }
216 SetCurHandleTime(AppExecFwk::InnerEvent::TimePoint::max());
217 TELEPHONY_LOGD("%{public}s RemoveAllEvents finish", name_.c_str());
218 }
219
IsEmpty()220 bool TelEventQueue::IsEmpty()
221 {
222 for (uint32_t i = 0; i < EVENT_QUEUE_NUM; ++i) {
223 if (!eventLists_[i].events.empty()) {
224 return false;
225 }
226 }
227 return true;
228 }
229
PopEvent(int32_t queueId,bool & isNeedSubmit)230 AppExecFwk::InnerEvent::Pointer TelEventQueue::PopEvent(int32_t queueId, bool &isNeedSubmit)
231 {
232 std::lock_guard<std::mutex> lock(eventCtx_);
233 if (IsEmpty() || queueId != queueId_.load()) {
234 isNeedSubmit = false;
235 SetCurHandleTime(AppExecFwk::InnerEvent::TimePoint::max());
236 return AppExecFwk::InnerEvent::Pointer(nullptr, nullptr);
237 }
238 uint32_t priorityIndex = GetPriorityIndex();
239 AppExecFwk::InnerEvent::Pointer event = std::move(eventLists_[priorityIndex].events.front());
240 eventLists_[priorityIndex].events.pop_front();
241 if (IsEmpty()) {
242 isNeedSubmit = false;
243 SetCurHandleTime(AppExecFwk::InnerEvent::TimePoint::max());
244 }
245 return event;
246 }
247
GetHandleTime()248 AppExecFwk::InnerEvent::TimePoint TelEventQueue::GetHandleTime()
249 {
250 std::lock_guard<std::mutex> lock(eventCtx_);
251 if (IsEmpty()) {
252 return AppExecFwk::InnerEvent::TimePoint::max();
253 }
254 return eventLists_[GetPriorityIndex()].events.front()->GetHandleTime();
255 }
256
GetPriorityIndex()257 uint32_t TelEventQueue::GetPriorityIndex()
258 {
259 AppExecFwk::InnerEvent::TimePoint now = AppExecFwk::InnerEvent::Clock::now();
260 AppExecFwk::InnerEvent::TimePoint needWakeUpTime = AppExecFwk::InnerEvent::TimePoint::max();
261 uint32_t priorityIndex = 0;
262 for (uint32_t i = 0; i < EVENT_QUEUE_NUM; ++i) {
263 if (eventLists_[i].events.empty()) {
264 continue;
265 }
266 auto handleTime = eventLists_[i].events.front()->GetHandleTime();
267 if (handleTime <= now) {
268 priorityIndex = i;
269 break;
270 }
271 if (handleTime < needWakeUpTime) {
272 needWakeUpTime = handleTime;
273 priorityIndex = i;
274 }
275 }
276 return priorityIndex;
277 }
278
279 } // namespace Telephony
280 } // namespace OHOS