/* * Copyright (c) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "napi_hisysevent_init.h" #include <memory> #include <mutex> #include <unordered_map> #include "def.h" #include "hilog/log.h" #include "hisysevent_base_manager.h" #include "napi/native_api.h" #include "napi/native_node_api.h" #include "napi_callback_context.h" #include "napi_hisysevent_listener.h" #include "napi_hisysevent_querier.h" #include "napi_hisysevent_util.h" #include "ret_def.h" using namespace OHOS::HiviewDFX; #undef LOG_DOMAIN #define LOG_DOMAIN 0xD002D08 #undef LOG_TAG #define LOG_TAG "NAPI_HISYSEVENT_JS" namespace { constexpr char RULES_ATTR[] = "rules"; constexpr size_t WRITE_FUNC_MAX_PARAM_NUM = 2; constexpr size_t ADD_LISTENER_FUNC_MAX_PARAM_NUM = 1; constexpr size_t REMOVE_LISTENER_FUNC_MAX_PARAM_NUM = 1; constexpr size_t QUERY_FUNC_MAX_PARAM_NUM = 3; constexpr size_t ADD_LISTENER_LISTENER_PARAM_INDEX = 0; constexpr size_t REMOVE_LISTENER_LISTENER_PARAM_INDEX = 0; constexpr size_t QUERY_QUERY_ARG_PARAM_INDEX = 0; constexpr size_t QUERY_RULE_ARRAY_PARAM_INDEX = 1; constexpr size_t QUERY_QUERIER_PARAM_INDEX = 2; constexpr size_t EXPORT_FUNC_MAX_PARAM_NUM = 2; constexpr size_t EXPORT_QUERY_ARG_PARAM_INDEX = 0; constexpr size_t EXPORT_RULE_ARRAY_PARAM_INDEX = 1; constexpr size_t SUBSCRIBE_FUNC_MAX_PARAM_NUM = 1; constexpr size_t SUBSCRIBE_RULE_ARRAY_PARAM_INDEX = 0; constexpr long long DEFAULT_TIME_STAMP = -1; constexpr int DEFAULT_EVENT_COUNT = 1000; constexpr int TIME_STAMP_LENGTH = 13; using NAPI_LISTENER_PAIR = std::pair<pid_t, std::shared_ptr<NapiHiSysEventListener>>; using NAPI_QUERIER_PAIR = std::pair<pid_t, std::shared_ptr<NapiHiSysEventQuerier>>; std::mutex g_listenerMapMutex; std::unordered_map<napi_ref, NAPI_LISTENER_PAIR> listeners; std::mutex g_querierMapMutex; std::unordered_map<napi_ref, NAPI_QUERIER_PAIR> queriers; } static napi_value Write(napi_env env, napi_callback_info info) { if (!NapiHiSysEventUtil::IsSystemAppCall()) { NapiHiSysEventUtil::ThrowSystemAppPermissionError(env); return nullptr; } size_t paramNum = WRITE_FUNC_MAX_PARAM_NUM; napi_value params[WRITE_FUNC_MAX_PARAM_NUM] = {0}; napi_value thisArg = nullptr; void *data = nullptr; NAPI_CALL(env, napi_get_cb_info(env, info, ¶mNum, params, &thisArg, &data)); napi_value val = nullptr; napi_get_undefined(env, &val); if (paramNum < WRITE_FUNC_MAX_PARAM_NUM - 1) { HILOG_ERROR(LOG_CORE, "count of parameters is not equal to %{public}zu or %{public}zu.", WRITE_FUNC_MAX_PARAM_NUM - 1, WRITE_FUNC_MAX_PARAM_NUM); NapiHiSysEventUtil::ThrowParamMandatoryError(env, "info"); return val; } HiSysEventAsyncContext* asyncContext = new(std::nothrow) HiSysEventAsyncContext { .env = env, .asyncWork = nullptr, .deferred = nullptr, }; if (asyncContext == nullptr) { HILOG_ERROR(LOG_CORE, "failed to new HiSysEventAsyncContext."); return val; } NapiHiSysEventUtil::ParseHiSysEventInfo(env, params, paramNum, asyncContext->eventInfo); NapiHiSysEventAdapter::ParseJsCallerInfo(env, asyncContext->jsCallerInfo); asyncContext->eventWroteResult = SUCCESS; // set callback function if it exists if (paramNum == WRITE_FUNC_MAX_PARAM_NUM) { napi_valuetype lastParamType; napi_typeof(env, params[paramNum - 1], &lastParamType); if (lastParamType == napi_valuetype::napi_function) { napi_create_reference(env, params[paramNum - 1], 1, &asyncContext->callback); } } else if (paramNum > WRITE_FUNC_MAX_PARAM_NUM) { HILOG_WARN(LOG_CORE, "count of params is invalid =%{public}d.", static_cast<int>(paramNum)); } // set promise object if callback function is null napi_value promise = nullptr; napi_get_undefined(env, &promise); if (asyncContext->callback == nullptr) { napi_create_promise(env, &asyncContext->deferred, &promise); } NapiHiSysEventAdapter::Write(env, asyncContext); return promise; } static napi_value AddWatcher(napi_env env, napi_callback_info info) { if (!NapiHiSysEventUtil::IsSystemAppCall()) { NapiHiSysEventUtil::ThrowSystemAppPermissionError(env); return nullptr; } size_t paramNum = ADD_LISTENER_FUNC_MAX_PARAM_NUM; napi_value params[ADD_LISTENER_FUNC_MAX_PARAM_NUM] = {0}; napi_value thisArg = nullptr; void* data = nullptr; NAPI_CALL(env, napi_get_cb_info(env, info, ¶mNum, params, &thisArg, &data)); if (paramNum < ADD_LISTENER_FUNC_MAX_PARAM_NUM) { HILOG_ERROR(LOG_CORE, "count of parameters is less than %{public}zu.", ADD_LISTENER_FUNC_MAX_PARAM_NUM); NapiHiSysEventUtil::ThrowParamMandatoryError(env, "watcher"); return nullptr; } std::vector<ListenerRule> rules; napi_value jsRulesVal = NapiHiSysEventUtil::GetPropertyByName(env, params[ADD_LISTENER_LISTENER_PARAM_INDEX], RULES_ATTR); if (auto ret = NapiHiSysEventUtil::ParseListenerRules(env, jsRulesVal, rules); ret != SUCCESS) { HILOG_ERROR(LOG_CORE, "failed to parse watch rules, result code is %{public}d.", ret); return nullptr; } CallbackContext* callbackContext = new CallbackContext(); callbackContext->env = env; callbackContext->threadId = getproctid(); napi_create_reference(env, params[ADD_LISTENER_LISTENER_PARAM_INDEX], 1, &callbackContext->ref); std::shared_ptr<NapiHiSysEventListener> listener = std::make_shared<NapiHiSysEventListener>(callbackContext); auto ret = HiSysEventBaseManager::AddListener(listener, rules); if (ret != NAPI_SUCCESS) { HILOG_ERROR(LOG_CORE, "failed to add event listener, result code is %{public}d.", ret); NapiHiSysEventUtil::ThrowErrorByRet(env, ret); return nullptr; } std::lock_guard<std::mutex> lock(g_listenerMapMutex); listeners[callbackContext->ref] = std::make_pair(callbackContext->threadId, listener); return nullptr; } static napi_value RemoveWatcher(napi_env env, napi_callback_info info) { if (!NapiHiSysEventUtil::IsSystemAppCall()) { NapiHiSysEventUtil::ThrowSystemAppPermissionError(env); return nullptr; } size_t paramNum = REMOVE_LISTENER_FUNC_MAX_PARAM_NUM; napi_value params[REMOVE_LISTENER_FUNC_MAX_PARAM_NUM] = {0}; napi_value thisArg = nullptr; void* data = nullptr; NAPI_CALL(env, napi_get_cb_info(env, info, ¶mNum, params, &thisArg, &data)); if (paramNum < REMOVE_LISTENER_FUNC_MAX_PARAM_NUM) { HILOG_ERROR(LOG_CORE, "count of parameters is less than %{public}zu.", REMOVE_LISTENER_FUNC_MAX_PARAM_NUM); NapiHiSysEventUtil::ThrowParamMandatoryError(env, "watcher"); return nullptr; } auto iter = NapiHiSysEventUtil::CompareAndReturnCacheItem<NapiHiSysEventListener>(env, params[REMOVE_LISTENER_LISTENER_PARAM_INDEX], listeners); if (iter == listeners.end()) { HILOG_ERROR(LOG_CORE, "listener not exist."); NapiHiSysEventUtil::ThrowErrorByRet(env, ERR_NAPI_LISTENER_NOT_FOUND); return nullptr; } if (auto ret = HiSysEventBaseManager::RemoveListener(iter->second.second); ret != NAPI_SUCCESS) { HILOG_ERROR(LOG_CORE, "failed to remove event listener, result code is %{public}d.", ret); NapiHiSysEventUtil::ThrowErrorByRet(env, ret); return nullptr; } std::lock_guard<std::mutex> lock(g_listenerMapMutex); listeners.erase(iter->first); return nullptr; } static napi_value Query(napi_env env, napi_callback_info info) { if (!NapiHiSysEventUtil::IsSystemAppCall()) { NapiHiSysEventUtil::ThrowSystemAppPermissionError(env); return nullptr; } size_t paramNum = QUERY_FUNC_MAX_PARAM_NUM; napi_value params[QUERY_FUNC_MAX_PARAM_NUM] = {0}; napi_value thisArg = nullptr; void* data = nullptr; NAPI_CALL(env, napi_get_cb_info(env, info, ¶mNum, params, &thisArg, &data)); if (paramNum < QUERY_FUNC_MAX_PARAM_NUM) { std::unordered_map<int32_t, std::string> paramError = { {QUERY_QUERY_ARG_PARAM_INDEX, "queryArg"}, {QUERY_RULE_ARRAY_PARAM_INDEX, "rules"}, {QUERY_QUERIER_PARAM_INDEX, "querier"}, }; HILOG_ERROR(LOG_CORE, "count of parameters is less than %{public}zu.", QUERY_FUNC_MAX_PARAM_NUM); NapiHiSysEventUtil::ThrowParamMandatoryError(env, paramError.at(paramNum)); return nullptr; } QueryArg queryArg = { DEFAULT_TIME_STAMP, DEFAULT_TIME_STAMP, DEFAULT_EVENT_COUNT }; if (auto ret = NapiHiSysEventUtil::ParseQueryArg(env, params[QUERY_QUERY_ARG_PARAM_INDEX], queryArg); ret != SUCCESS) { HILOG_ERROR(LOG_CORE, "failed to parse query arg, result code is %{public}d.", ret); return nullptr; } std::vector<QueryRule> rules; if (auto ret = NapiHiSysEventUtil::ParseQueryRules(env, params[QUERY_RULE_ARRAY_PARAM_INDEX], rules); ret != SUCCESS) { HILOG_ERROR(LOG_CORE, "failed to parse query rules, result code is %{public}d.", ret); return nullptr; } if (NapiHiSysEventUtil::IsNullOrUndefined(env, params[QUERY_QUERIER_PARAM_INDEX])) { NapiHiSysEventUtil::ThrowParamTypeError(env, "querier", "Querier"); HILOG_ERROR(LOG_CORE, "querier is null or undefined."); return nullptr; } CallbackContext* callbackContext = new CallbackContext(); callbackContext->env = env; callbackContext->threadId = getproctid(); napi_create_reference(env, params[QUERY_QUERIER_PARAM_INDEX], 1, &callbackContext->ref); std::shared_ptr<NapiHiSysEventQuerier> querier = std::make_shared<NapiHiSysEventQuerier>(callbackContext, [] (const napi_env env, const napi_ref ref) { napi_value querier = nullptr; napi_get_reference_value(env, ref, &querier); auto iter = NapiHiSysEventUtil::CompareAndReturnCacheItem<NapiHiSysEventQuerier>(env, querier, queriers); std::lock_guard<std::mutex> lock(g_querierMapMutex); if (iter != queriers.end()) { queriers.erase(iter->first); } }); auto ret = HiSysEventBaseManager::Query(queryArg, rules, querier); if (ret != NAPI_SUCCESS) { HILOG_ERROR(LOG_CORE, "failed to query hisysevent, result code is %{public}d.", ret); NapiHiSysEventUtil::ThrowErrorByRet(env, ret); } std::lock_guard<std::mutex> lock(g_querierMapMutex); queriers[callbackContext->ref] = std::make_pair(callbackContext->threadId, querier); return nullptr; } static napi_value ExportSysEvents(napi_env env, napi_callback_info info) { if (!NapiHiSysEventUtil::IsSystemAppCall()) { NapiHiSysEventUtil::ThrowSystemAppPermissionError(env); return nullptr; } size_t paramNum = EXPORT_FUNC_MAX_PARAM_NUM; napi_value params[EXPORT_FUNC_MAX_PARAM_NUM] = {0}; napi_value thisArg = nullptr; void* data = nullptr; NAPI_CALL(env, napi_get_cb_info(env, info, ¶mNum, params, &thisArg, &data)); if (paramNum < EXPORT_FUNC_MAX_PARAM_NUM) { std::unordered_map<int32_t, std::string> paramError = { {EXPORT_QUERY_ARG_PARAM_INDEX, "queryArg"}, {EXPORT_RULE_ARRAY_PARAM_INDEX, "rules"}, }; HILOG_ERROR(LOG_CORE, "count of parameters is less than %{public}zu.", EXPORT_FUNC_MAX_PARAM_NUM); NapiHiSysEventUtil::ThrowParamMandatoryError(env, paramError.at(paramNum)); return nullptr; } QueryArg queryArg = { DEFAULT_TIME_STAMP, DEFAULT_TIME_STAMP, DEFAULT_EVENT_COUNT }; if (auto ret = NapiHiSysEventUtil::ParseQueryArg(env, params[EXPORT_QUERY_ARG_PARAM_INDEX], queryArg); ret != SUCCESS) { HILOG_ERROR(LOG_CORE, "failed to parse query arg, result code is %{public}d.", ret); return nullptr; } std::vector<QueryRule> rules; if (auto ret = NapiHiSysEventUtil::ParseQueryRules(env, params[EXPORT_RULE_ARRAY_PARAM_INDEX], rules); ret != SUCCESS) { HILOG_ERROR(LOG_CORE, "failed to parse query rules, result code is %{public}d.", ret); return nullptr; } auto ret = HiSysEventBaseManager::Export(queryArg, rules); if (std::to_string(ret).length() < TIME_STAMP_LENGTH) { HILOG_ERROR(LOG_CORE, "failed to export event"); int32_t retCode = static_cast<int32_t>(ret); NapiHiSysEventUtil::ThrowErrorByRet(env, retCode); return nullptr; } napi_value result = nullptr; NapiHiSysEventUtil::CreateInt64Value(env, ret, result); return result; } static napi_value Subscribe(napi_env env, napi_callback_info info) { if (!NapiHiSysEventUtil::IsSystemAppCall()) { NapiHiSysEventUtil::ThrowSystemAppPermissionError(env); return nullptr; } size_t paramNum = SUBSCRIBE_FUNC_MAX_PARAM_NUM; napi_value params[SUBSCRIBE_FUNC_MAX_PARAM_NUM] = {0}; napi_value thisArg = nullptr; void* data = nullptr; NAPI_CALL(env, napi_get_cb_info(env, info, ¶mNum, params, &thisArg, &data)); if (paramNum < SUBSCRIBE_FUNC_MAX_PARAM_NUM) { HILOG_ERROR(LOG_CORE, "count of parameters is less than %{public}zu.", SUBSCRIBE_FUNC_MAX_PARAM_NUM); NapiHiSysEventUtil::ThrowParamMandatoryError(env, "rules"); return nullptr; } std::vector<QueryRule> rules; if (auto ret = NapiHiSysEventUtil::ParseQueryRules(env, params[SUBSCRIBE_RULE_ARRAY_PARAM_INDEX], rules); ret != SUCCESS) { HILOG_ERROR(LOG_CORE, "failed to parse query rules, result code is %{public}d.", ret); return nullptr; } auto ret = HiSysEventBaseManager::Subscribe(rules); if (std::to_string(ret).length() < TIME_STAMP_LENGTH) { HILOG_ERROR(LOG_CORE, "failed to subscribe event."); int32_t retCode = static_cast<int32_t>(ret); NapiHiSysEventUtil::ThrowErrorByRet(env, retCode); return nullptr; } napi_value result = nullptr; NapiHiSysEventUtil::CreateInt64Value(env, ret, result); return result; } static napi_value Unsubscribe(napi_env env, napi_callback_info info) { if (!NapiHiSysEventUtil::IsSystemAppCall()) { NapiHiSysEventUtil::ThrowSystemAppPermissionError(env); return nullptr; } auto ret = HiSysEventBaseManager::Unsubscribe(); if (ret != NAPI_SUCCESS) { HILOG_ERROR(LOG_CORE, "failed to unsubscribe, result code is %{public}d.", ret); int32_t retCode = static_cast<int32_t>(ret); NapiHiSysEventUtil::ThrowErrorByRet(env, retCode); } return nullptr; } EXTERN_C_START static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor desc[] = { DECLARE_NAPI_FUNCTION("write", Write), DECLARE_NAPI_FUNCTION("addWatcher", AddWatcher), DECLARE_NAPI_FUNCTION("removeWatcher", RemoveWatcher), DECLARE_NAPI_FUNCTION("query", Query), DECLARE_NAPI_FUNCTION("exportSysEvents", ExportSysEvents), DECLARE_NAPI_FUNCTION("subscribe", Subscribe), DECLARE_NAPI_FUNCTION("unsubscribe", Unsubscribe), }; NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(napi_property_descriptor), desc)); // init EventType class, Event class and Param class InitNapiClass(env, exports); return exports; } EXTERN_C_END static napi_module _module = { .nm_version = 1, .nm_flags = 0, .nm_filename = nullptr, .nm_register_func = Init, .nm_modname = "hiSysEvent", .nm_priv = ((void*)0), .reserved = {0} }; extern "C" __attribute__((constructor)) void RegisterModule(void) { napi_module_register(&_module); }