1/*
2 * Copyright (c) 2022-2023 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 "runninglock_napi.h"
17
18#include <memory>
19
20#include "napi_errors.h"
21#include "napi_utils.h"
22#include "power_common.h"
23#include "power_log.h"
24#include "runninglock_entity.h"
25#include "xpower_event_js.h"
26
27namespace OHOS {
28namespace PowerMgr {
29namespace {
30constexpr uint32_t CREATE_PROMISE_MAX_ARGC = 2;
31constexpr uint32_t CREATE_CALLBACK_MAX_ARGC = 3;
32constexpr uint32_t ISSUPPORTED_MAX_ARGC = 1;
33constexpr uint32_t HOLD_MAX_ARGC = 1;
34constexpr int32_t INDEX_0 = 0;
35constexpr int32_t INDEX_1 = 1;
36constexpr int32_t INDEX_2 = 2;
37}
38
39napi_value RunningLockNapi::Create(napi_env& env, napi_callback_info& info, napi_ref& napiRunningLockIns)
40{
41    size_t argc = CREATE_CALLBACK_MAX_ARGC;
42    napi_value argv[argc];
43    NapiUtils::GetCallbackInfo(env, info, argc, argv);
44
45    NapiErrors error;
46    if (argc != CREATE_CALLBACK_MAX_ARGC && argc != CREATE_PROMISE_MAX_ARGC) {
47        return error.ThrowError(env, PowerErrors::ERR_PARAM_INVALID);
48    }
49
50    std::unique_ptr<AsyncCallbackInfo> asyncInfo = std::make_unique<AsyncCallbackInfo>();
51    RETURN_IF_WITH_RET(asyncInfo == nullptr, nullptr);
52    asyncInfo->GetData().SetRunningLockInstance(napiRunningLockIns);
53    // callback
54    if (argc == CREATE_CALLBACK_MAX_ARGC) {
55        return CreateAsyncCallback(env, argv, asyncInfo);
56    }
57
58    // promise
59    return CreatePromise(env, argv, asyncInfo);
60}
61
62napi_value RunningLockNapi::IsSupported(napi_env env, napi_callback_info info)
63{
64    size_t argc = ISSUPPORTED_MAX_ARGC;
65    napi_value argv[argc];
66    NapiUtils::GetCallbackInfo(env, info, argc, argv);
67
68    NapiErrors error;
69    if (argc != ISSUPPORTED_MAX_ARGC || !NapiUtils::CheckValueType(env, argv[INDEX_0], napi_number)) {
70        return error.ThrowError(env, PowerErrors::ERR_PARAM_INVALID);
71    }
72
73    int32_t numType;
74    napi_get_value_int32(env, argv[INDEX_0], &numType);
75    RunningLockType type = static_cast<RunningLockType>(numType);
76
77    bool isSupported = (type == RunningLockType::RUNNINGLOCK_BACKGROUND) ||
78        (type == RunningLockType::RUNNINGLOCK_PROXIMITY_SCREEN_CONTROL);
79
80    napi_value result;
81    napi_get_boolean(env, isSupported, &result);
82    return result;
83}
84
85napi_value RunningLockNapi::Hold(napi_env env, napi_callback_info info)
86{
87    size_t argc = HOLD_MAX_ARGC;
88    napi_value argv[argc];
89    napi_value thisArg = NapiUtils::GetCallbackInfo(env, info, argc, argv);
90    NapiErrors error;
91    if (argc != HOLD_MAX_ARGC || !NapiUtils::CheckValueType(env, argv[INDEX_0], napi_number)) {
92        return error.ThrowError(env, PowerErrors::ERR_PARAM_INVALID);
93    }
94
95    int32_t timeOut;
96    if (napi_ok != napi_get_value_int32(env, argv[INDEX_0], &timeOut)) {
97        POWER_HILOGE(FEATURE_RUNNING_LOCK, "napi_get_value_uint32 failed");
98        return nullptr;
99    }
100    auto runningLock = UnwrapRunningLock(env, thisArg);
101    RETURN_IF_WITH_RET(runningLock == nullptr, nullptr);
102    ErrCode code = runningLock->Lock(timeOut);
103    if (code == E_PERMISSION_DENIED) {
104        return error.ThrowError(env, PowerErrors::ERR_PERMISSION_DENIED);
105    }
106    OHOS::HiviewDFX::ReportXPowerJsStackSysEvent(env, "RunningLockNapi::Hold");
107    return nullptr;
108}
109
110napi_value RunningLockNapi::IsHolding(napi_env env, napi_callback_info info)
111{
112    size_t argc = 0;
113    napi_value thisArg = NapiUtils::GetCallbackInfo(env, info, argc, nullptr);
114    auto runningLock = UnwrapRunningLock(env, thisArg);
115    RETURN_IF_WITH_RET(runningLock == nullptr, nullptr);
116    bool isUsed = runningLock->IsUsed();
117    napi_value result;
118    napi_get_boolean(env, isUsed, &result);
119    return result;
120}
121
122napi_value RunningLockNapi::UnHold(napi_env env, napi_callback_info info)
123{
124    size_t argc = 0;
125    napi_value thisArg = NapiUtils::GetCallbackInfo(env, info, argc, nullptr);
126    auto runningLock = UnwrapRunningLock(env, thisArg);
127    RETURN_IF_WITH_RET(runningLock == nullptr, nullptr);
128    ErrCode code = runningLock->UnLock();
129    NapiErrors error;
130    if (code == E_PERMISSION_DENIED) {
131        return error.ThrowError(env, PowerErrors::ERR_PERMISSION_DENIED);
132    }
133    return nullptr;
134}
135
136napi_value RunningLockNapi::CreateAsyncCallback(
137    napi_env& env, napi_value argv[], std::unique_ptr<AsyncCallbackInfo>& asyncInfo)
138{
139    bool isStr = NapiUtils::CheckValueType(env, argv[INDEX_0], napi_string);
140    bool isNum = NapiUtils::CheckValueType(env, argv[INDEX_1], napi_number);
141    bool isFunc = NapiUtils::CheckValueType(env, argv[INDEX_2], napi_function);
142    if (!isStr || !isNum || !isFunc) {
143        POWER_HILOGD(
144            FEATURE_RUNNING_LOCK, "isStr: %{public}d, isNum: %{public}d, isFunc: %{public}d", isStr, isNum, isFunc);
145        return asyncInfo->GetError().ThrowError(env, PowerErrors::ERR_PARAM_INVALID);
146    }
147    asyncInfo->GetData().SetName(env, argv[INDEX_0]);
148    asyncInfo->GetData().SetType(env, argv[INDEX_1]);
149    asyncInfo->CreateCallback(env, argv[INDEX_2]);
150
151    AsyncWork(
152        env, asyncInfo, "CreateAsyncCallback",
153        [](napi_env env, void* data) {
154            AsyncCallbackInfo* asyncInfo = reinterpret_cast<AsyncCallbackInfo*>(data);
155            RETURN_IF(asyncInfo == nullptr);
156            auto error = asyncInfo->GetData().CreateRunningLock();
157            asyncInfo->GetError().Error(error);
158        },
159        [](napi_env env, napi_status status, void* data) {
160            AsyncCallbackInfo* asyncInfo = reinterpret_cast<AsyncCallbackInfo*>(data);
161            RETURN_IF(asyncInfo == nullptr);
162            napi_value result = asyncInfo->GetData().CreateInstanceForRunningLock(env);
163            asyncInfo->CallFunction(env, result);
164            asyncInfo->Release(env);
165            delete asyncInfo;
166        });
167    return nullptr;
168}
169
170napi_value RunningLockNapi::CreatePromise(
171    napi_env& env, napi_value argv[], std::unique_ptr<AsyncCallbackInfo>& asyncInfo)
172{
173    bool isStr = NapiUtils::CheckValueType(env, argv[INDEX_0], napi_string);
174    bool isNum = NapiUtils::CheckValueType(env, argv[INDEX_1], napi_number);
175    if (!isStr || !isNum) {
176        POWER_HILOGW(FEATURE_RUNNING_LOCK, "isStr: %{public}d, isNum: %{public}d", isStr, isNum);
177        return asyncInfo->GetError().ThrowError(env, PowerErrors::ERR_PARAM_INVALID);
178    }
179
180    napi_value promise;
181    asyncInfo->CreatePromise(env, promise);
182    RETURN_IF_WITH_RET(promise == nullptr, nullptr);
183    asyncInfo->GetData().SetName(env, argv[INDEX_0]);
184    asyncInfo->GetData().SetType(env, argv[INDEX_1]);
185
186    AsyncWork(
187        env, asyncInfo, "CreatePromise",
188        [](napi_env env, void* data) {
189            AsyncCallbackInfo* asyncInfo = reinterpret_cast<AsyncCallbackInfo*>(data);
190            RETURN_IF(asyncInfo == nullptr);
191            auto error = asyncInfo->GetData().CreateRunningLock();
192            asyncInfo->GetError().Error(error);
193        },
194        [](napi_env env, napi_status status, void* data) {
195            AsyncCallbackInfo* asyncInfo = reinterpret_cast<AsyncCallbackInfo*>(data);
196            RETURN_IF(asyncInfo == nullptr);
197            if (asyncInfo->GetError().IsError()) {
198                napi_reject_deferred(env, asyncInfo->GetDeferred(), asyncInfo->GetError().GetNapiError(env));
199            } else {
200                napi_value result = asyncInfo->GetData().CreateInstanceForRunningLock(env);
201                napi_resolve_deferred(env, asyncInfo->GetDeferred(), result);
202            }
203            asyncInfo->Release(env);
204            delete asyncInfo;
205        });
206    return promise;
207}
208
209void RunningLockNapi::AsyncWork(napi_env& env, std::unique_ptr<AsyncCallbackInfo>& asyncInfo,
210    const std::string& resourceName, napi_async_execute_callback execute, napi_async_complete_callback complete)
211{
212    napi_value resource = nullptr;
213    napi_create_string_utf8(env, resourceName.c_str(), NAPI_AUTO_LENGTH, &resource);
214    napi_create_async_work(env, nullptr, resource, execute, complete,
215        reinterpret_cast<void*>(asyncInfo.get()), &asyncInfo->GetAsyncWork());
216    NAPI_CALL_RETURN_VOID(env, napi_queue_async_work_with_qos(env, asyncInfo->GetAsyncWork(), napi_qos_utility));
217    asyncInfo.release();
218}
219
220std::shared_ptr<RunningLock> RunningLockNapi::UnwrapRunningLock(napi_env& env, napi_value& thisArg)
221{
222    RunningLockEntity* entity = nullptr;
223    if (napi_ok != napi_unwrap(env, thisArg, (void**)&entity)) {
224        POWER_HILOGE(FEATURE_RUNNING_LOCK, "Cannot unwrap for pointer");
225        return nullptr;
226    }
227    if (entity == nullptr || entity->runningLock == nullptr) {
228        POWER_HILOGE(FEATURE_RUNNING_LOCK, "Entity runningLock is nullptr");
229        return nullptr;
230    }
231    return entity->runningLock;
232}
233} // namespace PowerMgr
234} // namespace OHOS
235