• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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