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
16 #include <functional>
17 #include <vector>
18 #include "native_parameters_js.h"
19 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, 0, "StartupParametersJs" };
20 using namespace OHOS::HiviewDFX;
21 using namespace OHOS::system;
22 static constexpr int ARGC_NUMBER = 2;
23 static constexpr int BUF_LENGTH = 128;
24
25 static napi_ref g_paramWatchRef;
26
27 using ParamAsyncContext = struct {
28 napi_env env = nullptr;
29 napi_async_work work = nullptr;
30
31 char key[BUF_LENGTH] = { 0 };
32 size_t keyLen = 0;
33 char value[BUF_LENGTH] = { 0 };
34 size_t valueLen = 0;
35 int32_t timeout = 0;
36 napi_deferred deferred = nullptr;
37 napi_ref callbackRef = nullptr;
38
39 int status = -1;
40 std::string getValue;
41 };
42
43 using ParamWatcher = struct {
44 napi_env env = nullptr;
45 napi_ref thisVarRef = nullptr;
46 char keyPrefix[BUF_LENGTH] = { 0 };
47 size_t keyLen = 0;
48 bool notifySwitch = false;
49 bool startWatch = false;
50 std::mutex mutex {};
51 napi_ref currCallbackRef = nullptr;
52 std::map<uint32_t, napi_ref> callbackReferences {};
53 };
54
55 using ParamWatcherWork = struct {
56 napi_async_work work = nullptr;
57 ParamWatcher *watcher = nullptr;
58 bool startWatch = false;
59 };
60
61 using ParamAsyncContextPtr = ParamAsyncContext *;
62 using ParamWatcherPtr = ParamWatcher *;
63
NapiGetNull(napi_env env)64 static napi_value NapiGetNull(napi_env env)
65 {
66 napi_value result = 0;
67 napi_get_null(env, &result);
68 return result;
69 }
70
GetNapiValue(napi_env env,int val)71 static napi_value GetNapiValue(napi_env env, int val)
72 {
73 napi_value result = nullptr;
74 napi_create_int32(env, val, &result);
75 return result;
76 }
77
GetParamValue(napi_env env,napi_value arg,napi_valuetype valueType,char * buffer,size_t & buffLen)78 static int GetParamValue(napi_env env, napi_value arg, napi_valuetype valueType, char *buffer, size_t &buffLen)
79 {
80 napi_valuetype type = napi_null;
81 napi_typeof(env, arg, &type);
82 PARAM_JS_CHECK(type == valueType, return -1, "Invalid type %d %d", type, valueType);
83 napi_status status = napi_ok;
84 if (valueType == napi_string) {
85 status = napi_get_value_string_utf8(env, arg, buffer, buffLen, &buffLen);
86 } else if (valueType == napi_number) {
87 status = napi_get_value_int32(env, arg, (int *)buffer);
88 }
89 return status;
90 }
91
WaitCallbackWork(napi_env env,ParamAsyncContextPtr asyncContext)92 static void WaitCallbackWork(napi_env env, ParamAsyncContextPtr asyncContext)
93 {
94 napi_value resource = nullptr;
95 napi_create_string_utf8(env, "JSStartupGet", NAPI_AUTO_LENGTH, &resource);
96 napi_create_async_work(
97 env, nullptr, resource,
98 [](napi_env env, void *data) {
99 ParamAsyncContext *asyncContext = (ParamAsyncContext *)data;
100 asyncContext->status = WaitParameter(asyncContext->key, asyncContext->value, asyncContext->timeout);
101 HiLog::Debug(LABEL, "JSApp Wait status: %{public}d, key: %{public}s",
102 asyncContext->status, asyncContext->key);
103 },
104 [](napi_env env, napi_status status, void *data) {
105 ParamAsyncContext *asyncContext = (ParamAsyncContext *)data;
106 napi_value result[ARGC_NUMBER] = { 0 };
107 napi_value message = nullptr;
108 napi_create_object(env, &result[0]);
109 napi_create_int32(env, asyncContext->status, &message);
110 napi_set_named_property(env, result[0], "code", message);
111 napi_get_undefined(env, &result[1]); // only one param
112
113 HiLog::Debug(LABEL, "JSApp Wait status: %{public}d, key: %{public}s ",
114 asyncContext->status, asyncContext->key);
115 if (asyncContext->deferred) {
116 if (asyncContext->status == 0) {
117 napi_resolve_deferred(env, asyncContext->deferred, result[1]);
118 } else {
119 napi_reject_deferred(env, asyncContext->deferred, result[0]);
120 }
121 } else {
122 napi_value callbackRef = nullptr;
123 napi_value callResult = nullptr;
124 napi_status status = napi_get_reference_value(env, asyncContext->callbackRef, &callbackRef);
125 PARAM_JS_CHECK(status == 0 && callbackRef != nullptr, return, "Failed to get reference ");
126 napi_value undefined;
127 napi_get_undefined(env, &undefined);
128 napi_call_function(env, undefined, callbackRef, ARGC_NUMBER, result, &callResult);
129 napi_delete_reference(env, asyncContext->callbackRef);
130 }
131 napi_delete_async_work(env, asyncContext->work);
132 delete asyncContext;
133 },
134 (void *)asyncContext, &asyncContext->work);
135 napi_queue_async_work(env, asyncContext->work);
136 }
137
ParamWait(napi_env env,napi_callback_info info)138 napi_value ParamWait(napi_env env, napi_callback_info info)
139 {
140 constexpr int PARAM_TIMEOUT_INDEX = 2;
141 constexpr int ARGC_THREE_NUMBER = 3;
142 size_t argc = ARGC_THREE_NUMBER + 1;
143 napi_value argv[ARGC_THREE_NUMBER + 1];
144 napi_value thisVar = nullptr;
145 napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
146 PARAM_JS_CHECK(status == napi_ok, return GetNapiValue(env, status), "Failed to get cb info");
147 PARAM_JS_CHECK(argc >= ARGC_THREE_NUMBER, return GetNapiValue(env, status), "Failed to get argc");
148
149 ParamAsyncContextPtr asyncContext = new ParamAsyncContext();
150 PARAM_JS_CHECK(asyncContext != nullptr, return GetNapiValue(env, status), "Failed to create context");
151 asyncContext->env = env;
152
153 // get param key
154 asyncContext->keyLen = BUF_LENGTH - 1;
155 asyncContext->valueLen = BUF_LENGTH - 1;
156 size_t len = sizeof(asyncContext->timeout);
157 int ret = GetParamValue(env, argv[0], napi_string, asyncContext->key, asyncContext->keyLen);
158 PARAM_JS_CHECK(ret == 0, delete asyncContext;
159 return GetNapiValue(env, ret), "Invalid param for wait");
160 ret = GetParamValue(env, argv[1], napi_string, asyncContext->value, asyncContext->valueLen);
161 PARAM_JS_CHECK(ret == 0, delete asyncContext;
162 return GetNapiValue(env, ret), "Invalid param for wait");
163 ret = GetParamValue(env, argv[PARAM_TIMEOUT_INDEX], napi_number, (char *)&asyncContext->timeout, len);
164 PARAM_JS_CHECK(ret == 0, delete asyncContext;
165 return GetNapiValue(env, ret), "Invalid param for wait");
166 if (argc > ARGC_THREE_NUMBER) {
167 napi_valuetype valueType = napi_null;
168 napi_typeof(env, argv[ARGC_THREE_NUMBER], &valueType);
169 PARAM_JS_CHECK(valueType == napi_function, delete asyncContext;
170 return GetNapiValue(env, ret), "Invalid param for wait callbackRef");
171 napi_create_reference(env, argv[ARGC_THREE_NUMBER], 1, &asyncContext->callbackRef);
172 }
173 HiLog::Debug(LABEL, "JSApp Wait key: %{public}s, value: %{public}s timeout %{public}d.",
174 asyncContext->key, asyncContext->value, asyncContext->timeout);
175
176 napi_value result = nullptr;
177 if (asyncContext->callbackRef == nullptr) {
178 napi_create_promise(env, &asyncContext->deferred, &result);
179 } else {
180 result = GetNapiValue(env, 0);
181 }
182 WaitCallbackWork(env, asyncContext);
183 return result;
184 }
185
GetFristRefence(ParamWatcherPtr watcher,uint32_t & next)186 static bool GetFristRefence(ParamWatcherPtr watcher, uint32_t &next)
187 {
188 std::lock_guard<std::mutex> lock(watcher->mutex);
189 auto iter = watcher->callbackReferences.begin();
190 if (iter != watcher->callbackReferences.end()) {
191 next = watcher->callbackReferences.begin()->first;
192 return true;
193 }
194 return false;
195 }
196
GetWatcherReference(ParamWatcherPtr watcher,uint32_t next)197 static napi_ref GetWatcherReference(ParamWatcherPtr watcher, uint32_t next)
198 {
199 std::lock_guard<std::mutex> lock(watcher->mutex);
200 auto iter = watcher->callbackReferences.find(next);
201 if (iter != watcher->callbackReferences.end()) {
202 return iter->second;
203 }
204 return nullptr;
205 }
206
GetNextRefence(ParamWatcherPtr watcher,uint32_t & next)207 static uint32_t GetNextRefence(ParamWatcherPtr watcher, uint32_t &next)
208 {
209 std::lock_guard<std::mutex> lock(watcher->mutex);
210 auto iter = watcher->callbackReferences.upper_bound(next);
211 if (iter == watcher->callbackReferences.end()) {
212 return false;
213 }
214 next = iter->first;
215 return true;
216 }
217
AddWatcherCallback(ParamWatcherPtr watcher,napi_ref callbackRef)218 static void AddWatcherCallback(ParamWatcherPtr watcher, napi_ref callbackRef)
219 {
220 static uint32_t watcherId = 0;
221 std::lock_guard<std::mutex> lock(watcher->mutex);
222 watcherId++;
223 watcher->callbackReferences[watcherId] = callbackRef;
224 HiLog::Debug(LABEL, "JSApp watcher add watcher callback %{public}s %{public}u.",
225 watcher->keyPrefix, watcherId);
226 }
227
DelWatcherCallback(ParamWatcherPtr watcher,uint32_t next)228 static void DelWatcherCallback(ParamWatcherPtr watcher, uint32_t next)
229 {
230 HiLog::Debug(LABEL, "JSApp watcher key %{public}s delete callack %{public}u", watcher->keyPrefix, next);
231 std::lock_guard<std::mutex> lock(watcher->mutex);
232 watcher->callbackReferences.erase(next);
233 }
234
DelCallbackRef(napi_env env,ParamWatcherPtr watcher,napi_ref callbackRef,uint32_t id)235 static void DelCallbackRef(napi_env env, ParamWatcherPtr watcher, napi_ref callbackRef, uint32_t id)
236 {
237 std::lock_guard<std::mutex> lock(watcher->mutex);
238 if (callbackRef == watcher->currCallbackRef) {
239 HiLog::Debug(LABEL, "JSApp watcher key %{public}s has been callbacked %{public}u.",
240 watcher->keyPrefix, id);
241 watcher->currCallbackRef = nullptr;
242 } else {
243 napi_delete_reference(env, callbackRef);
244 }
245 watcher->callbackReferences.erase(id);
246 }
247
DelCallback(napi_env env,napi_value callback,ParamWatcherPtr watcher)248 static void DelCallback(napi_env env, napi_value callback, ParamWatcherPtr watcher)
249 {
250 bool isEquals = false;
251 uint32_t next = 0;
252 bool ret = GetFristRefence(watcher, next);
253 while (ret) {
254 napi_ref callbackRef = GetWatcherReference(watcher, next);
255 if (callbackRef == nullptr) {
256 HiLog::Debug(LABEL, "JSApp watcher key %{public}s callbackRef has been deleted %{public}d.",
257 watcher->keyPrefix, next);
258 DelWatcherCallback(watcher, next);
259 } else if (callback != nullptr) {
260 napi_value handler = nullptr;
261 napi_get_reference_value(env, callbackRef, &handler);
262 napi_strict_equals(env, handler, callback, &isEquals);
263 if (isEquals) {
264 DelCallbackRef(env, watcher, callbackRef, next);
265 break;
266 }
267 } else {
268 DelCallbackRef(env, watcher, callbackRef, next);
269 }
270 ret = GetNextRefence(watcher, next);
271 }
272 }
273
CheckCallbackEqual(napi_env env,napi_value callback,ParamWatcherPtr watcher)274 static bool CheckCallbackEqual(napi_env env, napi_value callback, ParamWatcherPtr watcher)
275 {
276 bool isEquals = false;
277 uint32_t next = 0;
278 bool ret = GetFristRefence(watcher, next);
279 while (ret) {
280 napi_ref callbackRef = GetWatcherReference(watcher, next);
281 if (callbackRef != nullptr) {
282 napi_value handler = nullptr;
283 napi_get_reference_value(env, callbackRef, &handler);
284 napi_strict_equals(env, handler, callback, &isEquals);
285 if (isEquals) {
286 return true;
287 }
288 }
289 ret = GetNextRefence(watcher, next);
290 }
291 return false;
292 }
293
ParamWatchConstructor(napi_env env,napi_callback_info info)294 static napi_value ParamWatchConstructor(napi_env env, napi_callback_info info)
295 {
296 size_t argc = 1;
297 napi_value argv[1];
298 napi_value thisVar = nullptr;
299 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
300 ParamWatcherPtr watcher = new ParamWatcher();
301 PARAM_JS_CHECK(watcher != nullptr, return NapiGetNull(env), "Failed to create param watcher");
302 napi_status status = napi_create_reference(env, thisVar, 1, &watcher->thisVarRef);
303 PARAM_JS_CHECK(status == 0, delete watcher;
304 return NapiGetNull(env), "Failed to create reference %d", status);
305
306 napi_wrap(
307 env, thisVar, watcher,
308 [](napi_env env, void *data, void *hint) {
309 ParamWatcherPtr watcher = static_cast<ParamWatcherPtr>(data);
310 if (watcher) {
311 DelCallback(env, nullptr, watcher);
312 WatchParameter(watcher->keyPrefix, nullptr, nullptr);
313 delete watcher;
314 watcher = nullptr;
315 }
316 },
317 nullptr, nullptr);
318 return thisVar;
319 }
320
GetWatcher(napi_env env,napi_callback_info info)321 napi_value GetWatcher(napi_env env, napi_callback_info info)
322 {
323 size_t argc = 1;
324 napi_value argv[1];
325 napi_value thisVar = nullptr;
326 void *data = nullptr;
327 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
328
329 napi_value obj = thisVar;
330 ParamWatcherPtr watcher = nullptr;
331 napi_unwrap(env, thisVar, (void **)&watcher);
332 if (watcher == nullptr) { // check if watcher exist
333 napi_value constructor = nullptr;
334 int status = napi_get_reference_value(env, g_paramWatchRef, &constructor);
335 PARAM_JS_CHECK(status == 0, return NapiGetNull(env), "Failed to get reference");
336 status = napi_new_instance(env, constructor, 0, nullptr, &obj);
337 PARAM_JS_CHECK(status == 0, return NapiGetNull(env), "Failed to create instance for watcher");
338 napi_unwrap(env, obj, (void **)&watcher);
339 }
340 if (watcher != nullptr) {
341 watcher->keyLen = BUF_LENGTH;
342 int ret = GetParamValue(env, argv[0], napi_string, watcher->keyPrefix, watcher->keyLen);
343 PARAM_JS_CHECK(ret == 0, return NapiGetNull(env), "Failed to get key prefix");
344 HiLog::Debug(LABEL, "JSApp watcher keyPrefix = %{public}s ", watcher->keyPrefix);
345 ret = WatchParameter(watcher->keyPrefix, nullptr, watcher);
346 PARAM_JS_CHECK(ret == 0, return NapiGetNull(env), "Failed to get watcher ret %{public}d", ret);
347 }
348 return obj;
349 }
350
GetWatcherInfo(napi_env env,napi_callback_info info,napi_value * callback)351 static ParamWatcherPtr GetWatcherInfo(napi_env env, napi_callback_info info, napi_value *callback)
352 {
353 size_t argc = ARGC_NUMBER;
354 napi_value argv[ARGC_NUMBER];
355 napi_value thisVar = nullptr;
356 void *data = nullptr;
357 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
358
359 size_t typeLen = BUF_LENGTH - 1;
360 std::vector<char> eventType(typeLen, 0);
361 int ret = GetParamValue(env, argv[0], napi_string, eventType.data(), typeLen);
362 PARAM_JS_CHECK(ret == 0, return nullptr, "Failed to get event type");
363 if (strcmp(eventType.data(), "valueChange") != 0) {
364 return nullptr;
365 }
366 // argv[1]:callbackRef
367 if (argc > 1) {
368 napi_valuetype valuetype;
369 napi_status status = napi_typeof(env, argv[1], &valuetype);
370 PARAM_JS_CHECK(status == 0, return nullptr, "Failed to get type");
371 PARAM_JS_CHECK(valuetype == napi_function, return nullptr, "Invalid type %d", valuetype);
372 *callback = argv[1];
373 }
374 ParamWatcherPtr watcher = nullptr;
375 napi_unwrap(env, thisVar, (void **)&watcher);
376 return watcher;
377 }
378
NotifyValueChange(ParamWatcherPtr watcher,uint32_t id,napi_value thisVar,const napi_value result[])379 static void NotifyValueChange(ParamWatcherPtr watcher, uint32_t id, napi_value thisVar, const napi_value result[])
380 {
381 napi_ref callbackRef = GetWatcherReference(watcher, id);
382 PARAM_JS_CHECK(callbackRef != nullptr, return,
383 "Failed to get callback for %{public}s %{public}d", watcher->keyPrefix, id);
384 napi_value callbackFunc = nullptr;
385 napi_status status = napi_get_reference_value(watcher->env, callbackRef, &callbackFunc);
386 PARAM_JS_CHECK(status == 0 && callbackFunc != nullptr, return,
387 "Failed to get callback for %{public}s %{public}d", watcher->keyPrefix, id);
388 {
389 std::lock_guard<std::mutex> lock(watcher->mutex);
390 watcher->currCallbackRef = callbackRef;
391 }
392
393 napi_value callbackResult = nullptr;
394 napi_call_function(watcher->env, thisVar, callbackFunc, ARGC_NUMBER, result, &callbackResult);
395
396 {
397 std::lock_guard<std::mutex> lock(watcher->mutex);
398 if (watcher->currCallbackRef == nullptr) {
399 HiLog::Debug(LABEL, "JSApp watcher notify key %{public}s callback deleted watcherId %{public}u",
400 watcher->keyPrefix, id);
401 napi_delete_reference(watcher->env, callbackRef);
402 }
403 watcher->currCallbackRef = nullptr;
404 }
405 }
406
ProcessParamChange(const char * key,const char * value,void * context)407 static void ProcessParamChange(const char *key, const char *value, void *context)
408 {
409 ParamWatcherPtr watcher = static_cast<ParamWatcherPtr>(context);
410 PARAM_JS_CHECK(watcher != nullptr && watcher->env != nullptr, return, "Invalid param");
411 PARAM_JS_CHECK(watcher->callbackReferences.size() > 0, return, "No callback for watcher");
412
413 napi_handle_scope scope = nullptr;
414 napi_status status = napi_open_handle_scope(watcher->env, &scope);
415 PARAM_JS_CHECK(status == 0, return, "Failed to get reference ");
416 napi_value result[ARGC_NUMBER] = { 0 };
417 napi_create_string_utf8(watcher->env, key, strlen(key), &result[0]);
418 napi_create_string_utf8(watcher->env, value, strlen(value), &result[1]);
419 napi_value thisVar = nullptr;
420 status = napi_get_reference_value(watcher->env, watcher->thisVarRef, &thisVar);
421 PARAM_JS_CHECK(status == 0 && thisVar != nullptr, napi_close_handle_scope(watcher->env, scope);
422 return, "Failed to get reference ");
423 uint32_t next = 0;
424 bool ret = GetFristRefence(watcher, next);
425 while (ret) {
426 NotifyValueChange(watcher, next, thisVar, result);
427 ret = GetNextRefence(watcher, next);
428 }
429 napi_close_handle_scope(watcher->env, scope);
430 HiLog::Debug(LABEL, "JSApp watcher ProcessParamChange %{public}s finish", key);
431 }
432
WatchCallbackWork(napi_env env,ParamWatcherPtr watcher)433 static void WatchCallbackWork(napi_env env, ParamWatcherPtr watcher)
434 {
435 HiLog::Debug(LABEL, "JSApp WatchCallbackWork key: %{public}s", watcher->keyPrefix);
436 ParamWatcherWork *worker = new ParamWatcherWork();
437 PARAM_JS_CHECK(worker != nullptr, return, "Failed to create worker ");
438 worker->watcher = watcher;
439 worker->work = nullptr;
440 worker->startWatch = watcher->startWatch;
441
442 napi_value resource = nullptr;
443 napi_create_string_utf8(env, "JSStartupWatch", NAPI_AUTO_LENGTH, &resource);
444 napi_create_async_work(env, nullptr, resource,
445 [](napi_env env, void *data) {
446 ParamWatcherWork *worker = (ParamWatcherWork *)data;
447 PARAM_JS_CHECK(worker != nullptr && worker->watcher != nullptr, return, "Invalid worker ");
448 int status = WatchParameter(worker->watcher->keyPrefix,
449 worker->startWatch ? ProcessParamChange : nullptr, worker->watcher);
450 HiLog::Debug(LABEL, "JSApp WatchCallbackWork %{public}s status: %{public}d, key: %{public}s",
451 worker->startWatch ? "on" : "off", status, worker->watcher->keyPrefix);
452 },
453 [](napi_env env, napi_status status, void *data) {
454 ParamWatcherWork *worker = (ParamWatcherWork *)data;
455 HiLog::Debug(LABEL, "JSApp WatchCallbackWork delete %{public}s key: %{public}s",
456 worker->startWatch ? "on" : "off", worker->watcher->keyPrefix);
457 napi_delete_async_work(env, worker->work);
458 delete worker;
459 },
460 (void *)worker, &worker->work);
461 napi_queue_async_work(env, worker->work);
462 }
463
SwithWatchOn(napi_env env,napi_callback_info info)464 static napi_value SwithWatchOn(napi_env env, napi_callback_info info)
465 {
466 napi_value callback = nullptr;
467 ParamWatcherPtr watcher = GetWatcherInfo(env, info, &callback);
468 PARAM_JS_CHECK(watcher != nullptr, return GetNapiValue(env, -1), "Failed to get watcher swith param");
469
470 if (CheckCallbackEqual(env, callback, watcher)) {
471 HiLog::Warn(LABEL, "JSApp watcher repeater switch on %{public}s", watcher->keyPrefix);
472 return 0;
473 }
474 HiLog::Debug(LABEL, "JSApp watcher on %{public}s", watcher->keyPrefix);
475 // save callback
476 napi_ref callbackRef;
477 napi_create_reference(env, callback, 1, &callbackRef);
478 AddWatcherCallback(watcher, callbackRef);
479 watcher->env = env;
480 {
481 std::lock_guard<std::mutex> lock(watcher->mutex);
482 if (watcher->startWatch) {
483 return GetNapiValue(env, 0);
484 }
485 watcher->startWatch = true;
486 }
487
488 HiLog::Debug(LABEL, "JSApp watcher add %{public}s", watcher->keyPrefix);
489 WatchCallbackWork(env, watcher);
490 HiLog::Debug(LABEL, "JSApp watcher on %{public}s finish", watcher->keyPrefix);
491 return GetNapiValue(env, 0);
492 }
493
SwithWatchOff(napi_env env,napi_callback_info info)494 static napi_value SwithWatchOff(napi_env env, napi_callback_info info)
495 {
496 napi_value callback = nullptr;
497 ParamWatcherPtr watcher = GetWatcherInfo(env, info, &callback);
498 PARAM_JS_CHECK(watcher != nullptr, return GetNapiValue(env, -1), "Failed to get watcher");
499 HiLog::Debug(LABEL, "JSApp watcher off %{public}s", watcher->keyPrefix);
500 DelCallback(env, callback, watcher);
501 {
502 std::lock_guard<std::mutex> lock(watcher->mutex);
503 if (watcher->callbackReferences.size() == 0) {
504 watcher->startWatch = false;
505 WatchCallbackWork(env, watcher);
506 }
507 }
508 return GetNapiValue(env, 0);
509 }
510
RegisterWatcher(napi_env env,napi_value exports)511 napi_value RegisterWatcher(napi_env env, napi_value exports)
512 {
513 napi_property_descriptor properties[] = {
514 DECLARE_NAPI_FUNCTION("on", SwithWatchOn),
515 DECLARE_NAPI_FUNCTION("off", SwithWatchOff),
516 };
517
518 napi_value result = nullptr;
519 NAPI_CALL(env,
520 napi_define_class(env,
521 "paramWatcher",
522 NAPI_AUTO_LENGTH,
523 ParamWatchConstructor,
524 nullptr,
525 sizeof(properties) / sizeof(*properties),
526 properties,
527 &result));
528 napi_set_named_property(env, exports, "paramWatcher", result);
529 napi_create_reference(env, result, 1, &g_paramWatchRef);
530 return exports;
531 }