1 /*
2 * Copyright (c) 2021-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 "event_queue.h"
17
18 #include <algorithm>
19 #include <iterator>
20 #include <mutex>
21
22 #include "deamon_io_waiter.h"
23 #include "epoll_io_waiter.h"
24 #include "event_handler.h"
25 #include "event_handler_utils.h"
26 #include "event_logger.h"
27 #include "frame_report_sched.h"
28 #include "none_io_waiter.h"
29 #include "parameters.h"
30
31 namespace OHOS {
32 namespace AppExecFwk {
33 namespace {
34 static const bool MONITOR_FLAG =
35 system::GetBoolParameter("const.sys.param_file_description_monitor", false);
36 static bool g_vsyncFirstEnabled = true;
37 DEFINE_EH_HILOG_LABEL("EventQueue");
38
39 // Help to remove file descriptor listeners.
40 template<typename T>
RemoveFileDescriptorListenerLocked(std::map<int32_t,std::shared_ptr<FileDescriptorListener>> & listeners,const std::shared_ptr<IoWaiter> & ioWaiter,const T & filter,bool useDeamonIoWaiter_)41 void RemoveFileDescriptorListenerLocked(std::map<int32_t, std::shared_ptr<FileDescriptorListener>> &listeners,
42 const std::shared_ptr<IoWaiter>& ioWaiter, const T &filter, bool useDeamonIoWaiter_)
43 {
44 for (auto it = listeners.begin(); it != listeners.end();) {
45 if (filter(it->second)) {
46 if (useDeamonIoWaiter_ || (it->second->GetIsDeamonWaiter() && MONITOR_FLAG)) {
47 DeamonIoWaiter::GetInstance().RemoveFileDescriptor(it->first);
48 }
49 if (ioWaiter) {
50 ioWaiter->RemoveFileDescriptor(it->first);
51 }
52 it = listeners.erase(it);
53 } else {
54 ++it;
55 }
56 }
57 }
58 } // unnamed namespace
59
EventQueue()60 EventQueue::EventQueue() : ioWaiter_(std::make_shared<NoneIoWaiter>())
61 {
62 HILOGD("enter");
63 }
64
EventQueue(const std::shared_ptr<IoWaiter> & ioWaiter)65 EventQueue::EventQueue(const std::shared_ptr<IoWaiter> &ioWaiter)
66 : ioWaiter_(ioWaiter ? ioWaiter : std::make_shared<NoneIoWaiter>())
67 {
68 HILOGD("enter");
69 if (ioWaiter_->SupportListeningFileDescriptor()) {
70 // Set callback to handle events from file descriptors.
71 ioWaiter_->SetFileDescriptorEventCallback(
72 std::bind(&EventQueue::HandleFileDescriptorEvent, this, std::placeholders::_1, std::placeholders::_2,
73 std::placeholders::_3, std::placeholders::_4));
74 }
75 }
76
~EventQueue()77 EventQueue::~EventQueue()
78 {
79 EH_LOGD_LIMIT("EventQueue is unavailable hence");
80 }
81
GetEvent()82 InnerEvent::Pointer EventQueue::GetEvent()
83 {
84 return InnerEvent::Pointer(nullptr, nullptr);
85 }
86
GetExpiredEvent(InnerEvent::TimePoint & nextExpiredTime)87 InnerEvent::Pointer EventQueue::GetExpiredEvent(InnerEvent::TimePoint &nextExpiredTime)
88 {
89 return InnerEvent::Pointer(nullptr, nullptr);
90 }
91
WaitUntilLocked(const InnerEvent::TimePoint & when,std::unique_lock<std::mutex> & lock,bool vsyncOnly)92 void EventQueue::WaitUntilLocked(const InnerEvent::TimePoint &when, std::unique_lock<std::mutex> &lock, bool vsyncOnly)
93 {
94 // Get a temp reference of IO waiter, otherwise it maybe released while waiting.
95 auto ioWaiterHolder = ioWaiter_;
96 if (!ioWaiterHolder->WaitFor(lock, TimePointToTimeOut(when), vsyncOnly)) {
97 HILOGE("Failed to call wait, reset IO waiter");
98 ioWaiter_ = std::make_shared<NoneIoWaiter>();
99 listeners_.clear();
100 }
101 }
102
CheckFileDescriptorEvent()103 void EventQueue::CheckFileDescriptorEvent()
104 {
105 InnerEvent::TimePoint now = InnerEvent::Clock::now();
106 std::unique_lock<std::mutex> lock(queueLock_);
107 WaitUntilLocked(now, lock);
108 }
109
AddFileDescriptorByFd(int32_t fileDescriptor,uint32_t events,const std::string & taskName,const std::shared_ptr<FileDescriptorListener> & listener,EventQueue::Priority priority)110 bool EventQueue::AddFileDescriptorByFd(int32_t fileDescriptor, uint32_t events, const std::string &taskName,
111 const std::shared_ptr<FileDescriptorListener>& listener, EventQueue::Priority priority)
112 {
113 bool isVsyncListener = listener && listener->IsVsyncListener();
114 bool isDaemonListener = listener && listener->GetIsDeamonWaiter() && MONITOR_FLAG;
115
116 if (isVsyncListener) {
117 priority = Priority::VIP;
118 }
119 if (useDeamonIoWaiter_ || (isDaemonListener && !isVsyncListener)) {
120 return DeamonIoWaiter::GetInstance().AddFileDescriptor(fileDescriptor, events, taskName,
121 listener, priority);
122 }
123 if (ioWaiter_) {
124 auto handler = listener->GetOwner();
125 if (taskName == "vSyncTask" && handler && handler->GetEventRunner() == EventRunner::GetMainEventRunner()) {
126 DeamonIoWaiter::GetInstance().AddFileDescriptor(fileDescriptor, events, taskName, listener, priority);
127 }
128 return ioWaiter_->AddFileDescriptor(fileDescriptor, events, taskName, listener, priority);
129 }
130 return false;
131 }
132
EnsureIoWaiterLocked(const std::shared_ptr<FileDescriptorListener> & listener)133 bool EventQueue::EnsureIoWaiterLocked(const std::shared_ptr<FileDescriptorListener>& listener)
134 {
135 HILOGD("enter");
136 if (useDeamonIoWaiter_ || (listener && listener->GetIsDeamonWaiter() && MONITOR_FLAG)) {
137 if (!DeamonIoWaiter::GetInstance().Init()) {
138 HILOGE("Failed to initialize deamon waiter");
139 return false;
140 }
141 DeamonIoWaiter::GetInstance().StartEpollIoWaiter();
142 }
143
144 if (ioWaiter_->SupportListeningFileDescriptor()) {
145 return true;
146 }
147
148 auto newIoWaiter = std::make_shared<EpollIoWaiter>();
149 if (!newIoWaiter->Init()) {
150 HILOGE("Failed to initialize epoll");
151 return false;
152 }
153
154 // Set callback to handle events from file descriptors.
155 newIoWaiter->SetFileDescriptorEventCallback(
156 std::bind(&EventQueue::HandleFileDescriptorEvent, this, std::placeholders::_1, std::placeholders::_2,
157 std::placeholders::_3, std::placeholders::_4));
158
159 ioWaiter_->NotifyAll();
160 ioWaiter_ = newIoWaiter;
161 return true;
162 }
163
AddFileDescriptorListenerBase(int32_t fileDescriptor,uint32_t events,const std::shared_ptr<FileDescriptorListener> & listener,const std::string & taskName,Priority priority)164 ErrCode EventQueue::AddFileDescriptorListenerBase(int32_t fileDescriptor, uint32_t events,
165 const std::shared_ptr<FileDescriptorListener> &listener, const std::string &taskName, Priority priority)
166 {
167 if (!usable_.load()) {
168 HILOGW("EventQueue is unavailable.");
169 return EVENT_HANDLER_ERR_NO_EVENT_RUNNER;
170 }
171 auto it = listeners_.find(fileDescriptor);
172 if (it != listeners_.end()) {
173 HILOGE("File descriptor %{public}d is already in listening", fileDescriptor);
174 return EVENT_HANDLER_ERR_FD_ALREADY;
175 }
176
177 HILOGD("Add file descriptor %{public}d to io waiter %{public}d", fileDescriptor, useDeamonIoWaiter_);
178 if (!EnsureIoWaiterLocked(listener)) {
179 return EVENT_HANDLER_ERR_FD_NOT_SUPPORT;
180 }
181
182 if (!AddFileDescriptorByFd(fileDescriptor, events, taskName, listener, priority)) {
183 HILOGE("Failed to add file descriptor into IO waiter");
184 return EVENT_HANDLER_ERR_FD_FAILED;
185 }
186
187 listeners_.emplace(fileDescriptor, listener);
188 return ERR_OK;
189 }
190
PostTaskForVsync(const InnerEvent::Callback & cb,const std::string & name,const std::shared_ptr<EventHandler> & handler,EventQueue::Priority priority)191 static void PostTaskForVsync(const InnerEvent::Callback &cb, const std::string &name,
192 const std::shared_ptr<EventHandler> &handler, EventQueue::Priority priority)
193 {
194 auto runner = handler->GetEventRunner();
195 if (!runner) {
196 return;
197 }
198 auto queue = runner->GetEventQueue();
199 if (!queue) {
200 return;
201 }
202 auto event = InnerEvent::Get(cb, name);
203 if (!event) {
204 return;
205 }
206 event->MarkVsyncTask();
207 int64_t delayTime = queue->GetDelayTimeOfVsyncTask();
208 auto task = []() { EventRunner::Current()->GetEventQueue()->SetBarrierMode(true); };
209 handler->PostTask(task, "BarrierEvent", delayTime, priority);
210 if (!handler->SendEvent(event, delayTime, priority)) {
211 handler->RemoveTask("BarrierEvent");
212 queue->SetBarrierMode(false);
213 }
214 }
215
GetListenerByfd(int32_t fileDescriptor)216 std::shared_ptr<FileDescriptorListener> EventQueue::GetListenerByfd(int32_t fileDescriptor)
217 {
218 std::lock_guard<std::mutex> lock(queueLock_);
219 if (!usable_.load()) {
220 HILOGW("EventQueue is unavailable.");
221 return nullptr;
222 }
223 auto it = listeners_.find(fileDescriptor);
224 if (it == listeners_.end()) {
225 HILOGW("Can not found listener, maybe it is removed");
226 return nullptr;
227 }
228 // Hold instance of listener.
229 return it->second;
230 }
231
HandleFileDescriptorEvent(int32_t fileDescriptor,uint32_t events,const std::string & taskName,Priority priority)232 void EventQueue::HandleFileDescriptorEvent(int32_t fileDescriptor, uint32_t events,
233 const std::string &taskName, Priority priority) __attribute__((no_sanitize("cfi")))
234 {
235 std::shared_ptr<FileDescriptorListener> listener = GetListenerByfd(fileDescriptor);
236 if (!listener) {
237 return;
238 }
239
240 auto handler = listener->GetOwner();
241 if (!handler) {
242 HILOGW("Owner of listener is released");
243 return;
244 }
245
246 bool isVsyncTask = handler->GetEventRunner() && listener->IsVsyncListener();
247 std::weak_ptr<FileDescriptorListener> wp = listener;
248 auto f = [fileDescriptor, events, wp, isVsyncTask]() {
249 if (isVsyncTask) {
250 auto queue = EventRunner::Current()->GetEventQueue();
251 queue->HandleVsyncTaskNotify();
252 queue->SetBarrierMode(false);
253 }
254 auto listener = wp.lock();
255 if (!listener) {
256 HILOGW("Listener is released");
257 return;
258 }
259
260 if ((events & FILE_DESCRIPTOR_INPUT_EVENT) != 0) {
261 listener->OnReadable(fileDescriptor);
262 }
263
264 if ((events & FILE_DESCRIPTOR_OUTPUT_EVENT) != 0) {
265 listener->OnWritable(fileDescriptor);
266 }
267
268 if ((events & FILE_DESCRIPTOR_SHUTDOWN_EVENT) != 0) {
269 listener->OnShutdown(fileDescriptor);
270 }
271
272 if ((events & FILE_DESCRIPTOR_EXCEPTION_EVENT) != 0) {
273 listener->OnException(fileDescriptor);
274 }
275 };
276
277 HILOGD("Post fd %{public}d, task %{public}s, priority %{public}d.", fileDescriptor, taskName.c_str(), priority);
278 // Post a high priority task to handle file descriptor events.
279 if (isVsyncTask) {
280 PostTaskForVsync(f, taskName, handler, priority);
281 } else {
282 handler->PostTask(f, taskName, 0, priority);
283 }
284 }
285
RemoveListenerByOwner(const std::shared_ptr<EventHandler> & owner)286 void EventQueue::RemoveListenerByOwner(const std::shared_ptr<EventHandler> &owner)
287 {
288 if (!usable_.load()) {
289 HILOGW("EventQueue is unavailable.");
290 return;
291 }
292 auto listenerFilter = [&owner](const std::shared_ptr<FileDescriptorListener> &listener) {
293 if (!listener) {
294 return false;
295 }
296 return listener->GetOwner() == owner;
297 };
298 RemoveFileDescriptorListenerLocked(listeners_, ioWaiter_, listenerFilter, useDeamonIoWaiter_);
299 }
300
RemoveListenerByFd(int32_t fileDescriptor)301 void EventQueue::RemoveListenerByFd(int32_t fileDescriptor)
302 {
303 if (!usable_.load()) {
304 HILOGW("EventQueue is unavailable.");
305 return;
306 }
307 auto it = listeners_.find(fileDescriptor);
308 std::shared_ptr<FileDescriptorListener> listener;
309 if (it != listeners_.end()) {
310 listener = it->second;
311 }
312 if (listeners_.erase(fileDescriptor) > 0) {
313 std::shared_ptr<FileDescriptorInfo> fdInfo = DeamonIoWaiter::GetInstance().GetFileDescriptorMap(fileDescriptor);
314 if (useDeamonIoWaiter_ || (listener && listener->GetIsDeamonWaiter() && MONITOR_FLAG) ||
315 (fdInfo && fdInfo->taskName_ == "vSyncTask" && listener && listener->GetOwner() &&
316 listener->GetOwner()->GetEventRunner() == EventRunner::GetMainEventRunner())) {
317 DeamonIoWaiter::GetInstance().RemoveFileDescriptor(fileDescriptor);
318 }
319 if (ioWaiter_) {
320 ioWaiter_->RemoveFileDescriptor(fileDescriptor);
321 }
322 }
323 }
324
RemoveInvalidFileDescriptor()325 void EventQueue::RemoveInvalidFileDescriptor()
326 {
327 // Remove all listeners which lost its owner.
328 auto listenerFilter = [](const std::shared_ptr<FileDescriptorListener> &listener) {
329 if (!listener) {
330 return true;
331 }
332 HILOGD("Start get to GetOwner");
333 return !listener->GetOwner();
334 };
335
336 RemoveFileDescriptorListenerLocked(listeners_, ioWaiter_, listenerFilter, useDeamonIoWaiter_);
337 }
338
SetVsyncLazyMode(bool isLazy)339 void EventQueue::SetVsyncLazyMode(bool isLazy)
340 {
341 if (!g_vsyncFirstEnabled) {
342 return;
343 }
344 isLazyMode_.store(isLazy);
345 HILOGD("%{public}s(%{public}d)", __func__, isLazy);
346 }
347
SetVsyncFirst(bool isFirst)348 void EventQueue::SetVsyncFirst(bool isFirst)
349 {
350 HILOGD("%{public}s(%{public}d)", __func__, isFirst);
351 g_vsyncFirstEnabled = isFirst;
352 if (!isFirst) {
353 isLazyMode_.store(true);
354 }
355 }
356
TryEpollFd(const InnerEvent::TimePoint & when,std::unique_lock<std::mutex> & lock)357 void EventQueue::TryEpollFd(const InnerEvent::TimePoint &when, std::unique_lock<std::mutex> &lock)
358 {
359 bool need = needEpoll_;
360
361 WaitUntilLocked(when, lock, !need);
362
363 needEpoll_ = need ? false : needEpoll_;
364
365 if (!sumOfPendingVsync_ && !need) {
366 if (vsyncPeriod_ < MAX_CHECK_VSYNC_PERIOD_NS) {
367 vsyncCheckTime_ += vsyncPeriod_;
368 vsyncPeriod_ <<= 1;
369 } else {
370 vsyncCheckTime_ = INT64_MAX;
371 }
372 }
373 }
374
PrepareBase()375 void EventQueue::PrepareBase()
376 {
377 if (!usable_.load()) {
378 HILOGW("EventQueue is unavailable.");
379 return;
380 }
381 finished_ = false;
382 }
383
FinishBase()384 void EventQueue::FinishBase()
385 {
386 if (!usable_.load()) {
387 HILOGW("EventQueue is unavailable.");
388 return;
389 }
390 finished_ = true;
391 ioWaiter_->NotifyAll();
392 }
393
NotifyObserverVipDone(const InnerEvent::Pointer & event)394 void EventQueue::NotifyObserverVipDone(const InnerEvent::Pointer &event)
395 {
396 HILOGD("eventQueue NotifyObserverVipDone enter.");
397 }
398 } // namespace AppExecFwk
399 } // namespace OHOS