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