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 }