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