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