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 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 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 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 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 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 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 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 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 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 */ 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 */ 437 extern "C" __attribute__((constructor)) void RegisterModule(void) 438 { 439 napi_module_register(&_module); 440 napi_module_register(&_module_old); 441 } 442