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