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