1 /*
2  * Copyright (c) 2022-2024 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 "js_error_manager.h"
17 
18 #include <cstdint>
19 #include <unistd.h>
20 
21 #include "ability_business_error.h"
22 #include "application_data_manager.h"
23 #include "event_runner.h"
24 #include "hilog_tag_wrapper.h"
25 #include "js_error_observer.h"
26 #include "js_error_utils.h"
27 #include "js_runtime.h"
28 #include "js_runtime_utils.h"
29 #include "napi/native_api.h"
30 
31 namespace OHOS {
32 namespace AbilityRuntime {
33 namespace {
34 struct JsLoopObserver {
35     std::shared_ptr<AppExecFwk::EventRunner> mainRunner;
36     std::shared_ptr<NativeReference> observerObject;
37     napi_env env;
38 };
39 static std::shared_ptr<JsLoopObserver> loopObserver_;
40 constexpr int32_t INDEX_ZERO = 0;
41 constexpr int32_t INDEX_ONE = 1;
42 constexpr int32_t INDEX_TWO = 2;
43 constexpr size_t ARGC_ONE = 1;
44 constexpr size_t ARGC_TWO = 2;
45 constexpr size_t ARGC_THREE = 3;
46 constexpr const char* ON_OFF_TYPE = "error";
47 constexpr const char* ON_OFF_TYPE_UNHANDLED_REJECTION = "unhandledRejection";
48 constexpr const char* ON_OFF_TYPE_SYNC = "errorEvent";
49 constexpr const char* ON_OFF_TYPE_SYNC_LOOP = "loopObserver";
50 constexpr uint32_t INITITAL_REFCOUNT_ONE = 1;
51 
52 thread_local std::set<napi_ref> unhandledRejectionObservers;
53 thread_local std::map<napi_ref, napi_ref> pendingUnHandledRejections;
54 
AddRejection(napi_env env,napi_value promise,napi_value reason)55 napi_value AddRejection(napi_env env, napi_value promise, napi_value reason)
56 {
57     napi_ref promiseRef = nullptr;
58     NAPI_CALL(env, napi_create_reference(env, promise, INITITAL_REFCOUNT_ONE, &promiseRef));
59     napi_ref reasonRef = nullptr;
60     NAPI_CALL(env, napi_create_reference(env, reason, INITITAL_REFCOUNT_ONE, &reasonRef));
61     pendingUnHandledRejections.insert(std::make_pair(promiseRef, reasonRef));
62     return CreateJsUndefined(env);
63 }
64 
RemoveRejection(napi_env env,napi_value promise)65 napi_value RemoveRejection(napi_env env, napi_value promise)
66 {
67     napi_value ret = CreateJsUndefined(env);
68     auto iter = pendingUnHandledRejections.begin();
69     while (iter != pendingUnHandledRejections.end()) {
70         napi_value prom = nullptr;
71         NAPI_CALL(env, napi_get_reference_value(env, iter->first, &prom));
72         bool isEquals = false;
73         NAPI_CALL(env, napi_strict_equals(env, promise, prom, &isEquals));
74         if (isEquals) {
75             NAPI_CALL(env, napi_delete_reference(env, iter->first));
76             NAPI_CALL(env, napi_delete_reference(env, iter->second));
77             pendingUnHandledRejections.erase(iter);
78             return ret;
79         }
80         ++iter;
81     }
82     return ret;
83 }
84 
UnhandledRejectionHandler(napi_env env,napi_value promise,napi_value reason)85 napi_value UnhandledRejectionHandler(napi_env env, napi_value promise, napi_value reason)
86 {
87     napi_value global = nullptr;
88     NAPI_CALL(env, napi_get_global(env, &global));
89     size_t argc = ARGC_TWO;
90     napi_value args[] = {reason, promise};
91     for (auto& iter : unhandledRejectionObservers) {
92         napi_value cb = nullptr;
93         NAPI_CALL(env, napi_get_reference_value(env, iter, &cb));
94         napi_value result = nullptr;
95         NAPI_CALL(env, napi_call_function(env, global, cb, argc, args, &result));
96     }
97     return CreateJsUndefined(env);
98 }
99 
OnUnhandledRejection(napi_env env,napi_callback_info info)100 static napi_value OnUnhandledRejection(napi_env env, napi_callback_info info)
101 {
102     size_t argc = ARGC_THREE; // 3 parameter size
103     napi_value argv[ARGC_THREE] = {0}; // 3 array length
104     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
105     int32_t event = 0;
106     NAPI_CALL(env, napi_get_value_int32(env, argv[0], &event));
107     if (event == static_cast<int32_t>(UnhandledRejectionEvent::REJECT)) {
108         return AddRejection(env, argv[INDEX_ONE], argv[INDEX_TWO]); // 2 array index
109     }
110     if (event == static_cast<int32_t>(UnhandledRejectionEvent::HANDLE)) {
111         return RemoveRejection(env, argv[INDEX_ONE]);
112     }
113     ThrowError(env, AbilityErrorCode::ERROR_CODE_INNER);
114     return CreateJsUndefined(env);
115 }
116 
NotifyUnhandledRejectionHandler(napi_env env,napi_callback_info info)117 static napi_value NotifyUnhandledRejectionHandler(napi_env env, napi_callback_info info)
118 {
119     if (!pendingUnHandledRejections.empty()) {
120         auto iter = pendingUnHandledRejections.begin();
121         while (iter != pendingUnHandledRejections.end()) {
122             napi_value promise = nullptr;
123             NAPI_CALL(env, napi_get_reference_value(env, iter->first, &promise));
124             napi_value reason = nullptr;
125             NAPI_CALL(env, napi_get_reference_value(env, iter->second, &reason));
126 
127             UnhandledRejectionHandler(env, promise, reason);
128 
129             NAPI_CALL(env, napi_delete_reference(env, iter->first));
130             NAPI_CALL(env, napi_delete_reference(env, iter->second));
131             iter = pendingUnHandledRejections.erase(iter);
132         }
133     }
134     return CreateJsUndefined(env);
135 }
136 
137 class JsErrorManager final {
138 public:
JsErrorManager()139     JsErrorManager() {}
140     ~JsErrorManager() = default;
141 
Finalizer(napi_env env,void * data,void * hint)142     static void Finalizer(napi_env env, void* data, void* hint)
143     {
144         TAG_LOGI(AAFwkTag::JSNAPI, "finalizer called");
145         std::unique_ptr<JsErrorManager>(static_cast<JsErrorManager*>(data));
146         ClearReference(env);
147     }
148 
On(napi_env env,napi_callback_info info)149     static napi_value On(napi_env env, napi_callback_info info)
150     {
151         GET_CB_INFO_AND_CALL(env, info, JsErrorManager, OnOn);
152     }
153 
Off(napi_env env,napi_callback_info info)154     static napi_value Off(napi_env env, napi_callback_info info)
155     {
156         GET_CB_INFO_AND_CALL(env, info, JsErrorManager, OnOff);
157     }
158 
SetRejectionCallback(napi_env env) const159     napi_value SetRejectionCallback(napi_env env) const
160     {
161         napi_value rejectCallback = nullptr;
162         std::string rejectCallbackName = "OnUnhandledRejection";
163         NAPI_CALL(env, napi_create_function(env,
164                                             rejectCallbackName.c_str(),
165                                             rejectCallbackName.size(),
166                                             OnUnhandledRejection,
167                                             nullptr, &rejectCallback));
168         napi_ref rejectCallbackRef = nullptr;
169         NAPI_CALL(env, napi_create_reference(env, rejectCallback, INITITAL_REFCOUNT_ONE, &rejectCallbackRef));
170 
171         napi_value checkCallback = nullptr;
172         std::string checkCallbackName = "NotifyUnhandledRejectionHandler";
173         NAPI_CALL(env, napi_create_function(env,
174                                             checkCallbackName.c_str(),
175                                             checkCallbackName.size(),
176                                             NotifyUnhandledRejectionHandler,
177                                             nullptr, &checkCallback));
178         napi_ref checkCallbackRef = nullptr;
179         NAPI_CALL(env, napi_create_reference(env, checkCallback, INITITAL_REFCOUNT_ONE, &checkCallbackRef));
180 
181         NAPI_CALL(env, napi_set_promise_rejection_callback(env, rejectCallbackRef, checkCallbackRef));
182 
183         return CreateJsUndefined(env);
184     }
185 
ClearReference(napi_env env)186     static void ClearReference(napi_env env)
187     {
188         for (auto& iter : unhandledRejectionObservers) {
189             napi_delete_reference(env, iter);
190         }
191         unhandledRejectionObservers.clear();
192 
193         auto iter = pendingUnHandledRejections.begin();
194         while (iter != pendingUnHandledRejections.end()) {
195             napi_delete_reference(env, iter->first);
196             napi_delete_reference(env, iter->second);
197             ++iter;
198         }
199         pendingUnHandledRejections.clear();
200     }
201 
202 private:
OnOn(napi_env env,const size_t argc,napi_value * argv)203     napi_value OnOn(napi_env env, const size_t argc, napi_value* argv)
204     {
205         TAG_LOGD(AAFwkTag::JSNAPI, "called");
206         std::string type = ParseParamType(env, argc, argv);
207         if (type == ON_OFF_TYPE_SYNC) {
208             return OnOnNew(env, argc, argv);
209         }
210         if (type == ON_OFF_TYPE_SYNC_LOOP) {
211             if (!AppExecFwk::EventRunner::IsAppMainThread()) {
212                 TAG_LOGE(AAFwkTag::JSNAPI, "not mainThread");
213                 ThrowInvalidCallerError(env);
214                 return CreateJsUndefined(env);
215             }
216             return OnSetLoopWatch(env, argc, argv);
217         }
218         if (type == ON_OFF_TYPE_UNHANDLED_REJECTION) {
219             if (argc != ARGC_TWO) {
220                 TAG_LOGE(AAFwkTag::JSNAPI, "invalid argc");
221                 ThrowInvalidNumParametersError(env);
222                 return CreateJsUndefined(env);
223             }
224             return OnOnUnhandledRejection(env, argv[INDEX_ONE]);
225         }
226         return OnOnOld(env, argc, argv);
227     }
228 
OnOnOld(napi_env env,const size_t argc,napi_value * argv)229     napi_value OnOnOld(napi_env env, const size_t argc, napi_value* argv)
230     {
231         TAG_LOGD(AAFwkTag::JSNAPI, "called");
232         if (argc != ARGC_TWO) {
233             TAG_LOGE(AAFwkTag::JSNAPI, "invalid argc");
234             ThrowTooFewParametersError(env);
235             return CreateJsUndefined(env);
236         }
237 
238         std::string type;
239         if (!ConvertFromJsValue(env, argv[INDEX_ZERO], type) || type != ON_OFF_TYPE) {
240             ThrowInvalidParamError(env, "Parameter error: Parse type failed, must be a string error.");
241             TAG_LOGE(AAFwkTag::JSNAPI, "parse type failed");
242             return CreateJsUndefined(env);
243         }
244         int32_t observerId = serialNumber_;
245         if (serialNumber_ < INT32_MAX) {
246             serialNumber_++;
247         } else {
248             serialNumber_ = 0;
249         }
250 
251         if (observer_ == nullptr) {
252             TAG_LOGD(AAFwkTag::JSNAPI, "null observer_");
253             // create observer
254             observer_ = std::make_shared<JsErrorObserver>(env);
255             AppExecFwk::ApplicationDataManager::GetInstance().AddErrorObserver(observer_);
256         }
257         observer_->AddJsObserverObject(observerId, argv[INDEX_ONE]);
258         return CreateJsValue(env, observerId);
259     }
260 
OnOnUnhandledRejection(napi_env env,napi_value function)261     napi_value OnOnUnhandledRejection(napi_env env, napi_value function)
262     {
263         if (!ValidateFunction(env, function)) {
264             return nullptr;
265         }
266         for (auto& iter : unhandledRejectionObservers) {
267             napi_value observer = nullptr;
268             NAPI_CALL(env, napi_get_reference_value(env, iter, &observer));
269             bool equals = false;
270             NAPI_CALL(env, napi_strict_equals(env, observer, function, &equals));
271             if (equals) {
272                 NAPI_CALL(env, napi_delete_reference(env, iter));
273                 unhandledRejectionObservers.erase(iter);
274                 break;
275             }
276         }
277         napi_ref myCallRef = nullptr;
278         NAPI_CALL(env, napi_create_reference(env, function, INITITAL_REFCOUNT_ONE, &myCallRef));
279         unhandledRejectionObservers.insert(myCallRef);
280         return nullptr;
281     }
282 
OnOnNew(napi_env env,const size_t argc,napi_value * argv)283     napi_value OnOnNew(napi_env env, const size_t argc, napi_value* argv)
284     {
285         TAG_LOGD(AAFwkTag::JSNAPI, "called");
286         if (argc < ARGC_TWO) {
287             TAG_LOGE(AAFwkTag::JSNAPI, "invalid argc");
288             ThrowTooFewParametersError(env);
289             return CreateJsUndefined(env);
290         }
291 
292         if (!CheckTypeForNapiValue(env, argv[INDEX_ONE], napi_object)) {
293             TAG_LOGE(AAFwkTag::JSNAPI, "invalid param");
294             ThrowInvalidParamError(env, "Parameter error: Parse observer failed, must be a ErrorObserver.");
295             return CreateJsUndefined(env);
296         }
297 
298         int32_t observerId = serialNumber_;
299         if (serialNumber_ < INT32_MAX) {
300             serialNumber_++;
301         } else {
302             serialNumber_ = 0;
303         }
304 
305         if (observer_ == nullptr) {
306             // create observer
307             observer_ = std::make_shared<JsErrorObserver>(env);
308             AppExecFwk::ApplicationDataManager::GetInstance().AddErrorObserver(observer_);
309         }
310         observer_->AddJsObserverObject(observerId, argv[INDEX_ONE], true);
311         return CreateJsValue(env, observerId);
312     }
313 
OnOff(napi_env env,size_t argc,napi_value * argv)314     napi_value OnOff(napi_env env, size_t argc, napi_value* argv)
315     {
316         TAG_LOGD(AAFwkTag::JSNAPI, "called");
317         std::string type = ParseParamType(env, argc, argv);
318         if (type == ON_OFF_TYPE_SYNC) {
319             return OnOffNew(env, argc, argv);
320         }
321         if (type == ON_OFF_TYPE_SYNC_LOOP) {
322             if (!AppExecFwk::EventRunner::IsAppMainThread()) {
323                 TAG_LOGE(AAFwkTag::JSNAPI, "not mainThread");
324                 ThrowInvalidCallerError(env);
325                 return CreateJsUndefined(env);
326             }
327             return OnRemoveLoopWatch(env, argc, argv);
328         }
329         if (type == ON_OFF_TYPE_UNHANDLED_REJECTION) {
330             if (argc != ARGC_TWO && argc != ARGC_ONE) {
331                 TAG_LOGE(AAFwkTag::JSNAPI, "invalid argc");
332                 ThrowInvalidNumParametersError(env);
333                 return CreateJsUndefined(env);
334             }
335             return OnOffUnhandledRejection(env, argc, argv);
336         }
337         return OnOffOld(env, argc, argv);
338     }
339 
OnOffOld(napi_env env,size_t argc,napi_value * argv)340     napi_value OnOffOld(napi_env env, size_t argc, napi_value* argv)
341     {
342         TAG_LOGD(AAFwkTag::JSNAPI, "called");
343         int32_t observerId = -1;
344         if (argc != ARGC_TWO && argc != ARGC_THREE) {
345             ThrowTooFewParametersError(env);
346             TAG_LOGE(AAFwkTag::JSNAPI, "invalid argc");
347         } else {
348             napi_get_value_int32(env, argv[INDEX_ONE], &observerId);
349             TAG_LOGI(AAFwkTag::JSNAPI, "observer:%{public}d", observerId);
350         }
351 
352         std::string type;
353         if (!ConvertFromJsValue(env, argv[INDEX_ZERO], type) || type != ON_OFF_TYPE) {
354             TAG_LOGE(AAFwkTag::JSNAPI, "parse type failed");
355             ThrowInvalidParamError(env, "Parameter error: Parse type failed, must be a string error.");
356             return CreateJsUndefined(env);
357         }
358 
359         NapiAsyncTask::CompleteCallback complete =
360             [&observer = observer_, observerId](
361                 napi_env env, NapiAsyncTask& task, int32_t status) {
362             TAG_LOGI(AAFwkTag::JSNAPI, "complete called");
363                 if (observerId == -1) {
364                     task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INVALID_PARAM));
365                     return;
366                 }
367                 if (observer && observer->RemoveJsObserverObject(observerId)) {
368                     task.ResolveWithNoError(env, CreateJsUndefined(env));
369                 } else {
370                     task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INVALID_ID));
371                 }
372                 if (observer && observer->IsEmpty()) {
373                     AppExecFwk::ApplicationDataManager::GetInstance().RemoveErrorObserver();
374                     observer = nullptr;
375                 }
376             };
377 
378         napi_value lastParam = (argc <= ARGC_TWO) ? nullptr : argv[INDEX_TWO];
379         napi_value result = nullptr;
380         NapiAsyncTask::Schedule("JSErrorManager::OnUnregisterErrorObserver",
381             env, CreateAsyncTaskWithLastParam(env, lastParam, nullptr, std::move(complete), &result));
382         return result;
383     }
384 
OnOffUnhandledRejection(napi_env env,size_t argc,napi_value * argv)385     napi_value OnOffUnhandledRejection(napi_env env, size_t argc, napi_value* argv)
386     {
387         auto res = CreateJsUndefined(env);
388         if (argc == ARGC_ONE) {
389             for (auto& iter : unhandledRejectionObservers) {
390                 napi_delete_reference(env, iter);
391             }
392             unhandledRejectionObservers.clear();
393             return res;
394         }
395         napi_value function = argv[INDEX_ONE];
396         if (!ValidateFunction(env, function)) {
397             return res;
398         }
399         for (auto& iter : unhandledRejectionObservers) {
400             napi_value observer = nullptr;
401             NAPI_CALL(env, napi_get_reference_value(env, iter, &observer));
402             bool equals = false;
403             NAPI_CALL(env, napi_strict_equals(env, observer, function, &equals));
404             if (equals) {
405                 NAPI_CALL(env, napi_delete_reference(env, iter));
406                 unhandledRejectionObservers.erase(iter);
407                 return res;
408             }
409         }
410         TAG_LOGE(AAFwkTag::JSNAPI, "remove observer failed");
411         ThrowError(env, AbilityErrorCode::ERROR_CODE_OBSERVER_NOT_FOUND);
412         return res;
413     }
414 
OnOffNew(napi_env env,size_t argc,napi_value * argv)415     napi_value OnOffNew(napi_env env, size_t argc, napi_value* argv)
416     {
417         TAG_LOGD(AAFwkTag::JSNAPI, "called");
418         if (argc < ARGC_TWO) {
419             ThrowTooFewParametersError(env);
420             TAG_LOGE(AAFwkTag::JSNAPI, "invalid argc");
421             return CreateJsUndefined(env);
422         }
423         int32_t observerId = -1;
424         if (!ConvertFromJsValue(env, argv[INDEX_ONE], observerId)) {
425             TAG_LOGE(AAFwkTag::JSNAPI, "parse observerId failed");
426             ThrowInvalidParamError(env, "Parameter error: Parse observerId failed, must be a number.");
427             return CreateJsUndefined(env);
428         }
429         if (observer_ == nullptr) {
430             TAG_LOGE(AAFwkTag::JSNAPI, "null observer");
431             ThrowError(env, AbilityErrorCode::ERROR_CODE_INNER);
432             return CreateJsUndefined(env);
433         }
434         if (observer_->RemoveJsObserverObject(observerId, true)) {
435             TAG_LOGD(AAFwkTag::JSNAPI, "success");
436         } else {
437             TAG_LOGE(AAFwkTag::JSNAPI, "failed");
438             ThrowError(env, AbilityErrorCode::ERROR_CODE_INVALID_ID);
439         }
440         if (observer_->IsEmpty()) {
441             AppExecFwk::ApplicationDataManager::GetInstance().RemoveErrorObserver();
442             observer_ = nullptr;
443         }
444         return CreateJsUndefined(env);
445     }
446 
CallJsFunction(napi_env env,napi_value obj,const char * methodName,napi_value const * argv,size_t argc)447     static void CallJsFunction(napi_env env, napi_value obj, const char* methodName,
448         napi_value const* argv, size_t argc)
449     {
450         TAG_LOGI(AAFwkTag::JSNAPI, "call func: %{public}s", methodName);
451         if (obj == nullptr) {
452             TAG_LOGE(AAFwkTag::JSNAPI, "null obj");
453             return;
454         }
455 
456         napi_value method = nullptr;
457         napi_get_named_property(env, obj, methodName, &method);
458         if (method == nullptr) {
459             TAG_LOGE(AAFwkTag::JSNAPI, "null method");
460             return;
461         }
462         napi_value callResult = nullptr;
463         napi_call_function(env, obj, method, argc, argv, &callResult);
464     }
465 
CallbackTimeout(int64_t number)466     static void CallbackTimeout(int64_t number)
467     {
468         std::unique_ptr<NapiAsyncTask::CompleteCallback> complete = std::make_unique<NapiAsyncTask::CompleteCallback>
469             ([number](napi_env env, NapiAsyncTask &task, int32_t status) {
470                 if (loopObserver_ == nullptr) {
471                     TAG_LOGE(AAFwkTag::JSNAPI, "null loopObserver_");
472                     return;
473                 }
474                 if (loopObserver_->env == nullptr) {
475                     TAG_LOGE(AAFwkTag::JSNAPI, "null env");
476                     return;
477                 }
478                 if (loopObserver_->observerObject == nullptr) {
479                     TAG_LOGE(AAFwkTag::JSNAPI, "null observer");
480                     return;
481                 }
482                 napi_value jsValue[] = { CreateJsValue(loopObserver_->env, number) };
483                 CallJsFunction(loopObserver_->env, loopObserver_->observerObject->GetNapiValue(), "onLoopTimeOut",
484                     jsValue, ARGC_ONE);
485             });
486         napi_ref callback = nullptr;
487         std::unique_ptr<NapiAsyncTask::ExecuteCallback> execute = nullptr;
488         if (loopObserver_ && loopObserver_->env) {
489             NapiAsyncTask::Schedule("JsErrorObserver::CallbackTimeout",
490                 loopObserver_->env, std::make_unique<NapiAsyncTask>(callback, std::move(execute), std::move(complete)));
491         }
492     }
493 
OnSetLoopWatch(napi_env env,size_t argc,napi_value * argv)494     napi_value OnSetLoopWatch(napi_env env, size_t argc, napi_value* argv)
495     {
496         if (argc != ARGC_THREE) {
497             TAG_LOGE(AAFwkTag::JSNAPI, "invalid argc");
498             ThrowTooFewParametersError(env);
499             return CreateJsUndefined(env);
500         }
501         if (!CheckTypeForNapiValue(env, argv[INDEX_ONE], napi_number)) {
502             TAG_LOGE(AAFwkTag::JSNAPI, "invalid param");
503             ThrowInvalidParamError(env, "Parameter error: Failed to parse timeout, must be a number.");
504             return CreateJsUndefined(env);
505         }
506         if (!CheckTypeForNapiValue(env, argv[INDEX_TWO], napi_object)) {
507             TAG_LOGE(AAFwkTag::JSNAPI, "invalid param");
508             ThrowInvalidParamError(env, "Parameter error: Failed to parse observer, must be a LoopObserver.");
509             return CreateJsUndefined(env);
510         }
511         int64_t number;
512         if (!ConvertFromJsNumber(env, argv[INDEX_ONE], number)) {
513             TAG_LOGE(AAFwkTag::JSNAPI, "parse timeout failed");
514             ThrowInvalidParamError(env, "Parameter error: Failed to parse timeout, must be a number.");
515             return CreateJsUndefined(env);
516         }
517         if (number <= 0) {
518             TAG_LOGE(AAFwkTag::JSNAPI, "timeout<=0");
519             ThrowInvalidParamError(env, "Parameter error: The timeout cannot be less than 0.");
520             return CreateJsUndefined(env);
521         }
522 
523         if (loopObserver_ == nullptr) {
524             loopObserver_ = std::make_shared<JsLoopObserver>();
525         }
526         loopObserver_->mainRunner = AppExecFwk::EventRunner::GetMainEventRunner();
527         napi_ref ref = nullptr;
528         napi_create_reference(env, argv[INDEX_TWO], INITITAL_REFCOUNT_ONE, &ref);
529         loopObserver_->observerObject = std::shared_ptr<NativeReference>(reinterpret_cast<NativeReference*>(ref));
530         loopObserver_->env = env;
531         loopObserver_->mainRunner->SetTimeout(number);
532         loopObserver_->mainRunner->SetTimeoutCallback(CallbackTimeout);
533         return nullptr;
534     }
535 
OnRemoveLoopWatch(napi_env env,size_t argc,napi_value * argv)536     napi_value OnRemoveLoopWatch(napi_env env, size_t argc, napi_value* argv)
537     {
538         if (loopObserver_) {
539             loopObserver_.reset();
540             loopObserver_ = nullptr;
541             TAG_LOGI(AAFwkTag::JSNAPI, "success");
542         } else {
543             TAG_LOGI(AAFwkTag::JSNAPI, "called");
544         }
545         return nullptr;
546     }
547 
ParseParamType(napi_env env,const size_t argc,napi_value * argv)548     std::string ParseParamType(napi_env env, const size_t argc, napi_value* argv)
549     {
550         std::string type;
551         if (argc > INDEX_ZERO && ConvertFromJsValue(env, argv[INDEX_ZERO], type)) {
552             return type;
553         }
554         return "";
555     }
556 
ValidateFunction(napi_env env,napi_value function)557     bool ValidateFunction(napi_env env, napi_value function)
558     {
559         if (function == nullptr ||
560             CheckTypeForNapiValue(env, function, napi_null) ||
561             CheckTypeForNapiValue(env, function, napi_undefined)) {
562             TAG_LOGE(AAFwkTag::JSNAPI, "invalid func");
563             ThrowError(env, AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
564             return false;
565         }
566         return true;
567     }
568 
569     int32_t serialNumber_ = 0;
570     std::shared_ptr<JsErrorObserver> observer_;
571 };
572 } // namespace
573 
JsErrorManagerInit(napi_env env,napi_value exportObj)574 napi_value JsErrorManagerInit(napi_env env, napi_value exportObj)
575 {
576     TAG_LOGI(AAFwkTag::JSNAPI, "called");
577     if (env == nullptr || exportObj == nullptr) {
578         TAG_LOGI(AAFwkTag::JSNAPI, "null env or exportObj");
579         return nullptr;
580     }
581     std::unique_ptr<JsErrorManager> jsErrorManager = std::make_unique<JsErrorManager>();
582     jsErrorManager->SetRejectionCallback(env);
583     napi_wrap(env, exportObj, jsErrorManager.release(), JsErrorManager::Finalizer, nullptr, nullptr);
584 
585     TAG_LOGD(AAFwkTag::JSNAPI, "bind func ready");
586     const char *moduleName = "JsErrorManager";
587     BindNativeFunction(env, exportObj, "on", moduleName, JsErrorManager::On);
588     BindNativeFunction(env, exportObj, "off", moduleName, JsErrorManager::Off);
589     return CreateJsUndefined(env);
590 }
591 }  // namespace AbilityRuntime
592 }  // namespace OHOS
593