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 size_t newPeakUsingCount = 0;
78
79 {
80 // Check whether pool is empty.
81 std::lock_guard<std::mutex> lock(poolLock_);
82 ++usingCount_;
83 if (!events_.empty()) {
84 auto event = std::move(events_.back());
85 events_.pop_back();
86 return InnerEvent::Pointer(event.release(), Drop);
87 }
88
89 // Update peak using events count.
90 if (usingCount_ >= nextPeakUsingCount_) {
91 if (UINT32_MAX - nextPeakUsingCount_ > MAX_BUFFER_POOL_SIZE) {
92 nextPeakUsingCount_ += MAX_BUFFER_POOL_SIZE;
93 } else {
94 nextPeakUsingCount_ = UINT32_MAX;
95 }
96
97 newPeakUsingCount = usingCount_;
98 }
99 }
100
101 // Print the new peak using count of inner events
102 if (newPeakUsingCount > 0) {
103 HILOGD("Peak using count of inner events is up to %{public}zu", newPeakUsingCount);
104 }
105
106 // Allocate new memory, while pool is empty.
107 return InnerEvent::Pointer(new (std::nothrow) InnerEvent, Drop);
108 }
109
110 private:
Drop(InnerEvent * event)111 static void Drop(InnerEvent *event)
112 {
113 if (event == nullptr) {
114 return;
115 }
116
117 auto destructor = [](InnerEvent *event) {
118 if (event != nullptr) {
119 delete event;
120 }
121 };
122
123 // Clear content of the event
124 event->ClearEvent();
125 // Put event into event buffer pool
126 GetInstance().Put(InnerEvent::Pointer(event, destructor));
127 }
128
Put(InnerEvent::Pointer && event)129 void Put(InnerEvent::Pointer &&event)
130 {
131 // Check whether pool is full.
132 std::lock_guard<std::mutex> lock(poolLock_);
133 --usingCount_;
134 if (events_.size() < MAX_BUFFER_POOL_SIZE) {
135 events_.push_back(std::move(event));
136 }
137 }
138
139 static const size_t MAX_BUFFER_POOL_SIZE = 64;
140
141 std::mutex poolLock_;
142 std::vector<InnerEvent::Pointer> events_;
143
144 // Used to statistical peak value of count of using inner events.
145 size_t usingCount_ {0};
146 size_t nextPeakUsingCount_ {MAX_BUFFER_POOL_SIZE};
147 };
148
InnerEventPool()149 InnerEventPool::InnerEventPool() : poolLock_(), events_()
150 {
151 HILOGD("enter");
152 // Reserve enough memory
153 std::lock_guard<std::mutex> lock(poolLock_);
154 events_.reserve(MAX_BUFFER_POOL_SIZE);
155 }
156
~InnerEventPool()157 InnerEventPool::~InnerEventPool()
158 {
159 HILOGD("enter");
160 // Release all memory in the poll
161 std::lock_guard<std::mutex> lock(poolLock_);
162 events_.clear();
163 }
164
Get()165 InnerEvent::Pointer InnerEvent::Get()
166 {
167 auto event = InnerEventPool::GetInstance().Get();
168 return event;
169 }
170
Get(uint32_t innerEventId,int64_t param,const Caller & caller)171 InnerEvent::Pointer InnerEvent::Get(uint32_t innerEventId, int64_t param, const Caller &caller)
172 {
173 auto event = InnerEventPool::GetInstance().Get();
174 if (event != nullptr) {
175 event->innerEventId_ = innerEventId;
176 event->param_ = param;
177 event->caller_ = caller;
178 HILOGD("innerEventId is %{public}u, caller is %{public}s", innerEventId, caller.ToString().c_str());
179 }
180 return event;
181 }
182
Get(const EventId & innerEventId,int64_t param,const Caller & caller)183 InnerEvent::Pointer InnerEvent::Get(const EventId &innerEventId, int64_t param, const Caller &caller)
184 {
185 auto event = InnerEventPool::GetInstance().Get();
186 if (event != nullptr) {
187 event->innerEventId_ = innerEventId;
188 event->param_ = param;
189 event->caller_ = caller;
190 if (innerEventId.index() == TYPE_U32_INDEX) {
191 HILOGD("innerEventId is %{public}u, caller is %{public}s",
192 std::get<uint32_t>(innerEventId),
193 caller.ToString().c_str());
194 } else {
195 HILOGD("innerEventId is %{public}s, caller is %{public}s",
196 std::get<std::string>(innerEventId).c_str(),
197 caller.ToString().c_str());
198 }
199 }
200 return event;
201 }
202
Get(const Callback & callback,const std::string & name,const Caller & caller)203 InnerEvent::Pointer InnerEvent::Get(const Callback &callback, const std::string &name, const Caller &caller)
204 {
205 // Returns nullptr while callback is invalid.
206 if (!callback) {
207 HILOGW("Failed to create inner event with an invalid callback");
208 return InnerEvent::Pointer(nullptr, nullptr);
209 }
210
211 auto event = InnerEventPool::GetInstance().Get();
212 if (event != nullptr) {
213 event->taskCallback_ = callback;
214 event->taskName_ = name;
215 event->caller_ = caller;
216 HILOGD("event taskName is '%{public}s', caller is %{public}s", name.c_str(), caller.ToString().c_str());
217 }
218 return event;
219 }
220
ClearEvent()221 void InnerEvent::ClearEvent()
222 {
223 // Wake up all waiting threads.
224 if (waiter_) {
225 waiter_->Notify();
226 waiter_.reset();
227 }
228
229 if (HasTask()) {
230 // Clear members for task
231 taskCallback_ = nullptr;
232 taskName_.clear();
233 caller_ = {};
234 } else {
235 // Clear members for event
236 if (smartPtrDtor_) {
237 smartPtrDtor_(smartPtr_);
238 smartPtrDtor_ = nullptr;
239 smartPtr_ = nullptr;
240 smartPtrTypeId_ = 0;
241 }
242 }
243
244 if (hiTraceId_) {
245 hiTraceId_.reset();
246 }
247
248 // Clear owner
249 owner_.reset();
250 }
251
WarnSmartPtrCastMismatch()252 void InnerEvent::WarnSmartPtrCastMismatch()
253 {
254 HILOGD("Type of the shared_ptr, weak_ptr or unique_ptr mismatched");
255 }
256
CreateWaiter()257 const std::shared_ptr<InnerEvent::Waiter> &InnerEvent::CreateWaiter()
258 {
259 waiter_ = std::make_shared<WaiterImp>();
260 return waiter_;
261 }
262
HasWaiter() const263 bool InnerEvent::HasWaiter() const
264 {
265 return (waiter_ != nullptr);
266 }
267
GetOrCreateTraceId()268 const std::shared_ptr<HiTraceId> InnerEvent::GetOrCreateTraceId()
269 {
270 if (hiTraceId_) {
271 return hiTraceId_;
272 }
273
274 auto traceId = HiTraceChain::GetId();
275 if (!traceId.IsValid()) {
276 return nullptr;
277 }
278
279 hiTraceId_ = std::make_shared<HiTraceId>(HiTraceChain::CreateSpan());
280 return hiTraceId_;
281 }
282
GetTraceId()283 const std::shared_ptr<HiTraceId> InnerEvent::GetTraceId()
284 {
285 return hiTraceId_;
286 }
287
DumpTimeToString(const std::chrono::system_clock::time_point & time)288 std::string InnerEvent::DumpTimeToString(const std::chrono::system_clock::time_point &time)
289 {
290 auto tp = std::chrono::time_point_cast<std::chrono::milliseconds>(time);
291 auto tt = std::chrono::system_clock::to_time_t(time);
292 auto ms = tp.time_since_epoch().count() % MS_PER_SECOND;
293 auto msString = std::to_string(ms);
294 if (msString.length() < MAX_MS_LENGTH) {
295 msString = std::string(MAX_MS_LENGTH - msString.length(), '0') + msString;
296 }
297 struct tm curTime = {0};
298 localtime_r(&tt, &curTime);
299 char sysTime[DATETIME_STRING_LENGTH];
300 std::strftime(sysTime, sizeof(char) * DATETIME_STRING_LENGTH, "%Y-%m-%d %I:%M:%S.", &curTime);
301 return std::string(sysTime) + msString;
302 }
303
DumpTimeToString(const TimePoint & time)304 std::string InnerEvent::DumpTimeToString(const TimePoint &time)
305 {
306 auto tp = std::chrono::system_clock::now() +
307 std::chrono::duration_cast<std::chrono::milliseconds>(time - std::chrono::steady_clock::now());
308 return DumpTimeToString(tp);
309 }
310
Dump()311 std::string InnerEvent::Dump()
312 {
313 std::string content;
314
315 content.append("Event { ");
316 if (!owner_.expired()) {
317 content.append("send thread = " + std::to_string(senderKernelThreadId_));
318 content.append(", send time = " + DumpTimeToString(sendTime_));
319 content.append(", handle time = " + DumpTimeToString(handleTime_));
320 if (HasTask()) {
321 content.append(", task name = " + taskName_);
322 } else {
323 if (innerEventId_.index() == TYPE_U32_INDEX) {
324 content.append(", id = " + std::to_string(std::get<uint32_t>(innerEventId_)));
325 } else {
326 content.append(", id = " + std::get<std::string>(innerEventId_));
327 }
328 }
329 if (param_ != 0) {
330 content.append(", param = " + std::to_string(param_));
331 }
332 content.append(", caller = " + caller_.ToString());
333 } else {
334 content.append("No handler");
335 }
336 content.append(" }" + std::string(LINE_SEPARATOR));
337
338 return content;
339 }
340
SetEventUniqueId()341 void InnerEvent::SetEventUniqueId()
342 {
343 auto nowTime = std::chrono::duration_cast<std::chrono::nanoseconds>(
344 std::chrono::steady_clock::now().time_since_epoch()).count();
345 eventId = std::to_string(nowTime);
346 }
347
348 } // namespace AppExecFwk
349 } // namespace OHOS
350