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