1 /*
2 * Copyright (c) 2022 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
16 #include "napi_hisysevent_init.h"
17
18 #include <memory>
19 #include <mutex>
20 #include <unordered_map>
21
22 #include "def.h"
23 #include "hilog/log.h"
24 #include "hisysevent_base_manager.h"
25 #include "napi/native_api.h"
26 #include "napi/native_node_api.h"
27 #include "napi_callback_context.h"
28 #include "napi_hisysevent_listener.h"
29 #include "napi_hisysevent_querier.h"
30 #include "napi_hisysevent_util.h"
31 #include "ret_def.h"
32
33 using namespace OHOS::HiviewDFX;
34
35 #undef LOG_DOMAIN
36 #define LOG_DOMAIN 0xD002D08
37
38 #undef LOG_TAG
39 #define LOG_TAG "NAPI_HISYSEVENT_JS"
40
41 namespace {
42 constexpr char RULES_ATTR[] = "rules";
43 constexpr size_t WRITE_FUNC_MAX_PARAM_NUM = 2;
44 constexpr size_t ADD_LISTENER_FUNC_MAX_PARAM_NUM = 1;
45 constexpr size_t REMOVE_LISTENER_FUNC_MAX_PARAM_NUM = 1;
46 constexpr size_t QUERY_FUNC_MAX_PARAM_NUM = 3;
47 constexpr size_t ADD_LISTENER_LISTENER_PARAM_INDEX = 0;
48 constexpr size_t REMOVE_LISTENER_LISTENER_PARAM_INDEX = 0;
49 constexpr size_t QUERY_QUERY_ARG_PARAM_INDEX = 0;
50 constexpr size_t QUERY_RULE_ARRAY_PARAM_INDEX = 1;
51 constexpr size_t QUERY_QUERIER_PARAM_INDEX = 2;
52 constexpr size_t EXPORT_FUNC_MAX_PARAM_NUM = 2;
53 constexpr size_t EXPORT_QUERY_ARG_PARAM_INDEX = 0;
54 constexpr size_t EXPORT_RULE_ARRAY_PARAM_INDEX = 1;
55 constexpr size_t SUBSCRIBE_FUNC_MAX_PARAM_NUM = 1;
56 constexpr size_t SUBSCRIBE_RULE_ARRAY_PARAM_INDEX = 0;
57 constexpr long long DEFAULT_TIME_STAMP = -1;
58 constexpr int DEFAULT_EVENT_COUNT = 1000;
59 constexpr int TIME_STAMP_LENGTH = 13;
60 using NAPI_LISTENER_PAIR = std::pair<pid_t, std::shared_ptr<NapiHiSysEventListener>>;
61 using NAPI_QUERIER_PAIR = std::pair<pid_t, std::shared_ptr<NapiHiSysEventQuerier>>;
62 std::mutex g_listenerMapMutex;
63 std::unordered_map<napi_ref, NAPI_LISTENER_PAIR> listeners;
64 std::mutex g_querierMapMutex;
65 std::unordered_map<napi_ref, NAPI_QUERIER_PAIR> queriers;
66 }
67
Write(napi_env env,napi_callback_info info)68 static napi_value Write(napi_env env, napi_callback_info info)
69 {
70 if (!NapiHiSysEventUtil::IsSystemAppCall()) {
71 NapiHiSysEventUtil::ThrowSystemAppPermissionError(env);
72 return nullptr;
73 }
74 size_t paramNum = WRITE_FUNC_MAX_PARAM_NUM;
75 napi_value params[WRITE_FUNC_MAX_PARAM_NUM] = {0};
76 napi_value thisArg = nullptr;
77 void *data = nullptr;
78 NAPI_CALL(env, napi_get_cb_info(env, info, ¶mNum, params, &thisArg, &data));
79 napi_value val = nullptr;
80 napi_get_undefined(env, &val);
81 if (paramNum < WRITE_FUNC_MAX_PARAM_NUM - 1) {
82 HILOG_ERROR(LOG_CORE,
83 "count of parameters is not equal to %{public}zu or %{public}zu.",
84 WRITE_FUNC_MAX_PARAM_NUM - 1, WRITE_FUNC_MAX_PARAM_NUM);
85 NapiHiSysEventUtil::ThrowParamMandatoryError(env, "info");
86 return val;
87 }
88 HiSysEventAsyncContext* asyncContext = new(std::nothrow) HiSysEventAsyncContext {
89 .env = env,
90 .asyncWork = nullptr,
91 .deferred = nullptr,
92 };
93 if (asyncContext == nullptr) {
94 HILOG_ERROR(LOG_CORE, "failed to new HiSysEventAsyncContext.");
95 return val;
96 }
97 NapiHiSysEventUtil::ParseHiSysEventInfo(env, params, paramNum, asyncContext->eventInfo);
98 NapiHiSysEventAdapter::ParseJsCallerInfo(env, asyncContext->jsCallerInfo);
99 asyncContext->eventWroteResult = SUCCESS;
100 // set callback function if it exists
101 if (paramNum == WRITE_FUNC_MAX_PARAM_NUM) {
102 napi_valuetype lastParamType;
103 napi_typeof(env, params[paramNum - 1], &lastParamType);
104 if (lastParamType == napi_valuetype::napi_function) {
105 napi_create_reference(env, params[paramNum - 1], 1, &asyncContext->callback);
106 }
107 } else if (paramNum > WRITE_FUNC_MAX_PARAM_NUM) {
108 HILOG_WARN(LOG_CORE, "count of params is invalid =%{public}d.", static_cast<int>(paramNum));
109 }
110 // set promise object if callback function is null
111 napi_value promise = nullptr;
112 napi_get_undefined(env, &promise);
113 if (asyncContext->callback == nullptr) {
114 napi_create_promise(env, &asyncContext->deferred, &promise);
115 }
116 NapiHiSysEventAdapter::Write(env, asyncContext);
117 return promise;
118 }
119
AddWatcher(napi_env env,napi_callback_info info)120 static napi_value AddWatcher(napi_env env, napi_callback_info info)
121 {
122 if (!NapiHiSysEventUtil::IsSystemAppCall()) {
123 NapiHiSysEventUtil::ThrowSystemAppPermissionError(env);
124 return nullptr;
125 }
126 size_t paramNum = ADD_LISTENER_FUNC_MAX_PARAM_NUM;
127 napi_value params[ADD_LISTENER_FUNC_MAX_PARAM_NUM] = {0};
128 napi_value thisArg = nullptr;
129 void* data = nullptr;
130 NAPI_CALL(env, napi_get_cb_info(env, info, ¶mNum, params, &thisArg, &data));
131 if (paramNum < ADD_LISTENER_FUNC_MAX_PARAM_NUM) {
132 HILOG_ERROR(LOG_CORE, "count of parameters is less than %{public}zu.", ADD_LISTENER_FUNC_MAX_PARAM_NUM);
133 NapiHiSysEventUtil::ThrowParamMandatoryError(env, "watcher");
134 return nullptr;
135 }
136 std::vector<ListenerRule> rules;
137 napi_value jsRulesVal = NapiHiSysEventUtil::GetPropertyByName(env, params[ADD_LISTENER_LISTENER_PARAM_INDEX],
138 RULES_ATTR);
139 if (auto ret = NapiHiSysEventUtil::ParseListenerRules(env, jsRulesVal, rules);
140 ret != SUCCESS) {
141 HILOG_ERROR(LOG_CORE, "failed to parse watch rules, result code is %{public}d.", ret);
142 return nullptr;
143 }
144 CallbackContext* callbackContext = new CallbackContext();
145 callbackContext->env = env;
146 callbackContext->threadId = getproctid();
147 napi_create_reference(env, params[ADD_LISTENER_LISTENER_PARAM_INDEX], 1, &callbackContext->ref);
148 std::shared_ptr<NapiHiSysEventListener> listener = std::make_shared<NapiHiSysEventListener>(callbackContext);
149 auto ret = HiSysEventBaseManager::AddListener(listener, rules);
150 if (ret != NAPI_SUCCESS) {
151 HILOG_ERROR(LOG_CORE, "failed to add event listener, result code is %{public}d.", ret);
152 NapiHiSysEventUtil::ThrowErrorByRet(env, ret);
153 return nullptr;
154 }
155 std::lock_guard<std::mutex> lock(g_listenerMapMutex);
156 listeners[callbackContext->ref] = std::make_pair(callbackContext->threadId, listener);
157 return nullptr;
158 }
159
RemoveWatcher(napi_env env,napi_callback_info info)160 static napi_value RemoveWatcher(napi_env env, napi_callback_info info)
161 {
162 if (!NapiHiSysEventUtil::IsSystemAppCall()) {
163 NapiHiSysEventUtil::ThrowSystemAppPermissionError(env);
164 return nullptr;
165 }
166 size_t paramNum = REMOVE_LISTENER_FUNC_MAX_PARAM_NUM;
167 napi_value params[REMOVE_LISTENER_FUNC_MAX_PARAM_NUM] = {0};
168 napi_value thisArg = nullptr;
169 void* data = nullptr;
170 NAPI_CALL(env, napi_get_cb_info(env, info, ¶mNum, params, &thisArg, &data));
171 if (paramNum < REMOVE_LISTENER_FUNC_MAX_PARAM_NUM) {
172 HILOG_ERROR(LOG_CORE, "count of parameters is less than %{public}zu.", REMOVE_LISTENER_FUNC_MAX_PARAM_NUM);
173 NapiHiSysEventUtil::ThrowParamMandatoryError(env, "watcher");
174 return nullptr;
175 }
176 auto iter = NapiHiSysEventUtil::CompareAndReturnCacheItem<NapiHiSysEventListener>(env,
177 params[REMOVE_LISTENER_LISTENER_PARAM_INDEX], listeners);
178 if (iter == listeners.end()) {
179 HILOG_ERROR(LOG_CORE, "listener not exist.");
180 NapiHiSysEventUtil::ThrowErrorByRet(env, ERR_NAPI_LISTENER_NOT_FOUND);
181 return nullptr;
182 }
183 if (auto ret = HiSysEventBaseManager::RemoveListener(iter->second.second);
184 ret != NAPI_SUCCESS) {
185 HILOG_ERROR(LOG_CORE, "failed to remove event listener, result code is %{public}d.", ret);
186 NapiHiSysEventUtil::ThrowErrorByRet(env, ret);
187 return nullptr;
188 }
189 std::lock_guard<std::mutex> lock(g_listenerMapMutex);
190 listeners.erase(iter->first);
191 return nullptr;
192 }
193
Query(napi_env env,napi_callback_info info)194 static napi_value Query(napi_env env, napi_callback_info info)
195 {
196 if (!NapiHiSysEventUtil::IsSystemAppCall()) {
197 NapiHiSysEventUtil::ThrowSystemAppPermissionError(env);
198 return nullptr;
199 }
200 size_t paramNum = QUERY_FUNC_MAX_PARAM_NUM;
201 napi_value params[QUERY_FUNC_MAX_PARAM_NUM] = {0};
202 napi_value thisArg = nullptr;
203 void* data = nullptr;
204 NAPI_CALL(env, napi_get_cb_info(env, info, ¶mNum, params, &thisArg, &data));
205 if (paramNum < QUERY_FUNC_MAX_PARAM_NUM) {
206 std::unordered_map<int32_t, std::string> paramError = {
207 {QUERY_QUERY_ARG_PARAM_INDEX, "queryArg"},
208 {QUERY_RULE_ARRAY_PARAM_INDEX, "rules"},
209 {QUERY_QUERIER_PARAM_INDEX, "querier"},
210 };
211 HILOG_ERROR(LOG_CORE, "count of parameters is less than %{public}zu.", QUERY_FUNC_MAX_PARAM_NUM);
212 NapiHiSysEventUtil::ThrowParamMandatoryError(env, paramError.at(paramNum));
213 return nullptr;
214 }
215 QueryArg queryArg = { DEFAULT_TIME_STAMP, DEFAULT_TIME_STAMP, DEFAULT_EVENT_COUNT };
216 if (auto ret = NapiHiSysEventUtil::ParseQueryArg(env, params[QUERY_QUERY_ARG_PARAM_INDEX], queryArg);
217 ret != SUCCESS) {
218 HILOG_ERROR(LOG_CORE, "failed to parse query arg, result code is %{public}d.", ret);
219 return nullptr;
220 }
221 std::vector<QueryRule> rules;
222 if (auto ret = NapiHiSysEventUtil::ParseQueryRules(env, params[QUERY_RULE_ARRAY_PARAM_INDEX], rules);
223 ret != SUCCESS) {
224 HILOG_ERROR(LOG_CORE, "failed to parse query rules, result code is %{public}d.", ret);
225 return nullptr;
226 }
227 if (NapiHiSysEventUtil::IsNullOrUndefined(env, params[QUERY_QUERIER_PARAM_INDEX])) {
228 NapiHiSysEventUtil::ThrowParamTypeError(env, "querier", "Querier");
229 HILOG_ERROR(LOG_CORE, "querier is null or undefined.");
230 return nullptr;
231 }
232 CallbackContext* callbackContext = new CallbackContext();
233 callbackContext->env = env;
234 callbackContext->threadId = getproctid();
235 napi_create_reference(env, params[QUERY_QUERIER_PARAM_INDEX], 1, &callbackContext->ref);
236 std::shared_ptr<NapiHiSysEventQuerier> querier = std::make_shared<NapiHiSysEventQuerier>(callbackContext,
237 [] (const napi_env env, const napi_ref ref) {
238 napi_value querier = nullptr;
239 napi_get_reference_value(env, ref, &querier);
240 auto iter = NapiHiSysEventUtil::CompareAndReturnCacheItem<NapiHiSysEventQuerier>(env, querier, queriers);
241 std::lock_guard<std::mutex> lock(g_querierMapMutex);
242 if (iter != queriers.end()) {
243 queriers.erase(iter->first);
244 }
245 });
246 auto ret = HiSysEventBaseManager::Query(queryArg, rules, querier);
247 if (ret != NAPI_SUCCESS) {
248 HILOG_ERROR(LOG_CORE, "failed to query hisysevent, result code is %{public}d.", ret);
249 NapiHiSysEventUtil::ThrowErrorByRet(env, ret);
250 }
251 std::lock_guard<std::mutex> lock(g_querierMapMutex);
252 queriers[callbackContext->ref] = std::make_pair(callbackContext->threadId, querier);
253 return nullptr;
254 }
255
ExportSysEvents(napi_env env,napi_callback_info info)256 static napi_value ExportSysEvents(napi_env env, napi_callback_info info)
257 {
258 if (!NapiHiSysEventUtil::IsSystemAppCall()) {
259 NapiHiSysEventUtil::ThrowSystemAppPermissionError(env);
260 return nullptr;
261 }
262 size_t paramNum = EXPORT_FUNC_MAX_PARAM_NUM;
263 napi_value params[EXPORT_FUNC_MAX_PARAM_NUM] = {0};
264 napi_value thisArg = nullptr;
265 void* data = nullptr;
266 NAPI_CALL(env, napi_get_cb_info(env, info, ¶mNum, params, &thisArg, &data));
267 if (paramNum < EXPORT_FUNC_MAX_PARAM_NUM) {
268 std::unordered_map<int32_t, std::string> paramError = {
269 {EXPORT_QUERY_ARG_PARAM_INDEX, "queryArg"},
270 {EXPORT_RULE_ARRAY_PARAM_INDEX, "rules"},
271 };
272 HILOG_ERROR(LOG_CORE, "count of parameters is less than %{public}zu.", EXPORT_FUNC_MAX_PARAM_NUM);
273 NapiHiSysEventUtil::ThrowParamMandatoryError(env, paramError.at(paramNum));
274 return nullptr;
275 }
276 QueryArg queryArg = { DEFAULT_TIME_STAMP, DEFAULT_TIME_STAMP, DEFAULT_EVENT_COUNT };
277 if (auto ret = NapiHiSysEventUtil::ParseQueryArg(env, params[EXPORT_QUERY_ARG_PARAM_INDEX], queryArg);
278 ret != SUCCESS) {
279 HILOG_ERROR(LOG_CORE, "failed to parse query arg, result code is %{public}d.", ret);
280 return nullptr;
281 }
282 std::vector<QueryRule> rules;
283 if (auto ret = NapiHiSysEventUtil::ParseQueryRules(env, params[EXPORT_RULE_ARRAY_PARAM_INDEX], rules);
284 ret != SUCCESS) {
285 HILOG_ERROR(LOG_CORE, "failed to parse query rules, result code is %{public}d.", ret);
286 return nullptr;
287 }
288 auto ret = HiSysEventBaseManager::Export(queryArg, rules);
289 if (std::to_string(ret).length() < TIME_STAMP_LENGTH) {
290 HILOG_ERROR(LOG_CORE, "failed to export event");
291 int32_t retCode = static_cast<int32_t>(ret);
292 NapiHiSysEventUtil::ThrowErrorByRet(env, retCode);
293 return nullptr;
294 }
295 napi_value result = nullptr;
296 NapiHiSysEventUtil::CreateInt64Value(env, ret, result);
297 return result;
298 }
299
Subscribe(napi_env env,napi_callback_info info)300 static napi_value Subscribe(napi_env env, napi_callback_info info)
301 {
302 if (!NapiHiSysEventUtil::IsSystemAppCall()) {
303 NapiHiSysEventUtil::ThrowSystemAppPermissionError(env);
304 return nullptr;
305 }
306 size_t paramNum = SUBSCRIBE_FUNC_MAX_PARAM_NUM;
307 napi_value params[SUBSCRIBE_FUNC_MAX_PARAM_NUM] = {0};
308 napi_value thisArg = nullptr;
309 void* data = nullptr;
310 NAPI_CALL(env, napi_get_cb_info(env, info, ¶mNum, params, &thisArg, &data));
311 if (paramNum < SUBSCRIBE_FUNC_MAX_PARAM_NUM) {
312 HILOG_ERROR(LOG_CORE, "count of parameters is less than %{public}zu.", SUBSCRIBE_FUNC_MAX_PARAM_NUM);
313 NapiHiSysEventUtil::ThrowParamMandatoryError(env, "rules");
314 return nullptr;
315 }
316 std::vector<QueryRule> rules;
317 if (auto ret = NapiHiSysEventUtil::ParseQueryRules(env, params[SUBSCRIBE_RULE_ARRAY_PARAM_INDEX], rules);
318 ret != SUCCESS) {
319 HILOG_ERROR(LOG_CORE, "failed to parse query rules, result code is %{public}d.", ret);
320 return nullptr;
321 }
322 auto ret = HiSysEventBaseManager::Subscribe(rules);
323 if (std::to_string(ret).length() < TIME_STAMP_LENGTH) {
324 HILOG_ERROR(LOG_CORE, "failed to subscribe event.");
325 int32_t retCode = static_cast<int32_t>(ret);
326 NapiHiSysEventUtil::ThrowErrorByRet(env, retCode);
327 return nullptr;
328 }
329 napi_value result = nullptr;
330 NapiHiSysEventUtil::CreateInt64Value(env, ret, result);
331 return result;
332 }
333
Unsubscribe(napi_env env,napi_callback_info info)334 static napi_value Unsubscribe(napi_env env, napi_callback_info info)
335 {
336 if (!NapiHiSysEventUtil::IsSystemAppCall()) {
337 NapiHiSysEventUtil::ThrowSystemAppPermissionError(env);
338 return nullptr;
339 }
340 auto ret = HiSysEventBaseManager::Unsubscribe();
341 if (ret != NAPI_SUCCESS) {
342 HILOG_ERROR(LOG_CORE, "failed to unsubscribe, result code is %{public}d.", ret);
343 int32_t retCode = static_cast<int32_t>(ret);
344 NapiHiSysEventUtil::ThrowErrorByRet(env, retCode);
345 }
346 return nullptr;
347 }
348
349 EXTERN_C_START
Init(napi_env env,napi_value exports)350 static napi_value Init(napi_env env, napi_value exports)
351 {
352 napi_property_descriptor desc[] = {
353 DECLARE_NAPI_FUNCTION("write", Write),
354 DECLARE_NAPI_FUNCTION("addWatcher", AddWatcher),
355 DECLARE_NAPI_FUNCTION("removeWatcher", RemoveWatcher),
356 DECLARE_NAPI_FUNCTION("query", Query),
357 DECLARE_NAPI_FUNCTION("exportSysEvents", ExportSysEvents),
358 DECLARE_NAPI_FUNCTION("subscribe", Subscribe),
359 DECLARE_NAPI_FUNCTION("unsubscribe", Unsubscribe),
360 };
361 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(napi_property_descriptor), desc));
362
363 // init EventType class, Event class and Param class
364 InitNapiClass(env, exports);
365
366 return exports;
367 }
368 EXTERN_C_END
369
370 static napi_module _module = {
371 .nm_version = 1,
372 .nm_flags = 0,
373 .nm_filename = nullptr,
374 .nm_register_func = Init,
375 .nm_modname = "hiSysEvent",
376 .nm_priv = ((void*)0),
377 .reserved = {0}
378 };
379
RegisterModule(void)380 extern "C" __attribute__((constructor)) void RegisterModule(void)
381 {
382 napi_module_register(&_module);
383 }
384