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