1 /*
2 * Copyright (c) 2021-2022 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_handler.h"
17
18 #include <unistd.h>
19 #include "event_handler_utils.h"
20 #ifdef HAS_HICHECKER_NATIVE_PART
21 #include "hichecker.h"
22 #endif // HAS_HICHECKER_NATIVE_PART
23 #include "thread_local_data.h"
24
25 #ifdef _WIN32
26 #include <windows.h>
27 #define gettid GetCurrentThreadId
28 #define localtime_r(tm, time) localtime_s(time, tm)
29 #endif
30
31 #ifdef __APPLE__
32 #define gettid getpid
33 #endif
34
35 #ifdef __gnu_linux__
36 #include <sys/types.h>
37 #include <sys/syscall.h>
38 #define gettid []() -> int32_t { return static_cast<int32_t>(syscall(SYS_gettid)); }
39 #endif
40
41 DEFINE_HILOG_LABEL("EventHandler");
42
43 using namespace OHOS::HiviewDFX;
44 namespace OHOS {
45 namespace AppExecFwk {
46 static constexpr int DATETIME_STRING_LENGTH = 80;
47
48 thread_local std::weak_ptr<EventHandler> EventHandler::currentEventHandler;
49
Current()50 std::shared_ptr<EventHandler> EventHandler::Current()
51 {
52 return currentEventHandler.lock();
53 }
54
EventHandler(const std::shared_ptr<EventRunner> & runner)55 EventHandler::EventHandler(const std::shared_ptr<EventRunner> &runner) : eventRunner_(runner)
56 {}
57
~EventHandler()58 EventHandler::~EventHandler()
59 {
60 if (eventRunner_ && eventRunner_->GetEventQueue()) {
61 /*
62 * This handler is finishing, need to remove all events belong to it.
63 * But events only have weak pointer of this handler,
64 * now weak pointer is invalid, so these events become orphans.
65 */
66 eventRunner_->GetEventQueue()->RemoveOrphan();
67 }
68 }
69
SendEvent(InnerEvent::Pointer & event,int64_t delayTime,Priority priority)70 bool EventHandler::SendEvent(InnerEvent::Pointer &event, int64_t delayTime, Priority priority)
71 {
72 if (!event) {
73 HILOGE("SendEvent: Could not send an invalid event");
74 return false;
75 }
76
77 if (!eventRunner_ || !eventRunner_->GetEventQueue()) {
78 HILOGE("SendEvent: MUST Set event runner before sending events");
79 return false;
80 }
81
82 InnerEvent::TimePoint now = InnerEvent::Clock::now();
83 event->SetSendTime(now);
84
85 if (delayTime > 0) {
86 event->SetHandleTime(now + std::chrono::milliseconds(delayTime));
87 } else {
88 event->SetHandleTime(now);
89 }
90
91 event->SetOwner(shared_from_this());
92
93 eventRunner_->GetEventQueue()->Insert(event, priority);
94 return true;
95 }
96
SendTimingEvent(InnerEvent::Pointer & event,int64_t taskTime,Priority priority)97 bool EventHandler::SendTimingEvent(InnerEvent::Pointer &event, int64_t taskTime, Priority priority)
98 {
99 InnerEvent::TimePoint nowSys = InnerEvent::Clock::now();
100 auto epoch = nowSys.time_since_epoch();
101 long nowSysTime = std::chrono::duration_cast<std::chrono::milliseconds>(epoch).count();
102 int64_t delayTime = taskTime - nowSysTime;
103 if (delayTime < 0) {
104 HILOGE("SendTimingEvent: SendTime is before now systime, change to 0 delaytime Event");
105 return SendEvent(event, 0, priority);
106 }
107
108 return SendEvent(event, delayTime, priority);
109 }
110
SendSyncEvent(InnerEvent::Pointer & event,Priority priority)111 bool EventHandler::SendSyncEvent(InnerEvent::Pointer &event, Priority priority)
112 {
113 if ((!event) || (priority == Priority::IDLE)) {
114 HILOGE("SendSyncEvent: Could not send an invalid event or idle event");
115 return false;
116 }
117
118 if ((!eventRunner_) || (!eventRunner_->IsRunning())) {
119 HILOGE("SendSyncEvent: MUST Set a running event runner before sending sync events");
120 return false;
121 }
122
123 // If send a sync event in same event runner, distribute here.
124 if (eventRunner_ == EventRunner::Current()) {
125 DistributeEvent(event);
126 return true;
127 }
128
129 // Create waiter, used to block.
130 auto waiter = event->CreateWaiter();
131 // Send this event as normal one.
132 if (!SendEvent(event, 0, priority)) {
133 return false;
134 }
135 // Wait until event is processed(recycled).
136 if (!waiter) {
137 return false;
138 }
139 waiter->Wait();
140
141 return true;
142 }
143
RemoveAllEvents()144 void EventHandler::RemoveAllEvents()
145 {
146 if (!eventRunner_ || !eventRunner_->GetEventQueue()) {
147 HILOGE("RemoveAllEvents: MUST Set event runner before removing all events");
148 return;
149 }
150
151 eventRunner_->GetEventQueue()->Remove(shared_from_this());
152 }
153
RemoveEvent(uint32_t innerEventId)154 void EventHandler::RemoveEvent(uint32_t innerEventId)
155 {
156 if (!eventRunner_ || !eventRunner_->GetEventQueue()) {
157 HILOGE("RemoveEvent: MUST Set event runner before removing events by id");
158 return;
159 }
160
161 eventRunner_->GetEventQueue()->Remove(shared_from_this(), innerEventId);
162 }
163
RemoveEvent(uint32_t innerEventId,int64_t param)164 void EventHandler::RemoveEvent(uint32_t innerEventId, int64_t param)
165 {
166 if (!eventRunner_ || !eventRunner_->GetEventQueue()) {
167 HILOGE("RemoveEvent: MUST Set event runner before removing events by id and param");
168 return;
169 }
170
171 eventRunner_->GetEventQueue()->Remove(shared_from_this(), innerEventId, param);
172 }
173
RemoveTask(const std::string & name)174 void EventHandler::RemoveTask(const std::string &name)
175 {
176 if (!eventRunner_ || !eventRunner_->GetEventQueue()) {
177 HILOGE("RemoveTask: MUST Set event runner before removing events by task name");
178 return;
179 }
180
181 eventRunner_->GetEventQueue()->Remove(shared_from_this(), name);
182 }
183
AddFileDescriptorListener(int32_t fileDescriptor,uint32_t events,const std::shared_ptr<FileDescriptorListener> & listener)184 ErrCode EventHandler::AddFileDescriptorListener(
185 int32_t fileDescriptor, uint32_t events, const std::shared_ptr<FileDescriptorListener> &listener)
186 {
187 if ((fileDescriptor < 0) || ((events & FILE_DESCRIPTOR_EVENTS_MASK) == 0) || (!listener)) {
188 HILOGE("AddFileDescriptorListener(%{public}d, %{public}u, %{public}s): Invalid parameter",
189 fileDescriptor,
190 events,
191 listener ? "valid" : "null");
192 return EVENT_HANDLER_ERR_INVALID_PARAM;
193 }
194
195 if (!eventRunner_ || !eventRunner_->GetEventQueue()) {
196 HILOGE("AddFileDescriptorListener: MUST Set event runner before adding fd listener");
197 return EVENT_HANDLER_ERR_NO_EVENT_RUNNER;
198 }
199
200 listener->SetOwner(shared_from_this());
201 return eventRunner_->GetEventQueue()->AddFileDescriptorListener(fileDescriptor, events, listener);
202 }
203
RemoveAllFileDescriptorListeners()204 void EventHandler::RemoveAllFileDescriptorListeners()
205 {
206 if (!eventRunner_ || !eventRunner_->GetEventQueue()) {
207 HILOGE("RemoveAllFileDescriptorListeners: MUST Set event runner before removing all fd listener");
208 return;
209 }
210
211 eventRunner_->GetEventQueue()->RemoveFileDescriptorListener(shared_from_this());
212 }
213
RemoveFileDescriptorListener(int32_t fileDescriptor)214 void EventHandler::RemoveFileDescriptorListener(int32_t fileDescriptor)
215 {
216 if (fileDescriptor < 0) {
217 HILOGE("RemoveFileDescriptorListener(%{public}d): Invalid parameter", fileDescriptor);
218 return;
219 }
220
221 if (!eventRunner_ || !eventRunner_->GetEventQueue()) {
222 HILOGE("RemoveFileDescriptorListener: MUST Set event runner before removing fd listener by fd");
223 return;
224 }
225
226 eventRunner_->GetEventQueue()->RemoveFileDescriptorListener(fileDescriptor);
227 }
228
SetEventRunner(const std::shared_ptr<EventRunner> & runner)229 void EventHandler::SetEventRunner(const std::shared_ptr<EventRunner> &runner)
230 {
231 if (eventRunner_ == runner) {
232 return;
233 }
234
235 if (eventRunner_) {
236 HILOGW("SetEventRunner: It is not recommended to change the event runner dynamically");
237
238 // Remove all events and listeners from old event runner.
239 RemoveAllEvents();
240 RemoveAllFileDescriptorListeners();
241 }
242
243 // Switch event runner.
244 eventRunner_ = runner;
245 return;
246 }
247
DeliveryTimeAction(const InnerEvent::Pointer & event,InnerEvent::TimePoint nowStart)248 void EventHandler::DeliveryTimeAction(const InnerEvent::Pointer &event, InnerEvent::TimePoint nowStart)
249 {
250 #ifdef HAS_HICHECKER_NATIVE_PART
251 if (!HiChecker::NeedCheckSlowEvent()) {
252 return;
253 }
254 if (!eventRunner_ || !event) {
255 return;
256 }
257 int64_t deliveryTimeout = eventRunner_->GetDeliveryTimeout();
258 if (deliveryTimeout > 0) {
259 std::string threadName = eventRunner_->GetRunnerThreadName();
260 std::string eventName = GetEventName(event);
261 int64_t threadId = gettid();
262 std::string threadIdCharacter = std::to_string(threadId);
263 std::chrono::duration<double> deliveryTime = nowStart - event->GetSendTime();
264 std::string deliveryTimeCharacter = std::to_string((deliveryTime).count());
265 std::string deliveryTimeoutCharacter = std::to_string(deliveryTimeout);
266 std::string handOutTag = "threadId: " + threadIdCharacter + "," + "threadName: " + threadName + "," +
267 "eventName: " + eventName + "," + "deliveryTime: " + deliveryTimeCharacter + "," +
268 "deliveryTimeout: " + deliveryTimeoutCharacter;
269 if ((nowStart - std::chrono::milliseconds(deliveryTimeout)) > event->GetHandleTime()) {
270 HiChecker::NotifySlowEvent(handOutTag);
271 if (deliveryTimeoutCallback_) {
272 deliveryTimeoutCallback_();
273 }
274 }
275 }
276 #endif // HAS_HICHECKER_NATIVE_PART
277 }
278
DistributeTimeAction(const InnerEvent::Pointer & event,InnerEvent::TimePoint nowStart)279 void EventHandler::DistributeTimeAction(const InnerEvent::Pointer &event, InnerEvent::TimePoint nowStart)
280 {
281 #ifdef HAS_HICHECKER_NATIVE_PART
282 if (!HiChecker::NeedCheckSlowEvent()) {
283 return;
284 }
285 if (!eventRunner_ || !event) {
286 return;
287 }
288 int64_t distributeTimeout = eventRunner_->GetDistributeTimeout();
289 if (distributeTimeout > 0) {
290 std::string threadName = eventRunner_->GetRunnerThreadName();
291 std::string eventName = GetEventName(event);
292 int64_t threadId = gettid();
293 std::string threadIdCharacter = std::to_string(threadId);
294 InnerEvent::TimePoint nowEnd = InnerEvent::Clock::now();
295 std::chrono::duration<double> distributeTime = nowEnd - nowStart;
296 std::string distributeTimeCharacter = std::to_string((distributeTime).count());
297 std::string distributeTimeoutCharacter = std::to_string(distributeTimeout);
298 std::string executeTag = "threadId: " + threadIdCharacter + "," + "threadName: " + threadName + "," +
299 "eventName: " + eventName + "," + "distributeTime: " + distributeTimeCharacter + "," +
300 "distributeTimeout: " + distributeTimeoutCharacter;
301 if ((nowEnd - std::chrono::milliseconds(distributeTimeout)) > nowStart) {
302 HiChecker::NotifySlowEvent(executeTag);
303 if (distributeTimeoutCallback_) {
304 distributeTimeoutCallback_();
305 }
306 }
307 }
308 #endif // HAS_HICHECKER_NATIVE_PART
309 }
310
DistributeEvent(const InnerEvent::Pointer & event)311 void EventHandler::DistributeEvent(const InnerEvent::Pointer &event)
312 {
313 if (!event) {
314 HILOGE("DistributeEvent: Could not distribute an invalid event");
315 return;
316 }
317
318 currentEventHandler = shared_from_this();
319
320 InnerEvent::TimePoint nowStart = InnerEvent::Clock::now();
321 DeliveryTimeAction(event, nowStart);
322
323 if (event->HasTask()) {
324 // Call task callback directly if contains a task.
325 (event->GetTaskCallback())();
326 } else {
327 // Otherwise let developers to handle it.
328 ProcessEvent(event);
329 }
330
331 DistributeTimeAction(event, nowStart);
332 }
333
Dump(Dumper & dumper)334 void EventHandler::Dump(Dumper &dumper)
335 {
336 auto now = std::chrono::system_clock::now();
337 auto tp = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
338 auto tt = std::chrono::system_clock::to_time_t(now);
339 auto us = tp.time_since_epoch().count() % 1000;
340 struct tm curTime = {0};
341 localtime_r(&tt, &curTime);
342 char sysTime[DATETIME_STRING_LENGTH];
343 std::strftime(sysTime, sizeof(char) * DATETIME_STRING_LENGTH, "%Y%m%d %I:%M:%S.", &curTime);
344 auto message = dumper.GetTag() + " EventHandler dump begain curTime:" +
345 std::string(sysTime) + std::to_string(us) + LINE_SEPARATOR;
346 dumper.Dump(message);
347
348 if (eventRunner_ == nullptr) {
349 dumper.Dump(dumper.GetTag() + " event runner uninitialized!" + LINE_SEPARATOR);
350 } else {
351 eventRunner_->Dump(dumper);
352 }
353 }
354
HasInnerEvent(uint32_t innerEventId)355 bool EventHandler::HasInnerEvent(uint32_t innerEventId)
356 {
357 if (!eventRunner_ || !eventRunner_->GetEventQueue()) {
358 HILOGE("event runner uninitialized!");
359 return false;
360 }
361 return eventRunner_->GetEventQueue()->HasInnerEvent(shared_from_this(), innerEventId);
362 }
363
HasInnerEvent(int64_t param)364 bool EventHandler::HasInnerEvent(int64_t param)
365 {
366 if (!eventRunner_ || !eventRunner_->GetEventQueue()) {
367 HILOGE("event runner uninitialized!");
368 return false;
369 }
370 return eventRunner_->GetEventQueue()->HasInnerEvent(shared_from_this(), param);
371 }
372
GetEventName(const InnerEvent::Pointer & event)373 std::string EventHandler::GetEventName(const InnerEvent::Pointer &event)
374 {
375 std::string eventName;
376 if (!event) {
377 return eventName;
378 }
379
380 if (event->HasTask()) {
381 eventName = event->GetTaskName();
382 } else {
383 eventName = std::to_string(event->GetInnerEventId());
384 }
385 return eventName;
386 }
387
IsIdle()388 bool EventHandler::IsIdle()
389 {
390 if (!eventRunner_ || !eventRunner_->GetEventQueue()) {
391 return false;
392 }
393 return eventRunner_->GetEventQueue()->IsIdle();
394 }
395
ProcessEvent(const InnerEvent::Pointer &)396 void EventHandler::ProcessEvent(const InnerEvent::Pointer &)
397 {}
398 } // namespace AppExecFwk
399 } // namespace OHOS
400