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