• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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