1 /*
2 * Copyright (c) 2021 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 #include "native_parameters_js.h"
16 #include "sysparam_errno.h"
17
18 static constexpr int ARGC_NUMBER = 2;
19 static constexpr int ARGC_THREE_NUMBER = 3;
20 static constexpr int MAX_NAME_LENGTH = 128;
21 static constexpr int MAX_VALUE_LENGTH = PARAM_CONST_VALUE_LEN_MAX;
22
23 typedef struct StorageAsyncContext {
24 napi_env env = nullptr;
25 napi_async_work work = nullptr;
26
27 char key[MAX_NAME_LENGTH] = { 0 };
28 size_t keyLen = 0;
29 char value[MAX_VALUE_LENGTH] = { 0 };
30 size_t valueLen = 0;
31 napi_deferred deferred = nullptr;
32 napi_ref callbackRef = nullptr;
33
34 int status = -1;
35 std::string getValue;
36 } StorageAsyncContext;
37
38 using StorageAsyncContextPtr = StorageAsyncContext *;
39
GetErrorInfo(int status,std::string & errMsg)40 static int GetErrorInfo(int status, std::string &errMsg)
41 {
42 switch (status) {
43 case EC_FAILURE:
44 case EC_SYSTEM_ERR:
45 case SYSPARAM_SYSTEM_ERROR:
46 errMsg = "System internal error such as out memory or deadlock";
47 return -SYSPARAM_SYSTEM_ERROR;
48 case EC_INVALID:
49 case SYSPARAM_INVALID_INPUT:
50 errMsg = "Input parameter is missing or invalid";
51 return -SYSPARAM_INVALID_INPUT;
52 case SYSPARAM_PERMISSION_DENIED:
53 errMsg = "The operation on the system permission is denied";
54 return -SYSPARAM_PERMISSION_DENIED;
55 case SYSPARAM_NOT_FOUND:
56 errMsg = "System parameter not found";
57 return -SYSPARAM_NOT_FOUND;
58 case SYSPARAM_INVALID_VALUE:
59 errMsg = "Invalid system parameter value";
60 return -SYSPARAM_INVALID_VALUE;
61 default:
62 errMsg = "System internal error such as out memory or deadlock";
63 return -SYSPARAM_SYSTEM_ERROR;
64 }
65 return 0;
66 }
67
BusinessErrorCreate(napi_env env,int status)68 static napi_value BusinessErrorCreate(napi_env env, int status)
69 {
70 std::string errMsg = "";
71 int ret = GetErrorInfo(status, errMsg);
72 PARAM_JS_LOGV("BusinessErrorCreate status %d err %d msg: %s", status, ret, errMsg.c_str());
73 napi_value code = nullptr;
74 napi_create_int32(env, ret, &code);
75 napi_value msg = nullptr;
76 napi_create_string_utf8(env, errMsg.c_str(), NAPI_AUTO_LENGTH, &msg);
77 napi_value businessError = nullptr;
78 napi_create_error(env, nullptr, msg, &businessError);
79 napi_set_named_property(env, businessError, "code", code);
80 return businessError;
81 }
82
83 #define PARAM_NAPI_ASSERT(env, assertion, result, info) \
84 do { \
85 if (!(assertion)) { \
86 napi_value d_err = BusinessErrorCreate(env, result); \
87 napi_throw(env, d_err); \
88 return nullptr; \
89 } \
90 } while (0)
91
GetParamString(napi_env env,napi_value arg,char * buffer,size_t maxBuff,size_t * keySize)92 static int GetParamString(napi_env env, napi_value arg, char *buffer, size_t maxBuff, size_t *keySize)
93 {
94 (void)napi_get_value_string_utf8(env, arg, nullptr, maxBuff - 1, keySize);
95 if (*keySize >= maxBuff) {
96 return SYSPARAM_INVALID_INPUT;
97 }
98 (void)napi_get_value_string_utf8(env, arg, buffer, maxBuff - 1, keySize);
99 return 0;
100 }
101
SetCallbackWork(napi_env env,StorageAsyncContextPtr asyncContext)102 static void SetCallbackWork(napi_env env, StorageAsyncContextPtr asyncContext)
103 {
104 napi_value resource = nullptr;
105 napi_create_string_utf8(env, "JSStartupSet", NAPI_AUTO_LENGTH, &resource);
106 napi_create_async_work(
107 env, nullptr, resource,
108 [](napi_env env, void *data) {
109 StorageAsyncContext *asyncContext = reinterpret_cast<StorageAsyncContext *>(data);
110 asyncContext->status = SetParameter(asyncContext->key, asyncContext->value);
111 PARAM_JS_LOGV("JSApp set status: %d, key: '%s', value: '%s'.",
112 asyncContext->status, asyncContext->key, asyncContext->value);
113 },
114 [](napi_env env, napi_status status, void *data) {
115 StorageAsyncContext *asyncContext = reinterpret_cast<StorageAsyncContext *>(data);
116 napi_value result[ARGC_NUMBER] = { 0 };
117 if (asyncContext->status == 0) {
118 napi_get_undefined(env, &result[0]);
119 napi_get_undefined(env, &result[1]);
120 } else {
121 result[0] = BusinessErrorCreate(env, asyncContext->status);
122 napi_get_undefined(env, &result[1]);
123 }
124
125 if (asyncContext->deferred) {
126 if (asyncContext->status == 0) {
127 napi_resolve_deferred(env, asyncContext->deferred, result[1]);
128 } else {
129 napi_reject_deferred(env, asyncContext->deferred, result[0]);
130 }
131 } else {
132 napi_value callback = nullptr;
133 napi_value callResult = nullptr;
134 napi_get_reference_value(env, asyncContext->callbackRef, &callback);
135 napi_call_function(env, nullptr, callback, ARGC_NUMBER, result, &callResult);
136 napi_delete_reference(env, asyncContext->callbackRef);
137 }
138 napi_delete_async_work(env, asyncContext->work);
139 delete asyncContext;
140 },
141 reinterpret_cast<void *>(asyncContext), &asyncContext->work);
142 napi_queue_async_work(env, asyncContext->work);
143 }
144
Set(napi_env env,napi_callback_info info)145 static napi_value Set(napi_env env, napi_callback_info info)
146 {
147 size_t argc = ARGC_THREE_NUMBER;
148 napi_value argv[ARGC_THREE_NUMBER] = { nullptr };
149 napi_value thisVar = nullptr;
150 void *data = nullptr;
151 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
152 PARAM_NAPI_ASSERT(env, argc >= ARGC_NUMBER, SYSPARAM_INVALID_INPUT, "requires 2 parameter");
153 StorageAsyncContextPtr asyncContext = new StorageAsyncContext();
154 asyncContext->env = env;
155 for (size_t i = 0; i < argc; i++) {
156 napi_valuetype valueType = napi_null;
157 napi_typeof(env, argv[i], &valueType);
158 int ret = 0;
159 if (i == 0 && valueType == napi_string) {
160 ret = GetParamString(env, argv[i], asyncContext->key, MAX_NAME_LENGTH, &asyncContext->keyLen);
161 } else if (i == 1 && valueType == napi_string) {
162 ret = GetParamString(env, argv[i], asyncContext->value, MAX_VALUE_LENGTH, &asyncContext->valueLen);
163 } else if (i == ARGC_NUMBER && valueType == napi_function) {
164 napi_create_reference(env, argv[i], 1, &asyncContext->callbackRef);
165 } else {
166 ret = SYSPARAM_INVALID_INPUT;
167 }
168 if (ret != 0) {
169 delete asyncContext;
170 ret = (i == 1) ? SYSPARAM_INVALID_VALUE : ret;
171 napi_value err = BusinessErrorCreate(env, ret);
172 napi_throw(env, err);
173 return nullptr;
174 }
175 }
176 PARAM_JS_LOGV("JSApp set key: %s(%d), value: %s(%d).",
177 asyncContext->key, asyncContext->keyLen, asyncContext->value, asyncContext->valueLen);
178
179 napi_value result = nullptr;
180 if (asyncContext->callbackRef == nullptr) {
181 napi_create_promise(env, &asyncContext->deferred, &result);
182 } else {
183 napi_get_undefined(env, &result);
184 }
185
186 SetCallbackWork(env, asyncContext);
187 return result;
188 }
189
SetSync(napi_env env,napi_callback_info info)190 static napi_value SetSync(napi_env env, napi_callback_info info)
191 {
192 size_t argc = ARGC_NUMBER;
193 napi_value args[ARGC_NUMBER] = { nullptr };
194 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
195 PARAM_NAPI_ASSERT(env, argc == ARGC_NUMBER, SYSPARAM_INVALID_INPUT, "Wrong number of arguments");
196 napi_valuetype valuetype0 = napi_null;
197 NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0));
198 napi_valuetype valuetype1 = napi_null;
199 NAPI_CALL(env, napi_typeof(env, args[1], &valuetype1));
200 PARAM_NAPI_ASSERT(env, valuetype0 == napi_string && valuetype1 == napi_string,
201 SYSPARAM_INVALID_INPUT, "Wrong argument type. string expected.");
202
203 size_t keySize = 0;
204 std::vector<char> keyBuf(MAX_NAME_LENGTH, 0);
205 int ret = GetParamString(env, args[0], keyBuf.data(), MAX_NAME_LENGTH, &keySize);
206 if (ret != 0) {
207 napi_value err = BusinessErrorCreate(env, SYSPARAM_INVALID_INPUT);
208 napi_throw(env, err);
209 return nullptr;
210 }
211 std::vector<char> value(MAX_VALUE_LENGTH, 0);
212 size_t valueSize = 0;
213 ret = GetParamString(env, args[1], value.data(), MAX_VALUE_LENGTH, &valueSize);
214 if (ret != 0) {
215 napi_value err = BusinessErrorCreate(env, SYSPARAM_INVALID_VALUE);
216 napi_throw(env, err);
217 return nullptr;
218 }
219 ret = SetParameter(keyBuf.data(), value.data());
220 PARAM_JS_LOGV("JSApp SetSync result:%d, key: '%s'.", ret, keyBuf.data());
221 napi_value napiValue = nullptr;
222 if (ret != 0) { // set failed
223 napi_value err = BusinessErrorCreate(env, ret);
224 napi_throw(env, err);
225 } else {
226 napi_get_undefined(env, &napiValue);
227 }
228 return napiValue;
229 }
230
GetSync(napi_env env,napi_callback_info info)231 static napi_value GetSync(napi_env env, napi_callback_info info)
232 {
233 size_t argc = ARGC_NUMBER;
234 napi_value args[ARGC_NUMBER] = { nullptr };
235 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
236 PARAM_NAPI_ASSERT(env, argc == 1 || argc == ARGC_NUMBER, SYSPARAM_INVALID_INPUT, "Wrong number of arguments");
237 napi_valuetype valuetype0 = napi_null;
238 NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0));
239 PARAM_NAPI_ASSERT(env, valuetype0 == napi_string, SYSPARAM_INVALID_INPUT, "Wrong argument type. Numbers expected.");
240
241 napi_valuetype valuetype1 = napi_null;
242 if (argc == ARGC_NUMBER) {
243 NAPI_CALL(env, napi_typeof(env, args[1], &valuetype1));
244 PARAM_NAPI_ASSERT(env, (valuetype1 == napi_string) || (valuetype1 == napi_undefined),
245 SYSPARAM_INVALID_INPUT, "Wrong argument type. string expected.");
246 }
247
248 size_t keySize = 0;
249 std::vector<char> keyBuf(MAX_NAME_LENGTH, 0);
250 int ret = GetParamString(env, args[0], keyBuf.data(), MAX_NAME_LENGTH, &keySize);
251 if (ret != 0) {
252 napi_throw(env, BusinessErrorCreate(env, SYSPARAM_INVALID_INPUT));
253 return nullptr;
254 }
255 std::vector<char> defValue(MAX_VALUE_LENGTH, 0);
256 size_t valueSize = 0;
257 int flag = 0;
258 if (argc == ARGC_NUMBER) {
259 if (valuetype1 == napi_undefined) {
260 valueSize = 0;
261 } else {
262 ret = GetParamString(env, args[1], defValue.data(), MAX_VALUE_LENGTH, &valueSize);
263 if (ret != 0) {
264 napi_throw(env, BusinessErrorCreate(env, SYSPARAM_INVALID_INPUT));
265 return nullptr;
266 }
267 flag = 1;
268 }
269 }
270 std::vector<char> value(MAX_VALUE_LENGTH, 0);
271 ret = GetParameter(keyBuf.data(), (flag == 0) ? nullptr : defValue.data(), value.data(), MAX_VALUE_LENGTH);
272 PARAM_JS_LOGV("JSApp get status: %d, key: '%s', value: '%s', defValue: '%s'.",
273 ret, keyBuf.data(), value.data(), defValue.data());
274
275 if (ret < 0) {
276 napi_throw(env, BusinessErrorCreate(env, ret));
277 return nullptr;
278 }
279
280 napi_value napiValue = nullptr;
281 NAPI_CALL(env, napi_create_string_utf8(env, value.data(), strlen(value.data()), &napiValue));
282 return napiValue;
283 }
284
GetCallbackWork(napi_env env,StorageAsyncContextPtr asyncContext)285 static void GetCallbackWork(napi_env env, StorageAsyncContextPtr asyncContext)
286 {
287 napi_value resource = nullptr;
288 napi_create_string_utf8(env, "JSStartupGet", NAPI_AUTO_LENGTH, &resource);
289 napi_create_async_work(
290 env, nullptr, resource,
291 [](napi_env env, void *data) {
292 StorageAsyncContext *asyncContext = reinterpret_cast<StorageAsyncContext *>(data);
293 std::vector<char> value(MAX_VALUE_LENGTH, 0);
294 asyncContext->status = GetParameter(asyncContext->key,
295 (asyncContext->valueLen == 0) ? nullptr : asyncContext->value, value.data(), MAX_VALUE_LENGTH);
296 if (asyncContext->status == 0) {
297 asyncContext->getValue = "";
298 } else if (asyncContext->status > 0) {
299 asyncContext->getValue = std::string(value.begin(), value.end());
300 }
301 },
302 [](napi_env env, napi_status status, void *data) {
303 StorageAsyncContext *asyncContext = reinterpret_cast<StorageAsyncContext *>(data);
304 napi_value result[ARGC_NUMBER] = { 0 };
305 if (asyncContext->status >= 0) {
306 napi_get_undefined(env, &result[0]);
307 napi_create_string_utf8(env,
308 asyncContext->getValue.c_str(), strlen(asyncContext->getValue.c_str()), &result[1]);
309 } else {
310 result[0] = BusinessErrorCreate(env, asyncContext->status);
311 napi_get_undefined(env, &result[1]);
312 }
313
314 if (asyncContext->deferred) {
315 if (asyncContext->status >= 0) {
316 napi_resolve_deferred(env, asyncContext->deferred, result[1]);
317 } else {
318 napi_reject_deferred(env, asyncContext->deferred, result[0]);
319 }
320 } else {
321 napi_value callback = nullptr;
322 napi_value callResult = nullptr;
323 napi_get_reference_value(env, asyncContext->callbackRef, &callback);
324 napi_call_function(env, nullptr, callback, ARGC_NUMBER, result, &callResult);
325 napi_delete_reference(env, asyncContext->callbackRef);
326 }
327 napi_delete_async_work(env, asyncContext->work);
328 delete asyncContext;
329 },
330 reinterpret_cast<void *>(asyncContext), &asyncContext->work);
331 napi_queue_async_work(env, asyncContext->work);
332 }
333
Get(napi_env env,napi_callback_info info)334 static napi_value Get(napi_env env, napi_callback_info info)
335 {
336 size_t argc = ARGC_THREE_NUMBER;
337 napi_value argv[ARGC_THREE_NUMBER] = { nullptr };
338 napi_value thisVar = nullptr;
339 void *data = nullptr;
340 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
341 PARAM_NAPI_ASSERT(env, argc >= 1, SYSPARAM_INVALID_INPUT, "requires 1 parameter");
342 StorageAsyncContextPtr asyncContext = new StorageAsyncContext();
343 asyncContext->env = env;
344 for (size_t i = 0; i < argc; i++) {
345 napi_valuetype valueType = napi_null;
346 napi_typeof(env, argv[i], &valueType);
347
348 int ret = 0;
349 if (i == 0 && valueType == napi_string) {
350 ret = GetParamString(env, argv[i], asyncContext->key, MAX_NAME_LENGTH, &asyncContext->keyLen);
351 } else if (i == 1 && valueType == napi_string) {
352 ret = GetParamString(env, argv[i], asyncContext->value, MAX_VALUE_LENGTH, &asyncContext->valueLen);
353 } else if (i == 1 && valueType == napi_undefined) {
354 asyncContext->valueLen = 0;
355 } else if (i == 1 && valueType == napi_function) {
356 napi_create_reference(env, argv[i], 1, &asyncContext->callbackRef);
357 break;
358 } else if (i == ARGC_NUMBER && valueType == napi_function) {
359 napi_create_reference(env, argv[i], 1, &asyncContext->callbackRef);
360 } else {
361 ret = SYSPARAM_INVALID_INPUT;
362 }
363 if (ret != 0) {
364 delete asyncContext;
365 ret = (i == 1) ? SYSPARAM_INVALID_VALUE : ret;
366 napi_value err = BusinessErrorCreate(env, ret);
367 napi_throw(env, err);
368 return nullptr;
369 }
370 }
371 PARAM_JS_LOGV("JSApp Get key: '%s'(%d), def value: '%s'(%d).",
372 asyncContext->key, asyncContext->keyLen, asyncContext->value, asyncContext->valueLen);
373
374 napi_value result = nullptr;
375 if (asyncContext->callbackRef == nullptr) {
376 napi_create_promise(env, &asyncContext->deferred, &result);
377 } else {
378 napi_get_undefined(env, &result);
379 }
380
381 GetCallbackWork(env, asyncContext);
382 return result;
383 }
384
385 EXTERN_C_START
386 /*
387 * Module init
388 */
Init(napi_env env,napi_value exports)389 static napi_value Init(napi_env env, napi_value exports)
390 {
391 /*
392 * Attribute definition
393 */
394 const napi_property_descriptor desc[] = {
395 DECLARE_NAPI_FUNCTION("set", Set),
396 DECLARE_NAPI_FUNCTION("setSync", SetSync),
397 DECLARE_NAPI_FUNCTION("get", Get),
398 DECLARE_NAPI_FUNCTION("getSync", GetSync),
399 #ifdef PARAM_SUPPORT_WAIT
400 DECLARE_NAPI_FUNCTION("wait", ParamWait),
401 DECLARE_NAPI_FUNCTION("getWatcher", GetWatcher)
402 #endif
403 };
404 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(napi_property_descriptor), desc));
405 #ifdef PARAM_SUPPORT_WAIT
406 return RegisterWatcher(env, exports);
407 #else
408 return exports;
409 #endif
410 }
411 EXTERN_C_END
412
413 /*
414 * Module definition
415 */
416 static napi_module _module_old = {
417 .nm_version = 1,
418 .nm_flags = 0,
419 .nm_filename = NULL,
420 .nm_register_func = Init,
421 .nm_modname = "systemParameterV9",
422 .nm_priv = ((void *)0),
423 .reserved = { 0 }
424 };
425
426 static napi_module _module = {
427 .nm_version = 1,
428 .nm_flags = 0,
429 .nm_filename = NULL,
430 .nm_register_func = Init,
431 .nm_modname = "systemParameterEnhance",
432 .nm_priv = ((void *)0),
433 .reserved = { 0 }
434 };
435
436 /*
437 * Module registration function
438 */
RegisterModule(void)439 extern "C" __attribute__((constructor)) void RegisterModule(void)
440 {
441 napi_module_register(&_module);
442 napi_module_register(&_module_old);
443 }
444