diff --git a/interfaces/kits/common/include/napi_common.h b/interfaces/kits/common/include/napi_common.h index 22c77629348377422dec8c36bfe70c16d1810fd0..d08f4e1b05ab8bd83655475aac2a4bca03367b06 100644 --- a/interfaces/kits/common/include/napi_common.h +++ b/interfaces/kits/common/include/napi_common.h @@ -22,6 +22,7 @@ namespace OHOS { namespace Security { namespace AccessToken { +const int ARGS_ONE = 1; const int ARGS_TWO = 2; const int ARGS_THREE = 3; const int ARGS_FIVE = 5; diff --git a/interfaces/kits/privacy/napi/include/napi_context_common.h b/interfaces/kits/privacy/napi/include/napi_context_common.h index 2cf08dbf8f0dd0c46b13915fec40519a59468339..af4e2217ec0e1f6444457f391563cd2dec4cf275 100644 --- a/interfaces/kits/privacy/napi/include/napi_context_common.h +++ b/interfaces/kits/privacy/napi/include/napi_context_common.h @@ -15,8 +15,14 @@ #ifndef INTERFACES_PRIVACY_KITS_NAPI_CONTEXT_COMMON_H #define INTERFACES_PRIVACY_KITS_NAPI_CONTEXT_COMMON_H +#include +#include "accesstoken_log.h" +#include "active_change_response_info.h" #include "napi/native_api.h" #include "napi/native_node_api.h" +#include "napi_common.h" +#include "perm_active_status_customized_cbk.h" +#include "privacy_kit.h" namespace OHOS { namespace Security { @@ -30,6 +36,37 @@ struct PrivacyAsyncWorkData { napi_deferred deferred = nullptr; napi_ref callbackRef = nullptr; }; + +class PermActiveStatusPtr : public PermActiveStatusCustomizedCbk { +public: + explicit PermActiveStatusPtr(const std::vector& permList); + ~PermActiveStatusPtr(); + void ActiveStatusChangeCallback(ActiveChangeResponse& result) override; + void SetEnv(const napi_env& env); + void SetCallbackRef(const napi_ref& ref); +private: + napi_env env_ = nullptr; + napi_ref ref_ = nullptr; +}; + +struct PermActiveStatusWorker { + napi_env env = nullptr; + napi_ref ref = nullptr; + ActiveChangeResponse result; + PermActiveStatusPtr* subscriber = nullptr; // this +}; + +struct PermActiveChangeContext { + virtual ~PermActiveChangeContext(); + + napi_env env = nullptr; + napi_ref callbackRef = nullptr; + std::string type; + std::shared_ptr subscriber = nullptr; +}; + +void UvQueueWorkActiveStatusChange(uv_work_t* work, int status); +bool ConvertActiveChangeResponse(napi_env env, napi_value value, const ActiveChangeResponse& result); } // namespace AccessToken } // namespace Security } // namespace OHOS diff --git a/interfaces/kits/privacy/napi/include/native_module.h b/interfaces/kits/privacy/napi/include/native_module.h index 0e6d833bcfab3e41ffe7eeba0a62ef3d5d0f65a8..966e130c227e0700d1605dcbb2e8f8372f695b3d 100644 --- a/interfaces/kits/privacy/napi/include/native_module.h +++ b/interfaces/kits/privacy/napi/include/native_module.h @@ -19,7 +19,7 @@ #include #include #include - +#include "napi_context_common.h" #include "napi/native_api.h" #include "napi/native_node_api.h" diff --git a/interfaces/kits/privacy/napi/include/permission_record_manager_napi.h b/interfaces/kits/privacy/napi/include/permission_record_manager_napi.h index fbe729de1cd6931d00aca1ff66028ed861c48165..9de5b1b59dad10a033f465a950c09bad2915fa59 100644 --- a/interfaces/kits/privacy/napi/include/permission_record_manager_napi.h +++ b/interfaces/kits/privacy/napi/include/permission_record_manager_napi.h @@ -16,12 +16,13 @@ #define INTERFACES_KITS_PERMISSION_USED_MANAGER_NAPI_H #include +#include #include "access_token.h" +#include "active_change_response_info.h" #include "napi/native_api.h" #include "napi/native_node_api.h" #include "napi_context_common.h" -#include "napi_common.h" #include "permission_used_request.h" #include "permission_used_result.h" @@ -40,10 +41,18 @@ struct RecordManagerAsyncContext : public PrivacyAsyncWorkData { int32_t retCode = -1; }; +typedef PermActiveChangeContext RegisterPermActiveChangeContext; + +struct UnregisterPermActiveChangeContext : public PermActiveChangeContext { + std::vector permList; +}; + napi_value AddPermissionUsedRecord(napi_env env, napi_callback_info cbinfo); napi_value StartUsingPermission(napi_env env, napi_callback_info cbinfo); napi_value StopUsingPermission(napi_env env, napi_callback_info cbinfo); napi_value GetPermissionUsedRecords(napi_env env, napi_callback_info cbinfo); +napi_value RegisterPermActiveChangeCallback(napi_env env, napi_callback_info cbInfo); +napi_value UnregisterPermActiveChangeCallback(napi_env env, napi_callback_info cbInfo); } // namespace AccessToken } // namespace Security } // namespace OHOS diff --git a/interfaces/kits/privacy/napi/src/napi_context_common.cpp b/interfaces/kits/privacy/napi/src/napi_context_common.cpp index b36467c88ef4ffdb3d52e3ba2a57f14609e643cd..d9eae5ebe5fa865cb101fa454a5dae861fa5de42 100644 --- a/interfaces/kits/privacy/napi/src/napi_context_common.cpp +++ b/interfaces/kits/privacy/napi/src/napi_context_common.cpp @@ -17,6 +17,9 @@ namespace OHOS { namespace Security { namespace AccessToken { +namespace { +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, SECURITY_DOMAIN_PRIVACY, "PrivacyContextCommonNapi"}; +} // namespace PrivacyAsyncWorkData::PrivacyAsyncWorkData(napi_env envValue) { env = envValue; @@ -34,6 +37,112 @@ PrivacyAsyncWorkData::~PrivacyAsyncWorkData() asyncWork = nullptr; } } + +PermActiveChangeContext::~PermActiveChangeContext() +{ + if (callbackRef != nullptr) { + napi_delete_reference(env, callbackRef); + callbackRef = nullptr; + } +} + +PermActiveStatusPtr::PermActiveStatusPtr(const std::vector& permList) + : PermActiveStatusCustomizedCbk(permList) +{} + +PermActiveStatusPtr::~PermActiveStatusPtr() +{} + +void PermActiveStatusPtr::SetEnv(const napi_env& env) +{ + env_ = env; +} + +void PermActiveStatusPtr::SetCallbackRef(const napi_ref& ref) +{ + ref_ = ref; +} + +void PermActiveStatusPtr::ActiveStatusChangeCallback(ActiveChangeResponse& result) +{ + uv_loop_s* loop = nullptr; + NAPI_CALL_RETURN_VOID(env_, napi_get_uv_event_loop(env_, &loop)); + if (loop == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "loop instance is nullptr"); + return; + } + uv_work_t* work = new (std::nothrow) uv_work_t; + if (work == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "insufficient memory for work!"); + return; + } + std::unique_ptr uvWorkPtr {work}; + PermActiveStatusWorker* permActiveStatusWorker = new (std::nothrow) PermActiveStatusWorker(); + if (permActiveStatusWorker == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "insufficient memory for RegisterPermStateChangeWorker!"); + return; + } + std::unique_ptr workPtr {permActiveStatusWorker}; + permActiveStatusWorker->env = env_; + permActiveStatusWorker->ref = ref_; + permActiveStatusWorker->result = result; + ACCESSTOKEN_LOG_DEBUG(LABEL, + "result: tokenID = %{public}d, permissionName = %{public}s, type = %{public}d", + result.tokenID, result.permissionName.c_str(), result.type); + permActiveStatusWorker->subscriber = this; + work->data = reinterpret_cast(permActiveStatusWorker); + NAPI_CALL_RETURN_VOID(env_, + uv_queue_work(loop, work, [](uv_work_t* work) {}, UvQueueWorkActiveStatusChange)); + uvWorkPtr.release(); + workPtr.release(); +} + +void UvQueueWorkActiveStatusChange(uv_work_t* work, int status) +{ + (void)status; + if (work == nullptr || work->data == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "work == nullptr || work->data == nullptr"); + return; + } + std::unique_ptr uvWorkPtr {work}; + PermActiveStatusWorker* permActiveStatusData = reinterpret_cast(work->data); + std::unique_ptr workPtr {permActiveStatusData}; + napi_value result[ARGS_ONE] = {nullptr}; + NAPI_CALL_RETURN_VOID(permActiveStatusData->env, + napi_create_array(permActiveStatusData->env, &result[PARAM0])); + if (!ConvertActiveChangeResponse(permActiveStatusData->env, result[PARAM0], permActiveStatusData->result)) { + ACCESSTOKEN_LOG_ERROR(LABEL, "ConvertActiveChangeResponse failed"); + return; + } + napi_value undefined = nullptr; + napi_value callback = nullptr; + napi_value resultout = nullptr; + NAPI_CALL_RETURN_VOID(permActiveStatusData->env, + napi_get_undefined(permActiveStatusData->env, &undefined)); + NAPI_CALL_RETURN_VOID(permActiveStatusData->env, + napi_get_reference_value(permActiveStatusData->env, permActiveStatusData->ref, &callback)); + NAPI_CALL_RETURN_VOID(permActiveStatusData->env, + napi_call_function(permActiveStatusData->env, undefined, callback, ARGS_ONE, &result[PARAM0], &resultout)); +} + +bool ConvertActiveChangeResponse(napi_env env, napi_value value, const ActiveChangeResponse& result) +{ + napi_value element; + NAPI_CALL_BASE(env, napi_create_uint32(env, result.tokenID, &element), false); + NAPI_CALL_BASE(env, napi_set_named_property(env, value, "tokenId", element), false); + element = nullptr; + NAPI_CALL_BASE(env, napi_create_string_utf8(env, result.permissionName.c_str(), + NAPI_AUTO_LENGTH, &element), false); + NAPI_CALL_BASE(env, napi_set_named_property(env, value, "permissionName", element), false); + element = nullptr; + NAPI_CALL_BASE(env, napi_create_string_utf8(env, result.deviceId.c_str(), + NAPI_AUTO_LENGTH, &element), false); + NAPI_CALL_BASE(env, napi_set_named_property(env, value, "deviceId", element), false); + element = nullptr; + NAPI_CALL_BASE(env, napi_create_int32(env, result.type, &element), false); + NAPI_CALL_BASE(env, napi_set_named_property(env, value, "activeStatus", element), false); + return true; +} } // namespace AccessToken } // namespace Security } // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/privacy/napi/src/native_module.cpp b/interfaces/kits/privacy/napi/src/native_module.cpp index a5f2e7d70b2f11e02f8cd0aea09d3aa6b8319292..f9beea9ab1b8970ae5d99346c5ab92ea438f5c75 100644 --- a/interfaces/kits/privacy/napi/src/native_module.cpp +++ b/interfaces/kits/privacy/napi/src/native_module.cpp @@ -29,7 +29,9 @@ static napi_value Init(napi_env env, napi_value exports) DECLARE_NAPI_FUNCTION("addPermissionUsedRecord", AddPermissionUsedRecord), DECLARE_NAPI_FUNCTION("startUsingPermission", StartUsingPermission), DECLARE_NAPI_FUNCTION("stopUsingPermission", StopUsingPermission), - DECLARE_NAPI_FUNCTION("getPermissionUsedRecords", GetPermissionUsedRecords) + DECLARE_NAPI_FUNCTION("getPermissionUsedRecords", GetPermissionUsedRecords), + DECLARE_NAPI_FUNCTION("on", RegisterPermActiveChangeCallback), + DECLARE_NAPI_FUNCTION("off", UnregisterPermActiveChangeCallback) }; napi_define_properties(env, exports, sizeof(descriptor) / sizeof(descriptor[0]), descriptor); @@ -45,8 +47,24 @@ static napi_value Init(napi_env env, napi_value exports) napi_create_int32(env, FLAG_PERMISSION_USAGE_DETAIL, &prop); napi_set_named_property(env, permissionUsageFlag, "FLAG_PERMISSION_USAGE_DETAIL", prop); + napi_value permActiveStatus = nullptr; + napi_create_object(env, &permActiveStatus); // create enmu permActiveStatus + + prop = nullptr; + napi_create_int32(env, PERM_INACTIVE, &prop); + napi_set_named_property(env, permActiveStatus, "PERM_INACTIVE", prop); + + prop = nullptr; + napi_create_int32(env, PERM_ACTIVE_IN_FOREGROUND, &prop); + napi_set_named_property(env, permActiveStatus, "PERM_ACTIVE_IN_FOREGROUND", prop); + + prop = nullptr; + napi_create_int32(env, PERM_ACTIVE_IN_BACKGROUND, &prop); + napi_set_named_property(env, permActiveStatus, "PERM_ACTIVE_IN_BACKGROUND", prop); + napi_property_descriptor exportFuncs[] = { DECLARE_NAPI_PROPERTY("PermissionUsageFlag ", permissionUsageFlag), + DECLARE_NAPI_PROPERTY("PermissionActiveStatus ", permActiveStatus) }; napi_define_properties(env, exports, sizeof(exportFuncs) / sizeof(exportFuncs[0]), exportFuncs); diff --git a/interfaces/kits/privacy/napi/src/permission_record_manager_napi.cpp b/interfaces/kits/privacy/napi/src/permission_record_manager_napi.cpp index 7798f1e7b900489a85d78f5880d9227b40d40707..e41f10b75cc28ec645b52bc24a20963279a188f8 100644 --- a/interfaces/kits/privacy/napi/src/permission_record_manager_napi.cpp +++ b/interfaces/kits/privacy/napi/src/permission_record_manager_napi.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ #include "permission_record_manager_napi.h" - +#include #include "privacy_kit.h" #include "accesstoken_log.h" #include "napi_context_common.h" @@ -24,6 +24,9 @@ namespace OHOS { namespace Security { namespace AccessToken { +std::mutex g_lockForPermActiveChangeSubscribers; +std::vector g_permActiveChangeSubscribers; +static const size_t MAX_CALLBACK_SIZE = 200; namespace { static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, SECURITY_DOMAIN_PRIVACY, "PermissionRecordManagerNapi"}; } // namespace @@ -368,7 +371,6 @@ static void StartUsingPermissionComplete(napi_env env, napi_status status, void* napi_value StartUsingPermission(napi_env env, napi_callback_info cbinfo) { ACCESSTOKEN_LOG_DEBUG(LABEL, "StartUsingPermission begin."); - auto *asyncContext = new (std::nothrow) RecordManagerAsyncContext(env); if (asyncContext == nullptr) { ACCESSTOKEN_LOG_ERROR(LABEL, "new struct fail."); @@ -548,6 +550,197 @@ napi_value GetPermissionUsedRecords(napi_env env, napi_callback_info cbinfo) callbackPtr.release(); return result; } + +static bool ParseInputToRegister(const napi_env env, const napi_callback_info cbInfo, + RegisterPermActiveChangeContext& registerPermActiveChangeContext) +{ + size_t argc = ARGS_THREE; + napi_value argv[ARGS_THREE] = {nullptr}; + napi_value thisVar = nullptr; + napi_ref callback = nullptr; + if (napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, NULL) != napi_ok) { + ACCESSTOKEN_LOG_ERROR(LABEL, "napi_get_cb_info failed"); + return false; + } + std::string type = ParseString(env, argv[PARAM0]); + std::vector permList = ParseStringArray(env, argv[PARAM1]); + std::sort(permList.begin(), permList.end()); + napi_valuetype valueType = napi_undefined; + if (napi_typeof(env, argv[PARAM2], &valueType) != napi_ok) { + ACCESSTOKEN_LOG_ERROR(LABEL, "get napi type failed"); + return false; + } // get PRARM[2] callback type + if (valueType != napi_function) { + ACCESSTOKEN_LOG_ERROR(LABEL, "value type dismatch"); + return false; + } + if (napi_create_reference(env, argv[PARAM2], 1, &callback) != napi_ok) { + ACCESSTOKEN_LOG_ERROR(LABEL, "napi_create_reference failed"); + return false; + } + registerPermActiveChangeContext.env = env; + registerPermActiveChangeContext.callbackRef = callback; + registerPermActiveChangeContext.type = type; + registerPermActiveChangeContext.subscriber = std::make_shared(permList); + registerPermActiveChangeContext.subscriber->SetEnv(env); + registerPermActiveChangeContext.subscriber->SetCallbackRef(callback); + return true; +} + +static bool ParseInputToUnregister(const napi_env env, const napi_callback_info cbInfo, + UnregisterPermActiveChangeContext& unregisterPermActiveChangeContext) +{ + size_t argc = ARGS_THREE; + napi_value argv[ARGS_THREE] = {nullptr}; + napi_value thisVar = nullptr; + napi_ref callback = nullptr; + if (napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, NULL) != napi_ok) { + ACCESSTOKEN_LOG_ERROR(LABEL, "napi_get_cb_info failed"); + return false; + } + std::string type = ParseString(env, argv[PARAM0]); + std::vector permList = ParseStringArray(env, argv[PARAM1]); + std::sort(permList.begin(), permList.end()); + napi_valuetype valueType = napi_undefined; + if (argc >= ARGS_THREE) { + if (napi_typeof(env, argv[PARAM2], &valueType) != napi_ok) { + ACCESSTOKEN_LOG_ERROR(LABEL, "get napi type failed"); + return false; + } // get PRARM[2] callback type + if (valueType != napi_function) { + ACCESSTOKEN_LOG_ERROR(LABEL, "value type dismatch"); + return false; + } + if (napi_create_reference(env, argv[PARAM2], 1, &callback) != napi_ok) { + ACCESSTOKEN_LOG_ERROR(LABEL, "napi_create_reference failed"); + return false; + } + } + unregisterPermActiveChangeContext.env = env; + unregisterPermActiveChangeContext.callbackRef = callback; + unregisterPermActiveChangeContext.type = type; + unregisterPermActiveChangeContext.permList = permList; + return true; +} + +static bool IsExistRegister(const PermActiveChangeContext* permActiveChangeContext) +{ + std::vector targetPermList; + permActiveChangeContext->subscriber->GetPermList(targetPermList); + std::lock_guard lock(g_lockForPermActiveChangeSubscribers); + for (const auto& item : g_permActiveChangeSubscribers) { + std::vector permList; + item->subscriber->GetPermList(permList); + if (permList == targetPermList) { + return true; + } + } + return false; +} + +static void DeleteRegisterInVector(PermActiveChangeContext* permActiveChangeContext) +{ + std::vector targetPermList; + permActiveChangeContext->subscriber->GetPermList(targetPermList); + std::lock_guard lock(g_lockForPermActiveChangeSubscribers); + auto item = g_permActiveChangeSubscribers.begin(); + while (item != g_permActiveChangeSubscribers.end()) { + std::vector permList; + (*item)->subscriber->GetPermList(permList); + if (permList == targetPermList) { + delete *item; + *item = nullptr; + g_permActiveChangeSubscribers.erase(item); + return; + } else { + ++item; + } + } +} + +static bool FindAndGetSubscriber(UnregisterPermActiveChangeContext* unregisterPermActiveChangeContext) +{ + std::vector targetPermList = unregisterPermActiveChangeContext->permList; + std::lock_guard lock(g_lockForPermActiveChangeSubscribers); + for (const auto& item : g_permActiveChangeSubscribers) { + std::vector permList; + item->subscriber->GetPermList(permList); + if (permList == targetPermList) { + // targetCallback != nullptr, unregister the subscriber with same permList and callback + unregisterPermActiveChangeContext->subscriber = item->subscriber; + return true; + } + } + return false; +} + +napi_value RegisterPermActiveChangeCallback(napi_env env, napi_callback_info cbInfo) +{ + RegisterPermActiveChangeContext* registerPermActiveChangeContext = + new (std::nothrow) RegisterPermActiveChangeContext(); + if (registerPermActiveChangeContext == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "insufficient memory for subscribeCBInfo!"); + return nullptr; + } + std::unique_ptr callbackPtr {registerPermActiveChangeContext}; + if (!ParseInputToRegister(env, cbInfo, *registerPermActiveChangeContext)) { + return nullptr; + } + if (IsExistRegister(registerPermActiveChangeContext)) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Subscribe failed. The current subscriber has been existed"); + return nullptr; + } + if (PrivacyKit::RegisterPermActiveStatusCallback(registerPermActiveChangeContext->subscriber) != RET_SUCCESS) { + ACCESSTOKEN_LOG_ERROR(LABEL, "RegisterPermActiveStatusCallback failed"); + return nullptr; + } + { + std::lock_guard lock(g_lockForPermActiveChangeSubscribers); + if (g_permActiveChangeSubscribers.size() >= MAX_CALLBACK_SIZE) { + ACCESSTOKEN_LOG_ERROR(LABEL, "subscribers size has reached max value"); + return nullptr; + } + g_permActiveChangeSubscribers.emplace_back(registerPermActiveChangeContext); + } + callbackPtr.release(); + return nullptr; +} + +napi_value UnregisterPermActiveChangeCallback(napi_env env, napi_callback_info cbInfo) +{ + UnregisterPermActiveChangeContext* unregisterPermActiveChangeContext = + new (std::nothrow) UnregisterPermActiveChangeContext(); + if (unregisterPermActiveChangeContext == nullptr) { + ACCESSTOKEN_LOG_ERROR(LABEL, "insufficient memory for subscribeCBInfo!"); + return nullptr; + } + std::unique_ptr callbackPtr {unregisterPermActiveChangeContext}; + if (!ParseInputToUnregister(env, cbInfo, *unregisterPermActiveChangeContext)) { + return nullptr; + } + if (!FindAndGetSubscriber(unregisterPermActiveChangeContext)) { + ACCESSTOKEN_LOG_ERROR(LABEL, "Unsubscribe failed. The current subscriber does not exist"); + return nullptr; + } + if (PrivacyKit::UnRegisterPermActiveStatusCallback(unregisterPermActiveChangeContext->subscriber) == RET_SUCCESS) { + DeleteRegisterInVector(unregisterPermActiveChangeContext); + } else { + ACCESSTOKEN_LOG_ERROR(LABEL, "UnregisterPermActiveChangeCompleted failed"); + } + if (unregisterPermActiveChangeContext->callbackRef != nullptr) { + napi_value results[ARGS_ONE] = {nullptr}; + NAPI_CALL(env, napi_get_null(env, &results[PARAM0])); + napi_value undefined; + NAPI_CALL(env, napi_get_undefined(env, &undefined)); + napi_value resultout = nullptr; + napi_value callback = nullptr; + NAPI_CALL(env, + napi_get_reference_value(env, unregisterPermActiveChangeContext->callbackRef, &callback)); + NAPI_CALL(env, + napi_call_function(env, undefined, callback, ARGS_ONE, &results[PARAM0], &resultout)); + } + return nullptr; +} } // namespace AccessToken } // namespace Security } // namespace OHOS \ No newline at end of file