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 using StorageAsyncContext = 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 };
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 including out of memory, deadlock etc";
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 = "System permission operation permission denied";
54 return -SYSPARAM_PERMISSION_DENIED;
55 case SYSPARAM_NOT_FOUND:
56 errMsg = "System parameter can not be found";
57 return -SYSPARAM_NOT_FOUND;
58 case SYSPARAM_INVALID_VALUE:
59 errMsg = "System parameter value is invalid";
60 return -SYSPARAM_INVALID_VALUE;
61 default:
62 errMsg = "System internal error including out of memory, deadlock etc";
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 || *keySize == 0) {
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 if (argc == ARGC_NUMBER) {
258 if (valuetype1 == napi_undefined) {
259 valueSize = 0;
260 } else {
261 ret = GetParamString(env, args[1], defValue.data(), MAX_VALUE_LENGTH, &valueSize);
262 if (ret != 0) {
263 napi_throw(env, BusinessErrorCreate(env, SYSPARAM_INVALID_INPUT));
264 return nullptr;
265 }
266 }
267 }
268 std::vector<char> value(MAX_VALUE_LENGTH, 0);
269 ret = GetParameter(keyBuf.data(), (valueSize == 0) ? nullptr : defValue.data(), value.data(), MAX_VALUE_LENGTH);
270 PARAM_JS_LOGV("JSApp get status: %d, key: '%s', value: '%s', defValue: '%s'.",
271 ret, keyBuf.data(), value.data(), defValue.data());
272
273 if (ret < 0) {
274 napi_throw(env, BusinessErrorCreate(env, ret));
275 return nullptr;
276 }
277
278 napi_value napiValue = nullptr;
279 NAPI_CALL(env, napi_create_string_utf8(env, value.data(), strlen(value.data()), &napiValue));
280 return napiValue;
281 }
282
GetCallbackWork(napi_env env,StorageAsyncContextPtr asyncContext)283 static void GetCallbackWork(napi_env env, StorageAsyncContextPtr asyncContext)
284 {
285 napi_value resource = nullptr;
286 napi_create_string_utf8(env, "JSStartupGet", NAPI_AUTO_LENGTH, &resource);
287 napi_create_async_work(
288 env, nullptr, resource,
289 [](napi_env env, void *data) {
290 StorageAsyncContext *asyncContext = reinterpret_cast<StorageAsyncContext *>(data);
291 std::vector<char> value(MAX_VALUE_LENGTH, 0);
292 asyncContext->status = GetParameter(asyncContext->key,
293 (asyncContext->valueLen == 0) ? nullptr : asyncContext->value, value.data(), MAX_VALUE_LENGTH);
294 if (asyncContext->status == 0) {
295 asyncContext->getValue = "";
296 } else if (asyncContext->status > 0) {
297 asyncContext->getValue = std::string(value.begin(), value.end());
298 }
299 },
300 [](napi_env env, napi_status status, void *data) {
301 StorageAsyncContext *asyncContext = reinterpret_cast<StorageAsyncContext *>(data);
302 napi_value result[ARGC_NUMBER] = { 0 };
303 if (asyncContext->status >= 0) {
304 napi_get_undefined(env, &result[0]);
305 napi_create_string_utf8(env,
306 asyncContext->getValue.c_str(), strlen(asyncContext->getValue.c_str()), &result[1]);
307 } else {
308 result[0] = BusinessErrorCreate(env, asyncContext->status);
309 napi_get_undefined(env, &result[1]);
310 }
311
312 if (asyncContext->deferred) {
313 if (asyncContext->status >= 0) {
314 napi_resolve_deferred(env, asyncContext->deferred, result[1]);
315 } else {
316 napi_reject_deferred(env, asyncContext->deferred, result[0]);
317 }
318 } else {
319 napi_value callback = nullptr;
320 napi_value callResult = nullptr;
321 napi_get_reference_value(env, asyncContext->callbackRef, &callback);
322 napi_call_function(env, nullptr, callback, ARGC_NUMBER, result, &callResult);
323 napi_delete_reference(env, asyncContext->callbackRef);
324 }
325 napi_delete_async_work(env, asyncContext->work);
326 delete asyncContext;
327 },
328 reinterpret_cast<void *>(asyncContext), &asyncContext->work);
329 napi_queue_async_work(env, asyncContext->work);
330 }
331
Get(napi_env env,napi_callback_info info)332 static napi_value Get(napi_env env, napi_callback_info info)
333 {
334 size_t argc = ARGC_THREE_NUMBER;
335 napi_value argv[ARGC_THREE_NUMBER] = { nullptr };
336 napi_value thisVar = nullptr;
337 void *data = nullptr;
338 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
339 PARAM_NAPI_ASSERT(env, argc >= 1, SYSPARAM_INVALID_INPUT, "requires 1 parameter");
340 StorageAsyncContextPtr asyncContext = new StorageAsyncContext();
341 asyncContext->env = env;
342 for (size_t i = 0; i < argc; i++) {
343 napi_valuetype valueType = napi_null;
344 napi_typeof(env, argv[i], &valueType);
345
346 int ret = 0;
347 if (i == 0 && valueType == napi_string) {
348 ret = GetParamString(env, argv[i], asyncContext->key, MAX_NAME_LENGTH, &asyncContext->keyLen);
349 } else if (i == 1 && valueType == napi_string) {
350 ret = GetParamString(env, argv[i], asyncContext->value, MAX_VALUE_LENGTH, &asyncContext->valueLen);
351 } else if (i == 1 && valueType == napi_undefined) {
352 asyncContext->valueLen = 0;
353 } else if (i == 1 && valueType == napi_function) {
354 napi_create_reference(env, argv[i], 1, &asyncContext->callbackRef);
355 break;
356 } else if (i == ARGC_NUMBER && valueType == napi_function) {
357 napi_create_reference(env, argv[i], 1, &asyncContext->callbackRef);
358 } else {
359 ret = SYSPARAM_INVALID_INPUT;
360 }
361 if (ret != 0) {
362 delete asyncContext;
363 ret = (i == 1) ? SYSPARAM_INVALID_VALUE : ret;
364 napi_value err = BusinessErrorCreate(env, ret);
365 napi_throw(env, err);
366 return nullptr;
367 }
368 }
369 PARAM_JS_LOGV("JSApp Get key: '%s'(%d), def value: '%s'(%d).",
370 asyncContext->key, asyncContext->keyLen, asyncContext->value, asyncContext->valueLen);
371
372 napi_value result = nullptr;
373 if (asyncContext->callbackRef == nullptr) {
374 napi_create_promise(env, &asyncContext->deferred, &result);
375 } else {
376 napi_get_undefined(env, &result);
377 }
378
379 GetCallbackWork(env, asyncContext);
380 return result;
381 }
382
383 EXTERN_C_START
384 /*
385 * Module init
386 */
Init(napi_env env,napi_value exports)387 static napi_value Init(napi_env env, napi_value exports)
388 {
389 /*
390 * Attribute definition
391 */
392 const napi_property_descriptor desc[] = {
393 DECLARE_NAPI_FUNCTION("set", Set),
394 DECLARE_NAPI_FUNCTION("setSync", SetSync),
395 DECLARE_NAPI_FUNCTION("get", Get),
396 DECLARE_NAPI_FUNCTION("getSync", GetSync),
397 #ifdef PARAM_SUPPORT_WAIT
398 DECLARE_NAPI_FUNCTION("wait", ParamWait),
399 DECLARE_NAPI_FUNCTION("getWatcher", GetWatcher)
400 #endif
401 };
402 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(napi_property_descriptor), desc));
403 #ifdef PARAM_SUPPORT_WAIT
404 return RegisterWatcher(env, exports);
405 #else
406 return exports;
407 #endif
408 }
409 EXTERN_C_END
410
411 /*
412 * Module definition
413 */
414 static napi_module _module_old = {
415 .nm_version = 1,
416 .nm_flags = 0,
417 .nm_filename = NULL,
418 .nm_register_func = Init,
419 .nm_modname = "systemParameterV9",
420 .nm_priv = ((void *)0),
421 .reserved = { 0 }
422 };
423
424 static napi_module _module = {
425 .nm_version = 1,
426 .nm_flags = 0,
427 .nm_filename = NULL,
428 .nm_register_func = Init,
429 .nm_modname = "systemParameterEnhance",
430 .nm_priv = ((void *)0),
431 .reserved = { 0 }
432 };
433
434 /*
435 * Module registration function
436 */
RegisterModule(void)437 extern "C" __attribute__((constructor)) void RegisterModule(void)
438 {
439 napi_module_register(&_module);
440 napi_module_register(&_module_old);
441 }
442