1 /*
2 * Copyright (c) 2021-2023 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_hiappevent_watch.h"
16
17 #include <string>
18
19 #include "app_event_observer_mgr.h"
20 #include "hiappevent_base.h"
21 #include "hiappevent_config.h"
22 #include "hiappevent_verify.h"
23 #include "hilog/log.h"
24 #include "napi_app_event_holder.h"
25 #include "napi_app_event_watcher.h"
26 #include "napi_error.h"
27 #include "napi_util.h"
28
29 #undef LOG_DOMAIN
30 #define LOG_DOMAIN 0xD002D07
31
32 #undef LOG_TAG
33 #define LOG_TAG "NapiHiAppEventWatch"
34
35 namespace OHOS {
36 namespace HiviewDFX {
37 namespace NapiHiAppEventWatch {
38 namespace {
39 const std::string NAME_PROPERTY = "name";
40 const std::string COND_PROPERTY = "triggerCondition";
41 const std::string COND_PROPS[] = { "row", "size", "timeOut" };
42 const std::string FILTERS_PROPERTY = "appEventFilters";
43 const std::string FILTERS_DOAMIN_PROP = "domain";
44 const std::string FILTERS_TYPES_PROP = "eventTypes";
45 const std::string FILTERS_NAMES_PROP = "names";
46 const std::string TRIGGER_PROPERTY = "onTrigger";
47 const std::string RECEIVE_PROPERTY = "onReceive";
48 constexpr int BIT_MASK = 1;
49 constexpr unsigned int BIT_ALL_TYPES = 0xff;
50
IsValidName(const napi_env env,const napi_value name)51 bool IsValidName(const napi_env env, const napi_value name)
52 {
53 if (name == nullptr) {
54 NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg(NAME_PROPERTY));
55 return false;
56 }
57 if (!NapiUtil::IsString(env, name)) {
58 NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg(NAME_PROPERTY, "string"));
59 return false;
60 }
61 if (!IsValidWatcherName(NapiUtil::GetString(env, name))) {
62 NapiUtil::ThrowError(env, NapiError::ERR_INVALID_WATCHER_NAME, "Invalid watcher name.");
63 return false;
64 }
65 return true;
66 }
67
IsValidCondition(const napi_env env,const napi_value cond)68 bool IsValidCondition(const napi_env env, const napi_value cond)
69 {
70 if (cond == nullptr) {
71 return true;
72 }
73 if (!NapiUtil::IsObject(env, cond)) {
74 NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg(COND_PROPERTY, "TriggerCondition"));
75 return false;
76 }
77 for (auto& propName : COND_PROPS) {
78 napi_value propValue = NapiUtil::GetProperty(env, cond, propName);
79 if (propValue == nullptr) {
80 continue;
81 }
82 if (!NapiUtil::IsNumber(env, propValue)) {
83 NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg(propName, "number"));
84 return false;
85 }
86 }
87 return true;
88 }
89
IsValidFilter(const napi_env env,const napi_value filter)90 bool IsValidFilter(const napi_env env, const napi_value filter)
91 {
92 napi_value domain = NapiUtil::GetProperty(env, filter, FILTERS_DOAMIN_PROP);
93 if (domain == nullptr) {
94 NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg(FILTERS_DOAMIN_PROP));
95 return false;
96 }
97 if (!NapiUtil::IsString(env, domain)) {
98 NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg(FILTERS_DOAMIN_PROP, "string"));
99 return false;
100 }
101 if (!IsValidDomain(NapiUtil::GetString(env, domain))) {
102 NapiUtil::ThrowError(env, NapiError::ERR_INVALID_FILTER_DOMAIN, "Invalid filtering event domain.");
103 return false;
104 }
105 napi_value types = NapiUtil::GetProperty(env, filter, FILTERS_TYPES_PROP);
106 if (types != nullptr && !NapiUtil::IsArrayType(env, types, napi_number)) {
107 NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg(FILTERS_TYPES_PROP, "EventType[]"));
108 return false;
109 }
110 napi_value names = NapiUtil::GetProperty(env, filter, FILTERS_NAMES_PROP);
111 if (names != nullptr && !NapiUtil::IsArrayType(env, names, napi_string)) {
112 NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg(FILTERS_NAMES_PROP, "string[]"));
113 return false;
114 }
115 return true;
116 }
117
IsValidFilters(const napi_env env,const napi_value filters)118 bool IsValidFilters(const napi_env env, const napi_value filters)
119 {
120 if (filters == nullptr) {
121 return true;
122 }
123 if (!NapiUtil::IsArrayType(env, filters, napi_object)) {
124 NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg(FILTERS_PROPERTY, "AppEventFilter[]"));
125 return false;
126 }
127
128 size_t len = NapiUtil::GetArrayLength(env, filters);
129 for (size_t i = 0; i < len; i++) {
130 napi_value filter = NapiUtil::GetElement(env, filters, i);
131 if (!IsValidFilter(env, filter)) {
132 return false;
133 }
134 }
135 return true;
136 }
137
IsValidTrigger(const napi_env env,const napi_value trigger)138 bool IsValidTrigger(const napi_env env, const napi_value trigger)
139 {
140 if (trigger == nullptr) {
141 return true;
142 }
143 if (!NapiUtil::IsFunction(env, trigger)) {
144 NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg(TRIGGER_PROPERTY, "function"));
145 return false;
146 }
147 return true;
148 }
149
IsValidReceive(const napi_env env,const napi_value receive)150 bool IsValidReceive(const napi_env env, const napi_value receive)
151 {
152 if (receive == nullptr) {
153 return true;
154 }
155 if (!NapiUtil::IsFunction(env, receive)) {
156 NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg(RECEIVE_PROPERTY, "function"));
157 return false;
158 }
159 return true;
160 }
161
IsValidWatcher(const napi_env env,const napi_value watcher)162 bool IsValidWatcher(const napi_env env, const napi_value watcher)
163 {
164 if (!NapiUtil::IsObject(env, watcher)) {
165 NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg("watcher", "Watcher"));
166 return false;
167 }
168 return IsValidName(env, NapiUtil::GetProperty(env, watcher, NAME_PROPERTY))
169 && IsValidCondition(env, NapiUtil::GetProperty(env, watcher, COND_PROPERTY))
170 && IsValidFilters(env, NapiUtil::GetProperty(env, watcher, FILTERS_PROPERTY))
171 && IsValidTrigger(env, NapiUtil::GetProperty(env, watcher, TRIGGER_PROPERTY))
172 && IsValidReceive(env, NapiUtil::GetProperty(env, watcher, RECEIVE_PROPERTY));
173 }
174
GetConditionValue(const napi_env env,const napi_value cond,const std::string & name)175 int GetConditionValue(const napi_env env, const napi_value cond, const std::string& name)
176 {
177 if (auto value = NapiUtil::GetProperty(env, cond, name); value != nullptr) {
178 return NapiUtil::GetInt32(env, value);
179 }
180 return 0;
181 }
182
GetName(const napi_env env,const napi_value watcher)183 std::string GetName(const napi_env env, const napi_value watcher)
184 {
185 return NapiUtil::GetString(env, NapiUtil::GetProperty(env, watcher, NAME_PROPERTY));
186 }
187
GetCondition(const napi_env env,const napi_value watcher)188 TriggerCondition GetCondition(const napi_env env, const napi_value watcher)
189 {
190 TriggerCondition resCond = {
191 .row = 0,
192 .size = 0,
193 .timeout = 0
194 };
195 napi_value cond = NapiUtil::GetProperty(env, watcher, COND_PROPERTY);
196 if (cond == nullptr) {
197 return resCond;
198 }
199
200 size_t index = 0;
201 int row = GetConditionValue(env, cond, COND_PROPS[index++]);
202 if (row < 0) {
203 NapiUtil::ThrowError(env, NapiError::ERR_INVALID_COND_ROW, "Invalid row value.");
204 return resCond;
205 }
206 resCond.row = row;
207
208 int size = GetConditionValue(env, cond, COND_PROPS[index++]);
209 if (size < 0) {
210 NapiUtil::ThrowError(env, NapiError::ERR_INVALID_COND_SIZE, "Invalid size value.");
211 return resCond;
212 }
213 resCond.size = size;
214
215 int timeout = GetConditionValue(env, cond, COND_PROPS[index++]);
216 if (timeout < 0) {
217 NapiUtil::ThrowError(env, NapiError::ERR_INVALID_COND_TIMEOUT, "Invalid timeout value.");
218 return resCond;
219 }
220 constexpr int scale = 30; // step of time is 30s
221 resCond.timeout = timeout * scale;
222 return resCond;
223 }
224
GetFilters(const napi_env env,const napi_value watcher,std::vector<AppEventFilter> & filters)225 void GetFilters(const napi_env env, const napi_value watcher, std::vector<AppEventFilter>& filters)
226 {
227 napi_value filtersValue = NapiUtil::GetProperty(env, watcher, FILTERS_PROPERTY);
228 if (filtersValue == nullptr) {
229 return;
230 }
231 size_t len = NapiUtil::GetArrayLength(env, filtersValue);
232 for (size_t i = 0; i < len; i++) {
233 napi_value filterValue = NapiUtil::GetElement(env, filtersValue, i);
234 std::string domain = NapiUtil::GetString(env, NapiUtil::GetProperty(env, filterValue, FILTERS_DOAMIN_PROP));
235 napi_value namesValue = NapiUtil::GetProperty(env, filterValue, FILTERS_NAMES_PROP);
236 std::unordered_set<std::string> names;
237 if (namesValue != nullptr) {
238 NapiUtil::GetStringsToSet(env, namesValue, names);
239 }
240 napi_value typesValue = NapiUtil::GetProperty(env, filterValue, FILTERS_TYPES_PROP);
241 if (typesValue == nullptr) {
242 filters.emplace_back(AppEventFilter(domain, names, BIT_ALL_TYPES));
243 continue;
244 }
245 std::vector<int> types;
246 NapiUtil::GetInt32s(env, typesValue, types);
247 unsigned int filterType = 0;
248 for (auto type : types) {
249 if (!IsValidEventType(type)) {
250 std::string errMsg = NapiUtil::CreateErrMsg(FILTERS_TYPES_PROP, "EventType[]");
251 NapiUtil::ThrowError(env, NapiError::ERR_PARAM, errMsg);
252 continue;
253 }
254 filterType |= (BIT_MASK << type);
255 }
256 filterType = filterType > 0 ? filterType : BIT_ALL_TYPES;
257 filters.emplace_back(AppEventFilter(domain, names, filterType));
258 }
259 }
260
CreateHolder(const napi_env env,size_t argc,const napi_value argv[])261 napi_value CreateHolder(const napi_env env, size_t argc, const napi_value argv[])
262 {
263 napi_value constructor = nullptr;
264 if (napi_get_reference_value(env, NapiAppEventHolder::constructor_, &constructor) != napi_ok) {
265 HILOG_ERROR(LOG_CORE, "failed to get constructor of the holder");
266 return NapiUtil::CreateNull(env);
267 }
268 napi_value holder = nullptr;
269 if (napi_new_instance(env, constructor, argc, argv, &holder) != napi_ok) {
270 HILOG_ERROR(LOG_CORE, "failed to get new instance for holder");
271 return NapiUtil::CreateNull(env);
272 }
273 return holder;
274 }
275 }
276
AddWatcher(const napi_env env,const napi_value watcher)277 napi_value AddWatcher(const napi_env env, const napi_value watcher)
278 {
279 if (!IsValidWatcher(env, watcher)) {
280 HILOG_ERROR(LOG_CORE, "invalid watcher");
281 return NapiUtil::CreateNull(env);
282 }
283
284 // 1. build watcher object
285 std::vector<AppEventFilter> filters;
286 GetFilters(env, watcher, filters);
287 std::string name = GetName(env, watcher);
288 TriggerCondition cond = GetCondition(env, watcher);
289 auto watcherPtr = std::make_shared<NapiAppEventWatcher>(name, filters, cond);
290
291 // 2. set trigger if any
292 napi_value trigger = NapiUtil::GetProperty(env, watcher, TRIGGER_PROPERTY);
293 if (trigger != nullptr) {
294 watcherPtr->InitTrigger(env, trigger);
295 }
296
297 // 3. set receive if any
298 napi_value receiver = NapiUtil::GetProperty(env, watcher, RECEIVE_PROPERTY);
299 if (receiver != nullptr) {
300 watcherPtr->InitReceiver(env, receiver);
301 }
302
303 // 4. add the watcher to Manager
304 int64_t observerSeq = AppEventObserverMgr::GetInstance().RegisterObserver(watcherPtr);
305 if (observerSeq <= 0) {
306 HILOG_ERROR(LOG_CORE, "invalid observer sequence");
307 return NapiUtil::CreateNull(env);
308 }
309
310 // 5. create holder and add holder to the watcher
311 constexpr size_t holderParamNum = 2;
312 napi_value holderParams[holderParamNum] = {
313 NapiUtil::CreateString(env, name),
314 NapiUtil::CreateInt64(env, observerSeq)
315 };
316 napi_value holder = CreateHolder(env, holderParamNum, holderParams);
317 watcherPtr->InitHolder(env, holder);
318 return holder;
319 }
320
RemoveWatcher(const napi_env env,const napi_value watcher)321 napi_value RemoveWatcher(const napi_env env, const napi_value watcher)
322 {
323 if (!NapiUtil::IsObject(env, watcher)) {
324 NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg("watcher", "Watcher"));
325 return NapiUtil::CreateUndefined(env);
326 }
327 if (!IsValidName(env, NapiUtil::GetProperty(env, watcher, NAME_PROPERTY))) {
328 return NapiUtil::CreateUndefined(env);
329 }
330 (void)AppEventObserverMgr::GetInstance().UnregisterObserver(GetName(env, watcher));
331 return NapiUtil::CreateUndefined(env);
332 }
333 } // namespace NapiHiAppEventConfig
334 } // namespace HiviewDFX
335 } // namespace OHOS
336