• 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 #include <uv.h>
19 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(IOS_PLATFORM) && !defined(LINUX_PLATFORM)
20 #include <sys/epoll.h>
21 #endif
22 #ifdef IOS_PLATFORM
23 #include <sys/event.h>
24 #endif
25 
26 #include "ecmascript/napi/include/jsnapi.h"
27 #include "native_engine/native_utils.h"
28 #include "unicode/ucnv.h"
29 #include "utils/log.h"
30 
31 constexpr size_t NAME_BUFFER_SIZE = 64;
32 static constexpr size_t DESTRUCTION_TIMEOUT = 3000;
33 
34 using panda::JSValueRef;
35 using panda::Local;
36 using panda::LocalScope;
37 using panda::ObjectRef;
38 using panda::StringRef;
39 
40 namespace {
41 const char* g_errorMessages[] = {
42     nullptr,
43     "Invalid parameter",
44     "Need object",
45     "Need string",
46     "Need string or symbol",
47     "Need function",
48     "Need number",
49     "Need boolean",
50     "Need array",
51     "Generic failure",
52     "An exception is blocking",
53     "Asynchronous work cancelled",
54     "Escape called twice",
55     "Handle scope mismatch",
56     "Callback scope mismatch",
57     "Asynchronous work queue is full",
58     "Asynchronous work handle is closing",
59     "Need bigint",
60     "Need date",
61     "Need arraybuffer",
62     "Need detachable arraybuffer",
63 };
64 } // namespace
65 
66 static GetContainerScopeIdCallback getContainerScopeIdFunc_;
67 static ContainerScopeCallback initContainerScopeFunc_;
68 static ContainerScopeCallback finishContainerScopeFunc_;
69 
NativeEngine(void * jsEngine)70 NativeEngine::NativeEngine(void* jsEngine) : jsEngine_(jsEngine) {}
71 
~NativeEngine()72 NativeEngine::~NativeEngine()
73 {
74     HILOG_DEBUG("NativeEngine::~NativeEngine");
75     if (cleanEnv_ != nullptr) {
76         cleanEnv_();
77     }
78     std::lock_guard<std::mutex> insLock(instanceDataLock_);
79     FinalizerInstanceData();
80 }
81 
Init()82 void NativeEngine::Init()
83 {
84     HILOG_DEBUG("NativeEngine::Init");
85     moduleManager_ = NativeModuleManager::GetInstance();
86     referenceManager_ = new NativeReferenceManager();
87     callbackScopeManager_ = new NativeCallbackScopeManager();
88     loop_ = uv_loop_new();
89     if (loop_ == nullptr) {
90         return;
91     }
92     tid_ = pthread_self();
93     uv_async_init(loop_, &uvAsync_, nullptr);
94     uv_sem_init(&uvSem_, 0);
95 }
96 
Deinit()97 void NativeEngine::Deinit()
98 {
99     HILOG_DEBUG("NativeEngine::Deinit");
100     uv_sem_destroy(&uvSem_);
101     uv_close((uv_handle_t*)&uvAsync_, nullptr);
102     RunCleanup();
103     if (referenceManager_ != nullptr) {
104         delete referenceManager_;
105         referenceManager_ = nullptr;
106     }
107 
108     SetStopping(true);
109     uv_loop_delete(loop_);
110     loop_ = nullptr;
111 }
112 
GetReferenceManager()113 NativeReferenceManager* NativeEngine::GetReferenceManager()
114 {
115     return referenceManager_;
116 }
117 
GetModuleManager()118 NativeModuleManager* NativeEngine::GetModuleManager()
119 {
120     return moduleManager_;
121 }
122 
GetCallbackScopeManager()123 NativeCallbackScopeManager* NativeEngine::GetCallbackScopeManager()
124 {
125     return callbackScopeManager_;
126 }
127 
GetUVLoop() const128 uv_loop_t* NativeEngine::GetUVLoop() const
129 {
130     return loop_;
131 }
132 
GetTid() const133 pthread_t NativeEngine::GetTid() const
134 {
135     return tid_;
136 }
137 
ReinitUVLoop()138 bool NativeEngine::ReinitUVLoop()
139 {
140     if (loop_ != nullptr) {
141         uv_sem_destroy(&uvSem_);
142         uv_close((uv_handle_t*)&uvAsync_, nullptr);
143         uv_run(loop_, UV_RUN_ONCE);
144         uv_loop_delete(loop_);
145     }
146 
147     loop_ = uv_loop_new();
148     if (loop_ == nullptr) {
149         return false;
150     }
151     tid_ = pthread_self();
152     uv_async_init(loop_, &uvAsync_, nullptr);
153     uv_sem_init(&uvSem_, 0);
154     return true;
155 }
156 
Loop(LoopMode mode,bool needSync)157 void NativeEngine::Loop(LoopMode mode, bool needSync)
158 {
159     bool more = true;
160     switch (mode) {
161         case LoopMode::LOOP_DEFAULT:
162             more = uv_run(loop_, UV_RUN_DEFAULT);
163             break;
164         case LoopMode::LOOP_ONCE:
165             more = uv_run(loop_, UV_RUN_ONCE);
166             break;
167         case LoopMode::LOOP_NOWAIT:
168             more = uv_run(loop_, UV_RUN_NOWAIT);
169             break;
170         default:
171             return;
172     }
173     if (more == false) {
174         uv_loop_alive(loop_);
175     }
176 
177     if (needSync) {
178         uv_sem_post(&uvSem_);
179     }
180 }
181 
CreateAsyncWork(napi_value asyncResource,napi_value asyncResourceName,NativeAsyncExecuteCallback execute,NativeAsyncCompleteCallback complete,void * data)182 NativeAsyncWork* NativeEngine::CreateAsyncWork(napi_value asyncResource, napi_value asyncResourceName,
183     NativeAsyncExecuteCallback execute, NativeAsyncCompleteCallback complete, void* data)
184 {
185     (void)asyncResource;
186     (void)asyncResourceName;
187     char name[NAME_BUFFER_SIZE] = {0};
188     if (asyncResourceName != nullptr) {
189         auto val = LocalValueFromJsValue(asyncResourceName);
190         size_t strLength = 0;
191         auto vm = GetEcmaVm();
192         LocalScope scope(vm);
193         auto str = val->ToString(vm);
194         char* buffer = name;
195         if (buffer == nullptr) {
196             strLength = static_cast<size_t>(str->Utf8Length(vm) - 1);
197         } else if (NAME_BUFFER_SIZE != 0) {
198             int copied = str->WriteUtf8(buffer, NAME_BUFFER_SIZE - 1, true) - 1;
199             buffer[copied] = '\0';
200             strLength = static_cast<size_t>(copied);
201         } else {
202             strLength = 0;
203         }
204     }
205     return new NativeAsyncWork(this, execute, complete, name, data);
206 }
207 
CreateAsyncWork(const std::string & asyncResourceName,NativeAsyncExecuteCallback execute,NativeAsyncCompleteCallback complete,void * data)208 NativeAsyncWork* NativeEngine::CreateAsyncWork(const std::string& asyncResourceName, NativeAsyncExecuteCallback execute,
209     NativeAsyncCompleteCallback complete, void* data)
210 {
211     return new NativeAsyncWork(this, execute, complete, asyncResourceName, data);
212 }
213 
CreateSafeAsyncWork(napi_value func,napi_value asyncResource,napi_value asyncResourceName,size_t maxQueueSize,size_t threadCount,void * finalizeData,NativeFinalize finalizeCallback,void * context,NativeThreadSafeFunctionCallJs callJsCallback)214 NativeSafeAsyncWork* NativeEngine::CreateSafeAsyncWork(napi_value func, napi_value asyncResource,
215     napi_value asyncResourceName, size_t maxQueueSize, size_t threadCount, void* finalizeData,
216     NativeFinalize finalizeCallback, void* context, NativeThreadSafeFunctionCallJs callJsCallback)
217 {
218     return new NativeSafeAsyncWork(this, func, asyncResource, asyncResourceName, maxQueueSize, threadCount,
219         finalizeData, finalizeCallback, context, callJsCallback);
220 }
221 
GetLastError()222 NativeErrorExtendedInfo* NativeEngine::GetLastError()
223 {
224     return &lastError_;
225 }
226 
SetLastError(int errorCode,uint32_t engineErrorCode,void * engineReserved)227 void NativeEngine::SetLastError(int errorCode, uint32_t engineErrorCode, void* engineReserved)
228 {
229     lastError_.errorCode = errorCode;
230     lastError_.engineErrorCode = engineErrorCode;
231     lastError_.message = g_errorMessages[lastError_.errorCode];
232     lastError_.reserved = engineReserved;
233 }
234 
SubEncodeToUtf8(const EcmaVM * vm,Local<JSValueRef> & nativeValue,Local<StringRef> & nativeString,char * buffer,int32_t * written,size_t bufferSize,int32_t * nchars)235 void SubEncodeToUtf8(const EcmaVM* vm,
236                      Local<JSValueRef>& nativeValue,
237                      Local<StringRef>& nativeString,
238                      char* buffer,
239                      int32_t* written,
240                      size_t bufferSize,
241                      int32_t* nchars)
242 {
243     int32_t length = static_cast<int32_t>(nativeString->Length());
244     int32_t pos = 0;
245     int32_t writableSize = static_cast<int32_t>(bufferSize);
246     int32_t i = 0;
247     panda::Local<ObjectRef> strObj = nativeValue->ToObject(vm);
248     for (; i < length; i++) {
249         panda::Local<StringRef> str = strObj->Get(vm, i)->ToString(vm);
250         int32_t len = str->Utf8Length(vm) - 1;
251         if (len > writableSize) {
252             break;
253         }
254         str->WriteUtf8((buffer + pos), writableSize);
255         writableSize -= len;
256         pos += len;
257     }
258     *nchars = i;
259     HILOG_DEBUG("EncodeWriteUtf8 the result of buffer: %{public}s", buffer);
260     *written = pos;
261 }
262 
EncodeToUtf8(napi_value value,char * buffer,int32_t * written,size_t bufferSize,int32_t * nchars)263 void NativeEngine::EncodeToUtf8(napi_value value, char* buffer, int32_t* written, size_t bufferSize, int32_t* nchars)
264 {
265     auto nativeValue = LocalValueFromJsValue(value);
266     if (nativeValue->IsNull() || nchars == nullptr || written == nullptr) {
267         HILOG_ERROR("NativeEngine EncodeToUtf8 args is nullptr");
268         return;
269     }
270 
271     auto vm = GetEcmaVm();
272     LocalScope scope(vm);
273     auto nativeString = nativeValue->ToString(vm);
274     if (!nativeString->IsString()) {
275         HILOG_ERROR("nativeValue not is string");
276         return;
277     }
278 
279     if (buffer == nullptr) {
280         HILOG_ERROR("buffer is null");
281     }
282 
283     SubEncodeToUtf8(vm, nativeValue, nativeString, buffer, written, bufferSize, nchars);
284 }
285 
SubEncodeToChinese(const EcmaVM * vm,Local<JSValueRef> & nativeValue,Local<StringRef> & nativeString,std::string & buffer,const char * encode)286 void SubEncodeToChinese(const EcmaVM* vm,
287                         Local<JSValueRef>& nativeValue,
288                         Local<StringRef>& nativeString,
289                         std::string& buffer,
290                         const char* encode)
291 {
292     int32_t length = static_cast<int32_t>(nativeString->Length());
293     int32_t pos = 0;
294     const int32_t writableSize = 22; // 22 : encode max bytes of the ucnv_convent function;
295     std::string tempBuf = "";
296     tempBuf.resize(writableSize + 1);
297     UErrorCode ErrorCode = U_ZERO_ERROR;
298     const char* encFrom = "utf8";
299     panda::Local<ObjectRef> strObj = nativeValue->ToObject(vm);
300     for (int32_t i = 0; i < length; i++) {
301         panda::Local<StringRef> str = strObj->Get(vm, i)->ToString(vm);
302         int32_t len = str->Utf8Length(vm) - 1;
303         if ((pos + len) >= writableSize) {
304             char outBuf[writableSize] = {0};
305             ucnv_convert(encode, encFrom, outBuf, writableSize, tempBuf.c_str(), pos, &ErrorCode);
306             if (ErrorCode != U_ZERO_ERROR) {
307                 HILOG_ERROR("ucnv_convert is failed : ErrorCode = %{public}d", static_cast<int32_t>(ErrorCode));
308                 return;
309             }
310             buffer += outBuf;
311             tempBuf.clear();
312             pos = 0;
313         }
314         str->WriteUtf8((tempBuf.data() + pos), pos + len + 1);
315         pos += len;
316     }
317     if (pos > 0) {
318         char outBuf[writableSize] = {0};
319         ucnv_convert(encode, encFrom, outBuf, writableSize, tempBuf.c_str(), pos, &ErrorCode);
320         if (ErrorCode != U_ZERO_ERROR) {
321             HILOG_ERROR("ucnv_convert is failed : ErrorCode = %{public}d", static_cast<int32_t>(ErrorCode));
322             return;
323         }
324         buffer += outBuf;
325     }
326 }
327 
EncodeToChinese(napi_value value,std::string & buffer,const std::string & encoding)328 void NativeEngine::EncodeToChinese(napi_value value, std::string& buffer, const std::string& encoding)
329 {
330     if (value == nullptr) {
331         HILOG_ERROR("nativeValue GetInterface is nullptr");
332         return;
333     }
334 
335     auto nativeValue = LocalValueFromJsValue(value);
336     auto vm = GetEcmaVm();
337     LocalScope scope(vm);
338     auto nativeString = nativeValue->ToString(vm);
339     if (!nativeString->IsString()) {
340         HILOG_ERROR("nativeValue not is string");
341         return;
342     }
343 
344     auto encode = encoding.c_str();
345     if (encode == nullptr) {
346         HILOG_ERROR("encoding is nullptr");
347         return;
348     }
349 
350     SubEncodeToChinese(vm, nativeValue, nativeString, buffer, encode);
351 }
352 
353 #if !defined(PREVIEW)
CheckUVLoop()354 void NativeEngine::CheckUVLoop()
355 {
356     checkUVLoop_ = true;
357     uv_thread_create(&uvThread_, NativeEngine::UVThreadRunner, this);
358 }
359 
UVThreadRunner(void * nativeEngine)360 void NativeEngine::UVThreadRunner(void* nativeEngine)
361 {
362     std::string name("UVLoop");
363 #ifdef IOS_PLATFORM
364     pthread_setname_np(name.c_str());
365 #else
366     pthread_setname_np(pthread_self(), name.c_str());
367 #endif
368     auto engine = static_cast<NativeEngine*>(nativeEngine);
369     engine->PostLoopTask();
370     while (engine->checkUVLoop_) {
371         int32_t fd = uv_backend_fd(engine->loop_);
372         int32_t timeout = uv_backend_timeout(engine->loop_);
373         int32_t result = -1;
374 #ifdef IOS_PLATFORM
375         struct kevent events[1];
376         struct timespec spec;
377         static const int32_t mSec = 1000;
378         static const int32_t uSec = 1000000;
379         if (timeout != -1) {
380             spec.tv_sec = timeout / mSec;
381             spec.tv_nsec = (timeout % mSec) * uSec;
382         }
383         result = kevent(fd, NULL, 0, events, 1, timeout == -1 ? NULL : &spec);
384 
385 #else
386         struct epoll_event ev;
387         result = epoll_wait(fd, &ev, 1, timeout);
388 #endif
389 
390         if (!engine->checkUVLoop_) {
391             HILOG_INFO("break thread after epoll wait");
392             break;
393         }
394         if (result >= 0) {
395             engine->PostLoopTask();
396         } else {
397             HILOG_ERROR("epoll wait fail: result: %{public}d, errno: %{public}d", result, errno);
398         }
399         if (!engine->checkUVLoop_) {
400             HILOG_INFO("break thread after post loop task");
401             break;
402         }
403     }
404 }
405 
CancelCheckUVLoop()406 void NativeEngine::CancelCheckUVLoop()
407 {
408     checkUVLoop_ = false;
409     uv_async_send(&uvAsync_);
410     uv_sem_post(&uvSem_);
411     uv_thread_join(&uvThread_);
412 }
413 
PostLoopTask()414 void NativeEngine::PostLoopTask()
415 {
416     postTask_(true);
417     uv_sem_wait(&uvSem_);
418 }
419 #endif
420 
SetPostTask(PostTask postTask)421 void NativeEngine::SetPostTask(PostTask postTask)
422 {
423     postTask_ = postTask;
424 }
425 
TriggerPostTask()426 void NativeEngine::TriggerPostTask()
427 {
428     if (postTask_ == nullptr) {
429         HILOG_ERROR("postTask_ is nullptr");
430         return;
431     }
432     postTask_(false);
433 }
434 
GetJsEngine()435 void* NativeEngine::GetJsEngine()
436 {
437     return jsEngine_;
438 }
439 
440 // register init worker func
SetInitWorkerFunc(InitWorkerFunc func)441 void NativeEngine::SetInitWorkerFunc(InitWorkerFunc func)
442 {
443     initWorkerFunc_ = func;
444 }
GetInitWorkerFunc() const445 InitWorkerFunc NativeEngine::GetInitWorkerFunc() const
446 {
447     return initWorkerFunc_;
448 }
SetGetAssetFunc(GetAssetFunc func)449 void NativeEngine::SetGetAssetFunc(GetAssetFunc func)
450 {
451     getAssetFunc_ = func;
452 }
GetGetAssetFunc() const453 GetAssetFunc NativeEngine::GetGetAssetFunc() const
454 {
455     return getAssetFunc_;
456 }
SetOffWorkerFunc(OffWorkerFunc func)457 void NativeEngine::SetOffWorkerFunc(OffWorkerFunc func)
458 {
459     offWorkerFunc_ = func;
460 }
GetOffWorkerFunc() const461 OffWorkerFunc NativeEngine::GetOffWorkerFunc() const
462 {
463     return offWorkerFunc_;
464 }
465 
466 // call init worker func
CallInitWorkerFunc(NativeEngine * engine)467 bool NativeEngine::CallInitWorkerFunc(NativeEngine* engine)
468 {
469     if (initWorkerFunc_ != nullptr) {
470         initWorkerFunc_(engine);
471         return true;
472     }
473     return false;
474 }
CallGetAssetFunc(const std::string & uri,std::vector<uint8_t> & content,std::string & ami)475 bool NativeEngine::CallGetAssetFunc(const std::string& uri, std::vector<uint8_t>& content, std::string& ami)
476 {
477     if (getAssetFunc_ != nullptr) {
478         getAssetFunc_(uri, content, ami);
479         return true;
480     }
481     return false;
482 }
CallOffWorkerFunc(NativeEngine * engine)483 bool NativeEngine::CallOffWorkerFunc(NativeEngine* engine)
484 {
485     if (offWorkerFunc_ != nullptr) {
486         offWorkerFunc_(engine);
487         return true;
488     }
489     return false;
490 }
491 
492 // adapt worker to ace container
SetGetContainerScopeIdFunc(GetContainerScopeIdCallback func)493 void NativeEngine::SetGetContainerScopeIdFunc(GetContainerScopeIdCallback func)
494 {
495     getContainerScopeIdFunc_ = func;
496 }
SetInitContainerScopeFunc(ContainerScopeCallback func)497 void NativeEngine::SetInitContainerScopeFunc(ContainerScopeCallback func)
498 {
499     initContainerScopeFunc_ = func;
500 }
SetFinishContainerScopeFunc(ContainerScopeCallback func)501 void NativeEngine::SetFinishContainerScopeFunc(ContainerScopeCallback func)
502 {
503     finishContainerScopeFunc_ = func;
504 }
GetContainerScopeIdFunc()505 int32_t NativeEngine::GetContainerScopeIdFunc()
506 {
507     int32_t scopeId = -1;
508     if (getContainerScopeIdFunc_ != nullptr) {
509         scopeId = getContainerScopeIdFunc_();
510     }
511     return scopeId;
512 }
InitContainerScopeFunc(int32_t id)513 bool NativeEngine::InitContainerScopeFunc(int32_t id)
514 {
515     if (initContainerScopeFunc_ != nullptr) {
516         initContainerScopeFunc_(id);
517         return true;
518     }
519     return false;
520 }
FinishContainerScopeFunc(int32_t id)521 bool NativeEngine::FinishContainerScopeFunc(int32_t id)
522 {
523     if (finishContainerScopeFunc_ != nullptr) {
524         finishContainerScopeFunc_(id);
525         return true;
526     }
527     return false;
528 }
529 
530 #if !defined(PREVIEW)
CallDebuggerPostTaskFunc(std::function<void ()> && task)531 void NativeEngine::CallDebuggerPostTaskFunc(std::function<void()>&& task)
532 {
533     if (debuggerPostTaskFunc_ != nullptr) {
534         debuggerPostTaskFunc_(std::move(task));
535     }
536 }
537 
SetDebuggerPostTaskFunc(DebuggerPostTask func)538 void NativeEngine::SetDebuggerPostTaskFunc(DebuggerPostTask func)
539 {
540     debuggerPostTaskFunc_ = func;
541 }
542 #endif
543 
SetHostEngine(NativeEngine * engine)544 void NativeEngine::SetHostEngine(NativeEngine* engine)
545 {
546     hostEngine_ = engine;
547 }
548 
GetHostEngine() const549 NativeEngine* NativeEngine::GetHostEngine() const
550 {
551     return hostEngine_;
552 }
553 
AddCleanupHook(CleanupCallback fun,void * arg)554 void NativeEngine::AddCleanupHook(CleanupCallback fun, void* arg)
555 {
556     HILOG_DEBUG("%{public}s, start.", __func__);
557     auto insertion_info = cleanup_hooks_.emplace(CleanupHookCallback { fun, arg, cleanup_hook_counter_++ });
558     if (insertion_info.second != true) {
559         HILOG_ERROR("AddCleanupHook Failed.");
560     }
561     HILOG_DEBUG("%{public}s, end.", __func__);
562 }
563 
RemoveCleanupHook(CleanupCallback fun,void * arg)564 void NativeEngine::RemoveCleanupHook(CleanupCallback fun, void* arg)
565 {
566     HILOG_DEBUG("%{public}s, start.", __func__);
567     CleanupHookCallback hook { fun, arg, 0 };
568     cleanup_hooks_.erase(hook);
569     HILOG_DEBUG("%{public}s, end.", __func__);
570 }
571 
StartCleanupTimer()572 void NativeEngine::StartCleanupTimer()
573 {
574     uv_timer_init(loop_, &timer_);
575     timer_.data = this;
576     uv_timer_start(&timer_, [](uv_timer_t* handle) {
577         HILOG_DEBUG("NativeEngine:: timer is end with timeout.");
578         reinterpret_cast<NativeEngine*>(handle->data)->cleanupTimeout_ = true;
579     }, DESTRUCTION_TIMEOUT, 0);
580     uv_unref(reinterpret_cast<uv_handle_t*>(&timer_));
581 }
582 
RunCleanup()583 void NativeEngine::RunCleanup()
584 {
585     HILOG_DEBUG("%{public}s, start.", __func__);
586     StartCleanupTimer();
587     CleanupHandles();
588     // sync clean up
589     while (!cleanup_hooks_.empty()) {
590         HILOG_DEBUG("NativeEngine::RunCleanup cleanup_hooks is not empty");
591         // Copy into a vector, since we can't sort an unordered_set in-place.
592         std::vector<CleanupHookCallback> callbacks(cleanup_hooks_.begin(), cleanup_hooks_.end());
593         // We can't erase the copied elements from `cleanup_hooks_` yet, because we
594         // need to be able to check whether they were un-scheduled by another hook.
595 
596         std::sort(callbacks.begin(), callbacks.end(), [](const CleanupHookCallback& a, const CleanupHookCallback& b) {
597             // Sort in descending order so that the most recently inserted callbacks are run first.
598             return a.insertion_order_counter_ > b.insertion_order_counter_;
599         });
600         HILOG_DEBUG(
601             "NativeEngine::RunCleanup cleanup_hooks callbacks size:%{public}d", (int32_t)callbacks.size());
602         for (const CleanupHookCallback& cb : callbacks) {
603             if (cleanup_hooks_.count(cb) == 0) {
604                 // This hook was removed from the `cleanup_hooks_` set during another
605                 // hook that was run earlier. Nothing to do here.
606                 continue;
607             }
608             cb.fn_(cb.arg_);
609             cleanup_hooks_.erase(cb);
610         }
611         CleanupHandles();
612     }
613 
614     while (uv_run(loop_, UV_RUN_NOWAIT) != 0 && !cleanupTimeout_) {}
615     uv_timer_stop(&timer_);
616     uv_close(reinterpret_cast<uv_handle_t*>(&timer_), nullptr);
617     uv_run(loop_, UV_RUN_ONCE);
618 
619     if (cleanupTimeout_) {
620         HILOG_DEBUG("RunCleanup timeout");
621     }
622     HILOG_DEBUG("%{public}s, end.", __func__);
623 }
624 
CleanupHandles()625 void NativeEngine::CleanupHandles()
626 {
627     while (requestWaiting_.load() > 0 && !cleanupTimeout_) {
628         HILOG_INFO("%{public}s, request waiting:%{public}d.", __func__,
629             requestWaiting_.load(std::memory_order_relaxed));
630         uv_run(loop_, UV_RUN_ONCE);
631     }
632 }
633 
IncreaseWaitingRequestCounter()634 void NativeEngine::IncreaseWaitingRequestCounter()
635 {
636     requestWaiting_++;
637 }
638 
DecreaseWaitingRequestCounter()639 void NativeEngine::DecreaseWaitingRequestCounter()
640 {
641     requestWaiting_--;
642 }
643 
HasWaitingRequest()644 bool NativeEngine::HasWaitingRequest()
645 {
646     return requestWaiting_.load() != 0;
647 }
648 
IncreaseListeningCounter()649 void NativeEngine::IncreaseListeningCounter()
650 {
651     listeningCounter_++;
652 }
653 
DecreaseListeningCounter()654 void NativeEngine::DecreaseListeningCounter()
655 {
656     listeningCounter_--;
657 }
658 
HasListeningCounter()659 bool NativeEngine::HasListeningCounter()
660 {
661     return listeningCounter_.load() != 0;
662 }
663 
RegisterWorkerFunction(const NativeEngine * engine)664 void NativeEngine::RegisterWorkerFunction(const NativeEngine* engine)
665 {
666     if (engine == nullptr) {
667         return;
668     }
669     SetInitWorkerFunc(engine->GetInitWorkerFunc());
670     SetGetAssetFunc(engine->GetGetAssetFunc());
671     SetOffWorkerFunc(engine->GetOffWorkerFunc());
672 }
673 
RunScriptForAbc(const char * path,char * entryPoint)674 napi_value NativeEngine::RunScriptForAbc(const char* path, char* entryPoint)
675 {
676     std::vector<uint8_t> scriptContent;
677     std::string pathStr(path);
678     std::string ami;
679     if (!CallGetAssetFunc(pathStr, scriptContent, ami)) {
680         HILOG_ERROR("Get asset error");
681         return nullptr;
682     }
683     // if buffer is empty, return directly.
684     if (scriptContent.size() == 0) {
685         HILOG_ERROR("asset size is %{public}zu", scriptContent.size());
686         auto vm = GetEcmaVm();
687         Local<panda::JSValueRef> error =
688             panda::Exception::Error(vm, StringRef::NewFromUtf8(vm, "RunScriptForAbc: abc file is empty."));
689         panda::JSNApi::ThrowException(vm, error);
690         return nullptr;
691     }
692     return RunActor(scriptContent, ami.c_str(), entryPoint);
693 }
694 
RunScript(const char * path,char * entryPoint)695 napi_value NativeEngine::RunScript(const char* path, char* entryPoint)
696 {
697     std::vector<uint8_t> scriptContent;
698     std::string pathStr(path);
699     std::string ami;
700     if (!CallGetAssetFunc(pathStr, scriptContent, ami)) {
701         HILOG_ERROR("Get asset error");
702         return nullptr;
703     }
704     HILOG_INFO("asset size is %{public}zu", scriptContent.size());
705     return RunActor(scriptContent, ami.c_str(), entryPoint);
706 }
707 
SetInstanceData(void * data,NativeFinalize finalize_cb,void * hint)708 void NativeEngine::SetInstanceData(void* data, NativeFinalize finalize_cb, void* hint)
709 {
710     HILOG_INFO("NativeEngineWraper::%{public}s, start.", __func__);
711     std::lock_guard<std::mutex> insLock(instanceDataLock_);
712     FinalizerInstanceData();
713     instanceDataInfo_.engine = this;
714     instanceDataInfo_.callback = finalize_cb;
715     instanceDataInfo_.nativeObject = data;
716     instanceDataInfo_.hint = hint;
717 }
718 
GetInstanceData(void ** data)719 void NativeEngine::GetInstanceData(void** data)
720 {
721     HILOG_INFO("NativeEngineWraper::%{public}s, start.", __func__);
722     std::lock_guard<std::mutex> insLock(instanceDataLock_);
723     if (data) {
724         *data = instanceDataInfo_.nativeObject;
725     }
726 }
727 
FinalizerInstanceData(void)728 void NativeEngine::FinalizerInstanceData(void)
729 {
730     if (instanceDataInfo_.engine != nullptr && instanceDataInfo_.callback != nullptr) {
731         instanceDataInfo_.callback(instanceDataInfo_.engine, instanceDataInfo_.nativeObject, instanceDataInfo_.hint);
732     }
733     instanceDataInfo_.engine = nullptr;
734     instanceDataInfo_.callback = nullptr;
735     instanceDataInfo_.nativeObject = nullptr;
736     instanceDataInfo_.hint = nullptr;
737 }
738 
GetModuleFileName()739 const char* NativeEngine::GetModuleFileName()
740 {
741     HILOG_INFO("%{public}s, start.", __func__);
742     if (moduleFileName_.empty()) {
743         NativeModuleManager* moduleManager = GetModuleManager();
744         HILOG_INFO("NativeEngineWraper::GetFileName GetModuleManager");
745         if (moduleManager != nullptr) {
746             std::string moduleFileName = moduleManager->GetModuleFileName(moduleName_.c_str(), isAppModule_);
747             HILOG_INFO("NativeEngineWraper::GetFileName end filename:%{public}s", moduleFileName.c_str());
748             SetModuleFileName(moduleFileName);
749         }
750     }
751     return moduleFileName_.c_str();
752 }
753 
SetModuleName(std::string & moduleName)754 void NativeEngine::SetModuleName(std::string& moduleName)
755 {
756     moduleName_ = moduleName;
757 }
758 
SetModuleFileName(std::string & moduleFileName)759 void NativeEngine::SetModuleFileName(std::string& moduleFileName)
760 {
761     moduleFileName_ = moduleFileName;
762 }
763 
SetExtensionInfos(std::unordered_map<std::string,int32_t> && extensionInfos)764 void NativeEngine::SetExtensionInfos(std::unordered_map<std::string, int32_t>&& extensionInfos)
765 {
766     extensionInfos_ = extensionInfos;
767 }
768 
GetExtensionInfos()769 const std::unordered_map<std::string, int32_t>& NativeEngine::GetExtensionInfos()
770 {
771     return extensionInfos_;
772 }
773 
SetModuleLoadChecker(const std::shared_ptr<ModuleCheckerDelegate> & moduleCheckerDelegate)774 void NativeEngine::SetModuleLoadChecker(const std::shared_ptr<ModuleCheckerDelegate>& moduleCheckerDelegate)
775 {
776     NativeModuleManager* moduleManager = GetModuleManager();
777     if (!moduleManager) {
778         HILOG_ERROR("SetModuleLoadChecker failed, moduleManager is nullptr");
779         return;
780     }
781     moduleManager->SetModuleLoadChecker(moduleCheckerDelegate);
782 }