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