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 <unordered_map>
20
21 #include "def.h"
22 #include "hilog/log.h"
23 #include "hisysevent_base_manager.h"
24 #include "napi/native_api.h"
25 #include "napi/native_node_api.h"
26 #include "napi_callback_context.h"
27 #include "napi_hisysevent_init.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 namespace {
36 constexpr HiLogLabel LABEL = { LOG_CORE, 0xD002D08, "NAPI_HISYSEVENT_JS" };
37 constexpr char RULES_ATTR[] = "rules";
38 constexpr size_t WRITE_FUNC_MAX_PARAM_NUM = 2;
39 constexpr size_t ADD_LISTENER_FUNC_MAX_PARAM_NUM = 1;
40 constexpr size_t REMOVE_LISTENER_FUNC_MAX_PARAM_NUM = 1;
41 constexpr size_t QUERY_FUNC_MAX_PARAM_NUM = 3;
42 constexpr size_t ADD_LISTENER_LISTENER_PARAM_INDEX = 0;
43 constexpr size_t REMOVE_LISTENER_LISTENER_PARAM_INDEX = 0;
44 constexpr size_t QUERY_QUERY_ARG_PARAM_INDEX = 0;
45 constexpr size_t QUERY_RULE_ARRAY_PARAM_INDEX = 1;
46 constexpr size_t QUERY_QUERIER_PARAM_INDEX = 2;
47 constexpr long long DEFAULT_TIME_STAMP = -1;
48 constexpr int DEFAULT_EVENT_COUNT = 1000;
49 using NAPI_LISTENER_PAIR = std::pair<pid_t, std::shared_ptr<NapiHiSysEventListener>>;
50 using NAPI_QUERIER_PAIR = std::pair<pid_t, std::shared_ptr<NapiHiSysEventQuerier>>;
51 std::unordered_map<napi_ref, NAPI_LISTENER_PAIR> listeners;
52 std::unordered_map<napi_ref, NAPI_QUERIER_PAIR> queriers;
53 }
54
Write(napi_env env,napi_callback_info info)55 static napi_value Write(napi_env env, napi_callback_info info)
56 {
57 size_t paramNum = WRITE_FUNC_MAX_PARAM_NUM;
58 napi_value params[WRITE_FUNC_MAX_PARAM_NUM] = {0};
59 napi_value thisArg = nullptr;
60 void *data = nullptr;
61 NAPI_CALL(env, napi_get_cb_info(env, info, ¶mNum, params, &thisArg, &data));
62 napi_value val = nullptr;
63 napi_get_undefined(env, &val);
64 if (paramNum < WRITE_FUNC_MAX_PARAM_NUM - 1) {
65 HiLog::Error(LABEL,
66 "count of parameters is not equal to %{public}zu or %{public}zu.",
67 WRITE_FUNC_MAX_PARAM_NUM - 1, WRITE_FUNC_MAX_PARAM_NUM);
68 NapiHiSysEventUtil::ThrowParamMandatoryError(env, "info");
69 return val;
70 }
71 HiSysEventAsyncContext* asyncContext = new(std::nothrow) HiSysEventAsyncContext {
72 .env = env,
73 .asyncWork = nullptr,
74 .deferred = nullptr,
75 };
76 if (asyncContext == nullptr) {
77 HiLog::Error(LABEL, "failed to new HiSysEventAsyncContext.");
78 return val;
79 }
80 NapiHiSysEventUtil::ParseHiSysEventInfo(env, params, paramNum, asyncContext->eventInfo);
81 asyncContext->eventWroteResult = SUCCESS;
82 // set callback function if it exists
83 if (paramNum == WRITE_FUNC_MAX_PARAM_NUM) {
84 napi_valuetype lastParamType;
85 napi_typeof(env, params[paramNum - 1], &lastParamType);
86 if (lastParamType == napi_valuetype::napi_function) {
87 napi_create_reference(env, params[paramNum - 1], 1, &asyncContext->callback);
88 }
89 } else if (paramNum > WRITE_FUNC_MAX_PARAM_NUM) {
90 HiLog::Warn(LABEL, "count of params is invalid =%{public}d.", static_cast<int>(paramNum));
91 }
92 // set promise object if callback function is null
93 napi_value promise = nullptr;
94 napi_get_undefined(env, &promise);
95 if (asyncContext->callback == nullptr) {
96 napi_create_promise(env, &asyncContext->deferred, &promise);
97 }
98 NapiHiSysEventAdapter::Write(env, asyncContext);
99 return promise;
100 }
101
AddWatcher(napi_env env,napi_callback_info info)102 static napi_value AddWatcher(napi_env env, napi_callback_info info)
103 {
104 size_t paramNum = ADD_LISTENER_FUNC_MAX_PARAM_NUM;
105 napi_value params[ADD_LISTENER_FUNC_MAX_PARAM_NUM] = {0};
106 napi_value thisArg = nullptr;
107 void* data = nullptr;
108 NAPI_CALL(env, napi_get_cb_info(env, info, ¶mNum, params, &thisArg, &data));
109 if (paramNum < ADD_LISTENER_FUNC_MAX_PARAM_NUM) {
110 HiLog::Error(LABEL, "count of parameters is less than %{public}zu.", ADD_LISTENER_FUNC_MAX_PARAM_NUM);
111 NapiHiSysEventUtil::ThrowParamMandatoryError(env, "watcher");
112 return nullptr;
113 }
114 std::vector<ListenerRule> rules;
115 napi_value jsRulesVal = NapiHiSysEventUtil::GetPropertyByName(env, params[ADD_LISTENER_LISTENER_PARAM_INDEX],
116 RULES_ATTR);
117 if (auto ret = NapiHiSysEventUtil::ParseListenerRules(env, jsRulesVal, rules);
118 ret != SUCCESS) {
119 HiLog::Error(LABEL, "failed to parse watch rules, result code is %{public}d.", ret);
120 return nullptr;
121 }
122 CallbackContext* callbackContext = new CallbackContext();
123 callbackContext->env = env;
124 callbackContext->threadId = syscall(SYS_gettid);
125 napi_create_reference(env, params[ADD_LISTENER_LISTENER_PARAM_INDEX], 1, &callbackContext->ref);
126 std::shared_ptr<NapiHiSysEventListener> listener = std::make_shared<NapiHiSysEventListener>(callbackContext);
127 auto ret = HiSysEventBaseManager::AddListener(listener, rules);
128 if (ret != NAPI_SUCCESS) {
129 HiLog::Error(LABEL, "failed to add event listener, result code is %{public}d.", ret);
130 NapiHiSysEventUtil::ThrowErrorByRet(env, ret);
131 return nullptr;
132 }
133 listeners[callbackContext->ref] = std::make_pair(callbackContext->threadId, listener);
134 return nullptr;
135 }
136
RemoveWatcher(napi_env env,napi_callback_info info)137 static napi_value RemoveWatcher(napi_env env, napi_callback_info info)
138 {
139 size_t paramNum = REMOVE_LISTENER_FUNC_MAX_PARAM_NUM;
140 napi_value params[REMOVE_LISTENER_FUNC_MAX_PARAM_NUM] = {0};
141 napi_value thisArg = nullptr;
142 void* data = nullptr;
143 NAPI_CALL(env, napi_get_cb_info(env, info, ¶mNum, params, &thisArg, &data));
144 if (paramNum < REMOVE_LISTENER_FUNC_MAX_PARAM_NUM) {
145 HiLog::Error(LABEL, "count of parameters is less than %{public}zu.", REMOVE_LISTENER_FUNC_MAX_PARAM_NUM);
146 NapiHiSysEventUtil::ThrowParamMandatoryError(env, "watcher");
147 return nullptr;
148 }
149 auto iter = NapiHiSysEventUtil::CompareAndReturnCacheItem<NapiHiSysEventListener>(env,
150 params[REMOVE_LISTENER_LISTENER_PARAM_INDEX], listeners);
151 if (iter == listeners.end()) {
152 HiLog::Error(LABEL, "listener not exist.");
153 NapiHiSysEventUtil::ThrowErrorByRet(env, ERR_NAPI_LISTENER_NOT_FOUND);
154 return nullptr;
155 }
156 listeners.erase(iter->first);
157 if (auto ret = HiSysEventBaseManager::RemoveListener(iter->second.second);
158 ret != NAPI_SUCCESS) {
159 HiLog::Error(LABEL, "failed to remove event listener, result code is %{public}d.", ret);
160 NapiHiSysEventUtil::ThrowErrorByRet(env, ret);
161 }
162 return nullptr;
163 }
164
Query(napi_env env,napi_callback_info info)165 static napi_value Query(napi_env env, napi_callback_info info)
166 {
167 size_t paramNum = QUERY_FUNC_MAX_PARAM_NUM;
168 napi_value params[QUERY_FUNC_MAX_PARAM_NUM] = {0};
169 napi_value thisArg = nullptr;
170 void* data = nullptr;
171 NAPI_CALL(env, napi_get_cb_info(env, info, ¶mNum, params, &thisArg, &data));
172 if (paramNum < QUERY_FUNC_MAX_PARAM_NUM) {
173 std::unordered_map<int32_t, std::string> paramError = {
174 {QUERY_QUERY_ARG_PARAM_INDEX, "queryArg"},
175 {QUERY_RULE_ARRAY_PARAM_INDEX, "rules"},
176 {QUERY_QUERIER_PARAM_INDEX, "querier"},
177 };
178 HiLog::Error(LABEL, "count of parameters is less than %{public}zu.", QUERY_FUNC_MAX_PARAM_NUM);
179 NapiHiSysEventUtil::ThrowParamMandatoryError(env, paramError.at(paramNum));
180 return nullptr;
181 }
182 QueryArg queryArg = { DEFAULT_TIME_STAMP, DEFAULT_TIME_STAMP, DEFAULT_EVENT_COUNT };
183 if (auto ret = NapiHiSysEventUtil::ParseQueryArg(env, params[QUERY_QUERY_ARG_PARAM_INDEX], queryArg);
184 ret != SUCCESS) {
185 HiLog::Error(LABEL, "failed to parse query arg, result code is %{public}d.", ret);
186 return nullptr;
187 }
188 std::vector<QueryRule> rules;
189 if (auto ret = NapiHiSysEventUtil::ParseQueryRules(env, params[QUERY_RULE_ARRAY_PARAM_INDEX], rules);
190 ret != SUCCESS) {
191 HiLog::Error(LABEL, "failed to parse query rules, result code is %{public}d.", ret);
192 return nullptr;
193 }
194 CallbackContext* callbackContext = new CallbackContext();
195 callbackContext->env = env;
196 callbackContext->threadId = syscall(SYS_gettid);
197 napi_create_reference(env, params[QUERY_QUERIER_PARAM_INDEX], 1, &callbackContext->ref);
198 std::shared_ptr<NapiHiSysEventQuerier> querier = std::make_shared<NapiHiSysEventQuerier>(callbackContext,
199 [] (const napi_env env, const napi_ref ref) {
200 napi_value querier = nullptr;
201 napi_get_reference_value(env, ref, &querier);
202 auto iter = NapiHiSysEventUtil::CompareAndReturnCacheItem<NapiHiSysEventQuerier>(env, querier, queriers);
203 if (iter != queriers.end()) {
204 queriers.erase(iter->first);
205 }
206 });
207 auto ret = HiSysEventBaseManager::Query(queryArg, rules, querier);
208 if (ret != NAPI_SUCCESS) {
209 HiLog::Error(LABEL, "failed to query hisysevent, result code is %{public}d.", ret);
210 NapiHiSysEventUtil::ThrowErrorByRet(env, ret);
211 }
212 queriers[callbackContext->ref] = std::make_pair(callbackContext->threadId, querier);
213 return nullptr;
214 }
215
216 EXTERN_C_START
Init(napi_env env,napi_value exports)217 static napi_value Init(napi_env env, napi_value exports)
218 {
219 napi_property_descriptor desc[] = {
220 DECLARE_NAPI_FUNCTION("write", Write),
221 DECLARE_NAPI_FUNCTION("addWatcher", AddWatcher),
222 DECLARE_NAPI_FUNCTION("removeWatcher", RemoveWatcher),
223 DECLARE_NAPI_FUNCTION("query", Query),
224 };
225 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(napi_property_descriptor), desc));
226
227 // init EventType class, Event class and Param class
228 InitNapiClass(env, exports);
229
230 return exports;
231 }
232 EXTERN_C_END
233
234 static napi_module _module = {
235 .nm_version = 1,
236 .nm_flags = 0,
237 .nm_filename = nullptr,
238 .nm_register_func = Init,
239 .nm_modname = "hiSysEvent",
240 .nm_priv = ((void*)0),
241 .reserved = {0}
242 };
243
RegisterModule(void)244 extern "C" __attribute__((constructor)) void RegisterModule(void)
245 {
246 napi_module_register(&_module);
247 }
248