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