• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 "worker.h"
17 
18 #include <unordered_map>
19 
20 #include "sys_timer.h"
21 #include "helper/concurrent_helper.h"
22 #include "helper/error_helper.h"
23 #include "helper/hitrace_helper.h"
24 #include "helper/path_helper.h"
25 #if defined(OHOS_PLATFORM)
26 #include "parameters.h"
27 #endif
28 #ifdef ENABLE_QOS
29 #include "qos.h"
30 #endif
31 #include "native_engine.h"
32 
33 namespace Commonlibrary::Concurrent::WorkerModule {
34 using namespace OHOS::JsSysModule;
35 static constexpr int8_t NUM_WORKER_ARGS = 2;
36 static constexpr uint8_t NUM_GLOBAL_CALL_ARGS = 3;
37 static std::list<Worker *> g_workers;
38 static std::mutex g_workersMutex;
39 static std::list<Worker *> g_limitedworkers;
40 static std::mutex g_limitedworkersMutex;
41 static constexpr uint32_t WORKER_TYPE = 1;
42 static constexpr uint8_t BEGIN_INDEX_OF_ARGUMENTS = 2;
43 static constexpr uint32_t DEFAULT_TIMEOUT = 5000;
44 static constexpr uint32_t GLOBAL_CALL_ID_MAX = 4294967295;
45 static constexpr size_t GLOBAL_CALL_MAX_COUNT = 65535;
46 static constexpr uint32_t THREAD_NAME_MAX_LENGTH = 15;
47 
48 #ifdef ENABLE_QOS
49 static const std::unordered_map<WorkerPriority, OHOS::QOS::QosLevel> WORKERPRIORITY_QOSLEVEL_MAP = {
50     {WorkerPriority::HIGH, OHOS::QOS::QosLevel::QOS_USER_INITIATED},
51     {WorkerPriority::MEDIUM, OHOS::QOS::QosLevel::QOS_DEFAULT},
52     {WorkerPriority::LOW, OHOS::QOS::QosLevel::QOS_UTILITY},
53     {WorkerPriority::IDLE, OHOS::QOS::QosLevel::QOS_BACKGROUND},
54 };
55 #endif
56 
57 #if defined(ENABLE_WORKER_EVENTHANDLER)
GetMainThreadHandler()58 std::shared_ptr<OHOS::AppExecFwk::EventHandler> Worker::GetMainThreadHandler()
59 {
60     static std::shared_ptr<OHOS::AppExecFwk::EventHandler> mainThreadHandler;
61     static std::mutex mainThreadHandlerMutex;
62     if (mainThreadHandler == nullptr) {
63         std::lock_guard<std::mutex> lock(mainThreadHandlerMutex);
64         if (mainThreadHandler == nullptr) {
65             mainThreadHandler = std::make_shared<OHOS::AppExecFwk::EventHandler>(
66                 OHOS::AppExecFwk::EventRunner::GetMainEventRunner());
67         }
68     }
69     return mainThreadHandler;
70 }
71 #endif
72 
Worker(napi_env env,napi_ref thisVar)73 Worker::Worker(napi_env env, napi_ref thisVar)
74     : hostEnv_(env), workerRef_(thisVar)
75 {
76     workerWrapper_ = std::make_shared<WorkerWrapper>(this);
77 }
78 
InitWorker(napi_env env,napi_value exports)79 napi_value Worker::InitWorker(napi_env env, napi_value exports)
80 {
81     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
82     napi_property_descriptor properties[] = {
83         DECLARE_NAPI_FUNCTION("postMessage", PostMessage),
84         DECLARE_NAPI_FUNCTION("postMessageWithSharedSendable", PostMessageWithSharedSendable),
85         DECLARE_NAPI_FUNCTION("terminate", Terminate),
86         DECLARE_NAPI_FUNCTION("on", On),
87         DECLARE_NAPI_FUNCTION("registerGlobalCallObject", RegisterGlobalCallObject),
88         DECLARE_NAPI_FUNCTION("unregisterGlobalCallObject", UnregisterGlobalCallObject),
89         DECLARE_NAPI_FUNCTION("once", Once),
90         DECLARE_NAPI_FUNCTION("off", Off),
91         DECLARE_NAPI_FUNCTION("addEventListener", AddEventListener),
92         DECLARE_NAPI_FUNCTION("dispatchEvent", DispatchEvent),
93         DECLARE_NAPI_FUNCTION("removeEventListener", RemoveEventListener),
94         DECLARE_NAPI_FUNCTION("removeAllListener", RemoveAllListener),
95         DECLARE_NAPI_FUNCTION("cancelTasks", CancelTask),
96     };
97     // for worker.ThreadWorker
98     const char threadWorkerName[] = "ThreadWorker";
99     napi_value threadWorkerClazz = nullptr;
100     napi_define_class(env, threadWorkerName, sizeof(threadWorkerName), Worker::ThreadWorkerConstructor, nullptr,
101         sizeof(properties) / sizeof(properties[0]), properties, &threadWorkerClazz);
102     napi_set_named_property(env, exports, "ThreadWorker", threadWorkerClazz);
103 
104     // for worker.Worker
105     const char workerName[] = "Worker";
106     napi_value workerClazz = nullptr;
107     napi_define_class(env, workerName, sizeof(workerName), Worker::WorkerConstructor, nullptr,
108         sizeof(properties) / sizeof(properties[0]), properties, &workerClazz);
109     napi_set_named_property(env, exports, "Worker", workerClazz);
110 
111     // for worker.LimitedWorker
112     const char limitedWorkerName[] = "RestrictedWorker";
113     napi_value limitedWorkerClazz = nullptr;
114     napi_define_class(env, limitedWorkerName, sizeof(limitedWorkerName), Worker::LimitedWorkerConstructor, nullptr,
115         sizeof(properties) / sizeof(properties[0]), properties, &limitedWorkerClazz);
116     napi_set_named_property(env, exports, "RestrictedWorker", limitedWorkerClazz);
117 
118     InitPriorityObject(env, exports);
119 
120     return InitPort(env, exports);
121 }
122 
InitPriorityObject(napi_env env,napi_value exports)123 void Worker::InitPriorityObject(napi_env env, napi_value exports)
124 {
125     napi_value priorityObj = NapiHelper::CreateObject(env);
126 
127     napi_value highPriority = NapiHelper::CreateUint32(env, static_cast<uint32_t>(WorkerPriority::HIGH));
128     napi_value mediumPriority = NapiHelper::CreateUint32(env, static_cast<uint32_t>(WorkerPriority::MEDIUM));
129     napi_value lowPriority = NapiHelper::CreateUint32(env, static_cast<uint32_t>(WorkerPriority::LOW));
130     napi_value idlePriority = NapiHelper::CreateUint32(env, static_cast<uint32_t>(WorkerPriority::IDLE));
131     napi_property_descriptor exportPriority[] = {
132         DECLARE_NAPI_PROPERTY("HIGH", highPriority),
133         DECLARE_NAPI_PROPERTY("MEDIUM", mediumPriority),
134         DECLARE_NAPI_PROPERTY("LOW", lowPriority),
135         DECLARE_NAPI_PROPERTY("IDLE", idlePriority),
136     };
137     napi_define_properties(env, priorityObj, sizeof(exportPriority) / sizeof(exportPriority[0]), exportPriority);
138 
139     napi_property_descriptor exportObjs[] = {
140         DECLARE_NAPI_PROPERTY("ThreadWorkerPriority", priorityObj),
141     };
142     napi_define_properties(env, exports, sizeof(exportObjs) / sizeof(exportObjs[0]), exportObjs);
143 }
144 
InitPort(napi_env env,napi_value exports)145 napi_value Worker::InitPort(napi_env env, napi_value exports)
146 {
147     NativeEngine* engine = reinterpret_cast<NativeEngine*>(env);
148     Worker* worker = nullptr;
149     if (engine->IsRestrictedWorkerThread()) {
150         std::lock_guard<std::mutex> lock(g_limitedworkersMutex);
151         for (auto item = g_limitedworkers.begin(); item != g_limitedworkers.end(); item++) {
152             if ((*item)->IsSameWorkerEnv(env)) {
153                 worker = *item;
154             }
155         }
156     } else if (engine->IsWorkerThread()) {
157         std::lock_guard<std::mutex> lock(g_workersMutex);
158         for (auto item = g_workers.begin(); item != g_workers.end(); item++) {
159             if ((*item)->IsSameWorkerEnv(env)) {
160                 worker = *item;
161             }
162         }
163     } else {
164         return exports;
165     }
166 
167     if (worker == nullptr) {
168         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "worker is null when InitWorker");
169         return exports;
170     }
171 
172     napi_property_descriptor properties[] = {
173         DECLARE_NAPI_FUNCTION_WITH_DATA("postMessage", PostMessageToHost, worker),
174         DECLARE_NAPI_FUNCTION_WITH_DATA("postMessageWithSharedSendable", PostMessageWithSharedSendableToHost, worker),
175         DECLARE_NAPI_FUNCTION_WITH_DATA("callGlobalCallObjectMethod", GlobalCall, worker),
176         DECLARE_NAPI_FUNCTION_WITH_DATA("close", CloseWorker, worker),
177         DECLARE_NAPI_FUNCTION_WITH_DATA("cancelTasks", ParentPortCancelTask, worker),
178         DECLARE_NAPI_FUNCTION_WITH_DATA("addEventListener", ParentPortAddEventListener, worker),
179         DECLARE_NAPI_FUNCTION_WITH_DATA("dispatchEvent", ParentPortDispatchEvent, worker),
180         DECLARE_NAPI_FUNCTION_WITH_DATA("removeEventListener", ParentPortRemoveEventListener, worker),
181         DECLARE_NAPI_FUNCTION_WITH_DATA("removeAllListener", ParentPortRemoveAllListener, worker),
182     };
183     napi_value workerPortObj = nullptr;
184     napi_create_object(env, &workerPortObj);
185     napi_define_properties(env, workerPortObj, sizeof(properties) / sizeof(properties[0]), properties);
186 
187     // 5. register worker name in DedicatedWorkerGlobalScope
188     std::string name = worker->GetName();
189     if (!name.empty()) {
190         napi_value nameValue = nullptr;
191         napi_create_string_utf8(env, name.c_str(), name.length(), &nameValue);
192         napi_set_named_property(env, workerPortObj, "name", nameValue);
193     }
194 
195     napi_set_named_property(env, workerPortObj, "self", workerPortObj);
196 
197     if (worker->isNewVersion_) {
198         napi_set_named_property(env, exports, "workerPort", workerPortObj);
199     } else {
200         napi_set_named_property(env, exports, "parentPort", workerPortObj);
201     }
202     // register worker Port.
203     napi_create_reference(env, workerPortObj, 1, &worker->workerPort_);
204 #if defined(ENABLE_WORKER_EVENTHANDLER)
205     GetMainThreadHandler();
206 #endif
207     return exports;
208 }
209 
LimitedWorkerConstructor(napi_env env,napi_callback_info cbinfo)210 napi_value Worker::LimitedWorkerConstructor(napi_env env, napi_callback_info cbinfo)
211 {
212     if (CanCreateWorker(env, WorkerVersion::NEW)) {
213         return Constructor(env, cbinfo, true);
214     }
215     HILOG_ERROR("worker:: using both Worker and LimitedWorker is not supported");
216     ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_INITIALIZATION,
217         "Using both Worker and LimitedWorker is not supported.");
218     return nullptr;
219 }
220 
ThreadWorkerConstructor(napi_env env,napi_callback_info cbinfo)221 napi_value Worker::ThreadWorkerConstructor(napi_env env, napi_callback_info cbinfo)
222 {
223     HITRACE_HELPER_METER_NAME("ThreadWorkerConstructor: [Add Thread]");
224     if (CanCreateWorker(env, WorkerVersion::NEW)) {
225         return Constructor(env, cbinfo, false, WorkerVersion::NEW);
226     }
227     HILOG_ERROR("worker:: ThreadWorker construct failed");
228     ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_INITIALIZATION,
229         "Using both Worker and ThreadWorker is not supported.");
230     return nullptr;
231 }
232 
WorkerConstructor(napi_env env,napi_callback_info cbinfo)233 napi_value Worker::WorkerConstructor(napi_env env, napi_callback_info cbinfo)
234 {
235     HITRACE_HELPER_METER_NAME("WorkerConstructor: [Add Thread]");
236     if (CanCreateWorker(env, WorkerVersion::OLD)) {
237         return Constructor(env, cbinfo, false, WorkerVersion::OLD);
238     }
239     HILOG_ERROR("worker:: using both Worker and other Workers is not supported");
240     ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_INITIALIZATION,
241         "Using both Worker and other Workers is not supported.");
242     return nullptr;
243 }
244 
Constructor(napi_env env,napi_callback_info cbinfo,bool limitSign,WorkerVersion version)245 napi_value Worker::Constructor(napi_env env, napi_callback_info cbinfo, bool limitSign, WorkerVersion version)
246 {
247     napi_value thisVar = nullptr;
248     void* data = nullptr;
249     size_t argc = 2;  // 2: max args number is 2
250     napi_value args[argc];
251     napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, &data);
252     // check argv count
253     if (argc < 1) {
254         HILOG_ERROR("worker:: the number of create worker param must be more than 1 with new");
255         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the number of parameters must be more than 1.");
256         return nullptr;
257     }
258     // check 1st param is string
259     if (!NapiHelper::IsString(env, args[0])) {
260         HILOG_ERROR("worker:: the type of Worker 1st param must be string");
261         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of the first param must be string.");
262         return nullptr;
263     }
264     WorkerParams* workerParams = nullptr;
265     if (argc == 2) {  // 2: max args number is 2
266         workerParams = CheckWorkerArgs(env, args[1], version);
267         if (workerParams == nullptr) {
268             HILOG_ERROR("Worker:: arguments check failed.");
269             return nullptr;
270         }
271     }
272 
273     Worker* worker = nullptr;
274     if (limitSign) {
275         bool success = WorkerManager::IncrementWorkerCount(WorkerType::LIMITED_WORKER);
276         if (!success) {
277             HILOG_ERROR("worker:: IncrementWorkerCount failed");
278             ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_INITIALIZATION,
279                 "the number of limiteworkers exceeds the maximum.");
280             CloseHelp::DeletePointer(workerParams, false);
281             return nullptr;
282         }
283 
284         std::lock_guard<std::mutex> lock(g_limitedworkersMutex);
285         // 2. new worker instance
286         worker = new Worker(env, nullptr);
287         if (worker == nullptr) {
288             HILOG_ERROR("worker:: create worker error");
289             WorkerManager::DecrementWorkerCount(WorkerType::LIMITED_WORKER);
290             ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_INITIALIZATION, "create worker error");
291             CloseHelp::DeletePointer(workerParams, false);
292             return nullptr;
293         }
294         worker->workerType_ = WorkerType::LIMITED_WORKER;
295         g_limitedworkers.push_back(worker);
296         HILOG_INFO("worker:: limited workers num %{public}zu", g_limitedworkers.size());
297     } else {
298         WorkerType workerType = (version == WorkerVersion::NEW) ? THREAD_WORKER : OLD_WORKER;
299         bool success = WorkerManager::IncrementWorkerCount(workerType);
300         if (!success) {
301             HILOG_ERROR("worker:: IncrementWorkerCount failed");
302             ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_INITIALIZATION,
303                 "the number of workers exceeds the maximum.");
304             CloseHelp::DeletePointer(workerParams, false);
305             return nullptr;
306         }
307 
308         std::lock_guard<std::mutex> lock(g_workersMutex);
309         // 2. new worker instance
310         worker = new Worker(env, nullptr);
311         if (worker == nullptr) {
312             HILOG_ERROR("worker:: create worker error");
313             WorkerManager::DecrementWorkerCount(workerType);
314             ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_INITIALIZATION, "create worker error");
315             CloseHelp::DeletePointer(workerParams, false);
316             return nullptr;
317         }
318         worker->workerType_ = workerType;
319         g_workers.push_back(worker);
320         HILOG_INFO("worker:: workers num %{public}zu", g_workers.size());
321     }
322 
323     if (workerParams != nullptr) {
324         if (!workerParams->name_.empty()) {
325             worker->name_ = workerParams->name_;
326         }
327         // default classic
328         worker->SetScriptMode(workerParams->type_);
329         worker->workerPriority_ = workerParams->workerPriority_;
330 
331         CloseHelp::DeletePointer(workerParams, false);
332         workerParams = nullptr;
333     }
334     worker->isLimitedWorker_ = limitSign;
335     worker->isNewVersion_ = (version != WorkerVersion::OLD) ? true : false;
336 
337     // 3. execute in thread
338     char* script = NapiHelper::GetChars(env, args[0]);
339     if (script == nullptr) {
340         WorkerManager::DecrementWorkerCount(worker->workerType_);
341         HILOG_ERROR("worker:: the file path is invaild, maybe path is null");
342         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_INVALID_FILEPATH,
343             "the file path is invaild, maybe path is null.");
344         return nullptr;
345     }
346     if (limitSign) {
347         napi_add_env_cleanup_hook(env, LimitedWorkerHostEnvCleanCallback, worker);
348     } else {
349         napi_add_env_cleanup_hook(env, WorkerHostEnvCleanCallback, worker);
350     }
351     napi_status status = napi_wrap(env, thisVar, worker, WorkerDestructor, nullptr, &worker->workerRef_);
352     if (status != napi_ok) {
353         WorkerManager::DecrementWorkerCount(worker->workerType_);
354         HILOG_ERROR("worker::Constructor napi_wrap return value is %{public}d", status);
355         WorkerDestructor(env, worker, nullptr);
356         CloseHelp::DeletePointer(script, true);
357         return nullptr;
358     }
359     worker->StartExecuteInThread(env, script);
360     return thisVar;
361 }
362 
WorkerDestructor(napi_env env,void * data,void * hint)363 void Worker::WorkerDestructor(napi_env env, void *data, void *hint)
364 {
365     Worker* worker = static_cast<Worker*>(data);
366     if (worker == nullptr) {
367         HILOG_WARN("worker:: worker is null.");
368         return;
369     }
370     if (worker->isLimitedWorker_) {
371         napi_remove_env_cleanup_hook(env, LimitedWorkerHostEnvCleanCallback, worker);
372     } else {
373         napi_remove_env_cleanup_hook(env, WorkerHostEnvCleanCallback, worker);
374     }
375     std::lock_guard<std::recursive_mutex> lock(worker->liveStatusLock_);
376     if (worker->isHostEnvExited_) {
377         HILOG_INFO("worker:: host env exit.");
378         return;
379     }
380     if (worker->UpdateHostState(INACTIVE)) {
381 #if defined(ENABLE_WORKER_EVENTHANDLER)
382         if (!worker->isMainThreadWorker_ || worker->isLimitedWorker_) {
383             worker->CloseHostHandle();
384         }
385 #else
386         worker->CloseHostHandle();
387 #endif
388         worker->ReleaseHostThreadContent();
389     }
390     if (!worker->IsRunning()) {
391         HILOG_DEBUG("worker:: worker is not running");
392         return;
393     }
394     worker->TerminateInner();
395 }
396 
WorkerHostEnvCleanCallback(void * data)397 void Worker::WorkerHostEnvCleanCallback(void* data)
398 {
399     Worker* worker = static_cast<Worker*>(data);
400     if (worker == nullptr) {
401         HILOG_INFO("worker:: worker is nullptr when host env exit.");
402         return;
403     }
404     if (!IsValidWorker(worker)) {
405         HILOG_INFO("worker:: worker is terminated when host env exit.");
406         return;
407     }
408     HostEnvCleanCallbackInner(worker);
409 }
410 
LimitedWorkerHostEnvCleanCallback(void * data)411 void Worker::LimitedWorkerHostEnvCleanCallback(void* data)
412 {
413     Worker* limitedWorker = static_cast<Worker*>(data);
414     if (limitedWorker == nullptr) {
415         HILOG_INFO("worker:: limitedWorker is nullptr when host env exit.");
416         return;
417     }
418     if (!IsValidLimitedWorker(limitedWorker)) {
419         HILOG_INFO("worker:: limitedWorker is terminated when host env exit.");
420         return;
421     }
422     HostEnvCleanCallbackInner(limitedWorker);
423 }
424 
HostEnvCleanCallbackInner(Worker * worker)425 void Worker::HostEnvCleanCallbackInner(Worker* worker)
426 {
427     std::lock_guard<std::recursive_mutex> lock(worker->liveStatusLock_);
428     worker->isHostEnvExited_ = true;
429 #if defined(ENABLE_WORKER_EVENTHANDLER)
430     if (!worker->isMainThreadWorker_ || worker->isLimitedWorker_) {
431         worker->CloseHostHandle();
432     }
433 #else
434     worker->CloseHostHandle();
435 #endif
436     worker->ReleaseHostThreadContent();
437     worker->RemoveAllListenerInner();
438     worker->ClearGlobalCallObject();
439 }
440 
CheckWorkerArgs(napi_env env,napi_value argsValue,WorkerVersion version)441 Worker::WorkerParams* Worker::CheckWorkerArgs(napi_env env, napi_value argsValue, WorkerVersion version)
442 {
443     WorkerParams* workerParams = nullptr;
444     if (NapiHelper::IsObject(env, argsValue)) {
445         workerParams = new WorkerParams();
446         bool hasPriorityValue = NapiHelper::HasNameProperty(env, argsValue, "priority");
447         if (version != WorkerVersion::OLD && hasPriorityValue) {
448             workerParams->workerPriority_ = Worker::GetPriorityArg(env, argsValue);
449             if (workerParams->workerPriority_ == WorkerPriority::INVALID) {
450                 CloseHelp::DeletePointer(workerParams, false);
451                 WorkerThrowError(env, ErrorHelper::TYPE_ERROR, "the priority value is invalid");
452                 return nullptr;
453             }
454         }
455         napi_value nameValue = NapiHelper::GetNameProperty(env, argsValue, "name");
456         if (NapiHelper::IsNotUndefined(env, nameValue)) {
457             if (!NapiHelper::IsString(env, nameValue)) {
458                 CloseHelp::DeletePointer(workerParams, false);
459                 WorkerThrowError(env, ErrorHelper::TYPE_ERROR, "the type of name must be string.");
460                 return nullptr;
461             }
462             char* nameStr = NapiHelper::GetChars(env, nameValue);
463             if (nameStr == nullptr) {
464                 CloseHelp::DeletePointer(workerParams, false);
465                 ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_INITIALIZATION, "the name of worker is null.");
466                 return nullptr;
467             }
468             workerParams->name_ = std::string(nameStr);
469             CloseHelp::DeletePointer(nameStr, true);
470         }
471         napi_value typeValue = NapiHelper::GetNameProperty(env, argsValue, "type");
472         if (NapiHelper::IsNotUndefined(env, typeValue)) {
473             if (!NapiHelper::IsString(env, typeValue)) {
474                 CloseHelp::DeletePointer(workerParams, false);
475                 WorkerThrowError(env, ErrorHelper::TYPE_ERROR, "the type of type's value must be string.");
476                 return nullptr;
477             }
478             char* typeStr = NapiHelper::GetChars(env, typeValue);
479             if (typeStr == nullptr) {
480                 CloseHelp::DeletePointer(workerParams, false);
481                 ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_INITIALIZATION, "the type of worker is null.");
482                 return nullptr;
483             }
484             if (strcmp("classic", typeStr) == 0) {
485                 workerParams->type_ = CLASSIC;
486                 CloseHelp::DeletePointer(typeStr, true);
487             } else {
488                 CloseHelp::DeletePointer(workerParams, false);
489                 CloseHelp::DeletePointer(typeStr, true);
490                 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
491                     "the type must be classic, unsupport others now.");
492                 return nullptr;
493             }
494         }
495     }
496     return workerParams;
497 }
498 
GetPriorityArg(napi_env env,napi_value argsValue)499 WorkerPriority Worker::GetPriorityArg(napi_env env, napi_value argsValue)
500 {
501     napi_value priorityValue = NapiHelper::GetNameProperty(env, argsValue, "priority");
502     if (!NapiHelper::IsNumber(env, priorityValue)) {
503         HILOG_ERROR("worker:: GetPriorityArg error, not number");
504         return WorkerPriority::INVALID;
505     }
506 
507     int32_t priority = static_cast<int32_t>(WorkerPriority::INVALID);
508     napi_get_value_int32(env, priorityValue, static_cast<int32_t*>(&priority));
509     if (priority < static_cast<int32_t>(WorkerPriority::HIGH) ||
510         priority > static_cast<int32_t>(WorkerPriority::IDLE)) {
511         HILOG_ERROR("worker:: GetPriorityArg error, value not in scope");
512         return WorkerPriority::INVALID;
513     }
514     return static_cast<WorkerPriority>(priority);
515 }
516 
PostMessage(napi_env env,napi_callback_info cbinfo)517 napi_value Worker::PostMessage(napi_env env, napi_callback_info cbinfo)
518 {
519     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
520     return CommonPostMessage(env, cbinfo, true);
521 }
522 
PostMessageWithSharedSendable(napi_env env,napi_callback_info cbinfo)523 napi_value Worker::PostMessageWithSharedSendable(napi_env env, napi_callback_info cbinfo)
524 {
525     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
526     return CommonPostMessage(env, cbinfo, false);
527 }
528 
CommonPostMessage(napi_env env,napi_callback_info cbinfo,bool cloneSendable)529 napi_value Worker::CommonPostMessage(napi_env env, napi_callback_info cbinfo, bool cloneSendable)
530 {
531     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
532     size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
533     if (argc < 1) {
534         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "Worker messageObject must be not null with postMessage");
535         return nullptr;
536     }
537     napi_value* argv = new napi_value[argc];
538     ObjectScope<napi_value> scope(argv, true);
539     napi_value thisVar = nullptr;
540     napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, nullptr);
541     Worker* worker = nullptr;
542     napi_unwrap(env, thisVar, reinterpret_cast<void**>(&worker));
543 
544     if (worker == nullptr || worker->IsTerminated() || worker->IsTerminating()) {
545         HILOG_ERROR("worker:: worker is nullptr when PostMessage, maybe worker is terminated");
546         WorkerThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "maybe worker is terminated when PostMessage");
547         return nullptr;
548     }
549 
550     MessageDataType data = nullptr;
551     napi_status serializeStatus = napi_ok;
552     bool defaultClone = cloneSendable ? true : false;
553     napi_value undefined = NapiHelper::GetUndefinedValue(env);
554     if (argc >= NUM_WORKER_ARGS) {
555         if (!NapiHelper::IsArray(env, argv[1])) {
556             ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of the transfer list must be an array.");
557             return nullptr;
558         }
559         serializeStatus = napi_serialize_inner(env, argv[0], argv[1], undefined, false, defaultClone, &data);
560     } else {
561         serializeStatus = napi_serialize_inner(env, argv[0], undefined, undefined, false, defaultClone, &data);
562     }
563     if (serializeStatus != napi_ok || data == nullptr) {
564         worker->HostOnMessageErrorInner();
565         WorkerThrowError(env, ErrorHelper::ERR_WORKER_SERIALIZATION, "failed to serialize message.");
566         return nullptr;
567     }
568     worker->PostMessageInner(data);
569     return NapiHelper::GetUndefinedValue(env);
570 }
571 
Terminate(napi_env env,napi_callback_info cbinfo)572 napi_value Worker::Terminate(napi_env env, napi_callback_info cbinfo)
573 {
574     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
575     napi_value thisVar = nullptr;
576     napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr);
577     Worker* worker = nullptr;
578     napi_unwrap(env, thisVar, reinterpret_cast<void**>(&worker));
579     if (worker == nullptr) {
580         HILOG_ERROR("worker:: worker is nullptr when Terminate, maybe worker is terminated");
581         WorkerThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "worker is nullptr when Terminate");
582         return nullptr;
583     }
584     bool expected = false;
585     if (worker->isTerminated_.compare_exchange_weak(expected, true)) {
586         HILOG_DEBUG("worker:: Terminate worker");
587     } else {
588         HILOG_DEBUG("worker:: worker is terminated when Terminate");
589         return nullptr;
590     }
591     if (worker->IsTerminated() || worker->IsTerminating()) {
592         HILOG_DEBUG("worker:: worker is not in running when Terminate");
593         return nullptr;
594     }
595     worker->TerminateInner();
596     return NapiHelper::GetUndefinedValue(env);
597 }
598 
On(napi_env env,napi_callback_info cbinfo)599 napi_value Worker::On(napi_env env, napi_callback_info cbinfo)
600 {
601     return AddListener(env, cbinfo, PERMANENT);
602 }
603 
Once(napi_env env,napi_callback_info cbinfo)604 napi_value Worker::Once(napi_env env, napi_callback_info cbinfo)
605 {
606     return AddListener(env, cbinfo, ONCE);
607 }
608 
RegisterGlobalCallObject(napi_env env,napi_callback_info cbinfo)609 napi_value Worker::RegisterGlobalCallObject(napi_env env, napi_callback_info cbinfo)
610 {
611     size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
612     if (argc != NUM_WORKER_ARGS) {
613         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the number of parameters must be 2.");
614         return nullptr;
615     }
616     // check 1st param is string
617     napi_value thisVar = nullptr;
618     void* data = nullptr;
619     napi_value* args = new napi_value[argc];
620     ObjectScope<napi_value> scope(args, true);
621     napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, &data);
622     if (!NapiHelper::IsString(env, args[0])) {
623         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of instanceName must be string.");
624         return nullptr;
625     }
626     std::string instanceName = NapiHelper::GetString(env, args[0]);
627 
628     Worker* worker = nullptr;
629     napi_unwrap(env, thisVar, (void**)&worker);
630     if (worker == nullptr) {
631         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "maybe worker is terminated");
632         return nullptr;
633     }
634     napi_ref obj = NapiHelper::CreateReference(env, args[1], 1);
635     worker->AddGlobalCallObject(instanceName, obj);
636     return nullptr;
637 }
638 
UnregisterGlobalCallObject(napi_env env,napi_callback_info cbinfo)639 napi_value Worker::UnregisterGlobalCallObject(napi_env env, napi_callback_info cbinfo)
640 {
641     size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
642     if (argc > 1) {
643         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the number of the parameters must be 1 or 0.");
644         return nullptr;
645     }
646     napi_value thisVar = nullptr;
647     void* data = nullptr;
648     napi_value* args = new napi_value[argc];
649     ObjectScope<napi_value> scope(args, true);
650     napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, &data);
651     Worker* worker = nullptr;
652     napi_unwrap(env, thisVar, (void**)&worker);
653     if (worker == nullptr) {
654         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "maybe worker is terminated");
655         return nullptr;
656     }
657     if (argc == 0) {
658         worker->ClearGlobalCallObject();
659         HILOG_DEBUG("worker:: clear all registered globalCallObject");
660         return nullptr;
661     }
662     // check 1st param is string
663     if (!NapiHelper::IsString(env, args[0])) {
664         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of instanceName must be string.");
665         return nullptr;
666     }
667     std::string instanceName = NapiHelper::GetString(env, args[0]);
668     if (!worker->RemoveGlobalCallObject(instanceName)) {
669         HILOG_ERROR("worker:: unregister unexist globalCallObject");
670     }
671     return nullptr;
672 }
673 
Off(napi_env env,napi_callback_info cbinfo)674 napi_value Worker::Off(napi_env env, napi_callback_info cbinfo)
675 {
676     return RemoveListener(env, cbinfo);
677 }
678 
RemoveEventListener(napi_env env,napi_callback_info cbinfo)679 napi_value Worker::RemoveEventListener(napi_env env, napi_callback_info cbinfo)
680 {
681     return RemoveListener(env, cbinfo);
682 }
683 
AddEventListener(napi_env env,napi_callback_info cbinfo)684 napi_value Worker::AddEventListener(napi_env env, napi_callback_info cbinfo)
685 {
686     return AddListener(env, cbinfo, PERMANENT);
687 }
688 
AddListener(napi_env env,napi_callback_info cbinfo,ListenerMode mode)689 napi_value Worker::AddListener(napi_env env, napi_callback_info cbinfo, ListenerMode mode)
690 {
691     size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
692     if (argc < NUM_WORKER_ARGS) {
693         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the number of listener parameters is not less than 2.");
694         return nullptr;
695     }
696     // check 1st param is string
697     napi_value thisVar = nullptr;
698     void* data = nullptr;
699     napi_value* args = new napi_value[argc];
700     ObjectScope<napi_value> scope(args, true);
701     napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, &data);
702     if (!NapiHelper::IsString(env, args[0])) {
703         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of listener first param must be string.");
704         return nullptr;
705     }
706     if (!NapiHelper::IsCallable(env, args[1])) {
707         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
708             "the type of listener the second param must be callable.");
709         return nullptr;
710     }
711     Worker* worker = nullptr;
712     napi_unwrap(env, thisVar, (void**)&worker);
713     if (worker == nullptr) {
714         HILOG_ERROR("worker:: worker is nullptr when addListener, maybe worker is terminated");
715         WorkerThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "maybe worker is terminated");
716         return nullptr;
717     }
718 
719     napi_ref callback = NapiHelper::CreateReference(env, args[1], 1);
720     auto listener = new WorkerListener(env, callback, mode);
721     if (mode == ONCE && argc > NUM_WORKER_ARGS) {
722         if (NapiHelper::IsObject(env, args[NUM_WORKER_ARGS])) {
723             napi_value onceValue = NapiHelper::GetNameProperty(env, args[NUM_WORKER_ARGS], "once");
724             bool isOnce = NapiHelper::GetBooleanValue(env, onceValue);
725             if (!isOnce) {
726                 listener->SetMode(PERMANENT);
727             }
728         }
729     }
730     char* typeStr = NapiHelper::GetChars(env, args[0]);
731     worker->AddListenerInner(env, typeStr, listener);
732     CloseHelp::DeletePointer(typeStr, true);
733     return NapiHelper::GetUndefinedValue(env);
734 }
735 
RemoveListener(napi_env env,napi_callback_info cbinfo)736 napi_value Worker::RemoveListener(napi_env env, napi_callback_info cbinfo)
737 {
738     size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
739     if (argc < 1) {
740         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the number of parameters is not less than 1.");
741         return nullptr;
742     }
743     // check 1st param is string
744     napi_value thisVar = nullptr;
745     void* data = nullptr;
746     napi_value* args = new napi_value[argc];
747     ObjectScope<napi_value> scope(args, true);
748     napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, &data);
749     if (!NapiHelper::IsString(env, args[0])) {
750         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
751             "the type of removelistener the first param must be string.");
752         return nullptr;
753     }
754 
755     Worker* worker = nullptr;
756     napi_unwrap(env, thisVar, reinterpret_cast<void**>(&worker));
757     if (worker == nullptr) {
758         HILOG_ERROR("worker:: worker is nullptr when RemoveListener, maybe worker is terminated");
759         WorkerThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "maybe worker is terminated");
760         return nullptr;
761     }
762 
763     if (argc > 1 && !NapiHelper::IsCallable(env, args[1])) {
764         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
765             "the type of removelistener the second param must be callable.");
766         return nullptr;
767     }
768 
769     char* typeStr = NapiHelper::GetChars(env, args[0]);
770     if (typeStr == nullptr) {
771         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of remove listener type must be not null");
772         return nullptr;
773     }
774 
775     napi_ref callback = nullptr;
776     if (argc > 1 && NapiHelper::IsCallable(env, args[1])) {
777         napi_create_reference(env, args[1], 1, &callback);
778     }
779     worker->RemoveListenerInner(env, typeStr, callback);
780     CloseHelp::DeletePointer(typeStr, true);
781     NapiHelper::DeleteReference(env, callback);
782     return NapiHelper::GetUndefinedValue(env);
783 }
784 
CallWorkCallback(napi_env env,napi_value recv,size_t argc,const napi_value * argv,const char * type)785 void CallWorkCallback(napi_env env, napi_value recv, size_t argc, const napi_value* argv, const char* type)
786 {
787     napi_value callback = nullptr;
788     napi_get_named_property(env, recv, type, &callback);
789     if (NapiHelper::IsCallable(env, callback)) {
790         napi_value callbackResult = nullptr;
791         napi_call_function(env, recv, callback, argc, argv, &callbackResult);
792     }
793 }
794 
DispatchEvent(napi_env env,napi_callback_info cbinfo)795 napi_value Worker::DispatchEvent(napi_env env, napi_callback_info cbinfo)
796 {
797     size_t argc = 1;
798     napi_value args[1];
799     napi_value thisVar = nullptr;
800     void* data = nullptr;
801     napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, &data);
802     if (argc < 1) {
803         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the number of the parameters must be more than 1.");
804         return NapiHelper::CreateBooleanValue(env, false);
805     }
806 
807     // check 1st param is event
808     if (!NapiHelper::IsObject(env, args[0])) {
809         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
810             "the type of DispatchEvent first param must be event object.");
811         return NapiHelper::CreateBooleanValue(env, false);
812     }
813 
814     Worker* worker = nullptr;
815     napi_unwrap(env, thisVar, reinterpret_cast<void**>(&worker));
816     if (worker == nullptr) {
817         HILOG_ERROR("worker:: worker is nullptr when DispatchEvent, maybe worker is terminated");
818         WorkerThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "maybe worker has been terminated");
819         return NapiHelper::CreateBooleanValue(env, false);
820     }
821 
822     napi_value typeValue = NapiHelper::GetNameProperty(env, args[0], "type");
823     if (!NapiHelper::IsString(env, typeValue)) {
824         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of event type must be string.");
825         return NapiHelper::CreateBooleanValue(env, false);
826     }
827 
828     napi_value obj = NapiHelper::GetReferenceValue(env, worker->workerRef_);
829 
830     char* typeStr = NapiHelper::GetChars(env, typeValue);
831     if (typeStr == nullptr) {
832         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "dispatchEvent event type must be not null");
833         return NapiHelper::CreateBooleanValue(env, false);
834     }
835     if (strcmp(typeStr, "error") == 0) {
836         CallWorkCallback(env, obj, 1, args, "onerror");
837     } else if (strcmp(typeStr, "messageerror") == 0) {
838         CallWorkCallback(env, obj, 1, args, "onmessageerror");
839     } else if (strcmp(typeStr, "message") == 0) {
840         CallWorkCallback(env, obj, 1, args, "onmessage");
841     }
842 
843     worker->HandleEventListeners(env, obj, 1, args, typeStr);
844 
845     CloseHelp::DeletePointer(typeStr, true);
846     return NapiHelper::CreateBooleanValue(env, true);
847 }
848 
RemoveAllListener(napi_env env,napi_callback_info cbinfo)849 napi_value Worker::RemoveAllListener(napi_env env, napi_callback_info cbinfo)
850 {
851     napi_value thisVar = nullptr;
852     napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr);
853     Worker* worker = nullptr;
854     napi_unwrap(env, thisVar, reinterpret_cast<void**>(&worker));
855     if (worker == nullptr) {
856         HILOG_ERROR("worker:: worker is nullptr when RemoveAllListener, maybe worker is terminated");
857         WorkerThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "maybe worker is terminated");
858         return nullptr;
859     }
860 
861     worker->RemoveAllListenerInner();
862     return NapiHelper::GetUndefinedValue(env);
863 }
864 
CancelTask(napi_env env,napi_callback_info cbinfo)865 napi_value Worker::CancelTask(napi_env env, napi_callback_info cbinfo)
866 {
867     napi_value thisVar = nullptr;
868     napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr);
869     Worker* worker = nullptr;
870     napi_unwrap(env, thisVar, reinterpret_cast<void**>(&worker));
871     if (worker == nullptr) {
872         HILOG_ERROR("worker:: worker is nullptr when CancelTask, maybe worker is terminated");
873         return nullptr;
874     }
875 
876     if (worker->IsTerminated() || worker->IsTerminating()) {
877         HILOG_INFO("worker:: worker is not in running");
878         return nullptr;
879     }
880 
881     if (!worker->ClearWorkerTasks()) {
882         HILOG_ERROR("worker:: clear worker task error");
883     }
884     return NapiHelper::GetUndefinedValue(env);
885 }
886 
PostMessageToHost(napi_env env,napi_callback_info cbinfo)887 napi_value Worker::PostMessageToHost(napi_env env, napi_callback_info cbinfo)
888 {
889     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
890     return CommonPostMessageToHost(env, cbinfo, true);
891 }
892 
PostMessageWithSharedSendableToHost(napi_env env,napi_callback_info cbinfo)893 napi_value Worker::PostMessageWithSharedSendableToHost(napi_env env, napi_callback_info cbinfo)
894 {
895     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
896     return CommonPostMessageToHost(env, cbinfo, false);
897 }
898 
CommonPostMessageToHost(napi_env env,napi_callback_info cbinfo,bool cloneSendable)899 napi_value Worker::CommonPostMessageToHost(napi_env env, napi_callback_info cbinfo, bool cloneSendable)
900 {
901     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
902     size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
903     if (argc < 1) {
904         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the number of parameters must be more than 1.");
905         return nullptr;
906     }
907     napi_value* argv = new napi_value[argc];
908     ObjectScope<napi_value> scope(argv, true);
909     Worker* worker = nullptr;
910     napi_get_cb_info(env, cbinfo, &argc, argv, nullptr, reinterpret_cast<void**>(&worker));
911 
912     if (worker == nullptr) {
913         HILOG_ERROR("worker:: when post message to host occur worker is nullptr");
914         WorkerThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "worker is nullptr when post message to host");
915         return nullptr;
916     }
917 
918     if (!worker->IsRunning()) {
919         // if worker is not running, don't send any message to host thread
920         HILOG_DEBUG("worker:: when post message to host occur worker is not in running.");
921         return nullptr;
922     }
923 
924     MessageDataType data = nullptr;
925     napi_status serializeStatus = napi_ok;
926     bool defaultClone = cloneSendable ? true : false;
927     napi_value undefined = NapiHelper::GetUndefinedValue(env);
928     if (argc >= NUM_WORKER_ARGS) {
929         if (!NapiHelper::IsArray(env, argv[1])) {
930             ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "Transfer list must be an Array");
931             return nullptr;
932         }
933         serializeStatus = napi_serialize_inner(env, argv[0], argv[1], undefined, false, defaultClone, &data);
934     } else {
935         napi_value undefined = NapiHelper::GetUndefinedValue(env);
936         serializeStatus = napi_serialize_inner(env, argv[0], undefined, undefined, false, defaultClone, &data);
937     }
938 
939     if (serializeStatus != napi_ok || data == nullptr) {
940         worker->WorkerOnMessageErrorInner();
941         WorkerThrowError(env, ErrorHelper::ERR_WORKER_SERIALIZATION, "failed to serialize message.");
942         return nullptr;
943     }
944     worker->PostMessageToHostInner(data);
945     return NapiHelper::GetUndefinedValue(env);
946 }
947 
GlobalCall(napi_env env,napi_callback_info cbinfo)948 napi_value Worker::GlobalCall(napi_env env, napi_callback_info cbinfo)
949 {
950     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
951     size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
952     if (argc < NUM_GLOBAL_CALL_ARGS) {
953         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the number of parameters must be equal or more than 3.");
954         return nullptr;
955     }
956     napi_value* args = new napi_value[argc];
957     ObjectScope<napi_value> scope(args, true);
958     Worker* worker = nullptr;
959     napi_get_cb_info(env, cbinfo, &argc, args, nullptr, reinterpret_cast<void**>(&worker));
960     if (worker == nullptr) {
961         HILOG_ERROR("worker:: worker is null when callGlobalCallObjectMethod to host");
962         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING,
963             "worker is null when callGlobalCallObjectMethod to host");
964         return nullptr;
965     }
966 
967     if (!worker->IsRunning()) {
968         // if worker is not running, don't send any message to host thread
969         HILOG_DEBUG("worker:: when post message to host occur worker is not in running.");
970         return nullptr;
971     }
972 
973     if (!NapiHelper::IsString(env, args[0])) {
974         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of instanceName must be string.");
975         return nullptr;
976     }
977     if (!NapiHelper::IsString(env, args[1])) {
978         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of methodname must be string.");
979         return nullptr;
980     }
981     if (!NapiHelper::IsNumber(env, args[2])) { // 2: the index of argument "timeout"
982         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of timeout must be number.");
983         return nullptr;
984     }
985 
986     napi_status serializeStatus = napi_ok;
987     MessageDataType data = nullptr;
988     napi_value argsArray;
989     napi_create_array_with_length(env, argc - 1, &argsArray);
990     size_t index = 0;
991     uint32_t timeout = 0;
992     for (size_t i = 0; i < argc; i++) {
993         if (i == 2) { // 2: index of time limitation arg
994             timeout = NapiHelper::GetUint32Value(env, args[i]);
995             continue;
996         }
997         napi_set_element(env, argsArray, index, args[i]);
998         index++;
999     }
1000     if (timeout <= 0 || timeout > DEFAULT_TIMEOUT) {
1001         timeout = DEFAULT_TIMEOUT;
1002     }
1003 
1004     // defautly not transfer
1005     napi_value undefined = NapiHelper::GetUndefinedValue(env);
1006     // meaningless to copy sendable object when call globalObject
1007     bool defaultClone = true;
1008     bool defaultTransfer = false;
1009     serializeStatus = napi_serialize_inner(env, argsArray, undefined, undefined, defaultTransfer, defaultClone, &data);
1010     if (serializeStatus != napi_ok || data == nullptr) {
1011         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_SERIALIZATION, "failed to serialize message.");
1012         return nullptr;
1013     }
1014     worker->hostGlobalCallQueue_.Push(worker->globalCallId_, data);
1015 
1016     std::lock_guard<std::recursive_mutex> lock(worker->liveStatusLock_);
1017     if (env != nullptr && !worker->HostIsStop() && !worker->isHostEnvExited_) {
1018         worker->InitGlobalCallStatus(env);
1019 #if defined(ENABLE_WORKER_EVENTHANDLER)
1020         if (worker->isMainThreadWorker_ && !worker->isLimitedWorker_) {
1021             worker->PostWorkerGlobalCallTask();
1022         } else {
1023             uv_async_send(worker->hostOnGlobalCallSignal_);
1024         }
1025 #else
1026         uv_async_send(worker->hostOnGlobalCallSignal_);
1027 #endif
1028     } else {
1029         HILOG_ERROR("worker:: worker host engine is nullptr when callGloballCallObjectMethod.");
1030         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "worker is null");
1031         return nullptr;
1032     }
1033 
1034     {
1035         std::unique_lock lock(worker->globalCallMutex_);
1036         if (!worker->cv_.wait_for(lock, std::chrono::milliseconds(timeout), [worker]() {
1037             return !worker->workerGlobalCallQueue_.IsEmpty() || !worker->globalCallSuccess_;
1038         })) {
1039             worker->IncreaseGlobalCallId();
1040             HILOG_ERROR("worker:: callGlobalCallObjectMethod has exceeded the waiting time limitation, skip this turn");
1041             ErrorHelper::ThrowError(env, ErrorHelper::ERR_GLOBAL_CALL_TIMEOUT);
1042             return nullptr;
1043         }
1044     }
1045     worker->IncreaseGlobalCallId();
1046     if (!worker->globalCallSuccess_) {
1047         worker->HandleGlobalCallError(env);
1048         return nullptr;
1049     }
1050     if (!worker->workerGlobalCallQueue_.DeQueue(&data)) {
1051         HILOG_ERROR("worker:: message returned from host is empty when callGloballCallObjectMethod");
1052         return nullptr;
1053     }
1054     napi_value res = nullptr;
1055     serializeStatus = napi_deserialize(env, data, &res);
1056     napi_delete_serialization_data(env, data);
1057     if (serializeStatus != napi_ok || res == nullptr) {
1058         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_SERIALIZATION, "failed to serialize message.");
1059         return nullptr;
1060     }
1061     return res;
1062 }
1063 
InitGlobalCallStatus(napi_env env)1064 void Worker::InitGlobalCallStatus(napi_env env)
1065 {
1066     // worker side event data queue shall be empty before uv_async_send
1067     workerGlobalCallQueue_.Clear(env);
1068     ClearGlobalCallError(env);
1069     globalCallSuccess_ = true;
1070 }
1071 
IncreaseGlobalCallId()1072 void Worker::IncreaseGlobalCallId()
1073 {
1074     if (UNLIKELY(globalCallId_ == GLOBAL_CALL_ID_MAX)) {
1075         globalCallId_ = 1;
1076     } else {
1077         globalCallId_++;
1078     }
1079 }
1080 
CloseWorker(napi_env env,napi_callback_info cbinfo)1081 napi_value Worker::CloseWorker(napi_env env, napi_callback_info cbinfo)
1082 {
1083     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
1084     Worker* worker = nullptr;
1085     napi_get_cb_info(env, cbinfo, nullptr, nullptr, nullptr, (void**)&worker);
1086     if (worker != nullptr) {
1087         worker->CloseInner();
1088     } else {
1089         WorkerThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "worker is null");
1090         return nullptr;
1091     }
1092     return NapiHelper::GetUndefinedValue(env);
1093 }
1094 
ParentPortCancelTask(napi_env env,napi_callback_info cbinfo)1095 napi_value Worker::ParentPortCancelTask(napi_env env, napi_callback_info cbinfo)
1096 {
1097     Worker* worker = nullptr;
1098     napi_get_cb_info(env, cbinfo, nullptr, nullptr, nullptr, reinterpret_cast<void**>(&worker));
1099     if (worker == nullptr) {
1100         HILOG_ERROR("worker:: worker is nullptr when CancelTask, maybe worker is terminated");
1101         return nullptr;
1102     }
1103 
1104     if (worker->IsTerminated() || worker->IsTerminating()) {
1105         HILOG_INFO("worker:: worker is not in running");
1106         return nullptr;
1107     }
1108 
1109     if (!worker->ClearWorkerTasks()) {
1110         HILOG_ERROR("worker:: clear worker task error");
1111     }
1112     return NapiHelper::GetUndefinedValue(env);
1113 }
1114 
ParentPortAddEventListener(napi_env env,napi_callback_info cbinfo)1115 napi_value Worker::ParentPortAddEventListener(napi_env env, napi_callback_info cbinfo)
1116 {
1117     size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
1118     if (argc < NUM_WORKER_ARGS) {
1119         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
1120             "worker listener param count must be more than WORKPARAMNUM.");
1121         return nullptr;
1122     }
1123 
1124     napi_value* args = new napi_value[argc];
1125     ObjectScope<napi_value> scope(args, true);
1126     Worker* worker = nullptr;
1127     napi_get_cb_info(env, cbinfo, &argc, args, nullptr, reinterpret_cast<void**>(&worker));
1128 
1129     if (!NapiHelper::IsString(env, args[0])) {
1130         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
1131             "the type of worker listener first param must be string.");
1132         return nullptr;
1133     }
1134 
1135     if (!NapiHelper::IsCallable(env, args[1])) {
1136         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
1137             "the type of worker listener second param must be callable.");
1138         return nullptr;
1139     }
1140 
1141     if (worker == nullptr || !worker->IsNotTerminate()) {
1142         HILOG_ERROR("worker:: when post message to host occur worker is nullptr");
1143         WorkerThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "worker is not running.");
1144         return nullptr;
1145     }
1146 
1147     napi_ref callback = NapiHelper::CreateReference(env, args[1], 1);
1148     auto listener = new WorkerListener(env, callback, PERMANENT);
1149     if (argc > NUM_WORKER_ARGS && NapiHelper::IsObject(env, args[NUM_WORKER_ARGS])) {
1150         napi_value onceValue = NapiHelper::GetNameProperty(env, args[NUM_WORKER_ARGS], "once");
1151         bool isOnce = NapiHelper::GetBooleanValue(env, onceValue);
1152         if (isOnce) {
1153             listener->SetMode(ONCE);
1154         }
1155     }
1156     char* typeStr = NapiHelper::GetChars(env, args[0]);
1157     worker->ParentPortAddListenerInner(env, typeStr, listener);
1158     CloseHelp::DeletePointer(typeStr, true);
1159     return NapiHelper::GetUndefinedValue(env);
1160 }
1161 
ParentPortDispatchEvent(napi_env env,napi_callback_info cbinfo)1162 napi_value Worker::ParentPortDispatchEvent(napi_env env, napi_callback_info cbinfo)
1163 {
1164     size_t argc = 1;
1165     napi_value args[1];
1166     Worker* worker = nullptr;
1167     napi_get_cb_info(env, cbinfo, &argc, args, nullptr, reinterpret_cast<void**>(&worker));
1168     if (argc < 1) {
1169         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "DispatchEvent param count must be more than 1.");
1170         return NapiHelper::CreateBooleanValue(env, false);
1171     }
1172 
1173     if (!NapiHelper::IsObject(env, args[0])) {
1174         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
1175             "the type of worker DispatchEvent first param must be Event.");
1176         return NapiHelper::CreateBooleanValue(env, false);
1177     }
1178 
1179     napi_value typeValue = NapiHelper::GetNameProperty(env, args[0], "type");
1180     if (!NapiHelper::IsString(env, typeValue)) {
1181         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of worker event must be string.");
1182         return NapiHelper::CreateBooleanValue(env, false);
1183     }
1184 
1185     if (worker == nullptr || !worker->IsNotTerminate()) {
1186         HILOG_ERROR("worker:: when post message to host occur worker is nullptr");
1187         WorkerThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "worker is nullptr.");
1188         return NapiHelper::CreateBooleanValue(env, false);
1189     }
1190 
1191     char* typeStr = NapiHelper::GetChars(env, typeValue);
1192     if (typeStr == nullptr) {
1193         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "worker listener type must be not null.");
1194         return NapiHelper::CreateBooleanValue(env, false);
1195     }
1196 
1197     napi_value obj = NapiHelper::GetReferenceValue(env, worker->workerPort_);
1198 
1199     if (strcmp(typeStr, "error") == 0) {
1200         CallWorkCallback(env, obj, 1, args, "onerror");
1201     } else if (strcmp(typeStr, "messageerror") == 0) {
1202         CallWorkCallback(env, obj, 1, args, "onmessageerror");
1203     } else if (strcmp(typeStr, "message") == 0) {
1204         CallWorkCallback(env, obj, 1, args, "onmessage");
1205     }
1206 
1207     worker->ParentPortHandleEventListeners(env, obj, 1, args, typeStr, true);
1208 
1209     CloseHelp::DeletePointer(typeStr, true);
1210     return NapiHelper::CreateBooleanValue(env, true);
1211 }
1212 
ParentPortRemoveEventListener(napi_env env,napi_callback_info cbinfo)1213 napi_value Worker::ParentPortRemoveEventListener(napi_env env, napi_callback_info cbinfo)
1214 {
1215     size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
1216     if (argc < 1) {
1217         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the number of parameters must be more than 2.");
1218         return nullptr;
1219     }
1220 
1221     napi_value* args = new napi_value[argc];
1222     ObjectScope<napi_value> scope(args, true);
1223     Worker* worker = nullptr;
1224     napi_get_cb_info(env, cbinfo, &argc, args, nullptr, reinterpret_cast<void**>(&worker));
1225 
1226     if (!NapiHelper::IsString(env, args[0])) {
1227         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of worker listener 1st param must be string.");
1228         return nullptr;
1229     }
1230 
1231     if (argc > 1 && !NapiHelper::IsCallable(env, args[1])) {
1232         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
1233             "the type of worker listener second param must be callable.");
1234         return nullptr;
1235     }
1236 
1237     if (worker == nullptr || !worker->IsNotTerminate()) {
1238         HILOG_ERROR("worker:: when post message to host occur worker is nullptr");
1239         WorkerThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "worker is not running.");
1240         return nullptr;
1241     }
1242 
1243     napi_ref callback = nullptr;
1244     if (argc > 1 && NapiHelper::IsCallable(env, args[1])) {
1245         napi_create_reference(env, args[1], 1, &callback);
1246     }
1247 
1248     char* typeStr = NapiHelper::GetChars(env, args[0]);
1249     if (typeStr == nullptr) {
1250         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "worker listener type must be not null.");
1251         return nullptr;
1252     }
1253     worker->ParentPortRemoveListenerInner(env, typeStr, callback);
1254     CloseHelp::DeletePointer(typeStr, true);
1255     NapiHelper::DeleteReference(env, callback);
1256     return NapiHelper::GetUndefinedValue(env);
1257 }
1258 
ParentPortRemoveAllListener(napi_env env,napi_callback_info cbinfo)1259 napi_value Worker::ParentPortRemoveAllListener(napi_env env, napi_callback_info cbinfo)
1260 {
1261     Worker* worker = nullptr;
1262     napi_get_cb_info(env, cbinfo, nullptr, nullptr, nullptr, reinterpret_cast<void**>(&worker));
1263 
1264     if (worker == nullptr || !worker->IsNotTerminate()) {
1265         HILOG_ERROR("worker:: when post message to host occur worker is nullptr");
1266         WorkerThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING,
1267             "worker is nullptr when ParentPortRemoveAllListener");
1268         return nullptr;
1269     }
1270 
1271     worker->ParentPortRemoveAllListenerInner();
1272     return NapiHelper::GetUndefinedValue(env);
1273 }
1274 
GetContainerScopeId(napi_env env)1275 void Worker::GetContainerScopeId(napi_env env)
1276 {
1277     NativeEngine* hostEngine = reinterpret_cast<NativeEngine*>(env);
1278     scopeId_ = hostEngine->GetContainerScopeIdFunc();
1279 }
1280 
AddGlobalCallObject(const std::string & instanceName,napi_ref obj)1281 void Worker::AddGlobalCallObject(const std::string &instanceName, napi_ref obj)
1282 {
1283     globalCallObjects_.insert_or_assign(instanceName, obj);
1284 }
1285 
RemoveGlobalCallObject(const std::string & instanceName)1286 bool Worker::RemoveGlobalCallObject(const std::string &instanceName)
1287 {
1288     for (auto iter = globalCallObjects_.begin(); iter != globalCallObjects_.end(); iter++) {
1289         if (iter->first == instanceName) {
1290             NapiHelper::DeleteReference(hostEnv_, iter->second);
1291             globalCallObjects_.erase(iter);
1292             return true;
1293         }
1294     }
1295     return false;
1296 }
1297 
ClearGlobalCallObject()1298 void Worker::ClearGlobalCallObject()
1299 {
1300     for (auto iter = globalCallObjects_.begin(); iter != globalCallObjects_.end(); iter++) {
1301         napi_ref objRef = iter->second;
1302         NapiHelper::DeleteReference(hostEnv_, objRef);
1303     }
1304     globalCallObjects_.clear();
1305 }
1306 
StartExecuteInThread(napi_env env,const char * script)1307 void Worker::StartExecuteInThread(napi_env env, const char* script)
1308 {
1309     HILOG_INFO("worker:: Start execute in the thread!");
1310     // 1. init hostHandle in host loop
1311     uv_loop_t* loop = NapiHelper::GetLibUV(env);
1312     if (loop == nullptr) {
1313         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "engine loop is null");
1314         CloseHelp::DeletePointer(script, true);
1315         return;
1316     }
1317     GetContainerScopeId(env);
1318 #if defined(ENABLE_WORKER_EVENTHANDLER)
1319     if (!OHOS::AppExecFwk::EventRunner::IsAppMainThread()) {
1320         isMainThreadWorker_ = false;
1321         InitHostHandle(loop);
1322     } else if (isLimitedWorker_) {
1323         InitHostHandle(loop);
1324     }
1325 #else
1326     InitHostHandle(loop);
1327 #endif
1328 
1329     // 2. copy the script
1330     script_ = std::string(script);
1331     // isBundle : FA mode and BundlePack.
1332     bool isBundle = reinterpret_cast<NativeEngine*>(env)->GetIsBundle();
1333     // if worker file is packed in har, need find moduleName in hostVM, and concat new recordName.
1334     bool isHar = script_.find_first_of(PathHelper::NAME_SPACE_TAG) == 0;
1335     if ((isHar && script_.find(PathHelper::PREFIX_BUNDLE) == std::string::npos) ||
1336         (!isBundle && script_.find_first_of(PathHelper::POINT_TAG) == 0)) {
1337         PathHelper::ConcatFileNameForWorker(env, script_, fileName_, isRelativePath_);
1338         HILOG_INFO("worker:: Concated worker recordName: %{public}s, fileName: %{public}s",
1339                    script_.c_str(), fileName_.c_str());
1340     }
1341     // check the path is vaild.
1342     if (!isBundle) {
1343         if (!PathHelper::CheckWorkerPath(env, script_, fileName_, isRelativePath_)) {
1344             EraseWorker();
1345             HILOG_ERROR("worker:: the file path is invaild, can't find the file : %{public}s.", script);
1346             CloseHelp::DeletePointer(script, true);
1347             ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_INVALID_FILEPATH,
1348                 "the file path is invaild, can't find the file.");
1349             return;
1350         }
1351     }
1352 
1353     // 3. create WorkerRunner to Execute
1354     if (!runner_) {
1355         runner_ = std::make_unique<WorkerRunner>(WorkerStartCallback(ExecuteInThread, this));
1356     }
1357     if (runner_) {
1358         runner_->Execute(); // start a new thread
1359     } else {
1360         HILOG_ERROR("runner_ is nullptr");
1361     }
1362     CloseHelp::DeletePointer(script, true);
1363 }
1364 
ExecuteInThread(const void * data)1365 void Worker::ExecuteInThread(const void* data)
1366 {
1367     HITRACE_HELPER_START_TRACE(__PRETTY_FUNCTION__);
1368     auto worker = reinterpret_cast<Worker*>(const_cast<void*>(data));
1369 #ifdef ENABLE_QOS
1370     worker->SetQOSLevel();
1371 #endif
1372     // 1. create a runtime, nativeengine
1373     napi_env workerEnv = nullptr;
1374     {
1375         std::lock_guard<std::recursive_mutex> lock(worker->liveStatusLock_);
1376         if (worker->HostIsStop() || worker->isHostEnvExited_) {
1377             HILOG_ERROR("worker:: host thread is stop");
1378             worker->EraseWorker();
1379             CloseHelp::DeletePointer(worker, false);
1380             return;
1381         }
1382         napi_env env = worker->GetHostEnv();
1383         if (worker->isLimitedWorker_) {
1384             napi_create_limit_runtime(env, &workerEnv);
1385         } else {
1386             napi_create_runtime(env, &workerEnv);
1387         }
1388         if (workerEnv == nullptr) {
1389             HILOG_ERROR("worker:: Worker create runtime error");
1390             worker->EraseWorker();
1391             ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "Worker create runtime error");
1392             return;
1393         }
1394         if (worker->isLimitedWorker_) {
1395             reinterpret_cast<NativeEngine*>(workerEnv)->MarkRestrictedWorkerThread();
1396         } else {
1397             // mark worker env is workerThread
1398             reinterpret_cast<NativeEngine*>(workerEnv)->MarkWorkerThread();
1399         }
1400         // for load balance in taskpool
1401         reinterpret_cast<NativeEngine*>(env)->IncreaseSubEnvCounter();
1402 
1403         worker->SetWorkerEnv(workerEnv);
1404     }
1405 
1406     uv_loop_t* loop = worker->GetWorkerLoop();
1407     if (loop == nullptr) {
1408         HILOG_ERROR("worker:: Worker loop is nullptr");
1409         worker->EraseWorker();
1410         return;
1411     }
1412     reinterpret_cast<NativeEngine*>(workerEnv)->RegisterNapiUncaughtExceptionHandler(
1413         [workerEnv, worker] (napi_value exception) -> void {
1414         if (!NativeEngine::IsAlive(reinterpret_cast<NativeEngine*>(workerEnv))) {
1415             HILOG_WARN("napi_env has been destoryed!");
1416             return;
1417         }
1418         if (!IsValidWorker(worker)) {
1419             HILOG_WARN("worker:: the worker is not Valid.");
1420             return;
1421         }
1422         NapiErrorManager::GetInstance()->NotifyUncaughtException(workerEnv, exception, worker->GetName(), WORKER_TYPE);
1423         worker->HandleWorkerUncaughtException(workerEnv, exception);
1424     });
1425     reinterpret_cast<NativeEngine*>(workerEnv)->RegisterAllPromiseCallback(
1426         [workerEnv, worker] (napi_value* args) -> void {
1427         if (!NativeEngine::IsAlive(reinterpret_cast<NativeEngine*>(workerEnv))) {
1428             HILOG_WARN("napi_env has been destoryed!");
1429             return;
1430         }
1431         if (!IsValidWorker(worker)) {
1432             HILOG_WARN("worker:: the worker is not Valid.");
1433             return;
1434         }
1435         NapiErrorManager::GetInstance()->NotifyUnhandledRejection(workerEnv, args, worker->GetName(), WORKER_TYPE);
1436     });
1437 
1438     // 2. add some preparation for the worker
1439     if (worker->PrepareForWorkerInstance()) {
1440         ConcurrentHelper::UvHandleInit(loop, worker->workerOnMessageSignal_, Worker::WorkerOnMessage, worker);
1441         ConcurrentHelper::UvHandleInit(loop, worker->workerOnTerminateSignal_, Worker::WorkerOnMessage, worker);
1442 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
1443         ConcurrentHelper::UvHandleInit(loop, worker->debuggerOnPostTaskSignal_, Worker::HandleDebuggerTask, worker);
1444 #endif
1445         worker->UpdateWorkerState(RUNNING);
1446         // in order to invoke worker send before subThread start
1447         uv_async_send(worker->workerOnMessageSignal_);
1448         HITRACE_HELPER_FINISH_TRACE;
1449         // 3. start worker loop
1450         worker->Loop();
1451     } else {
1452         HILOG_ERROR("worker:: worker PrepareForWorkerInstance fail");
1453         worker->UpdateWorkerState(TERMINATED);
1454         HITRACE_HELPER_FINISH_TRACE;
1455     }
1456     worker->ReleaseWorkerThreadContent();
1457     std::lock_guard<std::recursive_mutex> lock(worker->liveStatusLock_);
1458     worker->EraseWorker();
1459     if (worker->HostIsStop() || worker->isHostEnvExited_) {
1460         HILOG_INFO("worker:: host is stopped");
1461         CloseHelp::DeletePointer(worker, false);
1462     } else {
1463         worker->PublishWorkerOverSignal();
1464     }
1465 }
1466 
PrepareForWorkerInstance()1467 bool Worker::PrepareForWorkerInstance()
1468 {
1469     std::string rawFileName = script_;
1470     uint8_t* scriptContent = nullptr;
1471     size_t scriptContentSize = 0;
1472     std::vector<uint8_t> content;
1473     std::string workerAmi;
1474     {
1475         std::lock_guard<std::recursive_mutex> lock(liveStatusLock_);
1476         if (HostIsStop() || isHostEnvExited_) {
1477             HILOG_INFO("worker:: host is stopped");
1478             return false;
1479         }
1480         auto workerEngine = reinterpret_cast<NativeEngine*>(workerEnv_);
1481         auto hostEngine = reinterpret_cast<NativeEngine*>(hostEnv_);
1482         // 1. init worker environment
1483 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
1484         workerEngine->SetDebuggerPostTaskFunc([this](std::function<void()>&& task) {
1485             this->DebuggerOnPostTask(std::move(task));
1486         });
1487 #endif
1488         if (!hostEngine->CallInitWorkerFunc(workerEngine)) {
1489             HILOG_ERROR("worker:: CallInitWorkerFunc error");
1490             return false;
1491         }
1492         // 2. get uril content
1493         if (isRelativePath_) {
1494             rawFileName = fileName_;
1495         }
1496         if (!hostEngine->GetAbcBuffer(rawFileName.c_str(), &scriptContent, &scriptContentSize, content, workerAmi)) {
1497             HILOG_ERROR("worker:: GetAbcBuffer error");
1498             return false;
1499         }
1500     }
1501     // add timer interface
1502     Timer::RegisterTime(workerEnv_);
1503     HILOG_DEBUG("worker:: stringContent size is %{public}zu", scriptContentSize);
1504     napi_value execScriptResult = nullptr;
1505     napi_status status = napi_run_actor(workerEnv_, scriptContent, scriptContentSize,
1506         workerAmi.c_str(), &execScriptResult, const_cast<char*>(script_.c_str()));
1507     if (status != napi_ok || execScriptResult == nullptr) {
1508         // An exception occurred when running the script.
1509         HILOG_ERROR("worker:: run script exception occurs, will handle exception");
1510         HandleException();
1511         return false;
1512     }
1513 
1514     ApplyNameSetting();
1515     return true;
1516 }
1517 
ApplyNameSetting()1518 void Worker::ApplyNameSetting()
1519 {
1520     std::string threadName = "WorkerThread";
1521     if (!name_.empty()) {
1522         napi_value nameValue = nullptr;
1523         napi_create_string_utf8(workerEnv_, name_.c_str(), name_.length(), &nameValue);
1524         NapiHelper::SetNamePropertyInGlobal(workerEnv_, "name", nameValue);
1525 
1526         threadName += "_" + name_;
1527         if (threadName.length() > THREAD_NAME_MAX_LENGTH) {
1528             threadName = threadName.substr(0, THREAD_NAME_MAX_LENGTH);
1529         }
1530     }
1531 #if defined IOS_PLATFORM || defined MAC_PLATFORM
1532     pthread_setname_np(threadName.c_str());
1533 #elif !defined(WINDOWS_PLATFORM)
1534     pthread_setname_np(pthread_self(), threadName.c_str());
1535 #endif
1536 }
1537 
HostOnMessage(const uv_async_t * req)1538 void Worker::HostOnMessage(const uv_async_t* req)
1539 {
1540     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
1541     Worker* worker = static_cast<Worker*>(req->data);
1542     if (worker == nullptr) {
1543         HILOG_ERROR("worker:: worker is null when host onmessage.");
1544         return;
1545     }
1546     worker->HostOnMessageInner();
1547 }
1548 
HostOnMessageInner()1549 void Worker::HostOnMessageInner()
1550 {
1551     if (hostEnv_ == nullptr || HostIsStop()) {
1552         HILOG_ERROR("worker:: host thread maybe is over when host onmessage.");
1553         return;
1554     }
1555 
1556     napi_status status = napi_ok;
1557     HandleScope scope(hostEnv_, status);
1558     NAPI_CALL_RETURN_VOID(hostEnv_, status);
1559 
1560     NativeEngine* engine = reinterpret_cast<NativeEngine*>(hostEnv_);
1561     ContainerScope containerScope(engine, scopeId_);
1562     if (!containerScope.IsInitialized()) {
1563         HILOG_WARN("worker:: InitContainerScopeFunc error when HostOnMessageInner begin(only stage model)");
1564     }
1565 
1566     napi_value obj = NapiHelper::GetReferenceValue(hostEnv_, workerRef_);
1567     napi_value callback = NapiHelper::GetNameProperty(hostEnv_, obj, "onmessage");
1568     bool isCallable = NapiHelper::IsCallable(hostEnv_, callback);
1569 
1570     MessageDataType data = nullptr;
1571     while (hostMessageQueue_.DeQueue(&data)) {
1572         // receive close signal.
1573         if (data == nullptr) {
1574             HILOG_DEBUG("worker:: worker received close signal");
1575 #if defined(ENABLE_WORKER_EVENTHANDLER)
1576             if ((!isMainThreadWorker_ || isLimitedWorker_) && !isHostEnvExited_) {
1577                 CloseHostHandle();
1578             }
1579 #else
1580             if (!isHostEnvExited_) {
1581                 CloseHostHandle();
1582             }
1583 #endif
1584             CloseHostCallback();
1585             return;
1586         }
1587         // handle data, call worker onMessage function to handle.
1588         napi_status status = napi_ok;
1589         HandleScope scope(hostEnv_, status);
1590         NAPI_CALL_RETURN_VOID(hostEnv_, status);
1591         napi_value result = nullptr;
1592         status = napi_deserialize(hostEnv_, data, &result);
1593         napi_delete_serialization_data(hostEnv_, data);
1594         if (status != napi_ok || result == nullptr) {
1595             HostOnMessageErrorInner();
1596             continue;
1597         }
1598         napi_value event = nullptr;
1599         napi_create_object(hostEnv_, &event);
1600         napi_set_named_property(hostEnv_, event, "data", result);
1601         napi_value argv[1] = { event };
1602         if (isCallable) {
1603             napi_value callbackResult = nullptr;
1604             napi_call_function(hostEnv_, obj, callback, 1, argv, &callbackResult);
1605         }
1606         // handle listeners.
1607         HandleEventListeners(hostEnv_, obj, 1, argv, "message");
1608         HandleHostException();
1609 #if defined(ENABLE_WORKER_EVENTHANDLER)
1610         if (isMainThreadWorker_ && !isLimitedWorker_) {
1611             auto handler = OHOS::AppExecFwk::EventHandler::Current();
1612             if (handler && (handler->HasPendingHigherEvent() && !hostMessageQueue_.IsEmpty())) {
1613                 PostWorkerMessageTask();
1614                 break;
1615             }
1616         }
1617 #endif
1618     }
1619 }
1620 
HostOnGlobalCall(const uv_async_t * req)1621 void Worker::HostOnGlobalCall(const uv_async_t* req)
1622 {
1623     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
1624     Worker* worker = static_cast<Worker*>(req->data);
1625     if (worker == nullptr) {
1626         HILOG_ERROR("worker:: worker is null");
1627         return;
1628     }
1629     worker->HostOnGlobalCallInner();
1630 }
1631 
HostOnGlobalCallInner()1632 void Worker::HostOnGlobalCallInner()
1633 {
1634     if (hostEnv_ == nullptr || HostIsStop()) {
1635         HILOG_ERROR("worker:: host thread maybe is over when host onmessage.");
1636         globalCallSuccess_ = false;
1637         cv_.notify_one();
1638         return;
1639     }
1640 
1641     napi_status scopeStatus = napi_ok;
1642     HandleScope handleScope(hostEnv_, scopeStatus);
1643     NAPI_CALL_RETURN_VOID(hostEnv_, scopeStatus);
1644 
1645     NativeEngine* engine = reinterpret_cast<NativeEngine*>(hostEnv_);
1646     ContainerScope containerScope(engine, scopeId_);
1647     if (!containerScope.IsInitialized()) {
1648         HILOG_WARN("worker:: InitContainerScopeFunc error when HostOnGlobalCallInner begin(only stage model)");
1649     }
1650 
1651     if (hostGlobalCallQueue_.IsEmpty()) {
1652         HILOG_ERROR("worker:: message queue is empty when HostOnGlobalCallInner");
1653         globalCallSuccess_ = false;
1654         cv_.notify_one();
1655         return;
1656     }
1657     MessageDataType data = nullptr;
1658     uint32_t currentCallId = 0;
1659     size_t size = hostGlobalCallQueue_.GetSize();
1660     if (size < 0 || size > GLOBAL_CALL_MAX_COUNT) {
1661         HILOG_ERROR("worker:: hostGlobalCallQueue_ size error");
1662         globalCallSuccess_ = false;
1663         cv_.notify_one();
1664         return;
1665     }
1666     for (size_t i = 0; i < size; i++) {
1667         std::pair<uint32_t, MessageDataType> pair = hostGlobalCallQueue_.Front();
1668         hostGlobalCallQueue_.Pop();
1669         if (pair.first == globalCallId_) {
1670             currentCallId = pair.first;
1671             data = pair.second;
1672             break;
1673         }
1674         napi_delete_serialization_data(hostEnv_, pair.second);
1675     }
1676     napi_value argsArray = nullptr;
1677     napi_status status = napi_ok;
1678     status = napi_deserialize(hostEnv_, data, &argsArray);
1679     napi_delete_serialization_data(hostEnv_, data);
1680     if (status != napi_ok || argsArray == nullptr) {
1681         AddGlobalCallError(ErrorHelper::ERR_WORKER_SERIALIZATION);
1682         globalCallSuccess_ = false;
1683         cv_.notify_one();
1684         return;
1685     }
1686     napi_value instanceName = nullptr;
1687     napi_get_element(hostEnv_, argsArray, 0, &instanceName);
1688     napi_value methodName = nullptr;
1689     napi_get_element(hostEnv_, argsArray, 1, &methodName);
1690 
1691     std::string instanceNameStr = NapiHelper::GetString(hostEnv_, instanceName);
1692     auto iter = globalCallObjects_.find(instanceNameStr);
1693     if (iter == globalCallObjects_.end()) {
1694         HILOG_ERROR("worker:: there is no instance: %{public}s registered for global call", instanceNameStr.c_str());
1695         AddGlobalCallError(ErrorHelper::ERR_TRIGGER_NONEXIST_EVENT);
1696         globalCallSuccess_ = false;
1697         cv_.notify_one();
1698         return;
1699     }
1700     napi_ref objRef = iter->second;
1701     napi_value obj = NapiHelper::GetReferenceValue(hostEnv_, objRef);
1702     bool hasProperty = false;
1703     napi_has_property(hostEnv_, obj, methodName, &hasProperty);
1704     if (!hasProperty) {
1705         std::string methodNameStr = NapiHelper::GetString(hostEnv_, methodName);
1706         HILOG_ERROR("worker:: registered obj for global call has no method: %{public}s", methodNameStr.c_str());
1707         AddGlobalCallError(ErrorHelper::ERR_CALL_METHOD_ON_BINDING_OBJ);
1708         globalCallSuccess_ = false;
1709         cv_.notify_one();
1710         return;
1711     }
1712     napi_value method = nullptr;
1713     napi_get_property(hostEnv_, obj, methodName, &method);
1714     // call method must not be generator function or async function
1715     bool validMethod = NapiHelper::IsCallable(hostEnv_, method) && !NapiHelper::IsAsyncFunction(hostEnv_, method) &&
1716         !NapiHelper::IsGeneratorFunction(hostEnv_, method);
1717     if (!validMethod) {
1718         std::string methodNameStr = NapiHelper::GetString(hostEnv_, methodName);
1719         HILOG_ERROR("worker:: method %{public}s shall be callable and not async or generator method",
1720             methodNameStr.c_str());
1721         AddGlobalCallError(ErrorHelper::ERR_CALL_METHOD_ON_BINDING_OBJ);
1722         globalCallSuccess_ = false;
1723         cv_.notify_one();
1724         return;
1725     }
1726     uint32_t argc = 0;
1727     napi_get_array_length(hostEnv_, argsArray, &argc);
1728     napi_value* args = nullptr;
1729     ObjectScope<napi_value> scope(args, true);
1730     if (argc > BEGIN_INDEX_OF_ARGUMENTS) {
1731         args = new napi_value[argc - BEGIN_INDEX_OF_ARGUMENTS];
1732         for (uint32_t index = 0; index < argc - BEGIN_INDEX_OF_ARGUMENTS; index++) {
1733             napi_get_element(hostEnv_, argsArray, index + BEGIN_INDEX_OF_ARGUMENTS, &args[index]);
1734         }
1735     }
1736 
1737     napi_value res = nullptr;
1738     napi_call_function(hostEnv_, obj, method, argc - BEGIN_INDEX_OF_ARGUMENTS, args, &res);
1739     bool hasPendingException = NapiHelper::IsExceptionPending(hostEnv_);
1740     if (hasPendingException) {
1741         napi_value exception = nullptr;
1742         napi_get_and_clear_last_exception(hostEnv_, &exception);
1743         napi_throw(hostEnv_, exception);
1744         globalCallSuccess_ = false;
1745         cv_.notify_one();
1746         return;
1747     }
1748     // defautly not transfer
1749     napi_value undefined = NapiHelper::GetUndefinedValue(hostEnv_);
1750     // meaningless to copy sendable object when call globalObject
1751     bool defaultClone = true;
1752     bool defaultTransfer = false;
1753     status = napi_serialize_inner(hostEnv_, res, undefined, undefined, defaultTransfer, defaultClone, &data);
1754     if (status != napi_ok || data == nullptr) {
1755         AddGlobalCallError(ErrorHelper::ERR_WORKER_SERIALIZATION);
1756         globalCallSuccess_ = false;
1757         cv_.notify_one();
1758         return;
1759     }
1760     // drop and destruct result if timeout
1761     if (currentCallId != globalCallId_ || currentCallId == 0) {
1762         napi_delete_serialization_data(hostEnv_, data);
1763         cv_.notify_one();
1764         return;
1765     }
1766     workerGlobalCallQueue_.EnQueue(data);
1767     globalCallSuccess_ = true;
1768     cv_.notify_one();
1769 }
1770 
AddGlobalCallError(int32_t errCode,napi_value errData)1771 void Worker::AddGlobalCallError(int32_t errCode, napi_value errData)
1772 {
1773     globalCallErrors_.push({errCode, errData});
1774 }
1775 
HandleGlobalCallError(napi_env env)1776 void Worker::HandleGlobalCallError(napi_env env)
1777 {
1778     while (!globalCallErrors_.empty()) {
1779         std::pair<int32_t, napi_value> pair = globalCallErrors_.front();
1780         globalCallErrors_.pop();
1781         int32_t errCode = pair.first;
1782         ErrorHelper::ThrowError(env, errCode);
1783     }
1784 }
1785 
ClearGlobalCallError(napi_env env)1786 void Worker::ClearGlobalCallError(napi_env env)
1787 {
1788     while (!globalCallErrors_.empty()) {
1789         std::pair<int32_t, napi_value> pair = globalCallErrors_.front();
1790         globalCallErrors_.pop();
1791         if (pair.second != nullptr) {
1792             napi_delete_serialization_data(env, pair.second);
1793         }
1794     }
1795 }
1796 
CallHostFunction(size_t argc,const napi_value * argv,const char * methodName) const1797 void Worker::CallHostFunction(size_t argc, const napi_value* argv, const char* methodName) const
1798 {
1799     if (hostEnv_ == nullptr) {
1800         HILOG_ERROR("worker:: host thread maybe is over");
1801         return;
1802     }
1803     if (HostIsStop()) {
1804         HILOG_ERROR("worker:: host thread maybe is over");
1805         WorkerThrowError(hostEnv_, ErrorHelper::ERR_WORKER_NOT_RUNNING,
1806             "host thread maybe is over when CallHostFunction");
1807         return;
1808     }
1809     napi_value obj = NapiHelper::GetReferenceValue(hostEnv_, workerRef_);
1810     napi_value callback = NapiHelper::GetNameProperty(hostEnv_, obj, methodName);
1811     bool isCallable = NapiHelper::IsCallable(hostEnv_, callback);
1812     if (!isCallable) {
1813         HILOG_DEBUG("worker:: host thread %{public}s is not Callable", methodName);
1814         return;
1815     }
1816     napi_value callbackResult = nullptr;
1817     napi_call_function(hostEnv_, obj, callback, argc, argv, &callbackResult);
1818     HandleHostException();
1819 }
1820 
CloseHostCallback()1821 void Worker::CloseHostCallback()
1822 {
1823     {
1824         napi_status status = napi_ok;
1825         HandleScope scope(hostEnv_, status);
1826         NAPI_CALL_RETURN_VOID(hostEnv_, status);
1827         napi_value exitValue = nullptr;
1828         if (isErrorExit_) {
1829             napi_create_int32(hostEnv_, 1, &exitValue); // 1 : exit because of error
1830         } else {
1831             napi_create_int32(hostEnv_, 0, &exitValue); // 0 : exit normally
1832         }
1833         napi_value argv[1] = { exitValue };
1834         CallHostFunction(1, argv, "onexit");
1835         napi_value obj = NapiHelper::GetReferenceValue(hostEnv_, workerRef_);
1836         // handle listeners
1837         HandleEventListeners(hostEnv_, obj, 1, argv, "exit");
1838     }
1839     CloseHelp::DeletePointer(this, false);
1840 }
1841 
HostOnError(const uv_async_t * req)1842 void Worker::HostOnError(const uv_async_t* req)
1843 {
1844     Worker* worker = static_cast<Worker*>(req->data);
1845     if (worker == nullptr) {
1846         HILOG_ERROR("worker:: worker is null");
1847         return;
1848     }
1849     worker->HostOnErrorInner();
1850 }
1851 
HostOnErrorInner()1852 void Worker::HostOnErrorInner()
1853 {
1854     if (hostEnv_ == nullptr || HostIsStop()) {
1855         HILOG_ERROR("worker:: host thread maybe is over when host onerror.");
1856         return;
1857     }
1858     napi_status status = napi_ok;
1859     HandleScope scope(hostEnv_, status);
1860     NAPI_CALL_RETURN_VOID(hostEnv_, status);
1861     NativeEngine* hostEngine = reinterpret_cast<NativeEngine*>(hostEnv_);
1862     ContainerScope containerScope(hostEngine, scopeId_);
1863     if (!containerScope.IsInitialized()) {
1864         HILOG_WARN("worker:: InitContainerScopeFunc error when HostOnErrorInner begin(only stage model)");
1865     }
1866 
1867     napi_value obj = NapiHelper::GetReferenceValue(hostEnv_, workerRef_);
1868     bool hasOnAllError = NapiHelper::HasNameProperty(hostEnv_, obj, "onAllErrors");
1869     napi_value callback = nullptr;
1870     if (hasOnAllError) {
1871         HILOG_INFO("worker:: host thread register onAllErrors.");
1872         callback = NapiHelper::GetNameProperty(hostEnv_, obj, "onAllErrors");
1873     } else {
1874         callback = NapiHelper::GetNameProperty(hostEnv_, obj, "onerror");
1875     }
1876     bool isCallable = NapiHelper::IsCallable(hostEnv_, callback);
1877 
1878     MessageDataType data;
1879     while (errorQueue_.DeQueue(&data)) {
1880         napi_value result = nullptr;
1881         napi_deserialize(hostEnv_, data, &result);
1882         napi_delete_serialization_data(hostEnv_, data);
1883 
1884         napi_value argv[1] = { result };
1885         if (isCallable) {
1886             napi_value callbackResult = nullptr;
1887             napi_call_function(hostEnv_, obj, callback, 1, argv, &callbackResult);
1888         }
1889         // handle listeners
1890         bool isHandle = HandleEventListeners(hostEnv_, obj, 1, argv, "error");
1891         if (!isCallable && !isHandle && !hasOnAllError) {
1892             napi_value businessError = ErrorHelper::ObjectToError(hostEnv_, result);
1893             napi_throw(hostEnv_, businessError);
1894             HandleHostException();
1895             TerminateInner();
1896             return;
1897         }
1898         HandleHostException();
1899     }
1900     if (!hasOnAllError) {
1901         // if host thread not register onAllErrors, worker still terminate.
1902         TerminateInner();
1903     }
1904 }
1905 
PostMessageInner(MessageDataType data)1906 void Worker::PostMessageInner(MessageDataType data)
1907 {
1908     if (IsTerminated()) {
1909         HILOG_DEBUG("worker:: worker has been terminated when PostMessageInner.");
1910         return;
1911     }
1912     workerMessageQueue_.EnQueue(data);
1913     std::lock_guard<std::mutex> lock(workerOnmessageMutex_);
1914     if (data == nullptr) {
1915         HILOG_INFO("worker:: host post nullptr to worker.");
1916         ConcurrentHelper::UvCheckAndAsyncSend(workerOnTerminateSignal_);
1917     } else {
1918         ConcurrentHelper::UvCheckAndAsyncSend(workerOnMessageSignal_);
1919     }
1920 }
1921 
HostOnMessageErrorInner()1922 void Worker::HostOnMessageErrorInner()
1923 {
1924     if (hostEnv_ == nullptr || HostIsStop()) {
1925         HILOG_ERROR("worker:: host thread maybe is over");
1926         return;
1927     }
1928     napi_value obj = NapiHelper::GetReferenceValue(hostEnv_, workerRef_);
1929     CallHostFunction(0, nullptr, "onmessageerror");
1930     // handle listeners
1931     HandleEventListeners(hostEnv_, obj, 0, nullptr, "messageerror");
1932 }
1933 
TerminateInner()1934 void Worker::TerminateInner()
1935 {
1936     if (IsTerminated() || IsTerminating()) {
1937         HILOG_INFO("worker:: worker is not in running when TerminateInner");
1938         return;
1939     }
1940     // 1. Update State
1941     UpdateWorkerState(TERMINATEING);
1942     // 2. send null signal
1943     PostMessageInner(nullptr);
1944 }
1945 
CloseInner()1946 void Worker::CloseInner()
1947 {
1948     bool expected = false;
1949     if (isTerminated_.compare_exchange_weak(expected, true)) {
1950         HILOG_INFO("worker:: Close worker");
1951     } else {
1952         HILOG_DEBUG("worker:: worker is terminated when Close");
1953         return;
1954     }
1955     UpdateWorkerState(TERMINATEING);
1956     TerminateWorker();
1957 }
1958 
UpdateWorkerState(RunnerState state)1959 bool Worker::UpdateWorkerState(RunnerState state)
1960 {
1961     bool done = false;
1962     do {
1963         RunnerState oldState = runnerState_.load(std::memory_order_acquire);
1964         if (oldState >= state) {
1965             // make sure state sequence is start, running, terminating, terminated
1966             return false;
1967         }
1968         done = runnerState_.compare_exchange_strong(oldState, state);
1969     } while (!done);
1970     return true;
1971 }
1972 
UpdateHostState(HostState state)1973 bool Worker::UpdateHostState(HostState state)
1974 {
1975     bool done = false;
1976     do {
1977         HostState oldState = hostState_.load(std::memory_order_acquire);
1978         if (oldState >= state) {
1979             // make sure state sequence is ACTIVE, INACTIVE
1980             return false;
1981         }
1982         done = hostState_.compare_exchange_strong(oldState, state);
1983     } while (!done);
1984     return true;
1985 }
1986 
TerminateWorker()1987 void Worker::TerminateWorker()
1988 {
1989     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
1990     // when there is no active handle, worker loop will stop automatic.
1991     {
1992         std::lock_guard<std::mutex> lock(workerOnmessageMutex_);
1993         ConcurrentHelper::UvHandleClose(workerOnMessageSignal_);
1994         ConcurrentHelper::UvHandleClose(workerOnTerminateSignal_);
1995     }
1996 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
1997     ConcurrentHelper::UvHandleClose(debuggerOnPostTaskSignal_);
1998 #endif
1999     CloseWorkerCallback();
2000     uv_loop_t* loop = GetWorkerLoop();
2001     if (loop != nullptr) {
2002         Timer::ClearEnvironmentTimer(workerEnv_);
2003         uv_stop(loop);
2004     }
2005     UpdateWorkerState(TERMINATED);
2006 }
2007 
PublishWorkerOverSignal()2008 void Worker::PublishWorkerOverSignal()
2009 {
2010     if (HostIsStop()) {
2011         return;
2012     }
2013     // post nullptr tell host worker is not running
2014     hostMessageQueue_.EnQueue(nullptr);
2015 #if defined(ENABLE_WORKER_EVENTHANDLER)
2016     if (isMainThreadWorker_ && !isLimitedWorker_) {
2017         PostWorkerOverTask();
2018     } else {
2019         uv_async_send(hostOnMessageSignal_);
2020     }
2021 #else
2022     uv_async_send(hostOnMessageSignal_);
2023 #endif
2024 }
2025 
2026 #if defined(ENABLE_WORKER_EVENTHANDLER)
PostWorkerOverTask()2027 void Worker::PostWorkerOverTask()
2028 {
2029     std::weak_ptr<WorkerWrapper> weak = workerWrapper_;
2030     auto hostOnOverSignalTask = [weak]() {
2031         auto strong = weak.lock();
2032         if (strong) {
2033             HILOG_INFO("worker:: host receive terminate.");
2034             HITRACE_HELPER_METER_NAME("Worker:: HostOnTerminateSignal");
2035             strong->GetWorker()->HostOnMessageInner();
2036         } else {
2037             HILOG_INFO("worker:: worker is null.");
2038         }
2039     };
2040     GetMainThreadHandler()->PostTask(hostOnOverSignalTask, "WorkerHostOnOverSignalTask",
2041         0, OHOS::AppExecFwk::EventQueue::Priority::HIGH);
2042 }
2043 
PostWorkerErrorTask()2044 void Worker::PostWorkerErrorTask()
2045 {
2046     auto hostOnErrorTask = [this]() {
2047         if (IsValidWorker(this)) {
2048             HILOG_INFO("worker:: host receive error.");
2049             HITRACE_HELPER_METER_NAME("Worker:: HostOnErrorMessage");
2050             this->HostOnErrorInner();
2051         }
2052     };
2053     GetMainThreadHandler()->PostTask(hostOnErrorTask, "WorkerHostOnErrorTask",
2054         0, OHOS::AppExecFwk::EventQueue::Priority::HIGH);
2055 }
2056 
PostWorkerMessageTask()2057 void Worker::PostWorkerMessageTask()
2058 {
2059     auto hostOnMessageTask = [this]() {
2060         if (IsValidWorker(this)) {
2061             HILOG_DEBUG("worker:: host thread receive message.");
2062             HITRACE_HELPER_METER_NAME("Worker:: HostOnMessage");
2063             this->HostOnMessageInner();
2064         }
2065     };
2066     GetMainThreadHandler()->PostTask(hostOnMessageTask, "WorkerHostOnMessageTask",
2067         0, OHOS::AppExecFwk::EventQueue::Priority::HIGH);
2068 }
2069 
PostWorkerGlobalCallTask()2070 void Worker::PostWorkerGlobalCallTask()
2071 {
2072     auto hostOnGlobalCallTask = [this]() {
2073         if (IsValidWorker(this)) {
2074             HILOG_DEBUG("worker:: host thread receive globalCall signal.");
2075             HITRACE_HELPER_METER_NAME("Worker:: HostOnGlobalCallSignal");
2076             this->HostOnGlobalCallInner();
2077         }
2078     };
2079     GetMainThreadHandler()->PostTask(hostOnGlobalCallTask, "WorkerHostOnGlobalCallTask",
2080         0, OHOS::AppExecFwk::EventQueue::Priority::HIGH);
2081 }
2082 
PostWorkerExceptionTask()2083 void Worker::PostWorkerExceptionTask()
2084 {
2085     auto hostOnAllErrorsTask = [this]() {
2086         if (IsValidWorker(this)) {
2087             HILOG_INFO("worker:: host receive exception.");
2088             HITRACE_HELPER_METER_NAME("Worker:: HostOnAllErrorsMessage");
2089             this->HostOnAllErrorsInner();
2090         }
2091     };
2092     GetMainThreadHandler()->PostTask(hostOnAllErrorsTask, "WorkerHostOnAllErrorsTask",
2093         0, OHOS::AppExecFwk::EventQueue::Priority::HIGH);
2094 }
2095 #endif
2096 
IsValidWorker(Worker * worker)2097 bool Worker::IsValidWorker(Worker* worker)
2098 {
2099     std::lock_guard<std::mutex> lock(g_workersMutex);
2100     std::list<Worker*>::iterator it = std::find(g_workers.begin(), g_workers.end(), worker);
2101     if (it == g_workers.end()) {
2102         return false;
2103     }
2104     return true;
2105 }
2106 
IsValidLimitedWorker(Worker * limitedWorker)2107 bool Worker::IsValidLimitedWorker(Worker* limitedWorker)
2108 {
2109     std::lock_guard<std::mutex> lock(g_limitedworkersMutex);
2110     std::list<Worker*>::iterator it = std::find(g_limitedworkers.begin(), g_limitedworkers.end(), limitedWorker);
2111     if (it == g_limitedworkers.end()) {
2112         return false;
2113     }
2114     return true;
2115 }
2116 
WorkerOnMessage(const uv_async_t * req)2117 void Worker::WorkerOnMessage(const uv_async_t* req)
2118 {
2119     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
2120     Worker* worker = static_cast<Worker*>(req->data);
2121     if (worker == nullptr) {
2122         HILOG_ERROR("worker::worker is null");
2123         return;
2124     }
2125     worker->WorkerOnMessageInner();
2126 }
2127 
WorkerOnMessageInner()2128 void Worker::WorkerOnMessageInner()
2129 {
2130     if (IsTerminated()) {
2131         return;
2132     }
2133     WorkerRunningScope workerRunningScope(workerEnv_);
2134     napi_status status;
2135     napi_handle_scope scope = nullptr;
2136     status = napi_open_handle_scope(workerEnv_, &scope);
2137     if (status != napi_ok || scope == nullptr) {
2138         HILOG_ERROR("worker:: WorkerOnMessage open handle scope failed.");
2139         return;
2140     }
2141     MessageDataType data = nullptr;
2142     while (!IsTerminated() && workerMessageQueue_.DeQueue(&data)) {
2143         if (data == nullptr) {
2144             HILOG_DEBUG("worker:: worker reveive terminate signal");
2145             // Close handlescope need before TerminateWorker
2146             napi_close_handle_scope(workerEnv_, scope);
2147             TerminateWorker();
2148             return;
2149         }
2150         napi_value result = nullptr;
2151         status = napi_deserialize(workerEnv_, data, &result);
2152         napi_delete_serialization_data(workerEnv_, data);
2153         if (status != napi_ok || result == nullptr) {
2154             WorkerOnMessageErrorInner();
2155             continue;
2156         }
2157 
2158         napi_value event = nullptr;
2159         napi_create_object(workerEnv_, &event);
2160         napi_set_named_property(workerEnv_, event, "data", result);
2161         napi_value argv[1] = { event };
2162         CallWorkerFunction(1, argv, "onmessage", true);
2163 
2164         napi_value obj = NapiHelper::GetReferenceValue(workerEnv_, this->workerPort_);
2165         ParentPortHandleEventListeners(workerEnv_, obj, 1, argv, "message", true);
2166     }
2167     napi_close_handle_scope(workerEnv_, scope);
2168 }
2169 
HandleEventListeners(napi_env env,napi_value recv,size_t argc,const napi_value * argv,const char * type)2170 bool Worker::HandleEventListeners(napi_env env, napi_value recv, size_t argc, const napi_value* argv, const char* type)
2171 {
2172     std::string listener(type);
2173     auto iter = eventListeners_.find(listener);
2174     if (iter == eventListeners_.end()) {
2175         HILOG_DEBUG("worker:: there is no listener for type %{public}s in host thread", type);
2176         return false;
2177     }
2178 
2179     std::list<WorkerListener*>& listeners = iter->second;
2180     std::list<WorkerListener*>::iterator it = listeners.begin();
2181     while (it != listeners.end()) {
2182         WorkerListener* data = *it++;
2183         napi_value callbackObj = NapiHelper::GetReferenceValue(env, data->callback_);
2184         if (!NapiHelper::IsCallable(env, callbackObj)) {
2185             HILOG_WARN("worker:: host thread listener %{public}s is not callable", type);
2186             return false;
2187         }
2188         napi_value callbackResult = nullptr;
2189         napi_call_function(env, recv, callbackObj, argc, argv, &callbackResult);
2190         if (!data->NextIsAvailable()) {
2191             listeners.remove(data);
2192             CloseHelp::DeletePointer(data, false);
2193         }
2194     }
2195     return true;
2196 }
2197 
HandleHostException() const2198 void Worker::HandleHostException() const
2199 {
2200     if (!NapiHelper::IsExceptionPending(hostEnv_)) {
2201         return;
2202     }
2203     auto hostEngine = reinterpret_cast<NativeEngine*>(hostEnv_);
2204     hostEngine->HandleUncaughtException();
2205 }
2206 
HandleException()2207 void Worker::HandleException()
2208 {
2209     if (!NapiHelper::IsExceptionPending(workerEnv_)) {
2210         return;
2211     }
2212 
2213     napi_status status = napi_ok;
2214     HandleScope scope(workerEnv_, status);
2215     NAPI_CALL_RETURN_VOID(workerEnv_, status);
2216     napi_value exception;
2217     napi_get_and_clear_last_exception(workerEnv_, &exception);
2218     if (exception == nullptr) {
2219         return;
2220     }
2221     NapiErrorManager::GetInstance()->NotifyUncaughtException(workerEnv_, exception, this->GetName(), WORKER_TYPE);
2222     HandleUncaughtException(exception);
2223 }
2224 
HandleUncaughtException(napi_value exception)2225 void Worker::HandleUncaughtException(napi_value exception)
2226 {
2227     napi_value obj = ErrorHelper::TranslateErrorEvent(workerEnv_, exception);
2228 
2229     // WorkerGlobalScope onerror
2230     WorkerOnErrorInner(obj);
2231 
2232     if (hostEnv_ == nullptr) {
2233         HILOG_ERROR("worker:: host engine is nullptr.");
2234         return;
2235     }
2236     MessageDataType data = nullptr;
2237     napi_value undefined = NapiHelper::GetUndefinedValue(workerEnv_);
2238     napi_serialize_inner(workerEnv_, obj, undefined, undefined, false, true, &data);
2239     {
2240         std::lock_guard<std::recursive_mutex> lock(liveStatusLock_);
2241         if (HostIsStop() || isHostEnvExited_) {
2242             return;
2243         }
2244         errorQueue_.EnQueue(data);
2245 #if defined(ENABLE_WORKER_EVENTHANDLER)
2246         if (isMainThreadWorker_ && !isLimitedWorker_) {
2247             PostWorkerErrorTask();
2248         } else {
2249             uv_async_send(hostOnErrorSignal_);
2250         }
2251 #else
2252         uv_async_send(hostOnErrorSignal_);
2253 #endif
2254     }
2255 }
2256 
WorkerOnMessageErrorInner()2257 void Worker::WorkerOnMessageErrorInner()
2258 {
2259     isErrorExit_ = true;
2260     CallWorkerFunction(0, nullptr, "onmessageerror", true);
2261     napi_value obj = NapiHelper::GetReferenceValue(workerEnv_, this->workerPort_);
2262     ParentPortHandleEventListeners(workerEnv_, obj, 0, nullptr, "messageerror", true);
2263 }
2264 
PostMessageToHostInner(MessageDataType data)2265 void Worker::PostMessageToHostInner(MessageDataType data)
2266 {
2267     std::lock_guard<std::recursive_mutex> lock(liveStatusLock_);
2268     if (hostEnv_ != nullptr && !HostIsStop() && !isHostEnvExited_) {
2269         hostMessageQueue_.EnQueue(data);
2270 #if defined(ENABLE_WORKER_EVENTHANDLER)
2271         if (isMainThreadWorker_ && !isLimitedWorker_) {
2272             PostWorkerMessageTask();
2273         } else {
2274             uv_async_send(hostOnMessageSignal_);
2275         }
2276 #else
2277         uv_async_send(hostOnMessageSignal_);
2278 #endif
2279     } else {
2280         HILOG_ERROR("worker:: worker host engine is nullptr when PostMessageToHostInner.");
2281     }
2282 }
2283 
operator ==(const WorkerListener & listener) const2284 bool Worker::WorkerListener::operator==(const WorkerListener& listener) const
2285 {
2286     napi_value obj = NapiHelper::GetReferenceValue(listener.env_, listener.callback_);
2287     napi_value compareObj = NapiHelper::GetReferenceValue(env_, callback_);
2288     // the env of listener and cmp listener must be same env because of Synchronization method
2289     return NapiHelper::StrictEqual(env_, compareObj, obj);
2290 }
2291 
AddListenerInner(napi_env env,const char * type,const WorkerListener * listener)2292 void Worker::AddListenerInner(napi_env env, const char* type, const WorkerListener* listener)
2293 {
2294     std::string typestr(type);
2295     auto iter = eventListeners_.find(typestr);
2296     if (iter == eventListeners_.end()) {
2297         std::list<WorkerListener*> listeners;
2298         listeners.emplace_back(const_cast<WorkerListener*>(listener));
2299         eventListeners_[typestr] = listeners;
2300     } else {
2301         std::list<WorkerListener*>& listenerList = iter->second;
2302         std::list<WorkerListener*>::iterator it = std::find_if(
2303             listenerList.begin(), listenerList.end(), Worker::FindWorkerListener(env, listener->callback_));
2304         if (it != listenerList.end()) {
2305             return;
2306         }
2307         listenerList.emplace_back(const_cast<WorkerListener*>(listener));
2308     }
2309 }
2310 
RemoveListenerInner(napi_env env,const char * type,napi_ref callback)2311 void Worker::RemoveListenerInner(napi_env env, const char* type, napi_ref callback)
2312 {
2313     std::string typestr(type);
2314     auto iter = eventListeners_.find(typestr);
2315     if (iter == eventListeners_.end()) {
2316         return;
2317     }
2318     std::list<WorkerListener*>& listenerList = iter->second;
2319     if (callback != nullptr) {
2320         std::list<WorkerListener*>::iterator it =
2321             std::find_if(listenerList.begin(), listenerList.end(), Worker::FindWorkerListener(env, callback));
2322         if (it != listenerList.end()) {
2323             CloseHelp::DeletePointer(*it, false);
2324             listenerList.erase(it);
2325         }
2326     } else {
2327         for (auto it = listenerList.begin(); it != listenerList.end(); it++) {
2328             CloseHelp::DeletePointer(*it, false);
2329         }
2330         eventListeners_.erase(typestr);
2331     }
2332 }
2333 
~Worker()2334 Worker::~Worker()
2335 {
2336     std::lock_guard<std::recursive_mutex> lock(liveStatusLock_);
2337     if (!HostIsStop() && !isHostEnvExited_) {
2338         ReleaseHostThreadContent();
2339         RemoveAllListenerInner();
2340         ClearGlobalCallObject();
2341     }
2342 }
2343 
RemoveAllListenerInner()2344 void Worker::RemoveAllListenerInner()
2345 {
2346     for (auto iter = eventListeners_.begin(); iter != eventListeners_.end(); iter++) {
2347         std::list<WorkerListener*>& listeners = iter->second;
2348         for (auto item = listeners.begin(); item != listeners.end(); item++) {
2349             WorkerListener* listener = *item;
2350             CloseHelp::DeletePointer(listener, false);
2351         }
2352     }
2353     eventListeners_.clear();
2354 }
2355 
ReleaseHostThreadContent()2356 void Worker::ReleaseHostThreadContent()
2357 {
2358     ClearHostMessage(hostEnv_);
2359     if (!HostIsStop()) {
2360         napi_status status = napi_ok;
2361         HandleScope scope(hostEnv_, status);
2362         NAPI_CALL_RETURN_VOID(hostEnv_, status);
2363         // 3. set thisVar's nativepointer be null
2364         napi_value thisVar = NapiHelper::GetReferenceValue(hostEnv_, workerRef_);
2365         Worker* worker = nullptr;
2366         napi_remove_wrap(hostEnv_, thisVar, reinterpret_cast<void**>(&worker));
2367         hostEnv_ = nullptr;
2368         // 4. set workerRef_ be null
2369         workerRef_ = nullptr;
2370     }
2371 }
2372 
WorkerOnErrorInner(napi_value error)2373 void Worker::WorkerOnErrorInner(napi_value error)
2374 {
2375     isErrorExit_ = true;
2376     napi_value argv[1] = { error };
2377     CallWorkerFunction(1, argv, "onerror", false);
2378     napi_value obj = NapiHelper::GetReferenceValue(workerEnv_, this->workerPort_);
2379     ParentPortHandleEventListeners(workerEnv_, obj, 1, argv, "error", false);
2380 }
2381 
CallWorkerFunction(size_t argc,const napi_value * argv,const char * methodName,bool tryCatch)2382 bool Worker::CallWorkerFunction(size_t argc, const napi_value* argv, const char* methodName, bool tryCatch)
2383 {
2384     if (workerEnv_ == nullptr) {
2385         HILOG_ERROR("Worker:: worker is not running when call workerPort.%{public}s.", methodName);
2386         return false;
2387     }
2388     napi_value callback = NapiHelper::GetNamePropertyInParentPort(workerEnv_, workerPort_, methodName);
2389     bool isCallable = NapiHelper::IsCallable(workerEnv_, callback);
2390     if (!isCallable) {
2391         HILOG_WARN("worker:: workerPort.%{public}s is not Callable", methodName);
2392         return false;
2393     }
2394     napi_value workerPortObj = NapiHelper::GetReferenceValue(workerEnv_, workerPort_);
2395     napi_value callbackResult = nullptr;
2396     napi_call_function(workerEnv_, workerPortObj, callback, argc, argv, &callbackResult);
2397     if (tryCatch && callbackResult == nullptr) {
2398         HILOG_ERROR("worker:: workerPort.%{public}s handle exception", methodName);
2399         HandleException();
2400         return false;
2401     }
2402     return true;
2403 }
2404 
CloseWorkerCallback()2405 void Worker::CloseWorkerCallback()
2406 {
2407     CallWorkerFunction(0, nullptr, "onclose", true);
2408     // off worker inited environment
2409     {
2410         std::lock_guard<std::recursive_mutex> lock(liveStatusLock_);
2411         if (HostIsStop() || isHostEnvExited_) {
2412             return;
2413         }
2414         auto hostEngine = reinterpret_cast<NativeEngine*>(hostEnv_);
2415         if (!hostEngine->CallOffWorkerFunc(reinterpret_cast<NativeEngine*>(workerEnv_))) {
2416             HILOG_ERROR("worker:: CallOffWorkerFunc error");
2417         }
2418     }
2419 }
2420 
ReleaseWorkerThreadContent()2421 void Worker::ReleaseWorkerThreadContent()
2422 {
2423     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
2424     {
2425         std::lock_guard<std::recursive_mutex> lock(liveStatusLock_);
2426         if (!HostIsStop() && !isHostEnvExited_) {
2427             auto hostEngine = reinterpret_cast<NativeEngine*>(hostEnv_);
2428             auto workerEngine = reinterpret_cast<NativeEngine*>(workerEnv_);
2429             if (hostEngine != nullptr && workerEngine != nullptr) {
2430                 if (!hostEngine->DeleteWorker(workerEngine)) {
2431                     HILOG_ERROR("worker:: DeleteWorker error");
2432                 }
2433                 hostEngine->DecreaseSubEnvCounter();
2434             }
2435         }
2436     }
2437     // 1. delete worker listener
2438     ParentPortRemoveAllListenerInner();
2439 
2440     // 2. delete worker's parentPort
2441     NapiHelper::DeleteReference(workerEnv_, workerPort_);
2442     workerPort_ = nullptr;
2443 
2444     // 3. clear message send to worker thread
2445     workerMessageQueue_.Clear(workerEnv_);
2446     workerGlobalCallQueue_.Clear(workerEnv_);
2447     CloseHelp::DeletePointer(reinterpret_cast<NativeEngine*>(workerEnv_), false);
2448     workerEnv_ = nullptr;
2449 }
2450 
ParentPortAddListenerInner(napi_env env,const char * type,const WorkerListener * listener)2451 void Worker::ParentPortAddListenerInner(napi_env env, const char* type, const WorkerListener* listener)
2452 {
2453     std::string typestr(type);
2454     auto iter = parentPortEventListeners_.find(typestr);
2455     if (iter == parentPortEventListeners_.end()) {
2456         std::list<WorkerListener*> listeners;
2457         listeners.emplace_back(const_cast<WorkerListener*>(listener));
2458         parentPortEventListeners_[typestr] = listeners;
2459     } else {
2460         std::list<WorkerListener*>& listenerList = iter->second;
2461         std::list<WorkerListener*>::iterator it = std::find_if(
2462             listenerList.begin(), listenerList.end(), Worker::FindWorkerListener(env, listener->callback_));
2463         if (it != listenerList.end()) {
2464             return;
2465         }
2466         listenerList.emplace_back(const_cast<WorkerListener*>(listener));
2467     }
2468 }
2469 
ParentPortRemoveAllListenerInner()2470 void Worker::ParentPortRemoveAllListenerInner()
2471 {
2472     for (auto iter = parentPortEventListeners_.begin(); iter != parentPortEventListeners_.end(); iter++) {
2473         std::list<WorkerListener*>& listeners = iter->second;
2474         for (auto item = listeners.begin(); item != listeners.end(); item++) {
2475             WorkerListener* listener = *item;
2476             CloseHelp::DeletePointer(listener, false);
2477         }
2478     }
2479     parentPortEventListeners_.clear();
2480 }
2481 
ParentPortRemoveListenerInner(napi_env env,const char * type,napi_ref callback)2482 void Worker::ParentPortRemoveListenerInner(napi_env env, const char* type, napi_ref callback)
2483 {
2484     std::string typestr(type);
2485     auto iter = parentPortEventListeners_.find(typestr);
2486     if (iter == parentPortEventListeners_.end()) {
2487         return;
2488     }
2489     std::list<WorkerListener*>& listenerList = iter->second;
2490     if (callback != nullptr) {
2491         std::list<WorkerListener*>::iterator it =
2492             std::find_if(listenerList.begin(), listenerList.end(), Worker::FindWorkerListener(env, callback));
2493         if (it != listenerList.end()) {
2494             CloseHelp::DeletePointer(*it, false);
2495             listenerList.erase(it);
2496         }
2497     } else {
2498         for (auto it = listenerList.begin(); it != listenerList.end(); it++) {
2499             CloseHelp::DeletePointer(*it, false);
2500         }
2501         parentPortEventListeners_.erase(typestr);
2502     }
2503 }
2504 
ParentPortHandleEventListeners(napi_env env,napi_value recv,size_t argc,const napi_value * argv,const char * type,bool tryCatch)2505 void Worker::ParentPortHandleEventListeners(napi_env env, napi_value recv, size_t argc,
2506                                             const napi_value* argv, const char* type, bool tryCatch)
2507 {
2508     std::string listener(type);
2509     auto iter = parentPortEventListeners_.find(listener);
2510     if (iter == parentPortEventListeners_.end()) {
2511         HILOG_DEBUG("worker:: there is no listener for type %{public}s in worker thread", type);
2512         return;
2513     }
2514 
2515     std::list<WorkerListener*>& listeners = iter->second;
2516     std::list<WorkerListener*>::iterator it = listeners.begin();
2517     while (it != listeners.end()) {
2518         WorkerListener* data = *it++;
2519         napi_value callbackObj = NapiHelper::GetReferenceValue(env, data->callback_);
2520         if (!NapiHelper::IsCallable(env, callbackObj)) {
2521             HILOG_WARN("worker:: workerPort.addEventListener %{public}s is not callable", type);
2522             return;
2523         }
2524         napi_value callbackResult = nullptr;
2525         napi_call_function(env, recv, callbackObj, argc, argv, &callbackResult);
2526         if (!data->NextIsAvailable()) {
2527             listeners.remove(data);
2528             CloseHelp::DeletePointer(data, false);
2529         }
2530         if (tryCatch && callbackResult == nullptr) {
2531             HandleException();
2532             return;
2533         }
2534     }
2535 }
2536 
WorkerThrowError(napi_env env,int32_t errCode,const char * errMessage)2537 void Worker::WorkerThrowError(napi_env env, int32_t errCode, const char* errMessage)
2538 {
2539     auto mainThreadEngine = NativeEngine::GetMainThreadEngine();
2540     if (mainThreadEngine == nullptr) {
2541         HILOG_ERROR("worker:: mainThreadEngine is nullptr");
2542         return;
2543     }
2544     if (mainThreadEngine->IsTargetWorkerVersion(WorkerVersion::NEW)) {
2545         ErrorHelper::ThrowError(env, errCode, errMessage);
2546     }
2547 }
2548 
CanCreateWorker(napi_env env,WorkerVersion target)2549 bool Worker::CanCreateWorker(napi_env env, WorkerVersion target)
2550 {
2551     auto mainThreadEngine = NativeEngine::GetMainThreadEngine();
2552     if (mainThreadEngine == nullptr) {
2553         HILOG_ERROR("worker:: mainThreadEngine is nullptr");
2554         return false;
2555     }
2556     if (mainThreadEngine->CheckAndSetWorkerVersion(WorkerVersion::NONE, target) ||
2557         mainThreadEngine->IsTargetWorkerVersion(target)) {
2558         return true;
2559     }
2560     return false;
2561 }
2562 
2563 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
HandleDebuggerTask(const uv_async_t * req)2564 void Worker::HandleDebuggerTask(const uv_async_t* req)
2565 {
2566     Worker* worker = static_cast<Worker*>(req->data);
2567     if (worker == nullptr) {
2568         HILOG_ERROR("worker::worker is null");
2569         return;
2570     }
2571 
2572     worker->debuggerMutex_.lock();
2573     auto task = std::move(worker->debuggerQueue_.front());
2574     worker->debuggerQueue_.pop();
2575     worker->debuggerMutex_.unlock();
2576     task();
2577 }
2578 
DebuggerOnPostTask(std::function<void ()> && task)2579 void Worker::DebuggerOnPostTask(std::function<void()>&& task)
2580 {
2581     if (IsTerminated()) {
2582         HILOG_ERROR("worker:: worker has been terminated.");
2583         return;
2584     }
2585     if (ConcurrentHelper::IsUvActive(debuggerOnPostTaskSignal_)) {
2586         std::lock_guard<std::mutex> lock(debuggerMutex_);
2587         debuggerQueue_.push(std::move(task));
2588         uv_async_send(debuggerOnPostTaskSignal_);
2589     }
2590 }
2591 #endif
2592 
InitHostHandle(uv_loop_t * loop)2593 void Worker::InitHostHandle(uv_loop_t* loop)
2594 {
2595     ConcurrentHelper::UvHandleInit(loop, hostOnMessageSignal_, Worker::HostOnMessage, this);
2596     ConcurrentHelper::UvHandleInit(loop, hostOnErrorSignal_, Worker::HostOnError, this);
2597     ConcurrentHelper::UvHandleInit(loop, hostOnAllErrorsSignal_, Worker::HostOnAllErrors, this);
2598     ConcurrentHelper::UvHandleInit(loop, hostOnGlobalCallSignal_, Worker::HostOnGlobalCall, this);
2599 }
2600 
CloseHostHandle()2601 void Worker::CloseHostHandle()
2602 {
2603     if (ConcurrentHelper::IsUvActive(hostOnMessageSignal_)) {
2604         ConcurrentHelper::UvHandleClose(hostOnMessageSignal_);
2605     }
2606     if (ConcurrentHelper::IsUvActive(hostOnErrorSignal_)) {
2607         ConcurrentHelper::UvHandleClose(hostOnErrorSignal_);
2608     }
2609     if (ConcurrentHelper::IsUvActive(hostOnAllErrorsSignal_)) {
2610         ConcurrentHelper::UvHandleClose(hostOnAllErrorsSignal_);
2611     }
2612     if (ConcurrentHelper::IsUvActive(hostOnGlobalCallSignal_)) {
2613         ConcurrentHelper::UvHandleClose(hostOnGlobalCallSignal_);
2614     }
2615 }
2616 
EraseWorker()2617 void Worker::EraseWorker()
2618 {
2619     if (!isLimitedWorker_) {
2620         std::lock_guard<std::mutex> lock(g_workersMutex);
2621         std::list<Worker*>::iterator it = std::find(g_workers.begin(), g_workers.end(), this);
2622         if (it != g_workers.end()) {
2623             Worker* worker = *it;
2624             if (worker != nullptr) {
2625                 WorkerManager::DecrementWorkerCount(worker->workerType_);
2626             }
2627             g_workers.erase(it);
2628         }
2629     } else {
2630         std::lock_guard<std::mutex> lock(g_limitedworkersMutex);
2631         std::list<Worker*>::iterator it = std::find(g_limitedworkers.begin(), g_limitedworkers.end(), this);
2632         if (it != g_limitedworkers.end()) {
2633             Worker* worker = *it;
2634             if (worker != nullptr) {
2635                 WorkerManager::DecrementWorkerCount(worker->workerType_);
2636             }
2637             g_limitedworkers.erase(it);
2638         }
2639     }
2640 }
2641 
ClearHostMessage(napi_env env)2642 void Worker::ClearHostMessage(napi_env env)
2643 {
2644     hostMessageQueue_.Clear(env);
2645     hostGlobalCallQueue_.Clear(env);
2646     errorQueue_.Clear(env);
2647     exceptionQueue_.Clear(env);
2648 }
2649 
2650 #ifdef ENABLE_QOS
SetQOSLevel()2651 void Worker::SetQOSLevel()
2652 {
2653     if (workerPriority_ == WorkerPriority::INVALID) {
2654         return;
2655     }
2656     auto iter = WORKERPRIORITY_QOSLEVEL_MAP.find(workerPriority_);
2657     if (iter == WORKERPRIORITY_QOSLEVEL_MAP.end()) {
2658         HILOG_ERROR("worker:: not in WORKERPRIORITY_QOSLEVEL_MAP");
2659         return;
2660     }
2661     OHOS::QOS::QosLevel qosLevel = iter->second;
2662     if (qosLevel != OHOS::QOS::QosLevel::QOS_MAX) {
2663         HILOG_INFO("SetThreadQos %{public}d", qosLevel);
2664         int ret = SetThreadQos(qosLevel);
2665         if (ret != 0) {
2666             HILOG_ERROR("worker:: SetThreadQos failed, return %{public}d", ret);
2667         }
2668         if (qosUpdatedCallback_ != nullptr) {
2669             qosUpdatedCallback_();
2670         }
2671     }
2672 }
2673 #endif
2674 
HostOnAllErrors(const uv_async_t * req)2675 void Worker::HostOnAllErrors(const uv_async_t* req)
2676 {
2677     Worker* worker = static_cast<Worker*>(req->data);
2678     if (worker == nullptr) {
2679         HILOG_ERROR("worker:: worker is null");
2680         return;
2681     }
2682     worker->HostOnAllErrorsInner();
2683 }
2684 
HandleWorkerUncaughtException(napi_env env,napi_value exception)2685 void Worker::HandleWorkerUncaughtException(napi_env env, napi_value exception)
2686 {
2687     if (NapiHelper::IsExceptionPending(env)) {
2688         napi_get_and_clear_last_exception(env, &exception);
2689     }
2690 
2691     if (hostEnv_ == nullptr) {
2692         HILOG_ERROR("worker:: host engine is nullptr.");
2693         return;
2694     }
2695 
2696     MessageDataType data = nullptr;
2697     napi_value undefined = NapiHelper::GetUndefinedValue(env);
2698     napi_serialize_inner(env, exception, undefined, undefined, false, true, &data);
2699     {
2700         std::lock_guard<std::recursive_mutex> lock(liveStatusLock_);
2701         if (HostIsStop() || isHostEnvExited_) {
2702             return;
2703         }
2704         exceptionQueue_.EnQueue(data);
2705 #if defined(ENABLE_WORKER_EVENTHANDLER)
2706         if (isMainThreadWorker_ && !isLimitedWorker_) {
2707             PostWorkerExceptionTask();
2708         } else {
2709             uv_async_send(hostOnAllErrorsSignal_);
2710         }
2711 #else
2712         uv_async_send(hostOnAllErrorsSignal_);
2713 #endif
2714     }
2715 }
2716 
HostOnAllErrorsInner()2717 void Worker::HostOnAllErrorsInner()
2718 {
2719     if (hostEnv_ == nullptr || HostIsStop()) {
2720         HILOG_ERROR("worker:: host thread maybe is over when host onerror.");
2721         return;
2722     }
2723     napi_status status = napi_ok;
2724     HandleScope scope(hostEnv_, status);
2725     NAPI_CALL_RETURN_VOID(hostEnv_, status);
2726     NativeEngine* hostEngine = reinterpret_cast<NativeEngine*>(hostEnv_);
2727     ContainerScope containerScope(hostEngine, scopeId_);
2728     if (!containerScope.IsInitialized()) {
2729         HILOG_WARN("worker:: InitContainerScopeFunc error when HostOnAllErrorsInner begin(only stage model)");
2730     }
2731 
2732     napi_value obj = NapiHelper::GetReferenceValue(hostEnv_, workerRef_);
2733     napi_value callback = NapiHelper::GetNameProperty(hostEnv_, obj, "onAllErrors");
2734     bool isCallable = NapiHelper::IsCallable(hostEnv_, callback);
2735     if (!isCallable) {
2736         HILOG_INFO("worker:: worker may not register onAllErrors.");
2737         exceptionQueue_.Clear(hostEnv_);
2738         return;
2739     }
2740 
2741     MessageDataType data = nullptr;
2742     while (exceptionQueue_.DeQueue(&data)) {
2743         if (data == nullptr) {
2744             return;
2745         }
2746         napi_value result = nullptr;
2747         napi_deserialize(hostEnv_, data, &result);
2748         napi_delete_serialization_data(hostEnv_, data);
2749 
2750         napi_value argv[1] = { result };
2751         napi_value callbackResult = nullptr;
2752         napi_call_function(hostEnv_, obj, callback, 1, argv, &callbackResult);
2753         HandleHostException();
2754     }
2755 }
2756 } // namespace Commonlibrary::Concurrent::WorkerModule
2757