137a09cd7Sopenharmony_ci/*
237a09cd7Sopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
337a09cd7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
437a09cd7Sopenharmony_ci * you may not use this file except in compliance with the License.
537a09cd7Sopenharmony_ci * You may obtain a copy of the License at
637a09cd7Sopenharmony_ci *
737a09cd7Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
837a09cd7Sopenharmony_ci *
937a09cd7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1037a09cd7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1137a09cd7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1237a09cd7Sopenharmony_ci * See the License for the specific language governing permissions and
1337a09cd7Sopenharmony_ci * limitations under the License.
1437a09cd7Sopenharmony_ci */
1537a09cd7Sopenharmony_ci
1637a09cd7Sopenharmony_ci#include "thermal_manager_napi.h"
1737a09cd7Sopenharmony_ci
1837a09cd7Sopenharmony_ci#include <uv.h>
1937a09cd7Sopenharmony_ci
2037a09cd7Sopenharmony_ci#include "napi_utils.h"
2137a09cd7Sopenharmony_ci#include "napi_errors.h"
2237a09cd7Sopenharmony_ci#include "thermal_common.h"
2337a09cd7Sopenharmony_ci#include "thermal_level_info.h"
2437a09cd7Sopenharmony_ci
2537a09cd7Sopenharmony_ciusing namespace OHOS::PowerMgr;
2637a09cd7Sopenharmony_ciusing namespace OHOS;
2737a09cd7Sopenharmony_ci
2837a09cd7Sopenharmony_cinamespace {
2937a09cd7Sopenharmony_ciconst uint8_t ARG_0 = 0;
3037a09cd7Sopenharmony_ciconst uint8_t ARG_1 = 1;
3137a09cd7Sopenharmony_ciconstexpr uint32_t MAX_ARGC = 1;
3237a09cd7Sopenharmony_cithread_local auto& g_thermalMgrClient = ThermalMgrClient::GetInstance();
3337a09cd7Sopenharmony_cithread_local sptr<ThermalLevelCallback> g_thermalLevelCallback = new (std::nothrow) ThermalLevelCallback();
3437a09cd7Sopenharmony_ci} // namespace
3537a09cd7Sopenharmony_ci
3637a09cd7Sopenharmony_ciThermalLevelCallback::~ThermalLevelCallback()
3737a09cd7Sopenharmony_ci{
3837a09cd7Sopenharmony_ci    ReleaseCallback();
3937a09cd7Sopenharmony_ci}
4037a09cd7Sopenharmony_ci
4137a09cd7Sopenharmony_civoid ThermalLevelCallback::UpdateCallback(napi_env env, napi_value jsCallback)
4237a09cd7Sopenharmony_ci{
4337a09cd7Sopenharmony_ci    std::lock_guard lock(mutex_);
4437a09cd7Sopenharmony_ci    if (napi_ok != napi_create_reference(env, jsCallback, 1, &callbackRef_)) {
4537a09cd7Sopenharmony_ci        THERMAL_HILOGW(COMP_FWK, "Failed to create a JS callback reference");
4637a09cd7Sopenharmony_ci        callbackRef_ = nullptr;
4737a09cd7Sopenharmony_ci    }
4837a09cd7Sopenharmony_ci    env_ = env;
4937a09cd7Sopenharmony_ci}
5037a09cd7Sopenharmony_ci
5137a09cd7Sopenharmony_civoid ThermalLevelCallback::ReleaseCallback()
5237a09cd7Sopenharmony_ci{
5337a09cd7Sopenharmony_ci    std::lock_guard lock(mutex_);
5437a09cd7Sopenharmony_ci    if (callbackRef_ != nullptr) {
5537a09cd7Sopenharmony_ci        napi_delete_reference(env_, callbackRef_);
5637a09cd7Sopenharmony_ci    }
5737a09cd7Sopenharmony_ci    callbackRef_ = nullptr;
5837a09cd7Sopenharmony_ci    env_ = nullptr;
5937a09cd7Sopenharmony_ci}
6037a09cd7Sopenharmony_ci
6137a09cd7Sopenharmony_cibool ThermalLevelCallback::OnThermalLevelChanged(ThermalLevel level)
6237a09cd7Sopenharmony_ci{
6337a09cd7Sopenharmony_ci    std::lock_guard lock(mutex_);
6437a09cd7Sopenharmony_ci    level_ = level;
6537a09cd7Sopenharmony_ci    THERMAL_RETURN_IF_WITH_RET(env_ == nullptr, false);
6637a09cd7Sopenharmony_ci    uv_loop_s* loop = nullptr;
6737a09cd7Sopenharmony_ci    napi_get_uv_event_loop(env_, &loop);
6837a09cd7Sopenharmony_ci    THERMAL_RETURN_IF_WITH_RET(loop == nullptr, false);
6937a09cd7Sopenharmony_ci    uv_work_t* work = new (std::nothrow) uv_work_t;
7037a09cd7Sopenharmony_ci    THERMAL_RETURN_IF_WITH_RET(work == nullptr, false);
7137a09cd7Sopenharmony_ci    work->data = reinterpret_cast<void*>(this);
7237a09cd7Sopenharmony_ci
7337a09cd7Sopenharmony_ci    int32_t ret = uv_queue_work_with_qos(
7437a09cd7Sopenharmony_ci        loop, work,
7537a09cd7Sopenharmony_ci        [](uv_work_t* work) {
7637a09cd7Sopenharmony_ci            THERMAL_HILOGD(COMP_FWK, "uv_queue_work callback function is called");
7737a09cd7Sopenharmony_ci        },
7837a09cd7Sopenharmony_ci        [](uv_work_t* work, int status) {
7937a09cd7Sopenharmony_ci            ThermalLevelCallback* callback = reinterpret_cast<ThermalLevelCallback*>(work->data);
8037a09cd7Sopenharmony_ci            if (callback != nullptr) {
8137a09cd7Sopenharmony_ci                callback->OnThermalLevel();
8237a09cd7Sopenharmony_ci            }
8337a09cd7Sopenharmony_ci            delete work;
8437a09cd7Sopenharmony_ci            work = nullptr;
8537a09cd7Sopenharmony_ci        },
8637a09cd7Sopenharmony_ci        uv_qos_utility);
8737a09cd7Sopenharmony_ci    if (ret != ERR_OK) {
8837a09cd7Sopenharmony_ci        delete work;
8937a09cd7Sopenharmony_ci        work = nullptr;
9037a09cd7Sopenharmony_ci        THERMAL_HILOGW(COMP_FWK, "uv_queue_work is failed");
9137a09cd7Sopenharmony_ci        return false;
9237a09cd7Sopenharmony_ci    }
9337a09cd7Sopenharmony_ci    return true;
9437a09cd7Sopenharmony_ci}
9537a09cd7Sopenharmony_ci
9637a09cd7Sopenharmony_civoid ThermalLevelCallback::OnThermalLevel()
9737a09cd7Sopenharmony_ci{
9837a09cd7Sopenharmony_ci    THERMAL_HILOGD(COMP_FWK, "level is: %{public}d", static_cast<int32_t>(level_));
9937a09cd7Sopenharmony_ci    THERMAL_RETURN_IF_WITH_LOG(callbackRef_ == nullptr || env_ == nullptr, "js callback ref or env is nullptr");
10037a09cd7Sopenharmony_ci
10137a09cd7Sopenharmony_ci    napi_handle_scope scope = nullptr;
10237a09cd7Sopenharmony_ci    napi_open_handle_scope(env_, &scope);
10337a09cd7Sopenharmony_ci    if (scope == nullptr) {
10437a09cd7Sopenharmony_ci        THERMAL_HILOGW(COMP_FWK, "scope is nullptr");
10537a09cd7Sopenharmony_ci        return;
10637a09cd7Sopenharmony_ci    }
10737a09cd7Sopenharmony_ci
10837a09cd7Sopenharmony_ci    napi_value levelValue = nullptr;
10937a09cd7Sopenharmony_ci    if (napi_ok != napi_create_int32(env_, static_cast<int32_t>(level_), &levelValue)) {
11037a09cd7Sopenharmony_ci        THERMAL_HILOGW(COMP_FWK, "napi_create_int32 callback failed");
11137a09cd7Sopenharmony_ci        napi_close_handle_scope(env_, scope);
11237a09cd7Sopenharmony_ci        return;
11337a09cd7Sopenharmony_ci    }
11437a09cd7Sopenharmony_ci
11537a09cd7Sopenharmony_ci    napi_value callback = nullptr;
11637a09cd7Sopenharmony_ci    napi_status status = napi_get_reference_value(env_, callbackRef_, &callback);
11737a09cd7Sopenharmony_ci    if (status != napi_ok) {
11837a09cd7Sopenharmony_ci        THERMAL_HILOGE(COMP_FWK, "napi_get_reference_value callback failed, status = %{public}d", status);
11937a09cd7Sopenharmony_ci        napi_close_handle_scope(env_, scope);
12037a09cd7Sopenharmony_ci        return;
12137a09cd7Sopenharmony_ci    }
12237a09cd7Sopenharmony_ci
12337a09cd7Sopenharmony_ci    napi_value callResult = nullptr;
12437a09cd7Sopenharmony_ci    status = napi_call_function(env_, nullptr, callback, ARG_1, &levelValue, &callResult);
12537a09cd7Sopenharmony_ci    if (status != napi_ok) {
12637a09cd7Sopenharmony_ci        THERMAL_HILOGE(COMP_FWK, "napi_call_function callback failed, status = %{public}d", status);
12737a09cd7Sopenharmony_ci    }
12837a09cd7Sopenharmony_ci    napi_close_handle_scope(env_, scope);
12937a09cd7Sopenharmony_ci}
13037a09cd7Sopenharmony_ci
13137a09cd7Sopenharmony_cinapi_value ThermalManagerNapi::Init(napi_env env, napi_value exports)
13237a09cd7Sopenharmony_ci{
13337a09cd7Sopenharmony_ci    napi_property_descriptor desc[] = {
13437a09cd7Sopenharmony_ci        // Old Interface
13537a09cd7Sopenharmony_ci        DECLARE_NAPI_STATIC_FUNCTION("subscribeThermalLevel", SubscribeThermalLevel),
13637a09cd7Sopenharmony_ci        DECLARE_NAPI_STATIC_FUNCTION("unsubscribeThermalLevel", UnSubscribeThermalLevel),
13737a09cd7Sopenharmony_ci        DECLARE_NAPI_STATIC_FUNCTION("getThermalLevel", GetThermalLevel),
13837a09cd7Sopenharmony_ci        // New Interface
13937a09cd7Sopenharmony_ci        DECLARE_NAPI_STATIC_FUNCTION("registerThermalLevelCallback", SubscribeThermalLevel),
14037a09cd7Sopenharmony_ci        DECLARE_NAPI_STATIC_FUNCTION("unregisterThermalLevelCallback", UnSubscribeThermalLevel),
14137a09cd7Sopenharmony_ci        DECLARE_NAPI_STATIC_FUNCTION("getLevel", GetThermalLevel),
14237a09cd7Sopenharmony_ci    };
14337a09cd7Sopenharmony_ci    NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
14437a09cd7Sopenharmony_ci    InitThermalLevel(env, exports);
14537a09cd7Sopenharmony_ci
14637a09cd7Sopenharmony_ci    return exports;
14737a09cd7Sopenharmony_ci}
14837a09cd7Sopenharmony_ci
14937a09cd7Sopenharmony_cinapi_value ThermalManagerNapi::InitThermalLevel(napi_env env, napi_value exports)
15037a09cd7Sopenharmony_ci{
15137a09cd7Sopenharmony_ci    napi_value cool;
15237a09cd7Sopenharmony_ci    napi_value normal;
15337a09cd7Sopenharmony_ci    napi_value warm;
15437a09cd7Sopenharmony_ci    napi_value hot;
15537a09cd7Sopenharmony_ci    napi_value overheated;
15637a09cd7Sopenharmony_ci    napi_value warning;
15737a09cd7Sopenharmony_ci    napi_value emergency;
15837a09cd7Sopenharmony_ci    napi_value escape;
15937a09cd7Sopenharmony_ci
16037a09cd7Sopenharmony_ci    napi_create_uint32(env, static_cast<uint32_t>(ThermalLevel::COOL), &cool);
16137a09cd7Sopenharmony_ci    napi_create_uint32(env, static_cast<uint32_t>(ThermalLevel::NORMAL), &normal);
16237a09cd7Sopenharmony_ci    napi_create_uint32(env, static_cast<uint32_t>(ThermalLevel::WARM), &warm);
16337a09cd7Sopenharmony_ci    napi_create_uint32(env, static_cast<uint32_t>(ThermalLevel::HOT), &hot);
16437a09cd7Sopenharmony_ci    napi_create_uint32(env, static_cast<uint32_t>(ThermalLevel::OVERHEATED), &overheated);
16537a09cd7Sopenharmony_ci    napi_create_uint32(env, static_cast<uint32_t>(ThermalLevel::WARNING), &warning);
16637a09cd7Sopenharmony_ci    napi_create_uint32(env, static_cast<uint32_t>(ThermalLevel::EMERGENCY), &emergency);
16737a09cd7Sopenharmony_ci    napi_create_uint32(env, static_cast<uint32_t>(ThermalLevel::ESCAPE), &escape);
16837a09cd7Sopenharmony_ci
16937a09cd7Sopenharmony_ci    napi_property_descriptor desc[] = {
17037a09cd7Sopenharmony_ci        DECLARE_NAPI_STATIC_PROPERTY("COOL", cool),
17137a09cd7Sopenharmony_ci        DECLARE_NAPI_STATIC_PROPERTY("NORMAL", normal),
17237a09cd7Sopenharmony_ci        DECLARE_NAPI_STATIC_PROPERTY("WARM", warm),
17337a09cd7Sopenharmony_ci        DECLARE_NAPI_STATIC_PROPERTY("HOT", hot),
17437a09cd7Sopenharmony_ci        DECLARE_NAPI_STATIC_PROPERTY("OVERHEATED", overheated),
17537a09cd7Sopenharmony_ci        DECLARE_NAPI_STATIC_PROPERTY("WARNING", warning),
17637a09cd7Sopenharmony_ci        DECLARE_NAPI_STATIC_PROPERTY("EMERGENCY", emergency),
17737a09cd7Sopenharmony_ci        DECLARE_NAPI_STATIC_PROPERTY("ESCAPE", escape),
17837a09cd7Sopenharmony_ci    };
17937a09cd7Sopenharmony_ci
18037a09cd7Sopenharmony_ci    napi_value result = nullptr;
18137a09cd7Sopenharmony_ci    napi_define_class(env, "ThermalLevel", NAPI_AUTO_LENGTH, EnumThermalLevelConstructor, nullptr,
18237a09cd7Sopenharmony_ci        sizeof(desc) / sizeof(*desc), desc, &result);
18337a09cd7Sopenharmony_ci    napi_set_named_property(env, exports, "ThermalLevel", result);
18437a09cd7Sopenharmony_ci    return exports;
18537a09cd7Sopenharmony_ci}
18637a09cd7Sopenharmony_ci
18737a09cd7Sopenharmony_cinapi_value ThermalManagerNapi::EnumThermalLevelConstructor(napi_env env, napi_callback_info info)
18837a09cd7Sopenharmony_ci{
18937a09cd7Sopenharmony_ci    size_t argc = 0;
19037a09cd7Sopenharmony_ci    napi_value argv[ARG_1] = {0};
19137a09cd7Sopenharmony_ci    napi_value jsthis = nullptr;
19237a09cd7Sopenharmony_ci    void* data = nullptr;
19337a09cd7Sopenharmony_ci
19437a09cd7Sopenharmony_ci    napi_status status = napi_get_cb_info(env, info, &argc, argv, &jsthis, &data);
19537a09cd7Sopenharmony_ci
19637a09cd7Sopenharmony_ci    THERMAL_HILOGI(COMP_FWK, "EnumThermalLevelConstructor %{public}d", status);
19737a09cd7Sopenharmony_ci    if (status != napi_ok) {
19837a09cd7Sopenharmony_ci        return nullptr;
19937a09cd7Sopenharmony_ci    }
20037a09cd7Sopenharmony_ci    return jsthis;
20137a09cd7Sopenharmony_ci}
20237a09cd7Sopenharmony_ci
20337a09cd7Sopenharmony_cinapi_value ThermalManagerNapi::GetThermalLevel(napi_env env, napi_callback_info info)
20437a09cd7Sopenharmony_ci{
20537a09cd7Sopenharmony_ci    ThermalLevel level = g_thermalMgrClient.GetThermalLevel();
20637a09cd7Sopenharmony_ci    int32_t levelValue = static_cast<int32_t>(level);
20737a09cd7Sopenharmony_ci    napi_value napiValue;
20837a09cd7Sopenharmony_ci    NAPI_CALL(env, napi_create_int32(env, levelValue, &napiValue));
20937a09cd7Sopenharmony_ci
21037a09cd7Sopenharmony_ci    THERMAL_HILOGI(COMP_FWK, "level is %{public}d", levelValue);
21137a09cd7Sopenharmony_ci    return napiValue;
21237a09cd7Sopenharmony_ci}
21337a09cd7Sopenharmony_ci
21437a09cd7Sopenharmony_cinapi_value ThermalManagerNapi::SubscribeThermalLevel(napi_env env, napi_callback_info info)
21537a09cd7Sopenharmony_ci{
21637a09cd7Sopenharmony_ci    size_t argc = MAX_ARGC;
21737a09cd7Sopenharmony_ci    napi_value argv[argc];
21837a09cd7Sopenharmony_ci    NapiUtils::GetCallbackInfo(env, info, argc, argv);
21937a09cd7Sopenharmony_ci
22037a09cd7Sopenharmony_ci    NapiErrors error;
22137a09cd7Sopenharmony_ci    if (argc != MAX_ARGC || !NapiUtils::CheckValueType(env, argv[ARG_0], napi_function)) {
22237a09cd7Sopenharmony_ci        return error.ThrowError(env, ThermalErrors::ERR_PARAM_INVALID);
22337a09cd7Sopenharmony_ci    }
22437a09cd7Sopenharmony_ci
22537a09cd7Sopenharmony_ci    napi_value result;
22637a09cd7Sopenharmony_ci    napi_get_undefined(env, &result);
22737a09cd7Sopenharmony_ci
22837a09cd7Sopenharmony_ci    THERMAL_RETURN_IF_WITH_RET(g_thermalLevelCallback == nullptr, result);
22937a09cd7Sopenharmony_ci    g_thermalLevelCallback->ReleaseCallback();
23037a09cd7Sopenharmony_ci    g_thermalLevelCallback->UpdateCallback(env, argv[ARG_0]);
23137a09cd7Sopenharmony_ci    g_thermalMgrClient.SubscribeThermalLevelCallback(g_thermalLevelCallback);
23237a09cd7Sopenharmony_ci
23337a09cd7Sopenharmony_ci    return result;
23437a09cd7Sopenharmony_ci}
23537a09cd7Sopenharmony_ci
23637a09cd7Sopenharmony_cinapi_value ThermalManagerNapi::UnSubscribeThermalLevel(napi_env env, napi_callback_info info)
23737a09cd7Sopenharmony_ci{
23837a09cd7Sopenharmony_ci    size_t argc = MAX_ARGC;
23937a09cd7Sopenharmony_ci    napi_value argv[argc];
24037a09cd7Sopenharmony_ci    NapiUtils::GetCallbackInfo(env, info, argc, argv);
24137a09cd7Sopenharmony_ci
24237a09cd7Sopenharmony_ci    THERMAL_RETURN_IF_WITH_RET(g_thermalLevelCallback == nullptr, nullptr);
24337a09cd7Sopenharmony_ci    g_thermalLevelCallback->ReleaseCallback();
24437a09cd7Sopenharmony_ci    g_thermalMgrClient.UnSubscribeThermalLevelCallback(g_thermalLevelCallback);
24537a09cd7Sopenharmony_ci
24637a09cd7Sopenharmony_ci    THERMAL_RETURN_IF_WITH_RET(argc == ARG_0, nullptr);
24737a09cd7Sopenharmony_ci    NapiErrors error;
24837a09cd7Sopenharmony_ci    if (argc > MAX_ARGC || !NapiUtils::CheckValueType(env, argv[ARG_0], napi_function)) {
24937a09cd7Sopenharmony_ci        return error.ThrowError(env, ThermalErrors::ERR_PARAM_INVALID);
25037a09cd7Sopenharmony_ci    }
25137a09cd7Sopenharmony_ci
25237a09cd7Sopenharmony_ci    napi_value handler = nullptr;
25337a09cd7Sopenharmony_ci    napi_ref handlerRef = nullptr;
25437a09cd7Sopenharmony_ci    napi_create_reference(env, argv[ARG_0], 1, &handlerRef);
25537a09cd7Sopenharmony_ci    napi_get_reference_value(env, handlerRef, &handler);
25637a09cd7Sopenharmony_ci    napi_delete_reference(env, handlerRef);
25737a09cd7Sopenharmony_ci
25837a09cd7Sopenharmony_ci    napi_value result = nullptr;
25937a09cd7Sopenharmony_ci    if (handler == nullptr) {
26037a09cd7Sopenharmony_ci        THERMAL_HILOGW(COMP_FWK, "Handler should not be nullptr");
26137a09cd7Sopenharmony_ci        return result;
26237a09cd7Sopenharmony_ci    }
26337a09cd7Sopenharmony_ci
26437a09cd7Sopenharmony_ci    napi_get_undefined(env, &result);
26537a09cd7Sopenharmony_ci    napi_status status = napi_call_function(env, nullptr, handler, ARG_0, nullptr, &result);
26637a09cd7Sopenharmony_ci    if (status != napi_ok) {
26737a09cd7Sopenharmony_ci        THERMAL_HILOGW(COMP_FWK, "status=%{public}d", status);
26837a09cd7Sopenharmony_ci        return result;
26937a09cd7Sopenharmony_ci    }
27037a09cd7Sopenharmony_ci    return result;
27137a09cd7Sopenharmony_ci}
27237a09cd7Sopenharmony_ci
27337a09cd7Sopenharmony_ciEXTERN_C_START
27437a09cd7Sopenharmony_ci/*
27537a09cd7Sopenharmony_ci * function for module exports
27637a09cd7Sopenharmony_ci */
27737a09cd7Sopenharmony_cistatic napi_value ThermalInit(napi_env env, napi_value exports)
27837a09cd7Sopenharmony_ci{
27937a09cd7Sopenharmony_ci    THERMAL_HILOGD(COMP_FWK, "Enter");
28037a09cd7Sopenharmony_ci
28137a09cd7Sopenharmony_ci    napi_value ret = ThermalManagerNapi::Init(env, exports);
28237a09cd7Sopenharmony_ci
28337a09cd7Sopenharmony_ci    THERMAL_HILOGD(COMP_FWK, "Exit");
28437a09cd7Sopenharmony_ci
28537a09cd7Sopenharmony_ci    return ret;
28637a09cd7Sopenharmony_ci}
28737a09cd7Sopenharmony_ciEXTERN_C_END
28837a09cd7Sopenharmony_ci
28937a09cd7Sopenharmony_ci/*
29037a09cd7Sopenharmony_ci * Module definition
29137a09cd7Sopenharmony_ci */
29237a09cd7Sopenharmony_cistatic napi_module g_module = {.nm_version = 1,
29337a09cd7Sopenharmony_ci    .nm_flags = 0,
29437a09cd7Sopenharmony_ci    .nm_filename = "thermal",
29537a09cd7Sopenharmony_ci    .nm_register_func = ThermalInit,
29637a09cd7Sopenharmony_ci    .nm_modname = "thermal",
29737a09cd7Sopenharmony_ci    .nm_priv = ((void*)0),
29837a09cd7Sopenharmony_ci    .reserved = {0}};
29937a09cd7Sopenharmony_ci
30037a09cd7Sopenharmony_ci/*
30137a09cd7Sopenharmony_ci * Module registration
30237a09cd7Sopenharmony_ci */
30337a09cd7Sopenharmony_ciextern "C" __attribute__((constructor)) void RegisterModule()
30437a09cd7Sopenharmony_ci{
30537a09cd7Sopenharmony_ci    napi_module_register(&g_module);
30637a09cd7Sopenharmony_ci}
307