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