• 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 "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