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