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