• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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