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