1 /*
2 * Copyright (c) 2021-2022 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 "native_engine/native_engine.h"
17
18 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(IOS_PLATFORM) && !defined(LINUX_PLATFORM)
19 #include <sys/epoll.h>
20 #endif
21 #ifdef IOS_PLATFORM
22 #include <sys/event.h>
23 #endif
24 #ifdef ENABLE_HITRACE
25 #include "hitrace_meter.h"
26 #endif
27
28 #include "native_engine/native_utils.h"
29 #include "unicode/ucnv.h"
30
31 constexpr size_t NAME_BUFFER_SIZE = 64;
32 static constexpr auto PANDA_MAIN_FUNCTION = "_GLOBAL::func_main_0";
33 static constexpr int32_t API11 = 11;
34 static constexpr int32_t API_VERSION_MASK = 1000;
35
36 using panda::JSValueRef;
37 using panda::Local;
38 using panda::LocalScope;
39 using panda::ObjectRef;
40 using panda::StringRef;
41
42 namespace {
43 const char* g_errorMessages[] = {
44 nullptr,
45 "Invalid parameter",
46 "Need object",
47 "Need string",
48 "Need string or symbol",
49 "Need function",
50 "Need number",
51 "Need boolean",
52 "Need array",
53 "Generic failure",
54 "An exception is blocking",
55 "Asynchronous work cancelled",
56 "Escape called twice",
57 "Handle scope mismatch",
58 "Callback scope mismatch",
59 "Asynchronous work queue is full",
60 "Asynchronous work handle is closing",
61 "Need bigint",
62 "Need date",
63 "Need arraybuffer",
64 "Need detachable arraybuffer",
65 };
66 } // namespace
67
68 thread_local static GetContainerScopeIdCallback g_getContainerScopeIdFunc;
69 thread_local static ContainerScopeCallback g_initContainerScopeFunc;
70 thread_local static ContainerScopeCallback g_finishContainerScopeFunc;
71
72 std::mutex NativeEngine::g_alivedEngineMutex_;
73 std::unordered_set<NativeEngine*> NativeEngine::g_alivedEngine_;
74 uint64_t NativeEngine::g_lastEngineId_ = 1;
75 std::mutex NativeEngine::g_mainThreadEngineMutex_;
76 NativeEngine* NativeEngine::g_mainThreadEngine_;
77 NapiErrorManager* NapiErrorManager::instance_ = NULL;
78 static std::mutex g_errorManagerInstanceMutex;
79
NativeEngine(void * jsEngine)80 NativeEngine::NativeEngine(void* jsEngine) : jsEngine_(jsEngine)
81 {
82 SetMainThreadEngine(this);
83 SetAlive();
84 InitUvField();
85 workerThreadState_ = new WorkerThreadState();
86 }
87
NativeEngine(NativeEngine * parent)88 NativeEngine::NativeEngine(NativeEngine* parent) : jsEngine_(parent->jsEngine_),
89 workerThreadState_(nullptr)
90 {
91 // make napi_async_work and napi_threadsafe_function is reachable
92 // update engine id
93 SetAlive();
94 // fill 0 to embedded uv members
95 InitUvField();
96 }
97
InitUvField()98 void NativeEngine::InitUvField()
99 {
100 if (memset_s(&uvAsync_, sizeof(uvAsync_), 0, sizeof(uvAsync_)) != EOK) {
101 HILOG_ERROR("failed to init uvAsync_");
102 return;
103 }
104 if (memset_s(&uvSem_, sizeof(uvSem_), 0, sizeof(uvSem_)) != EOK) {
105 HILOG_ERROR("failed to init uvSem_");
106 return;
107 }
108 #if !defined(PREVIEW)
109 if (memset_s(&uvThread_, sizeof(uvThread_), 0, sizeof(uvThread_)) != EOK) {
110 HILOG_ERROR("failed to init uvThread_");
111 return;
112 }
113 #endif
114 }
115
~NativeEngine()116 NativeEngine::~NativeEngine()
117 {
118 HILOG_INFO("NativeEngine::~NativeEngine");
119 isInDestructor_ = true;
120 if (cleanEnv_ != nullptr) {
121 cleanEnv_();
122 }
123 if (workerThreadState_ != nullptr) {
124 delete workerThreadState_;
125 }
126 std::lock_guard<std::mutex> insLock(instanceDataLock_);
127 FinalizerInstanceData();
128 RunInstanceFinalizer();
129 }
130
Init()131 void NativeEngine::Init()
132 {
133 HILOG_DEBUG("NativeEngine::Init");
134 InitWithoutUV();
135
136 loop_ = new (std::nothrow)uv_loop_t;
137 if (loop_ == nullptr) {
138 HILOG_ERROR("failed to create uv_loop, async task interface would not work");
139 return;
140 }
141 if (uv_loop_init(loop_) != EOK) {
142 HILOG_ERROR("failed to init uv_loop, async task interface would not work");
143 delete loop_;
144 loop_ = nullptr;
145 return;
146 }
147 uv_async_init(loop_, &uvAsync_, nullptr);
148 uv_sem_init(&uvSem_, 0);
149 NativeEvent::CreateDefaultFunction(this, defaultFunc_, eventMutex_);
150 }
151
Deinit()152 void NativeEngine::Deinit()
153 {
154 HILOG_INFO("NativeEngine::Deinit");
155 if (loop_ != nullptr) {
156 NativeEvent::DestoryDefaultFunction(true, defaultFunc_, eventMutex_);
157 uv_sem_destroy(&uvSem_);
158 uv_close((uv_handle_t*)&uvAsync_, nullptr);
159 }
160
161 RunCleanup();
162 // This should not call in `DeinitWithoutUV`, because one VM may have more than one env
163 NotifyVMIgnoreFinalizeCallback();
164 DeinitWithoutUV();
165
166 SetDead();
167 SetStopping(true);
168 if (loop_ == nullptr) {
169 return;
170 }
171 if (uv_loop_close(loop_) != EOK) {
172 HILOG_WARN("faild to close uv_loop, rerun it.");
173 // execute works posted from finalize_cb
174 uv_run(loop_, UV_RUN_DEFAULT);
175 if (uv_loop_close(loop_) != EOK) {
176 // it maybe up to fatal level later
177 HILOG_ERROR("faild to close uv_loop, after reran.");
178 }
179 };
180 delete loop_;
181 loop_ = nullptr;
182 }
183
InitWithoutUV()184 void NativeEngine::InitWithoutUV()
185 {
186 moduleManager_ = NativeModuleManager::GetInstance();
187 referenceManager_ = new NativeReferenceManager();
188 callbackScopeManager_ = new NativeCallbackScopeManager();
189 tid_ = pthread_self();
190 sysTid_ = GetCurSysTid();
191 }
192
DeinitWithoutUV()193 void NativeEngine::DeinitWithoutUV()
194 {
195 if (referenceManager_ != nullptr) {
196 delete referenceManager_;
197 referenceManager_ = nullptr;
198 }
199
200 if (callbackScopeManager_ != nullptr) {
201 delete callbackScopeManager_;
202 callbackScopeManager_ = nullptr;
203 }
204 }
205
GetReferenceManager()206 NativeReferenceManager* NativeEngine::GetReferenceManager()
207 {
208 return referenceManager_;
209 }
210
GetModuleManager()211 NativeModuleManager* NativeEngine::GetModuleManager()
212 {
213 return moduleManager_;
214 }
215
GetCallbackScopeManager()216 NativeCallbackScopeManager* NativeEngine::GetCallbackScopeManager()
217 {
218 return callbackScopeManager_;
219 }
220
GetUVLoop() const221 uv_loop_t* NativeEngine::GetUVLoop() const
222 {
223 return loop_;
224 }
225
GetTid() const226 pthread_t NativeEngine::GetTid() const
227 {
228 return tid_;
229 }
230
GetCurSysTid()231 ThreadId NativeEngine::GetCurSysTid()
232 {
233 return reinterpret_cast<ThreadId>(panda::JSNApi::GetCurrentThreadId());
234 }
235
236 // should only be called if process is forked, other case would cause fd_leak
ReinitUVLoop()237 bool NativeEngine::ReinitUVLoop()
238 {
239 if (defaultFunc_ != nullptr) {
240 NativeEvent::DestoryDefaultFunction(false, defaultFunc_, eventMutex_);
241 }
242
243 if (loop_ != nullptr) {
244 delete loop_; // only free mem due to uv_loop is invalid
245 loop_ = nullptr;
246 }
247
248 tid_ = pthread_self();
249 sysTid_ = GetCurSysTid();
250 UpdateCrossThreadCheckStatus();
251
252 loop_ = new (std::nothrow)uv_loop_t;
253 if (loop_ == nullptr) {
254 HILOG_ERROR("failed to create uv_loop, async task interface would not work");
255 return false;
256 }
257 if (uv_loop_init(loop_) != EOK) {
258 HILOG_ERROR("failed to init uv_loop, async task interface would not work");
259 delete loop_;
260 loop_ = nullptr;
261 return false;
262 }
263
264 uv_async_init(loop_, &uvAsync_, nullptr);
265 uv_sem_init(&uvSem_, 0);
266 NativeEvent::CreateDefaultFunction(this, defaultFunc_, eventMutex_);
267 panda::JSNApi::NotifyEnvInitialized(const_cast<EcmaVM*>(GetEcmaVm()));
268 return true;
269 }
270
Loop(LoopMode mode,bool needSync)271 void NativeEngine::Loop(LoopMode mode, bool needSync)
272 {
273 if (loop_ == nullptr) {
274 HILOG_ERROR("uv loop is nullptr");
275 return;
276 }
277 bool more = true;
278 switch (mode) {
279 case LoopMode::LOOP_DEFAULT:
280 more = uv_run(loop_, UV_RUN_DEFAULT);
281 break;
282 case LoopMode::LOOP_ONCE:
283 more = uv_run(loop_, UV_RUN_ONCE);
284 break;
285 case LoopMode::LOOP_NOWAIT:
286 more = uv_run(loop_, UV_RUN_NOWAIT);
287 break;
288 default:
289 return;
290 }
291 if (more == false) {
292 uv_loop_alive(loop_);
293 }
294
295 if (needSync) {
296 uv_sem_post(&uvSem_);
297 }
298 }
299
300 // should only call once in life cycle of ArkNativeEngine(NativeEngine)
SetAlive()301 void NativeEngine::SetAlive()
302 {
303 if (id_ != 0) {
304 HILOG_FATAL("id of native engine cannot set twice");
305 }
306 std::lock_guard<std::mutex> alivedEngLock(g_alivedEngineMutex_);
307 g_alivedEngine_.emplace(this);
308 // must be protected by g_alivedEngineMutex_
309 id_ = g_lastEngineId_++;
310 return;
311 }
312
CreateAsyncWork(napi_value asyncResource,napi_value asyncResourceName,NativeAsyncExecuteCallback execute,NativeAsyncCompleteCallback complete,void * data)313 NativeAsyncWork* NativeEngine::CreateAsyncWork(napi_value asyncResource, napi_value asyncResourceName,
314 NativeAsyncExecuteCallback execute, NativeAsyncCompleteCallback complete, void* data)
315 {
316 (void)asyncResource;
317 (void)asyncResourceName;
318 char name[NAME_BUFFER_SIZE] = {0};
319 if (asyncResourceName != nullptr) {
320 auto val = LocalValueFromJsValue(asyncResourceName);
321 [[maybe_unused]] size_t strLength = 0;
322 auto vm = GetEcmaVm();
323 LocalScope scope(vm);
324 auto str = val->ToString(vm);
325 char* buffer = name;
326 if (buffer == nullptr) {
327 strLength = static_cast<size_t>(str->Utf8Length(vm, true) - 1);
328 } else if (NAME_BUFFER_SIZE != 0) {
329 uint32_t copied = str->WriteUtf8(vm, buffer, NAME_BUFFER_SIZE - 1, true) - 1;
330 buffer[copied] = '\0';
331 strLength = copied;
332 } else {
333 strLength = 0;
334 }
335 }
336 return new NativeAsyncWork(this, execute, complete, name, data);
337 }
338
CreateAsyncWork(const std::string & asyncResourceName,NativeAsyncExecuteCallback execute,NativeAsyncCompleteCallback complete,void * data)339 NativeAsyncWork* NativeEngine::CreateAsyncWork(const std::string& asyncResourceName, NativeAsyncExecuteCallback execute,
340 NativeAsyncCompleteCallback complete, void* data)
341 {
342 return new NativeAsyncWork(this, execute, complete, asyncResourceName, data);
343 }
344
CreateSafeAsyncWork(napi_value func,napi_value asyncResource,napi_value asyncResourceName,size_t maxQueueSize,size_t threadCount,void * finalizeData,NativeFinalize finalizeCallback,void * context,NativeThreadSafeFunctionCallJs callJsCallback)345 NativeSafeAsyncWork* NativeEngine::CreateSafeAsyncWork(napi_value func, napi_value asyncResource,
346 napi_value asyncResourceName, size_t maxQueueSize, size_t threadCount, void* finalizeData,
347 NativeFinalize finalizeCallback, void* context, NativeThreadSafeFunctionCallJs callJsCallback)
348 {
349 return new NativeSafeAsyncWork(this, func, asyncResource, asyncResourceName, maxQueueSize, threadCount,
350 finalizeData, finalizeCallback, context, callJsCallback);
351 }
352
GetLastError()353 NativeErrorExtendedInfo* NativeEngine::GetLastError()
354 {
355 return &lastError_;
356 }
357
SetLastError(int errorCode,uint32_t engineErrorCode,void * engineReserved)358 void NativeEngine::SetLastError(int errorCode, uint32_t engineErrorCode, void* engineReserved)
359 {
360 lastError_.errorCode = errorCode;
361 lastError_.engineErrorCode = engineErrorCode;
362 lastError_.message = g_errorMessages[lastError_.errorCode];
363 lastError_.reserved = engineReserved;
364 }
365
SubEncodeToUtf8(const EcmaVM * vm,Local<JSValueRef> & nativeValue,Local<StringRef> & nativeString,char * buffer,uint32_t * written,size_t bufferSize,int32_t * nchars)366 static void SubEncodeToUtf8(const EcmaVM* vm,
367 Local<JSValueRef>& nativeValue,
368 Local<StringRef>& nativeString,
369 char* buffer,
370 uint32_t* written,
371 size_t bufferSize,
372 int32_t* nchars)
373 {
374 int32_t length = static_cast<int32_t>(nativeString->Length(vm));
375 uint32_t pos = 0;
376 uint32_t writableSize = bufferSize;
377 int32_t i = 0;
378 panda::Local<ObjectRef> strObj = nativeValue->ToObject(vm);
379 for (; i < length; i++) {
380 panda::Local<StringRef> str = strObj->Get(vm, i)->ToString(vm);
381 // return value of Uft8Length >= 1
382 uint32_t len = str->Utf8Length(vm) - 1;
383 if (len > writableSize) {
384 break;
385 }
386 str->WriteUtf8(vm, (buffer + pos), writableSize);
387 writableSize -= len;
388 pos += len;
389 }
390 *nchars = i;
391 HILOG_DEBUG("EncodeWriteUtf8 the result of buffer: %{public}s", buffer);
392 *written = pos;
393 }
394
EncodeToUtf8(napi_value value,char * buffer,uint32_t * written,size_t bufferSize,int32_t * nchars)395 void NativeEngine::EncodeToUtf8(napi_value value, char* buffer, uint32_t* written, size_t bufferSize, int32_t* nchars)
396 {
397 auto nativeValue = LocalValueFromJsValue(value);
398 if (nativeValue->IsNull() || nchars == nullptr || written == nullptr) {
399 HILOG_ERROR("NativeEngine EncodeToUtf8 args is nullptr");
400 return;
401 }
402
403 auto vm = GetEcmaVm();
404 LocalScope scope(vm);
405 auto nativeString = nativeValue->ToString(vm);
406 if (!nativeString->IsString(vm)) {
407 HILOG_ERROR("nativeValue not is string");
408 return;
409 }
410
411 if (buffer == nullptr) {
412 HILOG_ERROR("buffer is null");
413 return;
414 }
415
416 SubEncodeToUtf8(vm, nativeValue, nativeString, buffer, written, bufferSize, nchars);
417 }
418
SubEncodeToChinese(const EcmaVM * vm,Local<JSValueRef> & nativeValue,Local<StringRef> & nativeString,std::string & buffer,const char * encode)419 static void SubEncodeToChinese(const EcmaVM* vm,
420 Local<JSValueRef>& nativeValue,
421 Local<StringRef>& nativeString,
422 std::string& buffer,
423 const char* encode)
424 {
425 uint32_t length = nativeString->Length(vm);
426 uint32_t pos = 0;
427 const int32_t writableSize = 22; // 22 : encode max bytes of the ucnv_convent function;
428 std::string tempBuf = "";
429 tempBuf.resize(writableSize + 1);
430 UErrorCode errorCode = U_ZERO_ERROR;
431 const char* encFrom = "utf8";
432 panda::Local<ObjectRef> strObj = nativeValue->ToObject(vm);
433 for (uint32_t i = 0; i < length; i++) {
434 panda::Local<StringRef> str = strObj->Get(vm, i)->ToString(vm);
435 // return value of Utf8Length >= 1
436 uint32_t len = str->Utf8Length(vm) - 1;
437 if ((pos + len) >= writableSize) {
438 char outBuf[writableSize] = {0};
439 ucnv_convert(encode, encFrom, outBuf, writableSize, tempBuf.c_str(), pos, &errorCode);
440 if (errorCode != U_ZERO_ERROR) {
441 HILOG_ERROR("ucnv_convert is failed : ErrorCode = %{public}d", static_cast<int32_t>(errorCode));
442 return;
443 }
444 buffer += outBuf;
445 tempBuf.clear();
446 pos = 0;
447 }
448 str->WriteUtf8(vm, (tempBuf.data() + pos), pos + len + 1);
449 pos += len;
450 }
451 if (pos > 0) {
452 char outBuf[writableSize] = {0};
453 ucnv_convert(encode, encFrom, outBuf, writableSize, tempBuf.c_str(), pos, &errorCode);
454 if (errorCode != U_ZERO_ERROR) {
455 HILOG_ERROR("ucnv_convert is failed : ErrorCode = %{public}d", static_cast<int32_t>(errorCode));
456 return;
457 }
458 buffer += outBuf;
459 }
460 }
461
EncodeToChinese(napi_value value,std::string & buffer,const std::string & encoding)462 void NativeEngine::EncodeToChinese(napi_value value, std::string& buffer, const std::string& encoding)
463 {
464 if (value == nullptr) {
465 HILOG_ERROR("nativeValue GetInterface is nullptr");
466 return;
467 }
468
469 auto nativeValue = LocalValueFromJsValue(value);
470 auto vm = GetEcmaVm();
471 LocalScope scope(vm);
472 auto nativeString = nativeValue->ToString(vm);
473 if (!nativeString->IsString(vm)) {
474 HILOG_ERROR("nativeValue not is string");
475 return;
476 }
477
478 auto encode = encoding.c_str();
479 if (encode == nullptr) {
480 HILOG_ERROR("encoding is nullptr");
481 return;
482 }
483
484 SubEncodeToChinese(vm, nativeValue, nativeString, buffer, encode);
485 }
486
487 #if !defined(PREVIEW)
CheckUVLoop()488 void NativeEngine::CheckUVLoop()
489 {
490 checkUVLoop_ = true;
491 uv_thread_create(&uvThread_, NativeEngine::UVThreadRunner, this);
492 }
493
UVThreadRunner(void * nativeEngine)494 void NativeEngine::UVThreadRunner(void* nativeEngine)
495 {
496 std::string name("UVLoop");
497 #ifdef IOS_PLATFORM
498 pthread_setname_np(name.c_str());
499 #else
500 pthread_setname_np(pthread_self(), name.c_str());
501 #endif
502 auto engine = static_cast<NativeEngine*>(nativeEngine);
503 engine->PostLoopTask();
504 while (engine->checkUVLoop_) {
505 int32_t fd = uv_backend_fd(engine->loop_);
506 int32_t timeout = uv_backend_timeout(engine->loop_);
507 int32_t result = -1;
508 #ifdef IOS_PLATFORM
509 struct kevent events[1];
510 struct timespec spec;
511 static const int32_t mSec = 1000;
512 static const int32_t uSec = 1000000;
513 if (timeout != -1) {
514 spec.tv_sec = timeout / mSec;
515 spec.tv_nsec = (timeout % mSec) * uSec;
516 }
517 result = kevent(fd, NULL, 0, events, 1, timeout == -1 ? NULL : &spec);
518
519 #else
520 struct epoll_event ev;
521 result = epoll_wait(fd, &ev, 1, timeout);
522 #endif
523
524 if (!engine->checkUVLoop_) {
525 HILOG_INFO("break thread after epoll wait");
526 break;
527 }
528 if (result >= 0) {
529 engine->PostLoopTask();
530 } else {
531 HILOG_ERROR("epoll wait fail: result: %{public}d, errno: %{public}d", result, errno);
532 }
533 if (!engine->checkUVLoop_) {
534 HILOG_INFO("break thread after post loop task");
535 break;
536 }
537 }
538 }
539
CancelCheckUVLoop()540 void NativeEngine::CancelCheckUVLoop()
541 {
542 checkUVLoop_ = false;
543 uv_async_send(&uvAsync_);
544 uv_sem_post(&uvSem_);
545 uv_thread_join(&uvThread_);
546 }
547
PostLoopTask()548 void NativeEngine::PostLoopTask()
549 {
550 postTask_(true);
551 uv_sem_wait(&uvSem_);
552 }
553 #endif
554
SetPostTask(PostTask postTask)555 void NativeEngine::SetPostTask(PostTask postTask)
556 {
557 postTask_ = postTask;
558 }
559
TriggerPostTask()560 void NativeEngine::TriggerPostTask()
561 {
562 if (postTask_ == nullptr) {
563 HILOG_ERROR("postTask_ is nullptr");
564 return;
565 }
566 postTask_(false);
567 }
568
GetJsEngine()569 void* NativeEngine::GetJsEngine()
570 {
571 return jsEngine_;
572 }
573
574 // register init worker func
SetInitWorkerFunc(InitWorkerFunc func)575 void NativeEngine::SetInitWorkerFunc(InitWorkerFunc func)
576 {
577 initWorkerFunc_ = func;
578 }
GetInitWorkerFunc() const579 InitWorkerFunc NativeEngine::GetInitWorkerFunc() const
580 {
581 return initWorkerFunc_;
582 }
SetGetAssetFunc(GetAssetFunc func)583 void NativeEngine::SetGetAssetFunc(GetAssetFunc func)
584 {
585 getAssetFunc_ = func;
586 }
GetGetAssetFunc() const587 GetAssetFunc NativeEngine::GetGetAssetFunc() const
588 {
589 return getAssetFunc_;
590 }
SetOffWorkerFunc(OffWorkerFunc func)591 void NativeEngine::SetOffWorkerFunc(OffWorkerFunc func)
592 {
593 offWorkerFunc_ = func;
594 }
GetOffWorkerFunc() const595 OffWorkerFunc NativeEngine::GetOffWorkerFunc() const
596 {
597 return offWorkerFunc_;
598 }
599
SetReleaseWorkerSafeMemFunc(ReleaseWorkerSafeMemFunc func)600 void NativeEngine::SetReleaseWorkerSafeMemFunc(ReleaseWorkerSafeMemFunc func)
601 {
602 if (func == nullptr) {
603 return;
604 }
605 panda::JSNApi::SetReleaseSecureMemCallback(func);
606 }
607
608 // call init worker func
CallInitWorkerFunc(NativeEngine * engine)609 bool NativeEngine::CallInitWorkerFunc(NativeEngine* engine)
610 {
611 if (initWorkerFunc_ != nullptr) {
612 initWorkerFunc_(engine);
613 return true;
614 }
615 return false;
616 }
617
CallGetAssetFunc(const std::string & uri,uint8_t ** buffer,size_t * bufferSize,std::vector<uint8_t> & content,std::string & ami,bool & useSecureMem,void ** mapper,bool isRestrictedWorker)618 bool NativeEngine::CallGetAssetFunc(const std::string& uri, uint8_t** buffer, size_t* bufferSize,
619 std::vector<uint8_t>& content, std::string& ami, bool &useSecureMem, void** mapper, bool isRestrictedWorker)
620 {
621 if (getAssetFunc_ != nullptr) {
622 getAssetFunc_(uri, buffer, bufferSize, content, ami, useSecureMem, mapper, isRestrictedWorker);
623 return true;
624 }
625 return false;
626 }
627
CallOffWorkerFunc(NativeEngine * engine)628 bool NativeEngine::CallOffWorkerFunc(NativeEngine* engine)
629 {
630 if (offWorkerFunc_ != nullptr) {
631 offWorkerFunc_(engine);
632 return true;
633 }
634 return false;
635 }
636
637 // adapt worker to ace container
SetGetContainerScopeIdFunc(GetContainerScopeIdCallback func)638 void NativeEngine::SetGetContainerScopeIdFunc(GetContainerScopeIdCallback func)
639 {
640 g_getContainerScopeIdFunc = func;
641 }
SetInitContainerScopeFunc(ContainerScopeCallback func)642 void NativeEngine::SetInitContainerScopeFunc(ContainerScopeCallback func)
643 {
644 g_initContainerScopeFunc = func;
645 }
SetFinishContainerScopeFunc(ContainerScopeCallback func)646 void NativeEngine::SetFinishContainerScopeFunc(ContainerScopeCallback func)
647 {
648 g_finishContainerScopeFunc = func;
649 }
GetContainerScopeIdFunc()650 int32_t NativeEngine::GetContainerScopeIdFunc()
651 {
652 int32_t scopeId = -1;
653 if (g_getContainerScopeIdFunc != nullptr) {
654 scopeId = g_getContainerScopeIdFunc();
655 }
656 return scopeId;
657 }
InitContainerScopeFunc(int32_t id)658 bool NativeEngine::InitContainerScopeFunc(int32_t id)
659 {
660 if (g_initContainerScopeFunc != nullptr) {
661 g_initContainerScopeFunc(id);
662 return true;
663 }
664 return false;
665 }
FinishContainerScopeFunc(int32_t id)666 bool NativeEngine::FinishContainerScopeFunc(int32_t id)
667 {
668 if (g_finishContainerScopeFunc != nullptr) {
669 g_finishContainerScopeFunc(id);
670 return true;
671 }
672 return false;
673 }
674
675 #if !defined(PREVIEW)
CallDebuggerPostTaskFunc(std::function<void ()> && task)676 void NativeEngine::CallDebuggerPostTaskFunc(std::function<void()>&& task)
677 {
678 if (debuggerPostTaskFunc_ != nullptr) {
679 debuggerPostTaskFunc_(std::move(task));
680 }
681 }
682
SetDebuggerPostTaskFunc(DebuggerPostTask func)683 void NativeEngine::SetDebuggerPostTaskFunc(DebuggerPostTask func)
684 {
685 debuggerPostTaskFunc_ = func;
686 }
687 #endif
688
SetHostEngine(NativeEngine * engine)689 void NativeEngine::SetHostEngine(NativeEngine* engine)
690 {
691 hostEngine_ = engine;
692 }
693
GetHostEngine() const694 NativeEngine* NativeEngine::GetHostEngine() const
695 {
696 return hostEngine_;
697 }
698
SetApiVersion(int32_t apiVersion)699 void NativeEngine::SetApiVersion(int32_t apiVersion)
700 {
701 apiVersion_ = apiVersion;
702 realApiVersion_ = apiVersion % API_VERSION_MASK;
703 EcmaVM* vm = const_cast<EcmaVM*>(GetEcmaVm());
704 panda::JSNApi::SetVMAPIVersion(vm, apiVersion);
705 }
706
GetApiVersion()707 int32_t NativeEngine::GetApiVersion()
708 {
709 return apiVersion_;
710 }
711
GetRealApiVersion()712 int32_t NativeEngine::GetRealApiVersion()
713 {
714 return realApiVersion_;
715 }
716
IsApplicationApiVersionAPI11Plus()717 bool NativeEngine::IsApplicationApiVersionAPI11Plus()
718 {
719 return apiVersion_ > API11;
720 }
721
AddCleanupFinalizer(CleanupFinalizerCallBack fun,void * arg)722 napi_status NativeEngine::AddCleanupFinalizer(CleanupFinalizerCallBack fun, void* arg)
723 {
724 auto insertion_info = instanceFinalizer_.emplace(arg,
725 std::pair<CleanupFinalizerCallBack, uint64_t>(fun, instanceFinalizerCounter_++));
726 if (insertion_info.second) {
727 return napi_ok;
728 }
729
730 HILOG_ERROR("AddCleanupFinalizer Failed, this may cause memory leaks or unexpected behavior.");
731
732 return napi_generic_failure;
733 }
734
RemoveCleanupFinalizer(CleanupFinalizerCallBack fun,void * arg)735 napi_status NativeEngine::RemoveCleanupFinalizer(CleanupFinalizerCallBack fun, void* arg)
736 {
737 auto cleanupHook = instanceFinalizer_.find(arg);
738 if (cleanupHook != instanceFinalizer_.end() && cleanupHook->second.first == fun) {
739 instanceFinalizer_.erase(arg);
740 return napi_ok;
741 }
742
743 const char *failedReason = cleanupHook == instanceFinalizer_.end() ?
744 "data is not registered or already unregistered" : "callback not equals to last registered";
745
746 HILOG_ERROR("RemoveCleanupHook Failed, %{public}s, "
747 "this may cause memory leaks or unexpected behavior.", failedReason);
748
749 return napi_generic_failure;
750 }
751
RunInstanceFinalizer()752 void NativeEngine::RunInstanceFinalizer()
753 {
754 HILOG_DEBUG("%{public}s, start.", __func__);
755
756 while (!instanceFinalizer_.empty()) {
757 #ifdef ENABLE_HITRACE
758 StartTrace(HITRACE_TAG_ACE,
759 "NativeEngine::RunInstanceFinalizer callbacks size: " +
760 std::to_string(instanceFinalizer_.size()));
761 #endif
762 using CleanupDataCallbackPair = std::pair<void*, std::pair<CleanupFinalizerCallBack, uint64_t>>;
763 std::vector<CleanupDataCallbackPair> callbacks(instanceFinalizer_.begin(), instanceFinalizer_.end());
764 std::sort(callbacks.begin(), callbacks.end(), [](const CleanupDataCallbackPair& a,
765 const CleanupDataCallbackPair& b) {
766 // Sort in descending order so that the most recently inserted callbacks are run first.
767 return a.second.second > b.second.second;
768 });
769 HILOG_DEBUG(
770 "NativeEngine::RunInstanceFinalizer callbacks size:%{public}d", (int32_t)callbacks.size());
771 for (const CleanupDataCallbackPair& cb : callbacks) {
772 void* data = cb.first;
773 if (instanceFinalizer_.find(data) == instanceFinalizer_.end()) {
774 continue;
775 }
776
777 CleanupFinalizerCallBack fun = cb.second.first;
778 if (fun != nullptr) {
779 fun(data);
780 }
781 instanceFinalizer_.erase(data);
782 }
783 #ifdef ENABLE_HITRACE
784 FinishTrace(HITRACE_TAG_ACE);
785 #endif
786 }
787 }
788
AddCleanupHook(CleanupCallback fun,void * arg)789 napi_status NativeEngine::AddCleanupHook(CleanupCallback fun, void* arg)
790 {
791 auto insertion_info = cleanupHooks_.emplace(arg,
792 std::pair<CleanupCallback, uint64_t>(fun, cleanupHookCounter_++));
793 if (insertion_info.second) {
794 return napi_ok;
795 }
796
797 std::string stack;
798 if (IsCrossThreadCheckEnabled()) {
799 if (DumpHybridStack(GetEcmaVm(), stack, 1, 8)) { // 1: skipd frames, 8: backtrace deepth
800 HILOG_ERROR("AddCleanupHook Failed, data cannot register multiple times."
801 "\n%{public}s", stack.c_str());
802 } else {
803 HILOG_ERROR("AddCleanupHook Failed, data cannot register multiple times, "
804 "backtrace failed or unsupported platform.");
805 }
806 } else {
807 HILOG_WARN("AddCleanupHook Failed, data cannot register multiple times, "
808 "enable cross-thread check for more information.");
809 }
810
811 return napi_generic_failure;
812 }
813
RemoveCleanupHook(CleanupCallback fun,void * arg)814 napi_status NativeEngine::RemoveCleanupHook(CleanupCallback fun, void* arg)
815 {
816 auto cleanupHook = cleanupHooks_.find(arg);
817 if (cleanupHook != cleanupHooks_.end() && cleanupHook->second.first == fun) {
818 cleanupHooks_.erase(arg);
819 return napi_ok;
820 }
821
822 const char *failedReason = cleanupHook == cleanupHooks_.end() ? "data is not registered or already unregistered"
823 : "callback not equals to last registered";
824 std::string stack;
825 if (IsCrossThreadCheckEnabled()) {
826 if (DumpHybridStack(GetEcmaVm(), stack, 1, 8)) { // 1: skiped frames, 8: backtrace deepth
827 HILOG_ERROR("RemoveCleanupHook Failed, %{public}s"
828 ".\n%{public}s", failedReason, stack.c_str());
829 } else {
830 HILOG_ERROR("RemoveCleanupHook Failed %{public}s, "
831 "backtrace failed or unsupported platform.", failedReason);
832 }
833 } else {
834 HILOG_WARN("RemoveCleanupHook Failed, %{public}s, "
835 "enable cross thread check for more information.", failedReason);
836 }
837
838 return napi_generic_failure;
839 }
840
RunCleanupHooks(bool waitTasks)841 void NativeEngine::RunCleanupHooks(bool waitTasks)
842 {
843 // sync clean up
844 while (!cleanupHooks_.empty()) {
845 HILOG_DEBUG("NativeEngine::RunCleanup cleanupHooks_ is not empty");
846 using CleanupCallbackTuple = std::pair<void*, std::pair<CleanupCallback, uint64_t>>;
847 // Copy into a vector, since we can't sort an unordered_set in-place.
848 std::vector<CleanupCallbackTuple> callbacks(cleanupHooks_.begin(), cleanupHooks_.end());
849 // We can't erase the copied elements from `cleanupHooks_` yet, because we
850 // need to be able to check whether they were un-scheduled by another hook.
851
852 std::sort(callbacks.begin(), callbacks.end(), [](const CleanupCallbackTuple& a, const CleanupCallbackTuple& b) {
853 // Sort in descending order so that the most recently inserted callbacks are run first.
854 return a.second.second > b.second.second;
855 });
856 HILOG_DEBUG(
857 "NativeEngine::RunCleanup cleanup_hooks callbacks size:%{public}d", (int32_t)callbacks.size());
858 for (const CleanupCallbackTuple& cb : callbacks) {
859 void* data = cb.first;
860 if (cleanupHooks_.find(data) == cleanupHooks_.end()) {
861 // This hook was removed from the `cleanupHooks_` set during another
862 // hook that was run earlier. Nothing to do here.
863 continue;
864 }
865 CleanupCallback fun = cb.second.first;
866 if (fun != nullptr) {
867 fun(data);
868 }
869 cleanupHooks_.erase(data);
870 }
871 // We cannot re-run the uv_loop while it is already running.
872 if (waitTasks) {
873 CleanupHandles();
874 }
875 }
876 }
877
RunCleanup()878 void NativeEngine::RunCleanup()
879 {
880 HILOG_DEBUG("%{public}s, start.", __func__);
881 CleanupHandles();
882
883 RunCleanupHooks(true);
884
885 if (loop_ == nullptr) {
886 return;
887 }
888
889 // make sure tsfn relese by itself
890 uv_run(loop_, UV_RUN_NOWAIT);
891
892 // Close all unclosed uv handles
893 auto const ensureClosing = [](uv_handle_t *handle, void *arg) {
894 if (!uv_is_closing(handle)) {
895 uv_close(handle, nullptr);
896 }
897 };
898 uv_walk(loop_, ensureClosing, nullptr);
899
900 while (uv_run(loop_, UV_RUN_DEFAULT) != 0) {};
901
902 HILOG_DEBUG("%{public}s, end.", __func__);
903 }
904
CleanupHandles()905 void NativeEngine::CleanupHandles()
906 {
907 if (loop_ == nullptr) {
908 return;
909 }
910
911 while (requestWaiting_.load() > 0) {
912 HILOG_INFO("%{public}s, request waiting:%{public}d.", __func__,
913 requestWaiting_.load(std::memory_order_relaxed));
914 uv_run(loop_, UV_RUN_ONCE);
915 }
916 }
917
918 #define BODY_COUNTER_METHOD(_type, name, storage, LOAD) \
919 void NativeEngine::Increase##name##Counter() \
920 { \
921 (storage)++; \
922 } \
923 \
924 void NativeEngine::Decrease##name##Counter() \
925 { \
926 (storage)--; \
927 } \
928 \
929 bool NativeEngine::Has##name() \
930 { \
931 return LOAD((storage)) != 0; \
932 }
933
NAPI_COUNTER_METHOD(BODY_COUNTER_METHOD)934 NAPI_COUNTER_METHOD(BODY_COUNTER_METHOD)
935
936 #undef BODY_COUNTER_METHOD
937
938 // alias for HasListening
939 bool NativeEngine::HasListeningCounter()
940 {
941 return HasListening();
942 }
943
944 // custom CallbackbleRefCounter method
GetNonCallbackRefCount()945 uint64_t NativeEngine::GetNonCallbackRefCount()
946 {
947 return nonCallbackRefCounter_;
948 }
949
GetCallbackbleRefCount()950 uint64_t NativeEngine::GetCallbackbleRefCount()
951 {
952 return callbackbleRefCounter_;
953 }
954
RegisterWorkerFunction(const NativeEngine * engine)955 void NativeEngine::RegisterWorkerFunction(const NativeEngine* engine)
956 {
957 if (engine == nullptr) {
958 return;
959 }
960 SetInitWorkerFunc(engine->GetInitWorkerFunc());
961 SetGetAssetFunc(engine->GetGetAssetFunc());
962 SetOffWorkerFunc(engine->GetOffWorkerFunc());
963 }
964
965 // this interface for restrictedWorker with entryPoint to execute mergeabc
RunScriptForAbc(const char * path,char * entryPoint)966 napi_value NativeEngine::RunScriptForAbc(const char* path, char* entryPoint)
967 {
968 EcmaVM* vm = const_cast<EcmaVM*>(GetEcmaVm());
969 panda::EscapeLocalScope scope(vm);
970 std::string normalizedPath = panda::JSNApi::NormalizePath(path);
971 uint8_t* scriptContent = nullptr;
972 size_t scriptContentSize = 0;
973 std::vector<uint8_t> content;
974 std::string ami;
975 void* mapper = nullptr;
976 if (!GetAbcBuffer(normalizedPath.c_str(), &scriptContent, &scriptContentSize,
977 content, ami, &mapper, true)) {
978 HILOG_ERROR("RunScript: GetAbcBuffer failed");
979 return nullptr;
980 }
981 HILOG_DEBUG("RunScriptForAbc: GetAmi: %{private}s", ami.c_str());
982 // if buffer is empty, return directly.
983 if (scriptContentSize == 0) {
984 HILOG_ERROR("asset size is %{public}zu", scriptContentSize);
985 ThrowException("RunScriptForAbc: abc file is empty.");
986 return nullptr;
987 }
988 panda::JSNApi::Execute(vm, ami, entryPoint, false, panda::ecmascript::ExecuteTypes::NAPI);
989 if (panda::JSNApi::HasPendingException(vm)) {
990 HandleUncaughtException();
991 return nullptr;
992 }
993 Local<JSValueRef> undefObj = JSValueRef::Undefined(vm);
994 return JsValueFromLocalValue(scope.Escape(undefObj));
995 }
996
RunScript(const char * path,char * entryPoint)997 napi_value NativeEngine::RunScript(const char* path, char* entryPoint)
998 {
999 uint8_t* scriptContent = nullptr;
1000 size_t scriptContentSize = 0;
1001 std::vector<uint8_t> content;
1002 std::string ami;
1003 void* mapper = nullptr;
1004 if (!GetAbcBuffer(path, &scriptContent, &scriptContentSize, content, ami, &mapper)) {
1005 HILOG_ERROR("RunScript: GetAbcBuffer failed");
1006 return nullptr;
1007 }
1008 HILOG_DEBUG("RunScript: GetAmi: %{private}s", ami.c_str());
1009 // if buffer is empty, return directly.
1010 if (scriptContentSize == 0) {
1011 HILOG_ERROR("RunScript: buffer size is empty, please check abc path");
1012 return nullptr;
1013 }
1014 napi_value result = RunActor(scriptContent, scriptContentSize, ami.c_str(), entryPoint, false, mapper);
1015 return result;
1016 }
1017
RunScriptInRestrictedThread(const char * path)1018 napi_value NativeEngine::RunScriptInRestrictedThread(const char* path)
1019 {
1020 auto vm = GetEcmaVm();
1021 panda::EscapeLocalScope scope(vm);
1022 uint8_t* scriptContent = nullptr;
1023 size_t scriptContentSize = 0;
1024 std::vector<uint8_t> content;
1025 std::string ami;
1026 void* mapper = nullptr;
1027 if (!GetAbcBuffer(path, &scriptContent, &scriptContentSize, content, ami, &mapper, true)) {
1028 HILOG_ERROR("RunScriptInRestrictedThread: GetAbcBuffer failed");
1029 return nullptr;
1030 }
1031 HILOG_DEBUG("RunScriptInRestrictedThread: GetAmi: %{private}s", ami.c_str());
1032 panda::JSNApi::Execute(vm, ami, PANDA_MAIN_FUNCTION, false, panda::ecmascript::ExecuteTypes::NAPI);
1033 if (panda::JSNApi::HasPendingException(vm)) {
1034 HandleUncaughtException();
1035 return nullptr;
1036 }
1037 Local<JSValueRef> undefObj = JSValueRef::Undefined(vm);
1038 return JsValueFromLocalValue(scope.Escape(undefObj));
1039 }
1040
GetAbcBufferAndRunActor(std::string pathStr,char * entryPoint)1041 napi_value NativeEngine::GetAbcBufferAndRunActor(std::string pathStr, char *entryPoint)
1042 {
1043 uint8_t* scriptContent = nullptr;
1044 size_t scriptContentSize = 0;
1045 std::vector<uint8_t> content;
1046 std::string workerAmi;
1047 void* mapper = nullptr;
1048 if (!GetAbcBuffer(pathStr.c_str(), &scriptContent, &scriptContentSize, content, workerAmi, &mapper)) {
1049 HILOG_ERROR("GetAbcBufferAndRunActor: GetAbcBuffer error");
1050 return nullptr;
1051 }
1052 napi_value result = RunActor(scriptContent, scriptContentSize, workerAmi.c_str(), entryPoint, false, mapper);
1053 return result;
1054 }
1055
1056 /* buffer, bufferSize is for secureMem; content is for normalMem.
1057 * If output is not secureMem, fullfill buffer, bufferSize with content data and size.
1058 */
GetAbcBuffer(const char * path,uint8_t ** buffer,size_t * bufferSize,std::vector<uint8_t> & content,std::string & ami,void ** mapper,bool isRestrictedWorker)1059 bool NativeEngine::GetAbcBuffer(const char* path, uint8_t **buffer, size_t* bufferSize,
1060 std::vector<uint8_t>& content, std::string& ami, void** mapper, bool isRestrictedWorker)
1061 {
1062 std::string pathStr(path);
1063 bool useSecureMem = false;
1064 if (!CallGetAssetFunc(pathStr, buffer, bufferSize, content, ami, useSecureMem, mapper, isRestrictedWorker)) {
1065 HILOG_ERROR("Get asset error");
1066 return false;
1067 }
1068 if (!useSecureMem) {
1069 *buffer = content.data();
1070 *bufferSize = content.size();
1071 }
1072 return true;
1073 }
1074
SetInstanceData(void * data,NativeFinalize finalize_cb,void * hint)1075 void NativeEngine::SetInstanceData(void* data, NativeFinalize finalize_cb, void* hint)
1076 {
1077 HILOG_DEBUG("NativeEngineWraper::%{public}s, start.", __func__);
1078 std::lock_guard<std::mutex> insLock(instanceDataLock_);
1079 FinalizerInstanceData();
1080 instanceDataInfo_.engine = this;
1081 instanceDataInfo_.callback = finalize_cb;
1082 instanceDataInfo_.nativeObject = data;
1083 instanceDataInfo_.hint = hint;
1084 }
1085
GetInstanceData(void ** data)1086 void NativeEngine::GetInstanceData(void** data)
1087 {
1088 HILOG_DEBUG("NativeEngineWraper::%{public}s, start.", __func__);
1089 std::lock_guard<std::mutex> insLock(instanceDataLock_);
1090 if (data) {
1091 *data = instanceDataInfo_.nativeObject;
1092 }
1093 }
1094
FinalizerInstanceData(void)1095 void NativeEngine::FinalizerInstanceData(void)
1096 {
1097 if (instanceDataInfo_.engine != nullptr && instanceDataInfo_.callback != nullptr) {
1098 instanceDataInfo_.callback(instanceDataInfo_.engine, instanceDataInfo_.nativeObject, instanceDataInfo_.hint);
1099 }
1100 instanceDataInfo_.engine = nullptr;
1101 instanceDataInfo_.callback = nullptr;
1102 instanceDataInfo_.nativeObject = nullptr;
1103 instanceDataInfo_.hint = nullptr;
1104 }
1105
GetModuleFileName()1106 const char* NativeEngine::GetModuleFileName()
1107 {
1108 HILOG_DEBUG("%{public}s, start.", __func__);
1109 if (moduleFileName_.empty()) {
1110 NativeModuleManager* moduleManager = GetModuleManager();
1111 HILOG_DEBUG("NativeEngineWraper::GetFileName GetModuleManager");
1112 if (moduleManager != nullptr) {
1113 std::string moduleFileName = moduleManager->GetModuleFileName(moduleName_.c_str(), isAppModule_);
1114 HILOG_INFO("NativeEngineWraper::GetFileName end filename:%{public}s", moduleFileName.c_str());
1115 SetModuleFileName(moduleFileName);
1116 }
1117 }
1118 return moduleFileName_.c_str();
1119 }
1120
SetModuleName(std::string & moduleName)1121 void NativeEngine::SetModuleName(std::string& moduleName)
1122 {
1123 moduleName_ = moduleName;
1124 }
1125
SetModuleFileName(std::string & moduleFileName)1126 void NativeEngine::SetModuleFileName(std::string& moduleFileName)
1127 {
1128 moduleFileName_ = moduleFileName;
1129 }
1130
SetExtensionInfos(std::unordered_map<std::string,int32_t> && extensionInfos)1131 void NativeEngine::SetExtensionInfos(std::unordered_map<std::string, int32_t>&& extensionInfos)
1132 {
1133 extensionInfos_ = extensionInfos;
1134 }
1135
GetExtensionInfos()1136 const std::unordered_map<std::string, int32_t>& NativeEngine::GetExtensionInfos()
1137 {
1138 return extensionInfos_;
1139 }
1140
SetModuleLoadChecker(const std::shared_ptr<ModuleCheckerDelegate> & moduleCheckerDelegate)1141 void NativeEngine::SetModuleLoadChecker(const std::shared_ptr<ModuleCheckerDelegate>& moduleCheckerDelegate)
1142 {
1143 NativeModuleManager* moduleManager = GetModuleManager();
1144 if (!moduleManager) {
1145 HILOG_ERROR("SetModuleLoadChecker failed, moduleManager is nullptr");
1146 return;
1147 }
1148 moduleManager->SetModuleLoadChecker(moduleCheckerDelegate);
1149 }
1150
RunEventLoop(napi_event_mode mode)1151 napi_status NativeEngine::RunEventLoop(napi_event_mode mode)
1152 {
1153 HILOG_DEBUG("%{public}s, start.", __func__);
1154 if (loop_ == nullptr) {
1155 HILOG_ERROR("nullptr loop in native engine");
1156 return napi_status::napi_invalid_arg;
1157 }
1158
1159 if (!IsNativeThread()) {
1160 HILOG_ERROR("current thread is not native thread");
1161 return napi_status::napi_generic_failure;
1162 }
1163
1164 std::unique_lock<std::mutex> lock(loopRunningMutex_);
1165 if (isLoopRunning_) {
1166 HILOG_DEBUG("loop is already undered running state");
1167 return napi_status::napi_ok;
1168 }
1169 isLoopRunning_ = true;
1170 lock.unlock();
1171 HILOG_DEBUG("uv loop is running with mode %{public}d", mode);
1172 if (mode == napi_event_mode_default) {
1173 uv_run(loop_, UV_RUN_DEFAULT);
1174 }
1175 if (mode == napi_event_mode_nowait) {
1176 uv_run(loop_, UV_RUN_NOWAIT);
1177 }
1178 HILOG_DEBUG("uv loop is stopped");
1179 lock.lock();
1180 isLoopRunning_ = false;
1181 return napi_status::napi_ok;
1182 }
1183
StopEventLoop()1184 napi_status NativeEngine::StopEventLoop()
1185 {
1186 HILOG_DEBUG("%{public}s, start.", __func__);
1187 if (loop_ == nullptr) {
1188 HILOG_ERROR("nullptr loop in native engine");
1189 return napi_status::napi_invalid_arg;
1190 }
1191
1192 if (!IsNativeThread()) {
1193 HILOG_ERROR("current thread is not native thread");
1194 return napi_status::napi_generic_failure;
1195 }
1196 std::unique_lock<std::mutex> lock(loopRunningMutex_);
1197 if (!isLoopRunning_) {
1198 HILOG_DEBUG("loop is already undered stop state");
1199 return napi_status::napi_ok;
1200 }
1201 HILOG_DEBUG("uv loop is running");
1202 uv_stop(loop_);
1203 HILOG_DEBUG("uv loop is stopped");
1204 return napi_status::napi_ok;
1205 }
1206
ThrowException(const char * msg)1207 void NativeEngine::ThrowException(const char* msg)
1208 {
1209 auto vm = GetEcmaVm();
1210 Local<panda::JSValueRef> error = panda::Exception::Error(vm, StringRef::NewFromUtf8(vm, msg));
1211 panda::JSNApi::ThrowException(vm, error);
1212 }
1213
GetInstance()1214 NapiErrorManager* NapiErrorManager::GetInstance()
1215 {
1216 if (instance_ == NULL) {
1217 std::lock_guard<std::mutex> lock(g_errorManagerInstanceMutex);
1218 if (instance_ == NULL) {
1219 instance_ = new NapiErrorManager();
1220 HILOG_DEBUG("create error manager instance");
1221 }
1222 }
1223 return instance_;
1224 }
1225
NotifyUncaughtException(napi_env env,napi_value exception,std::string name,uint32_t type)1226 void NapiErrorManager::NotifyUncaughtException(napi_env env, napi_value exception, std::string name, uint32_t type)
1227 {
1228 auto hasOnErrorCallback = NapiErrorManager::GetInstance()->GetHasErrorCallback();
1229 if (!hasOnErrorCallback) {
1230 return;
1231 }
1232 if (!hasOnErrorCallback()) {
1233 return;
1234 }
1235 auto callback = NapiErrorManager::GetInstance()->GetOnWorkerErrorCallback();
1236 if (callback) {
1237 callback(env, exception, name, type);
1238 }
1239 }
1240
NotifyUncaughtException(napi_env env,const std::string & summary,const std::string & name,const std::string & message,const std::string & stack)1241 bool NapiErrorManager::NotifyUncaughtException(napi_env env, const std::string &summary, const std::string &name,
1242 const std::string &message, const std::string &stack)
1243 {
1244 auto hasOnErrorCallback = NapiErrorManager::GetInstance()->GetHasErrorCallback();
1245 if (!hasOnErrorCallback) {
1246 return false;
1247 }
1248 if (!hasOnErrorCallback()) {
1249 return false;
1250 }
1251 panda::JSNApi::GetAndClearUncaughtException(reinterpret_cast<NativeEngine*>(env)->GetEcmaVm());
1252 auto callback = NapiErrorManager::GetInstance()->GetOnMainThreadErrorCallback();
1253 if (!callback) {
1254 return false;
1255 }
1256 return callback(env, summary, name, message, stack);
1257 }
1258
NotifyUnhandledRejection(napi_env env,napi_value * args,std::string name,uint32_t type)1259 void NapiErrorManager::NotifyUnhandledRejection(napi_env env, napi_value* args, std::string name, uint32_t type)
1260 {
1261 auto hasAllUnhandledRejectionCallback = NapiErrorManager::GetInstance()->GetHasAllUnhandledRejectionCallback();
1262 if (!hasAllUnhandledRejectionCallback) {
1263 return;
1264 }
1265 if (!hasAllUnhandledRejectionCallback()) {
1266 return;
1267 }
1268 auto callback = NapiErrorManager::GetInstance()->GetAllUnhandledRejectionCallback();
1269 if (callback) {
1270 callback(env, args, name, type);
1271 }
1272 }
1273