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