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