1 /*
2 * Copyright (c) 2022-2024 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 #include "napi_app_event_watcher.h"
16
17 #include "app_event_store.h"
18 #include "ffrt.h"
19 #include "hiappevent_base.h"
20 #include "hilog/log.h"
21 #include "napi_util.h"
22 #include "uv.h"
23
24 #undef LOG_DOMAIN
25 #define LOG_DOMAIN 0xD002D07
26
27 #undef LOG_TAG
28 #define LOG_TAG "NapiWatcher"
29
30 namespace OHOS {
31 namespace HiviewDFX {
32 namespace {
33 constexpr size_t CALLBACK_PARAM_NUM = 3;
34 constexpr size_t RECEIVE_PARAM_NUM = 2;
35
SafeDeleteWork(uv_work_t * work)36 void SafeDeleteWork(uv_work_t* work)
37 {
38 if (work != nullptr) {
39 delete work;
40 }
41 }
42
DeleteEventMappingAsync(int64_t observerSeq,const std::vector<std::shared_ptr<AppEventPack>> & events)43 void DeleteEventMappingAsync(int64_t observerSeq, const std::vector<std::shared_ptr<AppEventPack>>& events)
44 {
45 std::vector<int64_t> eventSeqs;
46 for (const auto& event : events) {
47 eventSeqs.emplace_back(event->GetSeq());
48 }
49 ffrt::submit([observerSeq, eventSeqs]() {
50 if (!AppEventStore::GetInstance().DeleteData(observerSeq, eventSeqs)) {
51 HILOG_ERROR(LOG_CORE, "failed to delete mapping data, seq=%{public}" PRId64 ", event num=%{public}zu",
52 observerSeq, eventSeqs.size());
53 }
54 }, {}, {}, ffrt::task_attr().name("appevent_del_map"));
55 }
56
OnTriggerWork(uv_work_t * work,int status)57 void OnTriggerWork(uv_work_t* work, int status)
58 {
59 auto context = static_cast<OnTriggerContext*>(work->data);
60 napi_handle_scope scope = nullptr;
61 napi_open_handle_scope(context->env, &scope);
62 if (scope == nullptr) {
63 HILOG_ERROR(LOG_CORE, "failed to open handle scope");
64 SafeDeleteWork(work);
65 return;
66 }
67 napi_value callback = NapiUtil::GetReferenceValue(context->env, context->onTrigger);
68 if (callback == nullptr) {
69 HILOG_ERROR(LOG_CORE, "failed to get callback from the context");
70 SafeDeleteWork(work);
71 napi_close_handle_scope(context->env, scope);
72 return;
73 }
74 napi_value argv[CALLBACK_PARAM_NUM] = {
75 NapiUtil::CreateInt32(context->env, context->row),
76 NapiUtil::CreateInt32(context->env, context->size),
77 NapiUtil::GetReferenceValue(context->env, context->holder)
78 };
79 napi_value ret = nullptr;
80 if (napi_call_function(context->env, nullptr, callback, CALLBACK_PARAM_NUM, argv, &ret) != napi_ok) {
81 HILOG_ERROR(LOG_CORE, "failed to call onTrigger function");
82 }
83 napi_close_handle_scope(context->env, scope);
84 SafeDeleteWork(work);
85 }
86
OnReceiveWork(uv_work_t * work,int status)87 void OnReceiveWork(uv_work_t* work, int status)
88 {
89 auto context = static_cast<OnReceiveContext*>(work->data);
90 napi_handle_scope scope = nullptr;
91 napi_open_handle_scope(context->env, &scope);
92 if (scope == nullptr) {
93 HILOG_ERROR(LOG_CORE, "failed to open handle scope");
94 SafeDeleteWork(work);
95 return;
96 }
97 napi_value callback = NapiUtil::GetReferenceValue(context->env, context->onReceive);
98 if (callback == nullptr) {
99 HILOG_ERROR(LOG_CORE, "failed to get callback from the context");
100 SafeDeleteWork(work);
101 napi_close_handle_scope(context->env, scope);
102 return;
103 }
104 napi_value argv[RECEIVE_PARAM_NUM] = {
105 NapiUtil::CreateString(context->env, context->domain),
106 NapiUtil::CreateEventGroups(context->env, context->events)
107 };
108 napi_value ret = nullptr;
109 if (napi_call_function(context->env, nullptr, callback, RECEIVE_PARAM_NUM, argv, &ret) == napi_ok) {
110 DeleteEventMappingAsync(context->observerSeq, context->events);
111 } else {
112 HILOG_ERROR(LOG_CORE, "failed to call onReceive function");
113 }
114 napi_close_handle_scope(context->env, scope);
115 SafeDeleteWork(work);
116 }
117 }
~OnTriggerContext()118 OnTriggerContext::~OnTriggerContext()
119 {
120 if (onTrigger != nullptr) {
121 napi_delete_reference(env, onTrigger);
122 }
123 if (holder != nullptr) {
124 napi_delete_reference(env, holder);
125 }
126 }
127
~OnReceiveContext()128 OnReceiveContext::~OnReceiveContext()
129 {
130 if (onReceive != nullptr) {
131 napi_delete_reference(env, onReceive);
132 }
133 }
134
~WatcherContext()135 WatcherContext::~WatcherContext()
136 {
137 if (triggerContext != nullptr) {
138 delete triggerContext;
139 }
140 if (receiveContext != nullptr) {
141 delete receiveContext;
142 }
143 }
144
NapiAppEventWatcher(const std::string & name,const std::vector<AppEventFilter> & filters,TriggerCondition cond)145 NapiAppEventWatcher::NapiAppEventWatcher(
146 const std::string& name,
147 const std::vector<AppEventFilter>& filters,
148 TriggerCondition cond)
149 : AppEventWatcher(name, filters, cond), context_(nullptr)
150 {}
151
~NapiAppEventWatcher()152 NapiAppEventWatcher::~NapiAppEventWatcher()
153 {
154 HILOG_DEBUG(LOG_CORE, "start to destroy NapiAppEventWatcher object");
155 if (context_ == nullptr) {
156 return;
157 }
158 napi_env env = nullptr;
159 if (context_->receiveContext != nullptr) {
160 env = context_->receiveContext->env;
161 } else if (context_->triggerContext != nullptr) {
162 env = context_->triggerContext->env;
163 } else {
164 delete context_;
165 return;
166 }
167 uv_loop_t* loop = nullptr;
168 if (napi_get_uv_event_loop(env, &loop) != napi_ok || loop == nullptr) {
169 HILOG_ERROR(LOG_CORE, "failed to get loop.");
170 delete context_;
171 return;
172 }
173 uv_work_t* work = new(std::nothrow) uv_work_t();
174 if (work == nullptr) {
175 HILOG_ERROR(LOG_CORE, "failed to get work.");
176 delete context_;
177 return;
178 }
179 work->data = static_cast<void*>(context_);
180 uv_queue_work_with_qos(
181 loop,
182 work,
183 [] (uv_work_t* work) {
184 HILOG_DEBUG(LOG_CORE, "enter uv work callback.");
185 },
186 [] (uv_work_t* work, int status) {
187 WatcherContext* context = static_cast<WatcherContext*>(work->data);
188 HILOG_DEBUG(LOG_CORE, "start to destroy WatcherContext object");
189 delete context;
190 SafeDeleteWork(work);
191 },
192 uv_qos_default);
193 }
194
InitHolder(const napi_env env,const napi_value holder)195 void NapiAppEventWatcher::InitHolder(const napi_env env, const napi_value holder)
196 {
197 if (context_ == nullptr) {
198 context_ = new(std::nothrow) WatcherContext();
199 if (context_ == nullptr) {
200 return;
201 }
202 }
203 if (context_->triggerContext == nullptr) {
204 context_->triggerContext = new(std::nothrow) OnTriggerContext();
205 if (context_->triggerContext == nullptr) {
206 return;
207 }
208 }
209 context_->triggerContext->env = env;
210 context_->triggerContext->holder = NapiUtil::CreateReference(env, holder);
211 }
212
OnTrigger(const TriggerCondition & triggerCond)213 void NapiAppEventWatcher::OnTrigger(const TriggerCondition& triggerCond)
214 {
215 HILOG_DEBUG(LOG_CORE, "onTrigger start");
216 if (context_ == nullptr || context_->triggerContext == nullptr) {
217 HILOG_ERROR(LOG_CORE, "onTrigger context is null");
218 return;
219 }
220 context_->triggerContext->row = triggerCond.row;
221 context_->triggerContext->size = triggerCond.size;
222
223 uv_loop_t* loop = nullptr;
224 if (napi_get_uv_event_loop(context_->triggerContext->env, &loop) != napi_ok || loop == nullptr) {
225 HILOG_ERROR(LOG_CORE, "failed to get loop.");
226 return;
227 }
228 uv_work_t* work = new(std::nothrow) uv_work_t();
229 if (work == nullptr) {
230 return;
231 }
232 work->data = static_cast<void*>(context_->triggerContext);
233 uv_queue_work_with_qos(loop, work, [] (uv_work_t* work) { HILOG_DEBUG(LOG_CORE, "enter uv work callback."); },
234 OnTriggerWork, uv_qos_default);
235 }
236
InitTrigger(const napi_env env,const napi_value triggerFunc)237 void NapiAppEventWatcher::InitTrigger(const napi_env env, const napi_value triggerFunc)
238 {
239 HILOG_DEBUG(LOG_CORE, "start to init OnTrigger");
240 if (context_ == nullptr) {
241 context_ = new(std::nothrow) WatcherContext();
242 if (context_ == nullptr) {
243 return;
244 }
245 }
246 if (context_->triggerContext == nullptr) {
247 context_->triggerContext = new(std::nothrow) OnTriggerContext();
248 if (context_->triggerContext == nullptr) {
249 return;
250 }
251 }
252 context_->triggerContext->env = env;
253 context_->triggerContext->onTrigger = NapiUtil::CreateReference(env, triggerFunc);
254 }
255
InitReceiver(const napi_env env,const napi_value receiveFunc)256 void NapiAppEventWatcher::InitReceiver(const napi_env env, const napi_value receiveFunc)
257 {
258 HILOG_DEBUG(LOG_CORE, "start to init onReceive");
259 if (context_ == nullptr) {
260 context_ = new(std::nothrow) WatcherContext();
261 if (context_ == nullptr) {
262 return;
263 }
264 }
265 if (context_->receiveContext == nullptr) {
266 context_->receiveContext = new(std::nothrow) OnReceiveContext();
267 if (context_->receiveContext == nullptr) {
268 return;
269 }
270 }
271 context_->receiveContext->env = env;
272 context_->receiveContext->onReceive = NapiUtil::CreateReference(env, receiveFunc);
273 }
274
OnEvents(const std::vector<std::shared_ptr<AppEventPack>> & events)275 void NapiAppEventWatcher::OnEvents(const std::vector<std::shared_ptr<AppEventPack>>& events)
276 {
277 HILOG_DEBUG(LOG_CORE, "onEvents start, seq=%{public}" PRId64 ", event num=%{public}zu", GetSeq(), events.size());
278 if (context_ == nullptr || context_->receiveContext == nullptr || events.empty()) {
279 HILOG_ERROR(LOG_CORE, "onReceive context is null or events is empty");
280 return;
281 }
282 context_->receiveContext->domain = events[0]->GetDomain();
283 context_->receiveContext->events = events;
284 context_->receiveContext->observerSeq = GetSeq();
285
286 uv_loop_t* loop = nullptr;
287 if (napi_get_uv_event_loop(context_->receiveContext->env, &loop) != napi_ok || loop == nullptr) {
288 HILOG_ERROR(LOG_CORE, "failed to get loop.");
289 return;
290 }
291 uv_work_t* work = new(std::nothrow) uv_work_t();
292 if (work == nullptr) {
293 return;
294 }
295 work->data = static_cast<void*>(context_->receiveContext);
296 uv_queue_work_with_qos(loop, work, [] (uv_work_t* work) { HILOG_DEBUG(LOG_CORE, "enter uv work callback."); },
297 OnReceiveWork, uv_qos_default);
298 }
299
IsRealTimeEvent(std::shared_ptr<AppEventPack> event)300 bool NapiAppEventWatcher::IsRealTimeEvent(std::shared_ptr<AppEventPack> event)
301 {
302 return (context_ != nullptr && context_->receiveContext != nullptr);
303 }
304 } // namespace HiviewDFX
305 } // namespace OHOS
306