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