• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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