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, &paramNum, 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, &paramNum, 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, &paramNum, 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, &paramNum, 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, &paramNum, 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, &paramNum, 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