• 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 
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 }