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