1bae44755Sopenharmony_ci/*
2bae44755Sopenharmony_ci * Copyright (C) 2022-2022 Huawei Device Co., Ltd.
3bae44755Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4bae44755Sopenharmony_ci * you may not use this file except in compliance with the License.
5bae44755Sopenharmony_ci * You may obtain a copy of the License at
6bae44755Sopenharmony_ci *
7bae44755Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8bae44755Sopenharmony_ci *
9bae44755Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10bae44755Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11bae44755Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12bae44755Sopenharmony_ci * See the License for the specific language governing permissions and
13bae44755Sopenharmony_ci * limitations under the License.
14bae44755Sopenharmony_ci */
15bae44755Sopenharmony_ci
16bae44755Sopenharmony_ci#include <cstdint>
17bae44755Sopenharmony_ci#include <cstring>
18bae44755Sopenharmony_ci#include <cstdlib>
19bae44755Sopenharmony_ci#include <securec.h>
20bae44755Sopenharmony_ci#include "napi/native_api.h"
21bae44755Sopenharmony_ci#include "napi/native_node_api.h"
22bae44755Sopenharmony_ci#include "syscap_interface.h"
23bae44755Sopenharmony_ci#include "context_tool.h"
24bae44755Sopenharmony_ci
25bae44755Sopenharmony_cinamespace OHOS {
26bae44755Sopenharmony_ciEXTERN_C_START
27bae44755Sopenharmony_ciconstexpr size_t OS_SYSCAP_U32_NUM = 30;
28bae44755Sopenharmony_ciconstexpr size_t PCID_MAIN_U32 = OS_SYSCAP_U32_NUM + 2;
29bae44755Sopenharmony_ciconstexpr size_t U32_TO_STR_MAX_LEN = 11;
30bae44755Sopenharmony_ciconstexpr size_t KEY_BUFFER_SIZE = 32;
31bae44755Sopenharmony_ci
32bae44755Sopenharmony_ci#define GET_PARAMS(env, info, num) \
33bae44755Sopenharmony_ci    size_t argc = num;             \
34bae44755Sopenharmony_ci    napi_value argv[num] = {0};    \
35bae44755Sopenharmony_ci    napi_value thisVar = nullptr;  \
36bae44755Sopenharmony_ci    void *data;                    \
37bae44755Sopenharmony_ci    napi_get_cb_info(env, info, &argc, argv, &thisVar, &data)
38bae44755Sopenharmony_ci
39bae44755Sopenharmony_ci// Async Function Set
40bae44755Sopenharmony_cistruct SystemCapabilityAsyncContext {
41bae44755Sopenharmony_ci    napi_env env = nullptr;
42bae44755Sopenharmony_ci    napi_async_work work = nullptr;
43bae44755Sopenharmony_ci    char key[KEY_BUFFER_SIZE] = { 0 };
44bae44755Sopenharmony_ci    size_t keyLen = 0;
45bae44755Sopenharmony_ci    char *value = nullptr;
46bae44755Sopenharmony_ci    size_t valueLen = 0;
47bae44755Sopenharmony_ci    napi_deferred deferred = nullptr;
48bae44755Sopenharmony_ci    napi_ref callbackRef = nullptr;
49bae44755Sopenharmony_ci
50bae44755Sopenharmony_ci    int status = 0;
51bae44755Sopenharmony_ci};
52bae44755Sopenharmony_ci
53bae44755Sopenharmony_cistatic char* CalculateAllStringLength(char osCapArray[PCID_MAIN_U32][U32_TO_STR_MAX_LEN],
54bae44755Sopenharmony_ci    char (*priCapArray)[SINGLE_SYSCAP_LEN], bool retBool, int priCapArrayCnt)
55bae44755Sopenharmony_ci{
56bae44755Sopenharmony_ci    errno_t err = EOK;
57bae44755Sopenharmony_ci    char *temp = nullptr;
58bae44755Sopenharmony_ci    int retError;
59bae44755Sopenharmony_ci    int sumLen = 0;
60bae44755Sopenharmony_ci    char *allSyscapBuffer = nullptr;
61bae44755Sopenharmony_ci
62bae44755Sopenharmony_ci    if (!retBool) {
63bae44755Sopenharmony_ci        PRINT_ERR("get encoded private syscap failed.");
64bae44755Sopenharmony_ci        return allSyscapBuffer;
65bae44755Sopenharmony_ci    }
66bae44755Sopenharmony_ci
67bae44755Sopenharmony_ci    for (size_t i = 0; i < PCID_MAIN_U32; i++) {
68bae44755Sopenharmony_ci        sumLen += strlen(osCapArray[i]);
69bae44755Sopenharmony_ci    }
70bae44755Sopenharmony_ci    for (int i = 0; i < priCapArrayCnt; i++) {
71bae44755Sopenharmony_ci        sumLen += strlen(*(priCapArray + i));
72bae44755Sopenharmony_ci    }
73bae44755Sopenharmony_ci    sumLen += (PCID_MAIN_U32 + priCapArrayCnt + 1);  // split with ','
74bae44755Sopenharmony_ci
75bae44755Sopenharmony_ci    // splicing string
76bae44755Sopenharmony_ci    allSyscapBuffer = (char *)malloc(sumLen);
77bae44755Sopenharmony_ci    if (allSyscapBuffer == nullptr) {
78bae44755Sopenharmony_ci        PRINT_ERR("malloc failed!");
79bae44755Sopenharmony_ci        return allSyscapBuffer;
80bae44755Sopenharmony_ci    }
81bae44755Sopenharmony_ci    err = memset_s(allSyscapBuffer, sumLen, 0, sumLen);
82bae44755Sopenharmony_ci    if (err != EOK) {
83bae44755Sopenharmony_ci        PRINT_ERR("memset failed!");
84bae44755Sopenharmony_ci        free(allSyscapBuffer);
85bae44755Sopenharmony_ci        return nullptr;
86bae44755Sopenharmony_ci    }
87bae44755Sopenharmony_ci    temp = *osCapArray;
88bae44755Sopenharmony_ci
89bae44755Sopenharmony_ci    for (size_t i = 1; i < PCID_MAIN_U32; i++) {
90bae44755Sopenharmony_ci        retError = sprintf_s(allSyscapBuffer, sumLen, "%s,%s", temp, osCapArray[i]);
91bae44755Sopenharmony_ci        if (retError == -1) {
92bae44755Sopenharmony_ci            PRINT_ERR("splicing os syscap string failed.");
93bae44755Sopenharmony_ci            free(allSyscapBuffer);
94bae44755Sopenharmony_ci            return nullptr;
95bae44755Sopenharmony_ci        }
96bae44755Sopenharmony_ci        temp = allSyscapBuffer;
97bae44755Sopenharmony_ci    }
98bae44755Sopenharmony_ci    for (int i = 0; i < priCapArrayCnt; i++) {
99bae44755Sopenharmony_ci        retError = sprintf_s(allSyscapBuffer, sumLen, "%s,%s", temp, *(priCapArray + i));
100bae44755Sopenharmony_ci        if (retError == -1) {
101bae44755Sopenharmony_ci            PRINT_ERR("splicing pri syscap string failed.");
102bae44755Sopenharmony_ci            free(allSyscapBuffer);
103bae44755Sopenharmony_ci            return nullptr;
104bae44755Sopenharmony_ci        }
105bae44755Sopenharmony_ci        temp = allSyscapBuffer;
106bae44755Sopenharmony_ci    }
107bae44755Sopenharmony_ci    return allSyscapBuffer;
108bae44755Sopenharmony_ci}
109bae44755Sopenharmony_ci
110bae44755Sopenharmony_cistatic char* GetSystemCapability()
111bae44755Sopenharmony_ci{
112bae44755Sopenharmony_ci    bool retBool;
113bae44755Sopenharmony_ci    int retError, priOutputLen, priCapArrayCnt;
114bae44755Sopenharmony_ci    char osOutput[SINGLE_SYSCAP_LEN] = {};
115bae44755Sopenharmony_ci
116bae44755Sopenharmony_ci    uint32_t *osCapU32 = nullptr;
117bae44755Sopenharmony_ci    char *priOutput = nullptr;
118bae44755Sopenharmony_ci
119bae44755Sopenharmony_ci    char *allSyscapBuffer = nullptr;
120bae44755Sopenharmony_ci    char osCapArray[PCID_MAIN_U32][U32_TO_STR_MAX_LEN] = {};
121bae44755Sopenharmony_ci    char (*priCapArray)[SINGLE_SYSCAP_LEN] = nullptr;
122bae44755Sopenharmony_ci
123bae44755Sopenharmony_ci    retBool = EncodeOsSyscap(osOutput, PCID_MAIN_BYTES);
124bae44755Sopenharmony_ci    if (!retBool) {
125bae44755Sopenharmony_ci        PRINT_ERR("get encoded os syscap failed.");
126bae44755Sopenharmony_ci        return nullptr;
127bae44755Sopenharmony_ci    }
128bae44755Sopenharmony_ci    retBool = EncodePrivateSyscap(&priOutput, &priOutputLen);
129bae44755Sopenharmony_ci    if (!retBool) {
130bae44755Sopenharmony_ci        PRINT_ERR("get encoded private syscap failed.");
131bae44755Sopenharmony_ci        goto FREE_PRIOUTPUT;
132bae44755Sopenharmony_ci    }
133bae44755Sopenharmony_ci
134bae44755Sopenharmony_ci    osCapU32 = reinterpret_cast<uint32_t *>(osOutput);
135bae44755Sopenharmony_ci    for (size_t i = 0; i < PCID_MAIN_U32; i++) { // 2, header of pcid.sc
136bae44755Sopenharmony_ci        retError = sprintf_s(osCapArray[i], U32_TO_STR_MAX_LEN, "%u", osCapU32[i]);
137bae44755Sopenharmony_ci        if (retError == -1) {
138bae44755Sopenharmony_ci            PRINT_ERR("get uint32_t syscap string failed.");
139bae44755Sopenharmony_ci            goto FREE_PRIOUTPUT;
140bae44755Sopenharmony_ci        }
141bae44755Sopenharmony_ci    }
142bae44755Sopenharmony_ci    retBool = DecodePrivateSyscap(priOutput, &priCapArray, &priCapArrayCnt);
143bae44755Sopenharmony_ci    allSyscapBuffer = CalculateAllStringLength(osCapArray, priCapArray, retBool, priCapArrayCnt);
144bae44755Sopenharmony_ci    free(priCapArray);
145bae44755Sopenharmony_ci
146bae44755Sopenharmony_ciFREE_PRIOUTPUT:
147bae44755Sopenharmony_ci    free(priOutput);
148bae44755Sopenharmony_ci
149bae44755Sopenharmony_ci    return allSyscapBuffer;
150bae44755Sopenharmony_ci}
151bae44755Sopenharmony_ci
152bae44755Sopenharmony_cinapi_value PreHandleSystemCapability(
153bae44755Sopenharmony_ci    napi_env env, napi_callback_info info, SystemCapabilityAsyncContext *asyncContext)
154bae44755Sopenharmony_ci{
155bae44755Sopenharmony_ci    GET_PARAMS(env, info, 1);
156bae44755Sopenharmony_ci    NAPI_ASSERT(env, argc <= 1, "too many parameters");
157bae44755Sopenharmony_ci    napi_value result = nullptr;
158bae44755Sopenharmony_ci
159bae44755Sopenharmony_ci    asyncContext->env = env;
160bae44755Sopenharmony_ci
161bae44755Sopenharmony_ci    napi_valuetype valueType = napi_undefined;
162bae44755Sopenharmony_ci    if (argc == 1) {
163bae44755Sopenharmony_ci        napi_typeof(env, argv[0], &valueType);
164bae44755Sopenharmony_ci    }
165bae44755Sopenharmony_ci    if (valueType == napi_function) {
166bae44755Sopenharmony_ci        napi_create_reference(env, argv[0], 1, &asyncContext->callbackRef);
167bae44755Sopenharmony_ci    }
168bae44755Sopenharmony_ci
169bae44755Sopenharmony_ci    if (asyncContext->callbackRef == nullptr) {
170bae44755Sopenharmony_ci        napi_create_promise(env, &asyncContext->deferred, &result);
171bae44755Sopenharmony_ci    } else {
172bae44755Sopenharmony_ci        napi_get_undefined(env, &result);
173bae44755Sopenharmony_ci    }
174bae44755Sopenharmony_ci    return result;
175bae44755Sopenharmony_ci}
176bae44755Sopenharmony_ci
177bae44755Sopenharmony_cinapi_value QuerySystemCapability(napi_env env, napi_callback_info info)
178bae44755Sopenharmony_ci{
179bae44755Sopenharmony_ci    SystemCapabilityAsyncContext *asyncContext = new SystemCapabilityAsyncContext();
180bae44755Sopenharmony_ci    napi_value result = PreHandleSystemCapability(env, info, asyncContext);
181bae44755Sopenharmony_ci    napi_value resource = nullptr;
182bae44755Sopenharmony_ci    napi_create_string_utf8(env, "napi_value QuerySystemCapability", NAPI_AUTO_LENGTH, &resource);
183bae44755Sopenharmony_ci
184bae44755Sopenharmony_ci    napi_create_async_work(
185bae44755Sopenharmony_ci        env, nullptr, resource,
186bae44755Sopenharmony_ci        [](napi_env env, void* data) {
187bae44755Sopenharmony_ci            SystemCapabilityAsyncContext *asyncContext = (SystemCapabilityAsyncContext *)data;
188bae44755Sopenharmony_ci            char *syscapStr = GetSystemCapability();
189bae44755Sopenharmony_ci            if (syscapStr != nullptr) {
190bae44755Sopenharmony_ci                asyncContext->value = syscapStr;
191bae44755Sopenharmony_ci                asyncContext->status = 0;
192bae44755Sopenharmony_ci            } else {
193bae44755Sopenharmony_ci                asyncContext->status = 1;
194bae44755Sopenharmony_ci            }
195bae44755Sopenharmony_ci        },
196bae44755Sopenharmony_ci        [](napi_env env, napi_status status, void* data) {
197bae44755Sopenharmony_ci            SystemCapabilityAsyncContext *asyncContext = (SystemCapabilityAsyncContext *)data;
198bae44755Sopenharmony_ci            napi_value result[2] = {nullptr, nullptr};
199bae44755Sopenharmony_ci            if (!asyncContext->status) {
200bae44755Sopenharmony_ci                napi_get_undefined(env, &result[0]);
201bae44755Sopenharmony_ci                napi_create_string_utf8(env, asyncContext->value, strlen(asyncContext->value), &result[1]); // ?
202bae44755Sopenharmony_ci            } else {
203bae44755Sopenharmony_ci                napi_value message = nullptr;
204bae44755Sopenharmony_ci                napi_create_string_utf8(env, "key does not exist", NAPI_AUTO_LENGTH, &message);
205bae44755Sopenharmony_ci                napi_create_error(env, nullptr, message, &result[0]);
206bae44755Sopenharmony_ci                napi_get_undefined(env, &result[1]);
207bae44755Sopenharmony_ci            }
208bae44755Sopenharmony_ci            if (asyncContext->deferred) {
209bae44755Sopenharmony_ci                if (!asyncContext->status) {
210bae44755Sopenharmony_ci                    napi_resolve_deferred(env, asyncContext->deferred, result[1]);
211bae44755Sopenharmony_ci                } else {
212bae44755Sopenharmony_ci                    napi_reject_deferred(env, asyncContext->deferred, result[0]);
213bae44755Sopenharmony_ci                }
214bae44755Sopenharmony_ci            } else {
215bae44755Sopenharmony_ci                napi_value callback = nullptr;
216bae44755Sopenharmony_ci                napi_value returnVal;
217bae44755Sopenharmony_ci                napi_get_reference_value(env, asyncContext->callbackRef, &callback);
218bae44755Sopenharmony_ci                napi_call_function(env, nullptr, callback, 2, result, &returnVal); // 2, count of result
219bae44755Sopenharmony_ci                napi_delete_reference(env, asyncContext->callbackRef);
220bae44755Sopenharmony_ci            }
221bae44755Sopenharmony_ci            napi_delete_async_work(env, asyncContext->work);
222bae44755Sopenharmony_ci            delete asyncContext;
223bae44755Sopenharmony_ci        },
224bae44755Sopenharmony_ci        (void*)asyncContext, &asyncContext->work);
225bae44755Sopenharmony_ci    napi_queue_async_work(env, asyncContext->work);
226bae44755Sopenharmony_ci
227bae44755Sopenharmony_ci    return result;
228bae44755Sopenharmony_ci}
229bae44755Sopenharmony_ci
230bae44755Sopenharmony_cinapi_value QuerryExport(napi_env env, napi_value exports)
231bae44755Sopenharmony_ci{
232bae44755Sopenharmony_ci    napi_property_descriptor desc[] = {
233bae44755Sopenharmony_ci        DECLARE_NAPI_FUNCTION("querySystemCapabilities", QuerySystemCapability),
234bae44755Sopenharmony_ci    };
235bae44755Sopenharmony_ci
236bae44755Sopenharmony_ci    NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
237bae44755Sopenharmony_ci    return exports;
238bae44755Sopenharmony_ci}
239bae44755Sopenharmony_ciEXTERN_C_END
240bae44755Sopenharmony_ci
241bae44755Sopenharmony_ci/*
242bae44755Sopenharmony_ci * Module define
243bae44755Sopenharmony_ci */
244bae44755Sopenharmony_cistatic napi_module g_systemCapabilityModule = {
245bae44755Sopenharmony_ci    .nm_version = 1,
246bae44755Sopenharmony_ci    .nm_flags = 0,
247bae44755Sopenharmony_ci    .nm_filename = nullptr,
248bae44755Sopenharmony_ci    .nm_register_func = QuerryExport,
249bae44755Sopenharmony_ci    .nm_modname = "systemCapability",
250bae44755Sopenharmony_ci    .nm_priv = nullptr,
251bae44755Sopenharmony_ci    .reserved = {nullptr},
252bae44755Sopenharmony_ci};
253bae44755Sopenharmony_ci
254bae44755Sopenharmony_ci/*
255bae44755Sopenharmony_ci * Module register function
256bae44755Sopenharmony_ci */
257bae44755Sopenharmony_ciextern "C" __attribute__((constructor)) void SystemCapabilityRegisterModule(void)
258bae44755Sopenharmony_ci{
259bae44755Sopenharmony_ci    napi_module_register(&g_systemCapabilityModule);
260bae44755Sopenharmony_ci}
261bae44755Sopenharmony_ci}