1/*
2 * Copyright (c) 2021-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_interface.h"
17
18#include <cstdint>
19#include <memory>
20#include <string>
21
22#include "power_log.h"
23#include "power_mgr_client.h"
24#include "runninglock_entity.h"
25#include "xpower_event_js.h"
26
27namespace OHOS {
28namespace PowerMgr {
29namespace {
30constexpr int RESULT_SIZE = 2;
31constexpr int RUNNINGLOCK_NAME_MAX = 512;
32constexpr int CREATRUNNINGLOCK_ARGC = 3;
33constexpr int ISRUNNINGLOCKTYPESUPPORTED_ARGC = 2;
34constexpr int32_t INDEX_0 = 0;
35constexpr int32_t INDEX_1 = 1;
36constexpr int32_t INDEX_2 = 2;
37static PowerMgrClient& g_powerMgrClient = PowerMgrClient::GetInstance();
38}
39
40napi_value RunningLockInterface::CreateRunningLock(napi_env env, napi_callback_info info, napi_ref& napiRunningLock)
41{
42    size_t argc = CREATRUNNINGLOCK_ARGC;
43    napi_value argv[CREATRUNNINGLOCK_ARGC] = {0};
44    napi_value thisArg = nullptr;
45    void* data = nullptr;
46
47    napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisArg, &data);
48    NAPI_ASSERT(env, (status == napi_ok) && (argc >= CREATRUNNINGLOCK_ARGC - 1), "Failed to get cb info");
49
50    std::unique_ptr<RunningLockAsyncInfo> asyncInfo = std::make_unique<RunningLockAsyncInfo>();
51    if (asyncInfo == nullptr) {
52        POWER_HILOGE(FEATURE_RUNNING_LOCK, "asyncInfo is nullptr");
53        return nullptr;
54    }
55    asyncInfo->napiRunningLockIns = napiRunningLock;
56
57    napi_valuetype valueType = napi_undefined;
58    napi_typeof(env, argv[INDEX_0], &valueType);
59    NAPI_ASSERT(env, valueType == napi_string, "The input parameter type is not string");
60    char name[RUNNINGLOCK_NAME_MAX] = {0};
61    napi_get_value_string_utf8(env, argv[INDEX_0], name, RUNNINGLOCK_NAME_MAX + 1, &asyncInfo->nameLen);
62    asyncInfo->name = name;
63
64    napi_typeof(env, argv[INDEX_1], &valueType);
65    NAPI_ASSERT(env, valueType == napi_number, "The input parameter type is not number");
66    int32_t type = static_cast<int32_t>(RunningLockType::RUNNINGLOCK_BUTT);
67    napi_get_value_int32(env, argv[INDEX_1], &type);
68    asyncInfo->type = static_cast<RunningLockType>(type);
69
70    if (argc == CREATRUNNINGLOCK_ARGC) {
71        napi_typeof(env, argv[INDEX_2], &valueType);
72        NAPI_ASSERT(env, valueType == napi_function, "The input parameter type is not function");
73        napi_create_reference(env, argv[INDEX_2], 1, &asyncInfo->callbackRef);
74    }
75    napi_value result = nullptr;
76    if (asyncInfo->callbackRef == nullptr) {
77        POWER_HILOGD(FEATURE_RUNNING_LOCK, "callbackRef is null");
78        napi_create_promise(env, &asyncInfo->deferred, &result);
79    } else {
80        POWER_HILOGD(FEATURE_RUNNING_LOCK, "callbackRef is not null");
81        napi_get_undefined(env, &result);
82    }
83    CreateRunningLockCallBack(env, asyncInfo);
84    return result;
85}
86
87napi_value RunningLockInterface::IsRunningLockTypeSupported(napi_env env, napi_callback_info info)
88{
89    size_t argc = ISRUNNINGLOCKTYPESUPPORTED_ARGC;
90    napi_value argv[ISRUNNINGLOCKTYPESUPPORTED_ARGC] = {0};
91    napi_value thisArg = nullptr;
92    void* data = nullptr;
93
94    napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisArg, &data);
95    NAPI_ASSERT(env, (status == napi_ok) && (argc >= 1), "Failed to get cb info");
96
97    std::unique_ptr<RunningLockAsyncInfo> asyncInfo = std::make_unique<RunningLockAsyncInfo>();
98    if (asyncInfo == nullptr) {
99        POWER_HILOGE(FEATURE_RUNNING_LOCK, "asyncInfo is nullptr");
100        return nullptr;
101    }
102
103    napi_valuetype valueType = napi_undefined;
104    napi_typeof(env, argv[INDEX_0], &valueType);
105    NAPI_ASSERT(env, valueType == napi_number, "The input parameter type is not number");
106    int32_t type = static_cast<int32_t>(RunningLockType::RUNNINGLOCK_BUTT);
107    napi_get_value_int32(env, argv[INDEX_0], &type);
108    asyncInfo->type = static_cast<RunningLockType>(type);
109
110    if (argc == ISRUNNINGLOCKTYPESUPPORTED_ARGC) {
111        napi_typeof(env, argv[INDEX_1], &valueType);
112        NAPI_ASSERT(env, valueType == napi_function, "The input parameter type is not function");
113        napi_create_reference(env, argv[INDEX_1], 1, &asyncInfo->callbackRef);
114    }
115
116    napi_value result = nullptr;
117    if (asyncInfo->callbackRef == nullptr) {
118        POWER_HILOGD(FEATURE_RUNNING_LOCK, "callbackRef is null");
119        napi_create_promise(env, &asyncInfo->deferred, &result);
120    } else {
121        POWER_HILOGD(FEATURE_RUNNING_LOCK, "callbackRef is not null");
122        napi_get_undefined(env, &result);
123    }
124    IsRunningLockTypeSupportedCallBack(env, asyncInfo);
125    return result;
126}
127
128napi_value RunningLockInterface::Lock(napi_env env, napi_callback_info info)
129{
130    size_t argc = 1;
131    napi_value args[1] = {0};
132    napi_value thisArg = nullptr;
133    void* data = nullptr;
134
135    napi_status status = napi_get_cb_info(env, info, &argc, args, &thisArg, &data);
136    NAPI_ASSERT(env, (status == napi_ok) && (argc >= 1), "Failed to get cb info");
137    napi_valuetype type = napi_undefined;
138    NAPI_CALL(env, napi_typeof(env, args[0], &type));
139    NAPI_ASSERT(env, type == napi_number, "Wrong argument type. number expected.");
140
141    int32_t timeOut;
142    status = napi_get_value_int32(env, args[0], &timeOut);
143    if (status != napi_ok) {
144        POWER_HILOGE(FEATURE_RUNNING_LOCK, "napi_get_value_uint32 failed");
145        return nullptr;
146    }
147    RunningLockEntity* entity = nullptr;
148    status = napi_unwrap(env, thisArg, (void**)&entity);
149    if (status != napi_ok) {
150        POWER_HILOGE(FEATURE_RUNNING_LOCK, "Cannot unwrap for pointer");
151        return nullptr;
152    }
153    if (entity == nullptr || entity->runningLock == nullptr) {
154        POWER_HILOGE(FEATURE_RUNNING_LOCK, "Entity runningLock is nullptr");
155        return nullptr;
156    }
157    entity->runningLock->Lock(timeOut);
158    OHOS::HiviewDFX::ReportXPowerJsStackSysEvent(env, "RunningLockNapi::Lock");
159    return nullptr;
160}
161
162napi_value RunningLockInterface::IsUsed(napi_env env, napi_callback_info info)
163{
164    napi_value thisArg = nullptr;
165    napi_value result = nullptr;
166    void* data = nullptr;
167
168    napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, &data);
169    NAPI_ASSERT(env, (status == napi_ok), "Failed to get cb info");
170    napi_get_boolean(env, false, &result);
171    RunningLockEntity* entity = nullptr;
172    status = napi_unwrap(env, thisArg, (void**)&entity);
173    if (status != napi_ok) {
174        POWER_HILOGE(FEATURE_RUNNING_LOCK, "Cannot unwrap for pointer");
175        return result;
176    }
177    if (entity == nullptr || entity->runningLock == nullptr) {
178        POWER_HILOGE(FEATURE_RUNNING_LOCK, "Entity runningLock is nullptr");
179        return result;
180    }
181    bool isUsed = entity->runningLock->IsUsed();
182    napi_get_boolean(env, isUsed, &result);
183    return result;
184}
185
186napi_value RunningLockInterface::Unlock(napi_env env, napi_callback_info info)
187{
188    napi_value thisArg = nullptr;
189    void* data = nullptr;
190
191    napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, &data);
192    NAPI_ASSERT(env, (status == napi_ok), "Unlock: failed to get cb info");
193
194    RunningLockEntity* entity = nullptr;
195    status = napi_unwrap(env, thisArg, (void**)&entity);
196    if (status != napi_ok) {
197        POWER_HILOGE(FEATURE_RUNNING_LOCK, "Cannot unwrap for pointer");
198        return nullptr;
199    }
200    if (entity == nullptr || entity->runningLock == nullptr) {
201        POWER_HILOGE(FEATURE_RUNNING_LOCK, "Entity runningLock is nullptr");
202        return nullptr;
203    }
204    entity->runningLock->UnLock();
205    return nullptr;
206}
207
208napi_value RunningLockInterface::CreateInstanceForRunningLock(napi_env env, RunningLockAsyncInfo* asyncInfo)
209{
210    napi_value cons = nullptr;
211    napi_value instance = nullptr;
212    napi_status callBackStatus;
213    RunningLockEntity* entity = nullptr;
214
215    if (asyncInfo->runningLock == nullptr) {
216        POWER_HILOGE(FEATURE_RUNNING_LOCK, "RunningLock is nullptr");
217        return nullptr;
218    }
219    callBackStatus = napi_get_reference_value(env, asyncInfo->napiRunningLockIns, &cons);
220    if (callBackStatus != napi_ok) {
221        POWER_HILOGE(FEATURE_RUNNING_LOCK, "NAPI failed to create a reference value");
222        return nullptr;
223    }
224    callBackStatus = napi_new_instance(env, cons, 0, nullptr, &instance);
225    if (callBackStatus != napi_ok || instance == nullptr) {
226        POWER_HILOGE(FEATURE_RUNNING_LOCK, "NAPI failed to create a reference");
227        return nullptr;
228    }
229    callBackStatus = napi_unwrap(env, instance, (void**)&entity);
230    if (callBackStatus != napi_ok || entity == nullptr) {
231        POWER_HILOGE(FEATURE_RUNNING_LOCK, "Cannot unwrap entity from instance");
232        return nullptr;
233    }
234    entity->runningLock = asyncInfo->runningLock;
235    return instance;
236}
237
238void RunningLockInterface::CreateRunningLockCallBack(napi_env env, std::unique_ptr<RunningLockAsyncInfo>& asyncInfo)
239{
240    napi_value resource = nullptr;
241    napi_create_string_utf8(env, "createRunningLock", NAPI_AUTO_LENGTH, &resource);
242    napi_create_async_work(
243        env, nullptr, resource,
244        [](napi_env env, void* data) {
245            auto* asyncInfo = reinterpret_cast<RunningLockAsyncInfo*>(data);
246            if (!IsTypeSupported(asyncInfo->type)) {
247                auto type = static_cast<uint32_t>(asyncInfo->type);
248                POWER_HILOGW(FEATURE_RUNNING_LOCK, "type=%{public}u not supported", type);
249                return;
250            }
251            asyncInfo->runningLock = g_powerMgrClient.CreateRunningLock(std::string(asyncInfo->name), asyncInfo->type);
252        },
253        [](napi_env env, napi_status status, void* data) {
254            auto* asyncInfo = reinterpret_cast<RunningLockAsyncInfo*>(data);
255            napi_value result[RESULT_SIZE] = {0};
256            result[1] = CreateInstanceForRunningLock(env, asyncInfo);
257            if (result[1] == nullptr) {
258                napi_value message = nullptr;
259                napi_create_string_utf8(env, "runningLock create failed", NAPI_AUTO_LENGTH, &message);
260                napi_create_error(env, nullptr, message, &result[0]);
261            }
262            if (asyncInfo->deferred) {
263                if (result[1] != nullptr) {
264                    napi_resolve_deferred(env, asyncInfo->deferred, result[1]);
265                } else {
266                    napi_reject_deferred(env, asyncInfo->deferred, result[0]);
267                }
268            } else {
269                napi_value tmp = nullptr;
270                napi_value callback = nullptr;
271                napi_get_undefined(env, &result[0]);
272                napi_get_reference_value(env, asyncInfo->callbackRef, &callback);
273                napi_call_function(env, nullptr, callback, RESULT_SIZE, result, &tmp);
274                napi_delete_reference(env, asyncInfo->callbackRef);
275            }
276            napi_delete_async_work(env, asyncInfo->asyncWork);
277            delete asyncInfo;
278        },
279        reinterpret_cast<void*>(asyncInfo.get()), &asyncInfo->asyncWork);
280    if (napi_ok == napi_queue_async_work_with_qos(env, asyncInfo->asyncWork, napi_qos_utility)) {
281        asyncInfo.release();
282    }
283}
284
285void RunningLockInterface::IsRunningLockTypeSupportedCallBack(
286    napi_env env, std::unique_ptr<RunningLockAsyncInfo>& asyncInfo)
287{
288    napi_value resource = nullptr;
289    napi_create_string_utf8(env, "isRunningLockTypeSupported", NAPI_AUTO_LENGTH, &resource);
290    napi_create_async_work(
291        env, nullptr, resource,
292        [](napi_env env, void* data) {
293            auto* asyncInfo = reinterpret_cast<RunningLockAsyncInfo*>(data);
294            asyncInfo->isSupported = IsTypeSupported(asyncInfo->type);
295            POWER_HILOGD(FEATURE_RUNNING_LOCK, "type=%{public}u, isSupported=%{public}s",
296                static_cast<uint32_t>(asyncInfo->type), asyncInfo->isSupported ? "true" : "false");
297        },
298        [](napi_env env, napi_status status, void* data) {
299            auto* asyncInfo = reinterpret_cast<RunningLockAsyncInfo*>(data);
300            napi_value result[RESULT_SIZE] = {0};
301            napi_get_boolean(env, asyncInfo->isSupported, &result[1]);
302            if (asyncInfo->deferred) {
303                napi_resolve_deferred(env, asyncInfo->deferred, result[1]);
304            } else {
305                napi_value tmp = nullptr;
306                napi_value callback = nullptr;
307                napi_get_reference_value(env, asyncInfo->callbackRef, &callback);
308                napi_get_undefined(env, &result[0]);
309                napi_call_function(env, nullptr, callback, RESULT_SIZE, result, &tmp);
310                napi_delete_reference(env, asyncInfo->callbackRef);
311            }
312            napi_delete_async_work(env, asyncInfo->asyncWork);
313            delete asyncInfo;
314        },
315        reinterpret_cast<void*>(asyncInfo.get()), &asyncInfo->asyncWork);
316    if (napi_ok == napi_queue_async_work_with_qos(env, asyncInfo->asyncWork, napi_qos_utility)) {
317        asyncInfo.release();
318    }
319}
320
321bool RunningLockInterface::IsTypeSupported(RunningLockType type)
322{
323    return type == RunningLockType::RUNNINGLOCK_BACKGROUND ||
324        type == RunningLockType::RUNNINGLOCK_PROXIMITY_SCREEN_CONTROL;
325}
326} // namespace PowerMgr
327} // namespace OHOS
328