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