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