• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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.h"
17 
18 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
19 #include <sys/epoll.h>
20 #endif
21 #include <uv.h>
22 
23 #include "utils/log.h"
24 
25 namespace {
26 const char* g_errorMessages[] = {
27     nullptr,
28     "Invalid parameter",
29     "Need object",
30     "Need string",
31     "Need string or symbol",
32     "Need function",
33     "Need number",
34     "Need boolean",
35     "Need array",
36     "Generic failure",
37     "An exception is blocking",
38     "Asynchronous work cancelled",
39     "Escape called twice",
40     "Handle scope mismatch",
41     "Callback scope mismatch",
42     "Asynchronous work queue is full",
43     "Asynchronous work handle is closing",
44     "Need bigint",
45     "Need date",
46     "Need arraybuffer",
47     "Need detachable arraybuffer",
48 };
49 } // namespace
50 
NativeEngine(void * jsEngine)51 NativeEngine::NativeEngine(void* jsEngine) : jsEngine_(jsEngine) {}
52 
Init()53 void NativeEngine::Init()
54 {
55     moduleManager_ = NativeModuleManager::GetInstance();
56     referenceManager_ = new NativeReferenceManager();
57     scopeManager_ = new NativeScopeManager();
58     callbackScopeManager_ = new NativeCallbackScopeManager();
59     loop_ = uv_loop_new();
60     if (loop_ == nullptr) {
61         return;
62     }
63     tid_ = pthread_self();
64     uv_async_init(loop_, &uvAsync_, nullptr);
65     uv_sem_init(&uvSem_, 0);
66     lastException_ = nullptr;
67 }
68 
~NativeEngine()69 NativeEngine::~NativeEngine()
70 {
71     if (cleanEnv_ != nullptr) {
72         cleanEnv_();
73     }
74 }
75 
Deinit()76 void NativeEngine::Deinit()
77 {
78     if (referenceManager_ != nullptr) {
79         delete referenceManager_;
80         referenceManager_ = nullptr;
81     }
82     if (scopeManager_ != nullptr) {
83         delete scopeManager_;
84         scopeManager_ = nullptr;
85     }
86 
87     SetStopping(true);
88     uv_sem_destroy(&uvSem_);
89     uv_close((uv_handle_t*)&uvAsync_, nullptr);
90     uv_run(loop_, UV_RUN_ONCE);
91     uv_loop_delete(loop_);
92 }
93 
GetScopeManager()94 NativeScopeManager* NativeEngine::GetScopeManager()
95 {
96     return scopeManager_;
97 }
98 
GetReferenceManager()99 NativeReferenceManager* NativeEngine::GetReferenceManager()
100 {
101     return referenceManager_;
102 }
103 
GetModuleManager()104 NativeModuleManager* NativeEngine::GetModuleManager()
105 {
106     return moduleManager_;
107 }
108 
GetCallbackScopeManager()109 NativeCallbackScopeManager* NativeEngine::GetCallbackScopeManager()
110 {
111     return callbackScopeManager_;
112 }
113 
GetUVLoop() const114 uv_loop_t* NativeEngine::GetUVLoop() const
115 {
116     return loop_;
117 }
118 
GetTid() const119 pthread_t NativeEngine::GetTid() const
120 {
121     return tid_;
122 }
123 
Loop(LoopMode mode,bool needSync)124 void NativeEngine::Loop(LoopMode mode, bool needSync)
125 {
126     bool more = true;
127     switch (mode) {
128         case LOOP_DEFAULT:
129             more = uv_run(loop_, UV_RUN_DEFAULT);
130             break;
131         case LOOP_ONCE:
132             more = uv_run(loop_, UV_RUN_ONCE);
133             break;
134         case LOOP_NOWAIT:
135             more = uv_run(loop_, UV_RUN_NOWAIT);
136             break;
137         default:
138             return;
139     }
140     if (more == false) {
141         more = uv_loop_alive(loop_);
142     }
143 
144     if (needSync) {
145         uv_sem_post(&uvSem_);
146     }
147 }
148 
CreateAsyncWork(NativeValue * asyncResource,NativeValue * asyncResourceName,NativeAsyncExecuteCallback execute,NativeAsyncCompleteCallback complete,void * data)149 NativeAsyncWork* NativeEngine::CreateAsyncWork(NativeValue* asyncResource, NativeValue* asyncResourceName,
150     NativeAsyncExecuteCallback execute, NativeAsyncCompleteCallback complete, void* data)
151 {
152     (void)asyncResource;
153     (void)asyncResourceName;
154     return new NativeAsyncWork(this, execute, complete, data);
155 }
156 
CreateAsyncWork(NativeAsyncExecuteCallback execute,NativeAsyncCompleteCallback complete,void * data)157 NativeAsyncWork* NativeEngine::CreateAsyncWork(NativeAsyncExecuteCallback execute,
158                                                NativeAsyncCompleteCallback complete,
159                                                void* data)
160 {
161     return new NativeAsyncWork(this, execute, complete, data);
162 }
163 
CreateSafeAsyncWork(NativeValue * func,NativeValue * asyncResource,NativeValue * asyncResourceName,size_t maxQueueSize,size_t threadCount,void * finalizeData,NativeFinalize finalizeCallback,void * context,NativeThreadSafeFunctionCallJs callJsCallback)164 NativeSafeAsyncWork* NativeEngine::CreateSafeAsyncWork(NativeValue* func, NativeValue* asyncResource,
165     NativeValue* asyncResourceName, size_t maxQueueSize, size_t threadCount, void* finalizeData,
166     NativeFinalize finalizeCallback, void* context, NativeThreadSafeFunctionCallJs callJsCallback)
167 {
168     return new NativeSafeAsyncWork(this, func, asyncResource, asyncResourceName, maxQueueSize, threadCount,
169         finalizeData, finalizeCallback, context, callJsCallback);
170 }
171 
InitAsyncWork(NativeAsyncExecuteCallback execute,NativeAsyncCompleteCallback complete,void * data)172 void NativeEngine::InitAsyncWork(NativeAsyncExecuteCallback execute,
173                                  NativeAsyncCompleteCallback complete,
174                                  void* data)
175 {
176     asyncWorker_ = std::make_unique<NativeAsyncWork>(this, execute, complete, data);
177     asyncWorker_->Init();
178 }
179 
SendAsyncWork(void * data)180 bool NativeEngine::SendAsyncWork(void* data)
181 {
182     if (!asyncWorker_) {
183         HILOG_ERROR("asyncWorker_ is nullptr");
184         return false;
185     }
186     asyncWorker_->Send(data);
187     return true;
188 }
189 
CloseAsyncWork()190 void NativeEngine::CloseAsyncWork()
191 {
192     if (!asyncWorker_) {
193         HILOG_ERROR("asyncWorker_ is nullptr");
194         return;
195     }
196     asyncWorker_->Close();
197 }
198 
GetLastError()199 NativeErrorExtendedInfo* NativeEngine::GetLastError()
200 {
201     return &lastError_;
202 }
203 
SetLastError(int errorCode,uint32_t engineErrorCode,void * engineReserved)204 void NativeEngine::SetLastError(int errorCode, uint32_t engineErrorCode, void* engineReserved)
205 {
206     lastError_.errorCode = errorCode;
207     lastError_.engineErrorCode = engineErrorCode;
208     lastError_.message = g_errorMessages[lastError_.errorCode];
209     lastError_.reserved = engineReserved;
210 }
211 
ClearLastError()212 void NativeEngine::ClearLastError()
213 {
214     lastError_.errorCode = 0;
215     lastError_.engineErrorCode = 0;
216     lastError_.message = nullptr;
217     lastError_.reserved = nullptr;
218 }
219 
IsExceptionPending() const220 bool NativeEngine::IsExceptionPending() const
221 {
222     return !(lastException_ == nullptr);
223 }
224 
GetAndClearLastException()225 NativeValue* NativeEngine::GetAndClearLastException()
226 {
227     NativeValue* temp = lastException_;
228     lastException_ = nullptr;
229     return temp;
230 }
231 
EncodeToUtf8(NativeValue * nativeValue,char * buffer,int32_t * written,size_t bufferSize,int32_t * nchars)232 void NativeEngine::EncodeToUtf8(NativeValue* nativeValue,
233                                 char* buffer,
234                                 int32_t* written,
235                                 size_t bufferSize,
236                                 int32_t* nchars)
237 {
238     if (nativeValue == nullptr || nchars == nullptr || written == nullptr) {
239         HILOG_ERROR("NativeEngine EncodeToUtf8 args is nullptr");
240         return;
241     }
242 
243     auto nativeString = reinterpret_cast<NativeString*>(nativeValue->GetInterface(NativeString::INTERFACE_ID));
244 
245     if (nativeString == nullptr) {
246         HILOG_ERROR("nativeValue GetInterface is nullptr");
247         return;
248     }
249     *written = nativeString->EncodeWriteUtf8(buffer, bufferSize, nchars);
250 }
251 
252 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
CheckUVLoop()253 void NativeEngine::CheckUVLoop()
254 {
255     checkUVLoop_ = true;
256     uv_thread_create(&uvThread_, NativeEngine::UVThreadRunner, this);
257 }
258 
CancelCheckUVLoop()259 void NativeEngine::CancelCheckUVLoop()
260 {
261     checkUVLoop_ = false;
262     RunCleanup();
263     uv_async_send(&uvAsync_);
264     uv_sem_post(&uvSem_);
265     uv_thread_join(&uvThread_);
266 }
267 
PostLoopTask()268 void NativeEngine::PostLoopTask()
269 {
270     postTask_(true);
271     uv_sem_wait(&uvSem_);
272 }
273 
UVThreadRunner(void * nativeEngine)274 void NativeEngine::UVThreadRunner(void* nativeEngine)
275 {
276     auto engine = static_cast<NativeEngine*>(nativeEngine);
277     engine->PostLoopTask();
278     while (engine->checkUVLoop_) {
279         int32_t fd = uv_backend_fd(engine->loop_);
280         int32_t timeout = uv_backend_timeout(engine->loop_);
281         struct epoll_event ev;
282         int32_t result = epoll_wait(fd, &ev, 1, timeout);
283         if (!engine->checkUVLoop_) {
284             HILOG_INFO("break thread after epoll wait");
285             break;
286         }
287         if (result >= 0) {
288             engine->PostLoopTask();
289         } else {
290             HILOG_ERROR("epoll wait fail: result: %{public}d, errno: %{public}d", result, errno);
291         }
292         if (!engine->checkUVLoop_) {
293             HILOG_INFO("break thread after post loop task");
294             break;
295         }
296     }
297 }
298 #endif
299 
SetPostTask(PostTask postTask)300 void NativeEngine::SetPostTask(PostTask postTask)
301 {
302     HILOG_INFO("SetPostTask in");
303     postTask_ = postTask;
304 }
305 
TriggerPostTask()306 void NativeEngine::TriggerPostTask()
307 {
308     if (postTask_ == nullptr) {
309         HILOG_ERROR("postTask_ is nullptr");
310         return;
311     }
312     postTask_(false);
313 }
314 
GetJsEngine()315 void* NativeEngine::GetJsEngine()
316 {
317     return jsEngine_;
318 }
319 
320 // register init worker func
SetInitWorkerFunc(InitWorkerFunc func)321 void NativeEngine::SetInitWorkerFunc(InitWorkerFunc func)
322 {
323     initWorkerFunc_ = func;
324 }
SetGetAssetFunc(GetAssetFunc func)325 void NativeEngine::SetGetAssetFunc(GetAssetFunc func)
326 {
327     getAssetFunc_ = func;
328 }
SetOffWorkerFunc(OffWorkerFunc func)329 void NativeEngine::SetOffWorkerFunc(OffWorkerFunc func)
330 {
331     offWorkerFunc_ = func;
332 }
SetWorkerAsyncWorkFunc(NativeAsyncExecuteCallback executeCallback,NativeAsyncCompleteCallback completeCallback)333 void NativeEngine::SetWorkerAsyncWorkFunc(NativeAsyncExecuteCallback executeCallback,
334                                           NativeAsyncCompleteCallback completeCallback)
335 {
336     nativeAsyncExecuteCallback_ = executeCallback;
337     nativeAsyncCompleteCallback_ = completeCallback;
338 }
339 // call init worker func
CallInitWorkerFunc(NativeEngine * engine)340 bool NativeEngine::CallInitWorkerFunc(NativeEngine* engine)
341 {
342     if (initWorkerFunc_ != nullptr) {
343         initWorkerFunc_(engine);
344         return true;
345     }
346     return false;
347 }
CallGetAssetFunc(const std::string & uri,std::vector<uint8_t> & content,std::string & ami)348 bool NativeEngine::CallGetAssetFunc(const std::string& uri, std::vector<uint8_t>& content, std::string& ami)
349 {
350     if (getAssetFunc_ != nullptr) {
351         getAssetFunc_(uri, content, ami);
352         return true;
353     }
354     return false;
355 }
CallOffWorkerFunc(NativeEngine * engine)356 bool NativeEngine::CallOffWorkerFunc(NativeEngine* engine)
357 {
358     if (offWorkerFunc_ != nullptr) {
359         offWorkerFunc_(engine);
360         return true;
361     }
362     return false;
363 }
364 
365 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
CallDebuggerPostTaskFunc(std::function<void ()> && task)366 void NativeEngine::CallDebuggerPostTaskFunc(std::function<void()>&& task)
367 {
368     if (debuggerPostTaskFunc_ != nullptr) {
369         debuggerPostTaskFunc_(std::move(task));
370     }
371 }
372 
SetDebuggerPostTaskFunc(DebuggerPostTask func)373 void NativeEngine::SetDebuggerPostTaskFunc(DebuggerPostTask func)
374 {
375     debuggerPostTaskFunc_ = func;
376 }
377 #endif
378 
CallWorkerAsyncWorkFunc(NativeEngine * engine)379 bool NativeEngine::CallWorkerAsyncWorkFunc(NativeEngine* engine)
380 {
381     if (nativeAsyncExecuteCallback_ != nullptr && nativeAsyncCompleteCallback_ != nullptr) {
382         engine->InitAsyncWork(nativeAsyncExecuteCallback_, nativeAsyncCompleteCallback_, nullptr);
383         return true;
384     }
385     return false;
386 }
387 
AddCleanupHook(CleanupCallback fun,void * arg)388 void NativeEngine::AddCleanupHook(CleanupCallback fun, void* arg)
389 {
390     HILOG_INFO("%{public}s, start.", __func__);
391     auto insertion_info = cleanup_hooks_.emplace(CleanupHookCallback { fun, arg, cleanup_hook_counter_++ });
392     if (insertion_info.second != true) {
393         HILOG_ERROR("AddCleanupHook Failed.");
394     }
395     HILOG_INFO("%{public}s, end.", __func__);
396 }
397 
RemoveCleanupHook(CleanupCallback fun,void * arg)398 void NativeEngine::RemoveCleanupHook(CleanupCallback fun, void* arg)
399 {
400     HILOG_INFO("%{public}s, start.", __func__);
401     CleanupHookCallback hook { fun, arg, 0 };
402     cleanup_hooks_.erase(hook);
403     HILOG_INFO("%{public}s, end.", __func__);
404 }
405 
RunCleanup()406 void NativeEngine::RunCleanup()
407 {
408     HILOG_INFO("%{public}s, start.", __func__);
409     CleanupHandles();
410     // sync clean up
411     while (!cleanup_hooks_.empty()) {
412         HILOG_INFO("NativeEngine::RunCleanup cleanup_hooks is not empty");
413         // Copy into a vector, since we can't sort an unordered_set in-place.
414         std::vector<CleanupHookCallback> callbacks(cleanup_hooks_.begin(), cleanup_hooks_.end());
415         // We can't erase the copied elements from `cleanup_hooks_` yet, because we
416         // need to be able to check whether they were un-scheduled by another hook.
417 
418         std::sort(callbacks.begin(), callbacks.end(), [](const CleanupHookCallback& a, const CleanupHookCallback& b) {
419             // Sort in descending order so that the most recently inserted callbacks are run first.
420             return a.insertion_order_counter_ > b.insertion_order_counter_;
421         });
422         HILOG_INFO("NativeEngine::RunCleanup cleanup_hooks callbacks size:%{public}d", (int32_t)callbacks.size());
423         for (const CleanupHookCallback& cb : callbacks) {
424             if (cleanup_hooks_.count(cb) == 0) {
425                 // This hook was removed from the `cleanup_hooks_` set during another
426                 // hook that was run earlier. Nothing to do here.
427                 continue;
428             }
429             cb.fn_(cb.arg_);
430             cleanup_hooks_.erase(cb);
431         }
432         CleanupHandles();
433     }
434     HILOG_INFO("%{public}s, end.", __func__);
435 }
436 
CleanupHandles()437 void NativeEngine::CleanupHandles()
438 {
439     HILOG_INFO("%{public}s, start.", __func__);
440     while (request_waiting_ != 0) {
441         HILOG_INFO("%{public}s, request waiting:%{public}d.", __func__, request_waiting_);
442         uv_run(loop_, UV_RUN_ONCE);
443     }
444     HILOG_INFO("%{public}s, end.", __func__);
445 }
446 
IncreaseWaitingRequestCounter()447 void NativeEngine::IncreaseWaitingRequestCounter()
448 {
449     request_waiting_++;
450     HILOG_INFO("%{public}s, request waiting:%{public}d.", __func__, request_waiting_);
451 }
452 
DecreaseWaitingRequestCounter()453 void NativeEngine::DecreaseWaitingRequestCounter()
454 {
455     request_waiting_--;
456     HILOG_INFO("%{public}s, request waiting:%{public}d.", __func__, request_waiting_);
457 }
458 
RegisterWorkerFunction(const NativeEngine * engine)459 void NativeEngine::RegisterWorkerFunction(const NativeEngine* engine)
460 {
461     if (engine == nullptr) {
462         return;
463     }
464     SetInitWorkerFunc(engine->initWorkerFunc_);
465     SetGetAssetFunc(engine->getAssetFunc_);
466     SetOffWorkerFunc(engine->offWorkerFunc_);
467     SetWorkerAsyncWorkFunc(engine->nativeAsyncExecuteCallback_, engine->nativeAsyncCompleteCallback_);
468 }
469 
RunScript(const char * path)470 NativeValue* NativeEngine::RunScript(const char* path)
471 {
472     std::vector<uint8_t> scriptContent;
473     std::string pathStr(path);
474     std::string ami;
475     if (!CallGetAssetFunc(pathStr, scriptContent, ami)) {
476         HILOG_ERROR("Get asset error");
477         return nullptr;
478     }
479     HILOG_INFO("asset size is %{public}zu", scriptContent.size());
480     return RunActor(scriptContent, ami.c_str());
481 }