• 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_interface.h"
17 
18 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(IOS_PLATFORM) && !defined(LINUX_PLATFORM)
19 #include <sys/epoll.h>
20 #endif
21 
22 #ifdef IOS_PLATFORM
23 #include <sys/event.h>
24 #endif
25 
26 #include <uv.h>
27 
28 #include "utils/log.h"
29 
30 constexpr size_t NAME_BUFFER_SIZE = 64;
31 static constexpr size_t DESTRUCTION_TIMEOUT = 5000;
32 
33 namespace {
34 const char* g_errorMessages[] = {
35     nullptr,
36     "Invalid parameter",
37     "Need object",
38     "Need string",
39     "Need string or symbol",
40     "Need function",
41     "Need number",
42     "Need boolean",
43     "Need array",
44     "Generic failure",
45     "An exception is blocking",
46     "Asynchronous work cancelled",
47     "Escape called twice",
48     "Handle scope mismatch",
49     "Callback scope mismatch",
50     "Asynchronous work queue is full",
51     "Asynchronous work handle is closing",
52     "Need bigint",
53     "Need date",
54     "Need arraybuffer",
55     "Need detachable arraybuffer",
56 };
57 } // namespace
58 
NativeEngineInterface(NativeEngine * engine,void * jsEngineInterface)59 NativeEngineInterface::NativeEngineInterface(NativeEngine* engine, void* jsEngineInterface)
60     : jsEngineInterface_(jsEngineInterface), rootNativeEngine__(engine)
61 {
62 }
63 
Init()64 void NativeEngineInterface::Init()
65 {
66     HILOG_INFO("NativeEngineInterface::Init");
67     moduleManager_ = NativeModuleManager::GetInstance();
68     referenceManager_ = new NativeReferenceManager();
69     scopeManager_ = new NativeScopeManager();
70     callbackScopeManager_ = new NativeCallbackScopeManager();
71     loop_ = uv_loop_new();
72     if (loop_ == nullptr) {
73         return;
74     }
75     tid_ = pthread_self();
76     uv_async_init(loop_, &uvAsync_, nullptr);
77     uv_sem_init(&uvSem_, 0);
78 }
79 
~NativeEngineInterface()80 NativeEngineInterface::~NativeEngineInterface()
81 {
82     HILOG_INFO("NativeEngineInterface::~NativeEngineInterface");
83     if (cleanEnv_ != nullptr) {
84         cleanEnv_();
85     }
86 }
87 
Deinit()88 void NativeEngineInterface::Deinit()
89 {
90     HILOG_INFO("NativeEngineInterface::Deinit");
91     uv_sem_destroy(&uvSem_);
92     uv_close((uv_handle_t*)&uvAsync_, nullptr);
93     CleanUVResources();
94     if (referenceManager_ != nullptr) {
95         delete referenceManager_;
96         referenceManager_ = nullptr;
97     }
98     if (scopeManager_ != nullptr) {
99         delete scopeManager_;
100         scopeManager_ = nullptr;
101     }
102 
103     SetStopping(true);
104     uv_loop_delete(loop_);
105     loop_ = nullptr;
106 }
107 
GetScopeManager()108 NativeScopeManager* NativeEngineInterface::GetScopeManager()
109 {
110     return scopeManager_;
111 }
112 
GetReferenceManager()113 NativeReferenceManager* NativeEngineInterface::GetReferenceManager()
114 {
115     return referenceManager_;
116 }
117 
GetModuleManager()118 NativeModuleManager* NativeEngineInterface::GetModuleManager()
119 {
120     return moduleManager_;
121 }
122 
GetCallbackScopeManager()123 NativeCallbackScopeManager* NativeEngineInterface::GetCallbackScopeManager()
124 {
125     return callbackScopeManager_;
126 }
127 
GetUVLoop() const128 uv_loop_t* NativeEngineInterface::GetUVLoop() const
129 {
130     return loop_;
131 }
132 
GetTid() const133 pthread_t NativeEngineInterface::GetTid() const
134 {
135     return tid_;
136 }
137 
ReinitUVLoop()138 bool NativeEngineInterface::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 NativeEngineInterface::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(NativeEngine * engine,NativeValue * asyncResource,NativeValue * asyncResourceName,NativeAsyncExecuteCallback execute,NativeAsyncCompleteCallback complete,void * data)182 NativeAsyncWork* NativeEngineInterface::CreateAsyncWork(NativeEngine* engine, NativeValue* asyncResource,
183     NativeValue* asyncResourceName, NativeAsyncExecuteCallback execute, NativeAsyncCompleteCallback complete,
184     void* data)
185 {
186     (void)asyncResource;
187     (void)asyncResourceName;
188     char name[NAME_BUFFER_SIZE] = {0};
189     if (asyncResourceName != nullptr) {
190         auto nativeString = reinterpret_cast<NativeString*>(
191             asyncResourceName->GetInterface(NativeString::INTERFACE_ID));
192         size_t strLength = 0;
193         nativeString->GetCString(name, NAME_BUFFER_SIZE, &strLength);
194     }
195     return new NativeAsyncWork(engine, execute, complete, name, data);
196 }
197 
CreateAsyncWork(NativeEngine * engine,const std::string & asyncResourceName,NativeAsyncExecuteCallback execute,NativeAsyncCompleteCallback complete,void * data)198 NativeAsyncWork* NativeEngineInterface::CreateAsyncWork(NativeEngine* engine, const std::string &asyncResourceName,
199     NativeAsyncExecuteCallback execute, NativeAsyncCompleteCallback complete, void* data)
200 {
201     return new NativeAsyncWork(engine, execute, complete, asyncResourceName, data);
202 }
203 
CreateSafeAsyncWork(NativeEngine * engine,NativeValue * func,NativeValue * asyncResource,NativeValue * asyncResourceName,size_t maxQueueSize,size_t threadCount,void * finalizeData,NativeFinalize finalizeCallback,void * context,NativeThreadSafeFunctionCallJs callJsCallback)204 NativeSafeAsyncWork* NativeEngineInterface::CreateSafeAsyncWork(NativeEngine* engine, NativeValue* func,
205     NativeValue* asyncResource, NativeValue* asyncResourceName, size_t maxQueueSize, size_t threadCount,
206     void* finalizeData, NativeFinalize finalizeCallback, void* context, NativeThreadSafeFunctionCallJs callJsCallback)
207 {
208     return new NativeSafeAsyncWork(engine, func, asyncResource, asyncResourceName, maxQueueSize, threadCount,
209         finalizeData, finalizeCallback, context, callJsCallback);
210 }
211 
GetLastError()212 NativeErrorExtendedInfo* NativeEngineInterface::GetLastError()
213 {
214     return &lastError_;
215 }
216 
SetLastError(int errorCode,uint32_t engineErrorCode,void * engineReserved)217 void NativeEngineInterface::SetLastError(int errorCode, uint32_t engineErrorCode, void* engineReserved)
218 {
219     lastError_.errorCode = errorCode;
220     lastError_.engineErrorCode = engineErrorCode;
221     lastError_.message = g_errorMessages[lastError_.errorCode];
222     lastError_.reserved = engineReserved;
223 }
224 
ClearLastError()225 void NativeEngineInterface::ClearLastError()
226 {
227     lastError_.errorCode = 0;
228     lastError_.engineErrorCode = 0;
229     lastError_.message = nullptr;
230     lastError_.reserved = nullptr;
231 }
232 
EncodeToUtf8(NativeValue * nativeValue,char * buffer,int32_t * written,size_t bufferSize,int32_t * nchars)233 void NativeEngineInterface::EncodeToUtf8(
234     NativeValue* nativeValue, char* buffer, int32_t* written, size_t bufferSize, int32_t* nchars)
235 {
236     if (nativeValue == nullptr || nchars == nullptr || written == nullptr) {
237         HILOG_ERROR("NativeEngine EncodeToUtf8 args is nullptr");
238         return;
239     }
240 
241     auto nativeString = reinterpret_cast<NativeString*>(nativeValue->GetInterface(NativeString::INTERFACE_ID));
242     if (nativeString == nullptr) {
243         HILOG_ERROR("nativeValue GetInterface is nullptr");
244         return;
245     }
246     *written = nativeString->EncodeWriteUtf8(buffer, bufferSize, nchars);
247 }
248 
EncodeToChinese(NativeValue * nativeValue,std::string & buffer,const std::string & encoding)249 void NativeEngineInterface::EncodeToChinese(NativeValue* nativeValue, std::string& buffer, const std::string& encoding)
250 {
251     if (nativeValue == nullptr) {
252         HILOG_ERROR("NativeEngine is nullptr");
253         return;
254     }
255 
256     auto nativeString = reinterpret_cast<NativeString*>(nativeValue->GetInterface(NativeString::INTERFACE_ID));
257     if (nativeString == nullptr) {
258         HILOG_ERROR("nativeValue GetInterface is nullptr");
259         return;
260     }
261     nativeString->EncodeWriteChinese(buffer, encoding.c_str());
262 }
263 
264 #if !defined(PREVIEW)
CheckUVLoop()265 void NativeEngineInterface::CheckUVLoop()
266 {
267     checkUVLoop_ = true;
268     uv_thread_create(&uvThread_, NativeEngineInterface::UVThreadRunner, this);
269 }
270 
CancelCheckUVLoop()271 void NativeEngineInterface::CancelCheckUVLoop()
272 {
273     checkUVLoop_ = false;
274     RunCleanup();
275     uv_async_send(&uvAsync_);
276     uv_sem_post(&uvSem_);
277     uv_thread_join(&uvThread_);
278 }
279 
PostLoopTask()280 void NativeEngineInterface::PostLoopTask()
281 {
282     postTask_(true);
283     uv_sem_wait(&uvSem_);
284 }
285 
UVThreadRunner(void * nativeEngineImpl)286 void NativeEngineInterface::UVThreadRunner(void* nativeEngineImpl)
287 {
288     std::string name("UVLoop");
289 #ifdef IOS_PLATFORM
290     pthread_setname_np(name.c_str());
291 #else
292     pthread_setname_np(pthread_self(), name.c_str());
293 #endif
294     auto engineImpl = static_cast<NativeEngineInterface*>(nativeEngineImpl);
295     engineImpl->PostLoopTask();
296     while (engineImpl->checkUVLoop_) {
297         int32_t fd = uv_backend_fd(engineImpl->loop_);
298         int32_t timeout = uv_backend_timeout(engineImpl->loop_);
299         int32_t result = -1;
300 #ifdef IOS_PLATFORM
301         struct kevent events[1];
302         struct timespec spec;
303         static const int32_t mSec = 1000;
304         static const int32_t uSec = 1000000;
305         if (timeout != -1) {
306             spec.tv_sec = timeout / mSec;
307             spec.tv_nsec = (timeout % mSec) * uSec;
308         }
309         result = kevent(fd, NULL, 0, events, 1, timeout == -1 ? NULL : &spec);
310 
311 #else
312         struct epoll_event ev;
313         result = epoll_wait(fd, &ev, 1, timeout);
314 #endif
315 
316         if (!engineImpl->checkUVLoop_) {
317             HILOG_INFO("break thread after epoll wait");
318             break;
319         }
320         if (result >= 0) {
321             engineImpl->PostLoopTask();
322         } else {
323             HILOG_ERROR("epoll wait fail: result: %{public}d, errno: %{public}d", result, errno);
324         }
325         if (!engineImpl->checkUVLoop_) {
326             HILOG_INFO("break thread after post loop task");
327             break;
328         }
329     }
330 }
331 #endif
332 
SetPostTask(PostTask postTask)333 void NativeEngineInterface::SetPostTask(PostTask postTask)
334 {
335     postTask_ = postTask;
336 }
337 
TriggerPostTask()338 void NativeEngineInterface::TriggerPostTask()
339 {
340     if (postTask_ == nullptr) {
341         HILOG_ERROR("postTask_ is nullptr");
342         return;
343     }
344     postTask_(false);
345 }
346 
GetJsEngine()347 void* NativeEngineInterface::GetJsEngine()
348 {
349     return jsEngineInterface_;
350 }
351 
AddCleanupHook(CleanupCallback fun,void * arg)352 void NativeEngineInterface::AddCleanupHook(CleanupCallback fun, void* arg)
353 {
354     HILOG_INFO("%{public}s, start.", __func__);
355     auto insertion_info = cleanup_hooks_.emplace(CleanupHookCallback { fun, arg, cleanup_hook_counter_++ });
356     if (insertion_info.second != true) {
357         HILOG_ERROR("AddCleanupHook Failed.");
358     }
359     HILOG_INFO("%{public}s, end.", __func__);
360 }
361 
RemoveCleanupHook(CleanupCallback fun,void * arg)362 void NativeEngineInterface::RemoveCleanupHook(CleanupCallback fun, void* arg)
363 {
364     HILOG_INFO("%{public}s, start.", __func__);
365     CleanupHookCallback hook { fun, arg, 0 };
366     cleanup_hooks_.erase(hook);
367     HILOG_INFO("%{public}s, end.", __func__);
368 }
369 
RegisterCleanupCallback(CleanupCb & cb)370 void NativeEngineInterface::RegisterCleanupCallback(CleanupCb &cb)
371 {
372     cleanupQueue_.push_back(cb);
373 }
374 
CleanUVResources()375 void NativeEngineInterface::CleanUVResources()
376 {
377     uv_timer_init(loop_, &timer_);
378     timer_.data = this;
379     uv_timer_start(&timer_, [](uv_timer_t* handle) {
380         reinterpret_cast<NativeEngineInterface*>(handle->data)->cleanupTimeout_ = true;
381     }, DESTRUCTION_TIMEOUT, 0);
382     CleanupHandles();
383     while (!cleanupQueue_.empty() && !cleanupTimeout_) {
384         for (auto iter = cleanupQueue_.begin(); iter != cleanupQueue_.end();) {
385             auto finished = (*iter)();
386             if (finished) {
387                 iter = cleanupQueue_.erase(iter);
388             } else {
389                 ++iter;
390             }
391         }
392         if (!cleanupQueue_.empty()) {
393             uv_run(loop_, UV_RUN_ONCE);
394         }
395     }
396     uv_close(reinterpret_cast<uv_handle_t*>(&timer_), nullptr);
397     uv_run(loop_, UV_RUN_ONCE);
398     if (cleanupTimeout_) {
399         HILOG_ERROR("cleanup uv resources timeout");
400     }
401 }
402 
RunCleanup()403 void NativeEngineInterface::RunCleanup()
404 {
405     HILOG_INFO("%{public}s, start.", __func__);
406     CleanupHandles();
407     // sync clean up
408     while (!cleanup_hooks_.empty()) {
409         HILOG_INFO("NativeEngineInterface::RunCleanup cleanup_hooks is not empty");
410         // Copy into a vector, since we can't sort an unordered_set in-place.
411         std::vector<CleanupHookCallback> callbacks(cleanup_hooks_.begin(), cleanup_hooks_.end());
412         // We can't erase the copied elements from `cleanup_hooks_` yet, because we
413         // need to be able to check whether they were un-scheduled by another hook.
414 
415         std::sort(callbacks.begin(), callbacks.end(), [](const CleanupHookCallback& a, const CleanupHookCallback& b) {
416             // Sort in descending order so that the most recently inserted callbacks are run first.
417             return a.insertion_order_counter_ > b.insertion_order_counter_;
418         });
419         HILOG_INFO(
420             "NativeEngineInterface::RunCleanup cleanup_hooks callbacks size:%{public}d", (int32_t)callbacks.size());
421         for (const CleanupHookCallback& cb : callbacks) {
422             if (cleanup_hooks_.count(cb) == 0) {
423                 // This hook was removed from the `cleanup_hooks_` set during another
424                 // hook that was run earlier. Nothing to do here.
425                 continue;
426             }
427             cb.fn_(cb.arg_);
428             cleanup_hooks_.erase(cb);
429         }
430         CleanupHandles();
431     }
432     HILOG_INFO("%{public}s, end.", __func__);
433 }
434 
CleanupHandles()435 void NativeEngineInterface::CleanupHandles()
436 {
437     while (request_waiting_.load() > 0 && !cleanupTimeout_) {
438         HILOG_INFO("%{public}s, request waiting:%{public}d.", __func__,
439             request_waiting_.load(std::memory_order_relaxed));
440         uv_run(loop_, UV_RUN_ONCE);
441     }
442 }
443 
IncreaseWaitingRequestCounter()444 void NativeEngineInterface::IncreaseWaitingRequestCounter()
445 {
446     request_waiting_++;
447 }
448 
DecreaseWaitingRequestCounter()449 void NativeEngineInterface::DecreaseWaitingRequestCounter()
450 {
451     request_waiting_--;
452 }
453 
GetRootNativeEngine(void)454 NativeEngine* NativeEngineInterface::GetRootNativeEngine(void)
455 {
456     return rootNativeEngine__;
457 }
458