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 }
~OnTriggerContext()57 OnTriggerContext::~OnTriggerContext()
58 {
59 if (onTrigger != nullptr) {
60 napi_delete_reference(env, onTrigger);
61 }
62 if (holder != nullptr) {
63 napi_delete_reference(env, holder);
64 }
65 }
66
~OnReceiveContext()67 OnReceiveContext::~OnReceiveContext()
68 {
69 if (onReceive != nullptr) {
70 napi_delete_reference(env, onReceive);
71 }
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(LOG_CORE, "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 delete context_;
104 return;
105 }
106 auto task = [contextData = context_] () {
107 HILOG_DEBUG(LOG_CORE, "start to destroy WatcherContext object");
108 delete contextData;
109 };
110 if (napi_send_event(env, task, napi_eprio_high) != napi_status::napi_ok) {
111 HILOG_ERROR(LOG_CORE, "failed to SendEvent.");
112 delete context_;
113 }
114 }
115
InitHolder(const napi_env env,const napi_value holder)116 void NapiAppEventWatcher::InitHolder(const napi_env env, const napi_value holder)
117 {
118 if (context_ == nullptr) {
119 context_ = new(std::nothrow) WatcherContext();
120 if (context_ == nullptr) {
121 return;
122 }
123 }
124 if (context_->triggerContext == nullptr) {
125 context_->triggerContext = new(std::nothrow) OnTriggerContext();
126 if (context_->triggerContext == nullptr) {
127 return;
128 }
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(LOG_CORE, "onTrigger start");
137 if (context_ == nullptr || context_->triggerContext == nullptr) {
138 HILOG_ERROR(LOG_CORE, "onTrigger context is null");
139 return;
140 }
141 context_->triggerContext->row = triggerCond.row;
142 context_->triggerContext->size = triggerCond.size;
143 auto onTriggerWork = [triggerContext = context_->triggerContext] () {
144 auto context = static_cast<OnTriggerContext*>(triggerContext);
145 napi_handle_scope scope = nullptr;
146 napi_open_handle_scope(context->env, &scope);
147 if (scope == nullptr) {
148 HILOG_ERROR(LOG_CORE, "failed to open handle scope");
149 return;
150 }
151 napi_value callback = NapiUtil::GetReferenceValue(context->env, context->onTrigger);
152 if (callback == nullptr) {
153 HILOG_ERROR(LOG_CORE, "failed to get callback from the context");
154 napi_close_handle_scope(context->env, scope);
155 return;
156 }
157 napi_value argv[CALLBACK_PARAM_NUM] = {
158 NapiUtil::CreateInt32(context->env, context->row),
159 NapiUtil::CreateInt32(context->env, context->size),
160 NapiUtil::GetReferenceValue(context->env, context->holder)
161 };
162 napi_value ret = nullptr;
163 if (napi_call_function(context->env, nullptr, callback, CALLBACK_PARAM_NUM, argv, &ret) != napi_ok) {
164 HILOG_ERROR(LOG_CORE, "failed to call onTrigger function");
165 }
166 napi_close_handle_scope(context->env, scope);
167 };
168 if (napi_send_event(context_->triggerContext->env, onTriggerWork, napi_eprio_high) != napi_status::napi_ok) {
169 HILOG_ERROR(LOG_CORE, "failed to SendEvent.");
170 }
171 }
172
InitTrigger(const napi_env env,const napi_value triggerFunc)173 void NapiAppEventWatcher::InitTrigger(const napi_env env, const napi_value triggerFunc)
174 {
175 HILOG_DEBUG(LOG_CORE, "start to init OnTrigger");
176 if (context_ == nullptr) {
177 context_ = new(std::nothrow) WatcherContext();
178 if (context_ == nullptr) {
179 return;
180 }
181 }
182 if (context_->triggerContext == nullptr) {
183 context_->triggerContext = new(std::nothrow) OnTriggerContext();
184 if (context_->triggerContext == nullptr) {
185 return;
186 }
187 }
188 context_->triggerContext->env = env;
189 context_->triggerContext->onTrigger = NapiUtil::CreateReference(env, triggerFunc);
190 }
191
InitReceiver(const napi_env env,const napi_value receiveFunc)192 void NapiAppEventWatcher::InitReceiver(const napi_env env, const napi_value receiveFunc)
193 {
194 HILOG_DEBUG(LOG_CORE, "start to init onReceive");
195 if (context_ == nullptr) {
196 context_ = new(std::nothrow) WatcherContext();
197 if (context_ == nullptr) {
198 return;
199 }
200 }
201 if (context_->receiveContext == nullptr) {
202 context_->receiveContext = new(std::nothrow) OnReceiveContext();
203 if (context_->receiveContext == nullptr) {
204 return;
205 }
206 }
207 context_->receiveContext->env = env;
208 context_->receiveContext->onReceive = NapiUtil::CreateReference(env, receiveFunc);
209 }
210
OnEvents(const std::vector<std::shared_ptr<AppEventPack>> & events)211 void NapiAppEventWatcher::OnEvents(const std::vector<std::shared_ptr<AppEventPack>>& events)
212 {
213 HILOG_DEBUG(LOG_CORE, "onEvents start, seq=%{public}" PRId64 ", event num=%{public}zu", GetSeq(), events.size());
214 if (context_ == nullptr || context_->receiveContext == nullptr || events.empty()) {
215 HILOG_ERROR(LOG_CORE, "onReceive context is null or events is empty");
216 return;
217 }
218 context_->receiveContext->domain = events[0]->GetDomain();
219 context_->receiveContext->events = events;
220 context_->receiveContext->observerSeq = GetSeq();
221 auto onReceiveWork = [receiveContext = context_->receiveContext] () {
222 auto context = static_cast<OnReceiveContext*>(receiveContext);
223 napi_handle_scope scope = nullptr;
224 napi_open_handle_scope(context->env, &scope);
225 if (scope == nullptr) {
226 HILOG_ERROR(LOG_CORE, "failed to open handle scope");
227 return;
228 }
229 napi_value callback = NapiUtil::GetReferenceValue(context->env, context->onReceive);
230 if (callback == nullptr) {
231 HILOG_ERROR(LOG_CORE, "failed to get callback from the context");
232 napi_close_handle_scope(context->env, scope);
233 return;
234 }
235 napi_value argv[RECEIVE_PARAM_NUM] = {
236 NapiUtil::CreateString(context->env, context->domain),
237 NapiUtil::CreateEventGroups(context->env, context->events)
238 };
239 napi_value ret = nullptr;
240 if (napi_call_function(context->env, nullptr, callback, RECEIVE_PARAM_NUM, argv, &ret) == napi_ok) {
241 DeleteEventMappingAsync(context->observerSeq, context->events);
242 } else {
243 HILOG_ERROR(LOG_CORE, "failed to call onReceive function");
244 }
245 napi_close_handle_scope(context->env, scope);
246 };
247 if (napi_send_event(context_->receiveContext->env, onReceiveWork, napi_eprio_high) != napi_status::napi_ok) {
248 HILOG_ERROR(LOG_CORE, "failed to SendEvent.");
249 }
250 }
251
IsRealTimeEvent(std::shared_ptr<AppEventPack> event)252 bool NapiAppEventWatcher::IsRealTimeEvent(std::shared_ptr<AppEventPack> event)
253 {
254 return (context_ != nullptr && context_->receiveContext != nullptr);
255 }
256 } // namespace HiviewDFX
257 } // namespace OHOS
258