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