* Copyright (c) 2022-2023 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 "runninglock_napi.h"
#include <memory>
#include "power_mgr_client.h"
#include "napi_errors.h"
#include "napi_utils.h"
#include "power_common.h"
#include "power_log.h"
#include "runninglock_entity.h"
#ifdef HAS_DFX_HIVIEW_PART
#include "xpower_event_js.h"
#endif
#ifdef POWER_API_METRICS_ENABLE
#include "histogram_plugin_macros.h"
#endif
namespace OHOS {
namespace PowerMgr {
namespace {
constexpr uint32_t CREATE_PROMISE_MAX_ARGC = 2;
constexpr uint32_t CREATE_CALLBACK_MAX_ARGC = 3;
constexpr uint32_t ISSUPPORTED_MAX_ARGC = 1;
constexpr uint32_t HOLD_MAX_ARGC = 1;
constexpr int32_t INDEX_0 = 0;
constexpr int32_t INDEX_1 = 1;
constexpr int32_t INDEX_2 = 2;
#ifdef POWER_API_METRICS_ENABLE
constexpr int32_t HISTOGRAM_API_CALL_COUNT = 1;
#endif
}
napi_value RunningLockNapi::Create(napi_env& env, napi_callback_info& info, napi_ref& napiRunningLockIns)
{
size_t argc = CREATE_CALLBACK_MAX_ARGC;
napi_value argv[argc];
NapiUtils::GetCallbackInfo(env, info, argc, argv);
NapiErrors error;
if (argc != CREATE_CALLBACK_MAX_ARGC && argc != CREATE_PROMISE_MAX_ARGC) {
return error.ThrowError(env, PowerErrors::ERR_PARAM_INVALID);
}
std::unique_ptr<AsyncCallbackInfo> asyncInfo = std::make_unique<AsyncCallbackInfo>();
RETURN_IF_WITH_RET(asyncInfo == nullptr, nullptr);
asyncInfo->GetData().SetRunningLockInstance(napiRunningLockIns);
if (argc == CREATE_CALLBACK_MAX_ARGC) {
#ifdef POWER_API_METRICS_ENABLE
HISTOGRAM_BOOLEAN("BasicServicesKit.PowerManager.createAsync.Boolean", HISTOGRAM_API_CALL_COUNT);
#endif
return CreateAsyncCallback(env, argv, asyncInfo);
}
#ifdef POWER_API_METRICS_ENABLE
HISTOGRAM_BOOLEAN("BasicServicesKit.PowerManager.create.Boolean", HISTOGRAM_API_CALL_COUNT);
#endif
return CreatePromise(env, argv, asyncInfo);
}
napi_value RunningLockNapi::IsSupported(napi_env env, napi_callback_info info)
{
size_t argc = ISSUPPORTED_MAX_ARGC;
napi_value argv[argc];
NapiUtils::GetCallbackInfo(env, info, argc, argv);
NapiErrors error;
if (argc != ISSUPPORTED_MAX_ARGC || !NapiUtils::CheckValueType(env, argv[INDEX_0], napi_number)) {
return error.ThrowError(env, PowerErrors::ERR_PARAM_INVALID);
}
int32_t numType;
napi_get_value_int32(env, argv[INDEX_0], &numType);
RunningLockType type = static_cast<RunningLockType>(numType);
bool isSupported = (type == RunningLockType::RUNNINGLOCK_BACKGROUND) ||
(type == RunningLockType::RUNNINGLOCK_PROXIMITY_SCREEN_CONTROL) ||
(type == RunningLockType::RUNNINGLOCK_BACKGROUND_USER_IDLE &&
PowerMgrClient::GetInstance().IsRunningLockTypeSupported(type));
napi_value result;
napi_get_boolean(env, isSupported, &result);
return result;
}
napi_value RunningLockNapi::Hold(napi_env env, napi_callback_info info)
{
size_t argc = HOLD_MAX_ARGC;
napi_value argv[argc];
napi_value thisArg = NapiUtils::GetCallbackInfo(env, info, argc, argv);
NapiErrors error;
if (argc != HOLD_MAX_ARGC || !NapiUtils::CheckValueType(env, argv[INDEX_0], napi_number)) {
return error.ThrowError(env, PowerErrors::ERR_PARAM_INVALID);
}
int32_t timeOut;
if (napi_ok != napi_get_value_int32(env, argv[INDEX_0], &timeOut)) {
POWER_HILOGE(FEATURE_RUNNING_LOCK, "napi_get_value_uint32 failed");
return nullptr;
}
auto runningLock = UnwrapRunningLock(env, thisArg);
RETURN_IF_WITH_RET(runningLock == nullptr, nullptr);
ErrCode code = runningLock->Lock(timeOut);
if (code == E_PERMISSION_DENIED) {
return error.ThrowError(env, PowerErrors::ERR_PERMISSION_DENIED);
}
#ifdef HAS_DFX_HIVIEW_PART
OHOS::HiviewDFX::ReportXPowerJsStackSysEvent(env, "RunningLockNapi::Hold");
#endif
return nullptr;
}
napi_value RunningLockNapi::IsHolding(napi_env env, napi_callback_info info)
{
size_t argc = 0;
napi_value thisArg = NapiUtils::GetCallbackInfo(env, info, argc, nullptr);
auto runningLock = UnwrapRunningLock(env, thisArg);
RETURN_IF_WITH_RET(runningLock == nullptr, nullptr);
bool isUsed = runningLock->IsUsed();
napi_value result;
napi_get_boolean(env, isUsed, &result);
return result;
}
napi_value RunningLockNapi::UnHold(napi_env env, napi_callback_info info)
{
size_t argc = 0;
napi_value thisArg = NapiUtils::GetCallbackInfo(env, info, argc, nullptr);
auto runningLock = UnwrapRunningLock(env, thisArg);
RETURN_IF_WITH_RET(runningLock == nullptr, nullptr);
ErrCode code = runningLock->UnLock();
NapiErrors error;
if (code == E_PERMISSION_DENIED) {
return error.ThrowError(env, PowerErrors::ERR_PERMISSION_DENIED);
}
return nullptr;
}
napi_value RunningLockNapi::CreateAsyncCallback(
napi_env& env, napi_value argv[], std::unique_ptr<AsyncCallbackInfo>& asyncInfo)
{
bool isStr = NapiUtils::CheckValueType(env, argv[INDEX_0], napi_string);
bool isNum = NapiUtils::CheckValueType(env, argv[INDEX_1], napi_number);
bool isFunc = NapiUtils::CheckValueType(env, argv[INDEX_2], napi_function);
if (!isStr || !isNum || !isFunc) {
POWER_HILOGD(
FEATURE_RUNNING_LOCK, "isStr: %{public}d, isNum: %{public}d, isFunc: %{public}d", isStr, isNum, isFunc);
return asyncInfo->GetError().ThrowError(env, PowerErrors::ERR_PARAM_INVALID);
}
asyncInfo->GetData().SetName(env, argv[INDEX_0]);
asyncInfo->GetData().SetType(env, argv[INDEX_1]);
asyncInfo->CreateCallback(env, argv[INDEX_2]);
AsyncWork(
env, asyncInfo, "CreateAsyncCallback",
[](napi_env env, void* data) {
AsyncCallbackInfo* asyncInfo = reinterpret_cast<AsyncCallbackInfo*>(data);
RETURN_IF(asyncInfo == nullptr);
auto error = asyncInfo->GetData().CreateRunningLock();
asyncInfo->GetError().Error(error);
},
[](napi_env env, napi_status status, void* data) {
AsyncCallbackInfo* asyncInfo = reinterpret_cast<AsyncCallbackInfo*>(data);
RETURN_IF(asyncInfo == nullptr);
napi_value result = asyncInfo->GetData().CreateInstanceForRunningLock(env);
asyncInfo->CallFunction(env, result);
asyncInfo->Release(env);
delete asyncInfo;
});
return nullptr;
}
napi_value RunningLockNapi::CreatePromise(
napi_env& env, napi_value argv[], std::unique_ptr<AsyncCallbackInfo>& asyncInfo)
{
bool isStr = NapiUtils::CheckValueType(env, argv[INDEX_0], napi_string);
bool isNum = NapiUtils::CheckValueType(env, argv[INDEX_1], napi_number);
if (!isStr || !isNum) {
POWER_HILOGW(FEATURE_RUNNING_LOCK, "isStr: %{public}d, isNum: %{public}d", isStr, isNum);
return asyncInfo->GetError().ThrowError(env, PowerErrors::ERR_PARAM_INVALID);
}
napi_value promise;
asyncInfo->CreatePromise(env, promise);
RETURN_IF_WITH_RET(promise == nullptr, nullptr);
asyncInfo->GetData().SetName(env, argv[INDEX_0]);
asyncInfo->GetData().SetType(env, argv[INDEX_1]);
AsyncWork(
env, asyncInfo, "CreatePromise",
[](napi_env env, void* data) {
AsyncCallbackInfo* asyncInfo = reinterpret_cast<AsyncCallbackInfo*>(data);
RETURN_IF(asyncInfo == nullptr);
auto error = asyncInfo->GetData().CreateRunningLock();
asyncInfo->GetError().Error(error);
},
[](napi_env env, napi_status status, void* data) {
AsyncCallbackInfo* asyncInfo = reinterpret_cast<AsyncCallbackInfo*>(data);
RETURN_IF(asyncInfo == nullptr);
if (asyncInfo->GetError().IsError()) {
napi_reject_deferred(env, asyncInfo->GetDeferred(), asyncInfo->GetError().GetNapiError(env));
} else {
napi_value result = asyncInfo->GetData().CreateInstanceForRunningLock(env);
napi_resolve_deferred(env, asyncInfo->GetDeferred(), result);
}
asyncInfo->Release(env);
delete asyncInfo;
});
return promise;
}
void RunningLockNapi::AsyncWork(napi_env& env, std::unique_ptr<AsyncCallbackInfo>& asyncInfo,
const std::string& resourceName, napi_async_execute_callback execute, napi_async_complete_callback complete)
{
napi_value resource = nullptr;
napi_create_string_utf8(env, resourceName.c_str(), NAPI_AUTO_LENGTH, &resource);
napi_create_async_work(env, nullptr, resource, execute, complete,
reinterpret_cast<void*>(asyncInfo.get()), &asyncInfo->GetAsyncWork());
NAPI_CALL_RETURN_VOID(env, napi_queue_async_work_with_qos(env, asyncInfo->GetAsyncWork(), napi_qos_utility));
asyncInfo.release();
}
std::shared_ptr<RunningLock> RunningLockNapi::UnwrapRunningLock(napi_env& env, napi_value& thisArg)
{
RunningLockEntity* entity = nullptr;
if (napi_ok != napi_unwrap(env, thisArg, (void**)&entity)) {
POWER_HILOGE(FEATURE_RUNNING_LOCK, "Cannot unwrap for pointer");
return nullptr;
}
if (entity == nullptr || entity->runningLock == nullptr) {
POWER_HILOGE(FEATURE_RUNNING_LOCK, "Entity runningLock is nullptr");
return nullptr;
}
return entity->runningLock;
}
}
}