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 "inner_event.h"
17 
18 #include <chrono>
19 #include <condition_variable>
20 #include <mutex>
21 #include <vector>
22 
23 #include "event_handler_utils.h"
24 #include "event_logger.h"
25 #include "singleton.h"
26 
27 namespace OHOS {
28 namespace AppExecFwk {
29 namespace {
30 static constexpr int DATETIME_STRING_LENGTH = 80;
31 static constexpr int MAX_MS_LENGTH = 3;
32 static constexpr int MS_PER_SECOND = 1000;
33 DEFINE_EH_HILOG_LABEL("InnerEvent");
34 
35 class WaiterImp final : public InnerEvent::Waiter {
36 public:
WaiterImp()37     WaiterImp(){};
~WaiterImp()38     ~WaiterImp() override{};
39     DISALLOW_COPY_AND_MOVE(WaiterImp);
40 
Wait()41     void Wait() final
42     {
43         std::unique_lock<std::mutex> lock(mutex_);
44         while (!finished_) {
45             ++waitingCount_;
46             condition_.wait(lock);
47             --waitingCount_;
48         }
49     }
50 
Notify()51     void Notify() final
52     {
53         std::lock_guard<std::mutex> lock(mutex_);
54         finished_ = true;
55         if (waitingCount_ > 0) {
56             condition_.notify_all();
57         }
58     }
59 
60 private:
61     std::mutex mutex_;
62     std::condition_variable condition_;
63     uint32_t waitingCount_ {0};
64     bool finished_ {false};
65 };
66 }  // unnamed namespace
67 
68 // Implementation for event pool.
69 class InnerEventPool : public DelayedRefSingleton<InnerEventPool> {
70     DECLARE_DELAYED_REF_SINGLETON(InnerEventPool);
71 
72 public:
73     DISALLOW_COPY_AND_MOVE(InnerEventPool);
74 
Get()75     InnerEvent::Pointer Get()
76     {
77         // Allocate new memory, while pool is empty.
78         return InnerEvent::Pointer(new (std::nothrow) InnerEvent, Drop);
79     }
80 
81 private:
Drop(InnerEvent * event)82     static void Drop(InnerEvent *event)
83     {
84         if (event == nullptr) {
85             return;
86         }
87 
88         // Clear content of the event
89         event->ClearEvent();
90         if (event != nullptr) {
91             delete event;
92         }
93     }
94 };
95 
InnerEventPool()96 InnerEventPool::InnerEventPool()
97 {
98     HILOGD("InnerEventPool enter");
99 }
100 
~InnerEventPool()101 InnerEventPool::~InnerEventPool()
102 {
103     HILOGD("~InnerEventPool enter");
104 }
105 
Get()106 InnerEvent::Pointer InnerEvent::Get()
107 {
108     auto event = InnerEventPool::GetInstance().Get();
109     return event;
110 }
111 
Get(uint32_t innerEventId,int64_t param,const Caller & caller)112 InnerEvent::Pointer InnerEvent::Get(uint32_t innerEventId, int64_t param, const Caller &caller)
113 {
114     auto event = InnerEventPool::GetInstance().Get();
115     if (event != nullptr) {
116         event->innerEventId_ = innerEventId;
117         event->param_ = param;
118         event->caller_ = caller;
119         HILOGD("innerEventId is %{public}u, caller is %{public}s", innerEventId, caller.ToString().c_str());
120     }
121     return event;
122 }
123 
Get(const EventId & innerEventId,int64_t param,const Caller & caller)124 InnerEvent::Pointer InnerEvent::Get(const EventId &innerEventId, int64_t param, const Caller &caller)
125 {
126     auto event = InnerEventPool::GetInstance().Get();
127     if (event != nullptr) {
128         event->innerEventId_ = innerEventId;
129         event->param_ = param;
130         event->caller_ = caller;
131         if (innerEventId.index() == TYPE_U32_INDEX) {
132             HILOGD("innerEventId is %{public}u, caller is %{public}s",
133                 std::get<uint32_t>(innerEventId),
134                 caller.ToString().c_str());
135         } else {
136             HILOGD("innerEventId is %{public}s, caller is %{public}s",
137                 std::get<std::string>(innerEventId).c_str(),
138                 caller.ToString().c_str());
139         }
140     }
141     return event;
142 }
143 
Get(const Callback & callback,const std::string & name,const Caller & caller)144 InnerEvent::Pointer InnerEvent::Get(const Callback &callback, const std::string &name, const Caller &caller)
145 {
146     // Returns nullptr while callback is invalid.
147     if (!callback) {
148         HILOGW("Failed to create inner event with an invalid callback");
149         return InnerEvent::Pointer(nullptr, nullptr);
150     }
151 
152     auto event = InnerEventPool::GetInstance().Get();
153     if (event != nullptr) {
154         event->taskCallback_ = callback;
155         event->taskName_ = name;
156         event->caller_ = caller;
157         HILOGD("event taskName is '%{public}s', caller is %{public}s", name.c_str(), caller.ToString().c_str());
158     }
159     return event;
160 }
161 
ClearEvent()162 void InnerEvent::ClearEvent()
163 {
164     // Wake up all waiting threads.
165     if (waiter_) {
166         waiter_->Notify();
167         waiter_.reset();
168     }
169 
170     if (HasTask()) {
171         // Clear members for task
172         taskName_.clear();
173         caller_.ClearCaller();
174     } else {
175         // Clear members for event
176         if (smartPtrDtor_) {
177             smartPtrDtor_(smartPtr_);
178             smartPtrDtor_ = nullptr;
179             smartPtr_ = nullptr;
180             smartPtrTypeId_ = 0;
181         }
182     }
183 
184     if (hiTraceId_) {
185         hiTraceId_.reset();
186     }
187 
188     // Clear owner
189     owner_.reset();
190 }
191 
WarnSmartPtrCastMismatch()192 void InnerEvent::WarnSmartPtrCastMismatch()
193 {
194     HILOGD("Type of the shared_ptr, weak_ptr or unique_ptr mismatched");
195 }
196 
CreateWaiter()197 const std::shared_ptr<InnerEvent::Waiter> &InnerEvent::CreateWaiter()
198 {
199     waiter_ = std::make_shared<WaiterImp>();
200     return waiter_;
201 }
202 
HasWaiter() const203 bool InnerEvent::HasWaiter() const
204 {
205     return (waiter_ != nullptr);
206 }
207 
GetOrCreateTraceId()208 const std::shared_ptr<HiTraceId> InnerEvent::GetOrCreateTraceId()
209 {
210     if (hiTraceId_) {
211         return hiTraceId_;
212     }
213 
214     auto traceId = HiTraceChain::GetId();
215     if (!traceId.IsValid()) {
216         return nullptr;
217     }
218 
219     hiTraceId_ = std::make_shared<HiTraceId>(HiTraceChain::CreateSpan());
220     return hiTraceId_;
221 }
222 
GetTraceId()223 const std::shared_ptr<HiTraceId> InnerEvent::GetTraceId()
224 {
225     return hiTraceId_;
226 }
227 
DumpTimeToString(const std::chrono::system_clock::time_point & time)228 std::string InnerEvent::DumpTimeToString(const std::chrono::system_clock::time_point &time)
229 {
230     auto tp = std::chrono::time_point_cast<std::chrono::milliseconds>(time);
231     auto tt = std::chrono::system_clock::to_time_t(time);
232     auto ms = tp.time_since_epoch().count() % MS_PER_SECOND;
233     auto msString = std::to_string(ms);
234     if (msString.length() < MAX_MS_LENGTH) {
235         msString = std::string(MAX_MS_LENGTH - msString.length(), '0') + msString;
236     }
237     struct tm curTime = {0};
238     localtime_r(&tt, &curTime);
239     char sysTime[DATETIME_STRING_LENGTH];
240     std::strftime(sysTime, sizeof(char) * DATETIME_STRING_LENGTH, "%Y-%m-%d %I:%M:%S.", &curTime);
241     return std::string(sysTime) + msString;
242 }
243 
DumpTimeToString(const TimePoint & time)244 std::string InnerEvent::DumpTimeToString(const TimePoint &time)
245 {
246     auto tp = std::chrono::system_clock::now() +
247         std::chrono::duration_cast<std::chrono::milliseconds>(time - std::chrono::steady_clock::now());
248     return DumpTimeToString(tp);
249 }
250 
Dump()251 std::string InnerEvent::Dump()
252 {
253     std::string content;
254 
255     content.append("Event { ");
256     if (!owner_.expired()) {
257         content.append("send thread = " + std::to_string(senderKernelThreadId_));
258         content.append(", send time = " + DumpTimeToString(sendTime_));
259         content.append(", handle time = " + DumpTimeToString(handleTime_));
260         if (HasTask()) {
261             content.append(", task name = " + taskName_);
262         } else {
263             if (innerEventId_.index() == TYPE_U32_INDEX) {
264                 content.append(", id = " + std::to_string(std::get<uint32_t>(innerEventId_)));
265             } else {
266                 content.append(", id = " + std::get<std::string>(innerEventId_));
267             }
268         }
269         if (param_ != 0) {
270             content.append(", param = " + std::to_string(param_));
271         }
272         content.append(", caller = " + caller_.ToString());
273     } else {
274         content.append("No handler");
275     }
276     content.append(" }" + std::string(LINE_SEPARATOR));
277 
278     return content;
279 }
280 
TraceInfo()281 std::string InnerEvent::TraceInfo()
282 {
283     std::string content;
284 
285     content.append("Et:");
286     if (!owner_.expired()) {
287         content.append(std::to_string(senderKernelThreadId_));
288         content.append("," + std::to_string(sendTime_.time_since_epoch().count()));
289         content.append("," + std::to_string(handleTime_.time_since_epoch().count()));
290         if (HasTask()) {
291             content.append("," + taskName_);
292         } else {
293             if (innerEventId_.index() == TYPE_U32_INDEX) {
294                 content.append("," + std::to_string(std::get<uint32_t>(innerEventId_)));
295             } else {
296                 content.append("," + std::get<std::string>(innerEventId_));
297             }
298         }
299         content.append("," + std::to_string(priority));
300         content.append("," + caller_.ToString());
301     } else {
302         content.append("NA");
303     }
304 
305     return content;
306 }
307 
SetEventUniqueId()308 void InnerEvent::SetEventUniqueId()
309 {
310     auto nowTime = std::chrono::duration_cast<std::chrono::nanoseconds>(
311         std::chrono::steady_clock::now().time_since_epoch()).count();
312     eventId = std::to_string(nowTime);
313 }
314 
315 }  // namespace AppExecFwk
316 }  // namespace OHOS
317