diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..f433b1a53f5b830a205fd2df78e2b34974656c7b
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,177 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
diff --git a/OAT.xml b/OAT.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e7ffe698d19486f77961f350929fce3538ed91f8
--- /dev/null
+++ b/OAT.xml
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jsapi/BUILD.gn b/jsapi/BUILD.gn
new file mode 100644
index 0000000000000000000000000000000000000000..ff9a25824ebec138c051ec7c4c00533d6652c558
--- /dev/null
+++ b/jsapi/BUILD.gn
@@ -0,0 +1,51 @@
+# Copyright (c) 2021 Huawei Device Co., Ltd.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//build/ohos.gni")
+
+ohos_shared_library("worker") {
+ include_dirs = [
+ "//base/compileruntime/js_worker_module/jsapi/worker",
+ "//base/compileruntime/js_worker_module/jsapi/interfaces/innerkits/worker_core/include",
+ ]
+
+ sources = [
+ "worker/message_queue.cpp",
+ "worker/native_module_worker.cpp",
+ "worker/thread.cpp",
+ "worker/worker.cpp",
+ "worker/worker_helper.cpp",
+ "worker/worker_runner.cpp",
+ ]
+
+ deps = [
+ "//base/compileruntime/js_worker_module/jsapi/interfaces/innerkits/worker_core:worker_init",
+ "//foundation/ace/napi:ace_napi",
+ "//foundation/ace/napi:ace_napi_quickjs",
+ ]
+
+ if (is_standard_system) {
+ external_deps = [ "hiviewdfx_hilog_native:libhilog" ]
+ } else {
+ external_deps = [ "hilog:libhilog" ]
+ }
+
+ subsystem_name = "ccruntime"
+ part_name = "jsapi_worker"
+
+ relative_install_dir = "module"
+}
+
+group("jsapi_packages") {
+ deps = [ ":worker" ]
+}
diff --git a/jsapi/interfaces/innerkits/worker_core/BUILD.gn b/jsapi/interfaces/innerkits/worker_core/BUILD.gn
new file mode 100644
index 0000000000000000000000000000000000000000..e4b5abde63cc91af2f856288179a1f9e48cb0db2
--- /dev/null
+++ b/jsapi/interfaces/innerkits/worker_core/BUILD.gn
@@ -0,0 +1,39 @@
+# Copyright (c) 2021 Huawei Device Co., Ltd.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//build/ohos.gni")
+
+config("worker_init_config") {
+ include_dirs = [ "//base/compileruntime/js_worker_module/jsapi/interfaces/innerkits/worker_core/include" ]
+}
+
+ohos_shared_library("worker_init") {
+ include_dirs = [ "//base/compileruntime/js_worker_module/jsapi/interfaces/innerkits/worker_core/include" ]
+
+ sources =
+ [ "//base/compileruntime/js_worker_module/jsapi/worker/worker_init.cpp" ]
+
+ deps = [
+ "//foundation/ace/napi:ace_napi",
+ "//foundation/ace/napi:ace_napi_quickjs",
+ ]
+
+ public_configs = [ ":worker_init_config" ]
+
+ subsystem_name = "ccruntime"
+ part_name = "jsapi_worker"
+}
+
+group("jsapi_init_packages") {
+ deps = [ ":worker_init" ]
+}
diff --git a/jsapi/interfaces/innerkits/worker_core/include/worker_init.h b/jsapi/interfaces/innerkits/worker_core/include/worker_init.h
new file mode 100644
index 0000000000000000000000000000000000000000..2f33c9976cafc8f3bd8c1e153bbcfb9956155b86
--- /dev/null
+++ b/jsapi/interfaces/innerkits/worker_core/include/worker_init.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FOUNDATION_CCRUNTIME_JSAPI_INTERFACES_INNERKITS_WORKER_CORE_INCLUDE_H
+#define FOUNDATION_CCRUNTIME_JSAPI_INTERFACES_INNERKITS_WORKER_CORE_INCLUDE_H
+
+#include
+
+#include "native_engine/native_engine.h"
+
+using InitWorkerFunc = std::function;
+using GetAssetFunc = std::function&)>;
+using OffWorkerFunc = std::function;
+
+namespace OHOS::CCRuntime::Worker {
+class WorkerCore {
+public:
+ static InitWorkerFunc initWorkerFunc;
+ static void RegisterInitWorkerFunc(InitWorkerFunc func);
+
+ static GetAssetFunc getAssertFunc;
+ static void RegisterAssetFunc(GetAssetFunc func);
+
+ static OffWorkerFunc offWorkerFunc;
+ static void RegisterOffWorkerFunc(OffWorkerFunc func);
+};
+} // namespace OHOS::CCRuntime::Worker
+#endif // FOUNDATION_CCRUNTIME_JSAPI_INTERFACES_INNERKITS_WORKER_CORE_INCLUDE_H
diff --git a/jsapi/worker/message_queue.cpp b/jsapi/worker/message_queue.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1ef3de08f23840ce0da12fc1944c5859f5bff944
--- /dev/null
+++ b/jsapi/worker/message_queue.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "message_queue.h"
+
+namespace OHOS::CCRuntime::Worker {
+void MessageQueue::EnQueue(MessageDataType data)
+{
+ queueLock_.lock();
+ queue_.push(data);
+ queueLock_.unlock();
+}
+
+bool MessageQueue::DeQueue(MessageDataType *data)
+{
+ queueLock_.lock();
+ if (queue_.empty()) {
+ queueLock_.unlock();
+ return false;
+ }
+ *data = queue_.front();
+ queue_.pop();
+ queueLock_.unlock();
+ return true;
+}
+
+bool MessageQueue::IsEmpty() const
+{
+ return queue_.empty();
+}
+
+void MessageQueue::Clear(napi_env env)
+{
+ queueLock_.lock();
+ size_t size = queue_.size();
+ for (size_t i = 0; i < size; i++) {
+ MessageDataType data = queue_.front();
+ napi_delete_serialization_data(env, data);
+ queue_.pop();
+ }
+ queueLock_.unlock();
+}
+} // namespace worker
\ No newline at end of file
diff --git a/jsapi/worker/message_queue.h b/jsapi/worker/message_queue.h
new file mode 100644
index 0000000000000000000000000000000000000000..ff4c7c5c37c23e5b847571902593921ddc674dd5
--- /dev/null
+++ b/jsapi/worker/message_queue.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FOUNDATION_CCRUNTIME_JSAPI_WORKER_MESSAGE_QUEUE_H
+#define FOUNDATION_CCRUNTIME_JSAPI_WORKER_MESSAGE_QUEUE_H
+
+#include
+#include
+#include "napi/native_api.h"
+
+namespace OHOS::CCRuntime::Worker {
+using MessageDataType = napi_value;
+class MessageQueue final {
+public:
+ void EnQueue(MessageDataType data);
+ bool DeQueue(MessageDataType *data);
+ bool IsEmpty() const;
+ void Clear(napi_env env);
+ size_t GetSize() const
+ {
+ return queue_.size();
+ }
+
+private:
+ std::mutex queueLock_;
+ std::queue queue_;
+};
+} // namespace OHOS::CCRuntime::Worker
+#endif // FOUNDATION_CCRUNTIME_JSAPI_WORKER_MESSAGE_QUEUE_H
diff --git a/jsapi/worker/native_module_worker.cpp b/jsapi/worker/native_module_worker.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c7386e2a959553c3a79ef4e8a0da8614a6a733de
--- /dev/null
+++ b/jsapi/worker/native_module_worker.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "worker.h"
+
+/*
+ * module define
+ */
+static napi_module g_workerModule = {
+ .nm_version = 1,
+ .nm_flags = 0,
+ .nm_filename = nullptr,
+ .nm_register_func = OHOS::CCRuntime::Worker::Worker::InitWorker,
+ .nm_modname = "worker",
+ .nm_priv = ((void*)0),
+ .reserved = { 0 },
+};
+/*
+ * module register
+ */
+extern "C" __attribute__((constructor)) void Register()
+{
+ napi_module_register(&g_workerModule);
+}
\ No newline at end of file
diff --git a/jsapi/worker/thread.cpp b/jsapi/worker/thread.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..79dacaa44772ac6f06cc1aa70a828ecf2005de8c
--- /dev/null
+++ b/jsapi/worker/thread.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "thread.h"
+
+namespace OHOS::CCRuntime::Worker {
+Thread::Thread() : tId_() {}
+
+bool Thread::Start()
+{
+ int ret = uv_thread_create(&tId_, [](void* arg) {
+ Thread* thread = reinterpret_cast(arg);
+ thread->Run();
+ }, this);
+ return ret != 0;
+}
+} // namespace OHOS::CCRuntime::Worker
\ No newline at end of file
diff --git a/jsapi/worker/thread.h b/jsapi/worker/thread.h
new file mode 100644
index 0000000000000000000000000000000000000000..c0e047047620d621652a6f824e2a05aa7b2d9e21
--- /dev/null
+++ b/jsapi/worker/thread.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FOUNDATION_CCRUNTIME_JSAPI_WORKER_THREAD_H
+#define FOUNDATION_CCRUNTIME_JSAPI_WORKER_THREAD_H
+
+#include
+
+namespace OHOS::CCRuntime::Worker {
+class Thread {
+public:
+ Thread();
+ virtual ~Thread() = default;
+ bool Start();
+ virtual void Run() = 0;
+
+ uv_thread_t GetThreadId() const
+ {
+ return tId_;
+ }
+
+private:
+ uv_thread_t tId_ {0};
+};
+} // namespace OHOS::CCRuntime::Worker
+
+#endif // #define FOUNDATION_CCRUNTIME_JSAPI_WORKER_THREAD_H
\ No newline at end of file
diff --git a/jsapi/worker/worker.cpp b/jsapi/worker/worker.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a3a1aaf75ec79d1d068769c29a7f6c7a74a88a63
--- /dev/null
+++ b/jsapi/worker/worker.cpp
@@ -0,0 +1,1055 @@
+/*
+ * Copyright (c) 2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "worker.h"
+
+#include "worker_init.h"
+
+namespace OHOS::CCRuntime::Worker {
+const static int MAXWORKERS = 50;
+static std::list g_workers;
+static std::mutex g_workersMutex;
+
+Worker::Worker(NativeEngine* env, napi_ref thisVar)
+ : script_(nullptr), name_(nullptr), scriptMode_(CLASSIC), runnerState_(STARTING), runner_(nullptr),
+ mainEngine_(env), workerEngine_(nullptr), workerWrapper_(thisVar), parentPort_(nullptr)
+{}
+
+void Worker::StartExecuteInThread(napi_env env, const char* script)
+{
+ // 1. init mainOnMessageSignal_ in main loop
+ auto engine = reinterpret_cast(env);
+ uv_loop_t* loop = engine->GetUVLoop();
+ if (loop == nullptr) {
+ napi_throw_error(env, nullptr, "worker::engine loop is null");
+ return;
+ }
+ uv_async_init(loop, &mainOnMessageSignal_, reinterpret_cast(Worker::MainOnMessage));
+ uv_async_init(loop, &mainOnErrorSignal_, reinterpret_cast(Worker::MainOnError));
+
+ // 2. copy the script
+ script_ = strdup(script);
+ CloseHelp::DeletePointer(script, true);
+
+ // 4. create WorkerRunner to Execute
+ if (runner_ == nullptr) {
+ runner_ = new WorkerRunner(WorkerStartCallback(ExecuteInThread, this));
+ }
+ runner_->Execute(); // start a new thread
+}
+
+void Worker::CloseInner()
+{
+ UpdateWorkerState(TERMINATEING);
+ TerminateWorker();
+}
+
+napi_value Worker::CloseWorker(napi_env env, napi_callback_info cbinfo)
+{
+ Worker* worker = nullptr;
+ napi_get_cb_info(env, cbinfo, nullptr, nullptr, nullptr, (void**)&worker);
+ if (worker != nullptr) {
+ worker->CloseInner();
+ }
+ return NapiValueHelp::GetUndefinedValue(env);
+}
+
+void CallWorkCallback(napi_env env, napi_value recv, size_t argc, const napi_value* argv, const char* type)
+{
+ napi_value callback = nullptr;
+ napi_get_named_property(env, recv, type, &callback);
+ if (NapiValueHelp::IsCallable(env, callback)) {
+ napi_value callbackResult = nullptr;
+ napi_call_function(env, recv, callback, 1, argv, &callbackResult);
+ }
+}
+
+void Worker::PrepareForWorkerInstance(const Worker* worker)
+{
+ napi_env env = reinterpret_cast(const_cast(worker->GetWorkerEngine()));
+ // 1. init worker environment
+ if (OHOS::CCRuntime::Worker::WorkerCore::initWorkerFunc != NULL) {
+ OHOS::CCRuntime::Worker::WorkerCore::initWorkerFunc(const_cast(worker->GetWorkerEngine()));
+ }
+ // 2. Execute script
+ if (OHOS::CCRuntime::Worker::WorkerCore::getAssertFunc == NULL) {
+ HILOG_ERROR("worker::getAssertFunc is null");
+ napi_throw_error(env, nullptr, "worker::getAssertFunc is null");
+ return;
+ }
+ std::vector scriptContent;
+ OHOS::CCRuntime::Worker::WorkerCore::getAssertFunc(std::string(worker->GetScript()), scriptContent);
+ std::string stringContent(scriptContent.begin(), scriptContent.end());
+ HILOG_INFO("worker:: stringContent = %{private}s", stringContent.c_str());
+ napi_value scriptStringNapiValue = nullptr;
+ napi_create_string_utf8(env, stringContent.c_str(), stringContent.length(), &scriptStringNapiValue);
+
+ napi_value execScriptResult = nullptr;
+ napi_run_script(env, scriptStringNapiValue, &execScriptResult);
+ if (execScriptResult == nullptr) {
+ // An exception occurred when running the script.
+ HILOG_ERROR("worker:: run script exception occurs, will handle exception");
+ (const_cast(worker))->HandleException(worker->GetWorkerEngine());
+ return;
+ }
+
+ // 3. register postMessage in DedicatedWorkerGlobalScope
+ napi_value postFunctionObj = nullptr;
+ napi_create_function(env, "postMessage", NAPI_AUTO_LENGTH, Worker::PostMessageToMain,
+ const_cast(worker), &postFunctionObj);
+ NapiValueHelp::SetNamePropertyInGlobal(env, "postMessage", postFunctionObj);
+ // 4. register close in DedicatedWorkerGlobalScope
+ napi_value closeFuncObj = nullptr;
+ napi_create_function(env, "close", NAPI_AUTO_LENGTH, Worker::CloseWorker,
+ const_cast(worker), &closeFuncObj);
+ NapiValueHelp::SetNamePropertyInGlobal(env, "close", closeFuncObj);
+ // 5. register worker name in DedicatedWorkerGlobalScope
+ if (worker->GetName() != nullptr) {
+ napi_value nameValue = nullptr;
+ napi_create_string_utf8(env, worker->GetName(), strlen(worker->GetName()), &nameValue);
+ NapiValueHelp::SetNamePropertyInGlobal(env, "name", nameValue);
+ }
+}
+
+bool Worker::UpdateWorkerState(RunnerState state)
+{
+ bool done = false;
+ do {
+ RunnerState oldState = runnerState_.load(std::memory_order_acquire);
+ if (oldState < state) {
+ done = runnerState_.compare_exchange_strong(oldState, state);
+ } else {
+ return false;
+ }
+ } while (!done);
+ return true;
+}
+
+void Worker::PublishWorkerOverSignal()
+{
+ // post NULL tell main worker is not running
+ mainMessageQueue_.EnQueue(NULL);
+ uv_async_send(&mainOnMessageSignal_);
+ // mainEngine_->TriggerPostTask();
+}
+
+void Worker::ExecuteInThread(const void* data)
+{
+ auto worker = reinterpret_cast(const_cast(data));
+ // 1. create a runtime, nativeengine
+ napi_env env = reinterpret_cast(const_cast(worker->GetMainEngine()));
+ napi_env newEnv = nullptr;
+ napi_create_runtime(env, &newEnv);
+ if (newEnv == nullptr) {
+ napi_throw_error(env, nullptr, "Worker create runtime error");
+ return;
+ }
+ NativeEngine *workerEngine = reinterpret_cast(newEnv);
+ // mark worker env is subThread
+ workerEngine->MarkSubThread();
+ worker->SetWorkerEngine(workerEngine);
+
+ uv_loop_t* loop = worker->GetWorkerLoop();
+ if (loop == nullptr) {
+ napi_throw_error(env, nullptr, "Worker loop is nullptr");
+ return;
+ }
+ uv_async_init(loop, &worker->workerOnMessageSignal_, reinterpret_cast(Worker::WorkerOnMessage));
+
+ if (worker->UpdateWorkerState(RUNNING)) {
+ // 2. add some preparation for the worker
+ PrepareForWorkerInstance(worker);
+ // 3. start worker loop
+ const NativeEngine* workerEngine = worker->GetWorkerEngine();
+ if (workerEngine == nullptr) {
+ HILOG_ERROR("worker::worker engine is null");
+ } else {
+ uv_async_send(&worker->workerOnMessageSignal_);
+ const_cast(workerEngine)->Loop(LOOP_DEFAULT);
+ }
+ } else {
+ worker->CloseInner();
+ }
+ worker->PublishWorkerOverSignal();
+}
+
+void Worker::MainOnMessage(const uv_async_t* req)
+{
+ Worker* worker = DereferenceHelp::DereferenceOf(&Worker::mainOnMessageSignal_, req);
+ if (worker == nullptr) {
+ HILOG_ERROR("worker::worker is null");
+ return;
+ }
+ worker->MainOnMessageInner(worker->GetMainEngine());
+}
+
+void Worker::MainOnErrorInner(const NativeEngine* engine)
+{
+ napi_env env = reinterpret_cast(const_cast(engine));
+ napi_value callback = nullptr;
+ napi_value obj = nullptr;
+ napi_get_reference_value(env, workerWrapper_, &obj);
+ napi_get_named_property(env, obj, "onerror", &callback);
+ bool isCallable = NapiValueHelp::IsCallable(env, callback);
+ if (!isCallable) {
+ HILOG_ERROR("worker:: worker onerror is not Callable");
+ return;
+ }
+ MessageDataType data;
+ while (errorQueue_.DeQueue(&data)) {
+ napi_value result = nullptr;
+ napi_deserialize(env, data, &result);
+
+ napi_value argv[1] = { result };
+ napi_value callbackResult = nullptr;
+ napi_call_function(env, obj, callback, 1, argv, &callbackResult);
+
+ // handle listeners
+ HandleEventListeners(env, obj, 1, argv, "error");
+ }
+}
+
+void Worker::MainOnError(const uv_async_t* req)
+{
+ Worker* worker = DereferenceHelp::DereferenceOf(&Worker::mainOnErrorSignal_, req);
+ if (worker == nullptr) {
+ HILOG_ERROR("worker::worker is null");
+ return;
+ }
+ worker->MainOnErrorInner(worker->GetMainEngine());
+ worker->TerminateInner();
+}
+
+void Worker::WorkerOnMessage(const uv_async_t* req)
+{
+ Worker* worker = DereferenceHelp::DereferenceOf(&Worker::workerOnMessageSignal_, req);
+ if (worker == nullptr) {
+ HILOG_ERROR("worker::worker is null");
+ return;
+ }
+ worker->WorkerOnMessageInner(worker->GetWorkerEngine());
+}
+
+void Worker::CloseMainCallback() const
+{
+ napi_value exitValue = nullptr;
+ napi_env env = reinterpret_cast(const_cast(GetMainEngine()));
+ napi_create_int32(env, 1, &exitValue);
+ napi_value argv[1] = { exitValue };
+ CallMainFunction(GetMainEngine(), 1, argv, "onexit");
+
+ std::lock_guard lock(g_workersMutex);
+ std::list::iterator it = std::find(g_workers.begin(), g_workers.end(), this);
+ if (it != g_workers.end()) {
+ g_workers.erase(it);
+ }
+ CloseHelp::DeletePointer(this, false);
+}
+
+void Worker::HandleEventListeners(napi_env env, napi_value recv, size_t argc, const napi_value* argv, const char* type)
+{
+ std::string listener(type);
+ auto iter = eventListeners_.find(listener);
+ if (iter == eventListeners_.end()) {
+ HILOG_INFO("worker:: there is no listener for type %{public}s", type);
+ return;
+ }
+
+ std::list& listeners = iter->second;
+ std::list::iterator it = listeners.begin();
+ while (it != listeners.end()) {
+ WorkerListener* data = *it++;
+ napi_ref callback = data->GetCallback();
+ napi_value callbackObj = nullptr;
+ napi_get_reference_value(env, callback, &callbackObj);
+ napi_value callbackResult = nullptr;
+ napi_call_function(env, recv, callbackObj, argc, argv, &callbackResult);
+ if (!data->NextIsAvailable()) {
+ listeners.remove(data);
+ CloseHelp::DeletePointer(data, false);
+ }
+ }
+}
+
+void Worker::MainOnMessageInner(const NativeEngine* engine)
+{
+ napi_env env = reinterpret_cast(const_cast(engine));
+
+ napi_value callback = nullptr;
+ napi_value obj = nullptr;
+ napi_get_reference_value(env, workerWrapper_, &obj);
+ napi_get_named_property(env, obj, "onmessage", &callback);
+ bool isCallable = NapiValueHelp::IsCallable(env, callback);
+
+ MessageDataType data = nullptr;
+ while (mainMessageQueue_.DeQueue(&data)) {
+ // receive close signal.
+ if (data == nullptr) {
+ HILOG_INFO("worker:: worker received close signal");
+ uv_unref((uv_handle_t*)&mainOnMessageSignal_);
+ uv_close((uv_handle_t*)&mainOnMessageSignal_, nullptr);
+
+ uv_unref((uv_handle_t*)&mainOnErrorSignal_);
+ uv_close((uv_handle_t*)&mainOnErrorSignal_, nullptr);
+ CloseMainCallback();
+ return;
+ }
+ if (!isCallable) {
+ // onmessage is not func, no need to continue
+ HILOG_ERROR("worker:: worker onmessage is not a callable");
+ return;
+ }
+ // handle data, call worker onMessage function to handle.
+ napi_value result = nullptr;
+ napi_deserialize(env, data, &result);
+ napi_value event = nullptr;
+ napi_create_object(env, &event);
+ napi_set_named_property(env, event, "data", result);
+ napi_value argv[1] = { event };
+ napi_value callbackResult = nullptr;
+ napi_call_function(env, obj, callback, 1, argv, &callbackResult);
+ // handle listeners.
+ HandleEventListeners(env, obj, 1, argv, "message");
+ }
+}
+
+void Worker::TerminateWorker()
+{
+ // when there is no active handle, worker loop will stop automatic.
+ std::lock_guard lock(workerAsyncMutex_);
+ uv_close((uv_handle_t*)&workerOnMessageSignal_, nullptr);
+ CloseWorkerCallback();
+ uv_loop_t* loop = GetWorkerLoop();
+ if (loop != nullptr) {
+ uv_stop(loop);
+ }
+ UpdateWorkerState(TERMINATED);
+}
+
+void Worker::HandleException(const NativeEngine* engine)
+{
+ // obj.message, obj.filename, obj.lineno, obj.colno
+ napi_env env = reinterpret_cast(const_cast(engine));
+ napi_value exception = nullptr;
+ napi_create_object(env, &exception);
+
+ napi_get_exception_info_for_worker(env, exception);
+
+ // add obj.filename
+ napi_value filenameValue = nullptr;
+ napi_create_string_utf8(env, script_, strlen(script_), &filenameValue);
+ napi_set_named_property(env, exception, "filename", filenameValue);
+
+ // WorkerGlobalScope onerror
+ WorkerOnErrorInner(engine, exception);
+
+ if (mainEngine_ != nullptr) {
+ napi_value data = nullptr;
+ napi_serialize(env, exception, NapiValueHelp::GetUndefinedValue(env), &data);
+ errorQueue_.EnQueue(data);
+ uv_async_send(&mainOnErrorSignal_);
+ // mainEngine_->TriggerPostTask();
+ } else {
+ HILOG_ERROR("worker:: main engine is nullptr.");
+ }
+}
+
+void Worker::WorkerOnMessageInner(const NativeEngine* engine)
+{
+ if (IsTerminated()) {
+ return;
+ }
+ MessageDataType data = nullptr;
+ napi_env env = reinterpret_cast(const_cast(engine));
+ while (workerMessageQueue_.DeQueue(&data)) {
+ if (data == NULL || IsTerminating()) {
+ HILOG_INFO("worker:: worker reveive terminate signal");
+ TerminateWorker();
+ return;
+ }
+ napi_value result = nullptr;
+ napi_status status = napi_deserialize(env, data, &result);
+ if (status != napi_ok || result == nullptr) {
+ WorkerOnMessageErrorInner(workerEngine_);
+ return;
+ }
+
+ napi_value event = nullptr;
+ napi_create_object(env, &event);
+ napi_set_named_property(env, event, "data", result);
+ napi_value argv[1] = { event };
+ bool callFeedback = CallWorkerFunction(engine, 1, argv, "onmessage", true);
+ if (!callFeedback) {
+ // onmessage is not function, exit the loop directly.
+ return;
+ }
+ }
+}
+
+void Worker::MainOnMessageErrorInner(const NativeEngine* engine)
+{
+ napi_env env = reinterpret_cast(const_cast(engine));
+ napi_value obj = nullptr;
+ napi_get_reference_value(env, workerWrapper_, &obj);
+ CallMainFunction(engine, 0, nullptr, "onmessageerror");
+ // handle listeners
+ HandleEventListeners(env, obj, 0, nullptr, "messageerror");
+}
+
+void Worker::WorkerOnMessageErrorInner(const NativeEngine* engine)
+{
+ CallWorkerFunction(engine, 0, nullptr, "onmessageerror", true);
+}
+
+napi_value Worker::PostMessage(napi_env env, napi_callback_info cbinfo)
+{
+ size_t argc = NapiValueHelp::GetCallbackInfoArgc(env, cbinfo);
+ if (argc < 1) {
+ napi_throw_error(env, nullptr, "Worker param count must be more than 1 with new");
+ return nullptr;
+ }
+ napi_value* argv = new napi_value[argc];
+ [[maybe_unused]] ObjectScope scope(argv, true);
+ napi_value thisVar = nullptr;
+ napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, nullptr);
+ Worker* worker = nullptr;
+ napi_unwrap(env, thisVar, (void**)&worker);
+
+ if (worker == nullptr) {
+ HILOG_ERROR("worker:: worker is nullptr when PostMessage, maybe worker is terminated");
+ return nullptr;
+ }
+
+ if (worker->IsTerminated() || worker->IsTerminating()) {
+ HILOG_INFO("worker:: worker not in running state");
+ return nullptr;
+ }
+
+ napi_value data = nullptr;
+ napi_status serializeStatus = napi_ok;
+ if (argc >= WORKERPARAMNUM) {
+ if (!NapiValueHelp::IsArray(argv[1])) {
+ napi_throw_error(env, nullptr, "Transfer list must be an Array");
+ return nullptr;
+ }
+ serializeStatus = napi_serialize(env, argv[0], argv[1], &data);
+ } else {
+ serializeStatus = napi_serialize(env, argv[0], NapiValueHelp::GetUndefinedValue(env), &data);
+ }
+ if (serializeStatus != napi_ok || data == nullptr) {
+ worker->MainOnMessageErrorInner(worker->GetMainEngine());
+ return nullptr;
+ }
+
+ if (data != nullptr) {
+ worker->PostMessageInner(data);
+ }
+
+ return NapiValueHelp::GetUndefinedValue(env);
+}
+
+napi_value Worker::PostMessageToMain(napi_env env, napi_callback_info cbinfo)
+{
+ size_t argc = NapiValueHelp::GetCallbackInfoArgc(env, cbinfo);
+ if (argc < 1) {
+ napi_throw_error(env, nullptr, "Worker param count must be more than 1 with new");
+ return nullptr;
+ }
+ napi_value* argv = new napi_value[argc];
+ [[maybe_unused]] ObjectScope scope(argv, true);
+ Worker* worker = nullptr;
+ napi_get_cb_info(env, cbinfo, &argc, argv, nullptr, (void**)&worker);
+
+ if (worker == nullptr) {
+ HILOG_ERROR("worker:: when post message to main occur worker is nullptr");
+ return nullptr;
+ }
+
+ if (!worker->IsRunning()) {
+ // if worker is not running, don't send any message to main thread
+ HILOG_INFO("worker:: when post message to main occur worker is not in running.");
+ return nullptr;
+ }
+
+ napi_value data = nullptr;
+ if (argc >= WORKERPARAMNUM) {
+ if (!NapiValueHelp::IsArray(argv[1])) {
+ napi_throw_error(env, nullptr, "Transfer list must be an Array");
+ return nullptr;
+ }
+ napi_serialize(env, argv[0], argv[1], &data);
+ } else {
+ napi_serialize(env, argv[0], NapiValueHelp::GetUndefinedValue(env), &data);
+ }
+
+ if (data != nullptr) {
+ worker->PostMessageToMainInner(data);
+ }
+
+ return NapiValueHelp::GetUndefinedValue(env);
+}
+
+void Worker::PostMessageToMainInner(MessageDataType data)
+{
+ if (mainEngine_ != nullptr) {
+ mainMessageQueue_.EnQueue(data);
+ uv_async_send(&mainOnMessageSignal_);
+ // mainEngine_->TriggerPostTask();
+ } else {
+ HILOG_ERROR("worker:: worker main engine is nullptr.");
+ }
+}
+
+void Worker::PostMessageInner(MessageDataType data)
+{
+ if (IsTerminating()) {
+ HILOG_INFO("worker:: worker is terminating, will not handle andy worker.");
+ return;
+ }
+ if (IsTerminated()) {
+ HILOG_INFO("worker:: worker has been terminated.");
+ return;
+ }
+ std::lock_guard lock(workerAsyncMutex_);
+ workerMessageQueue_.EnQueue(data);
+ if (IsRunning()) {
+ uv_async_send(&workerOnMessageSignal_);
+ }
+}
+
+napi_value Worker::Terminate(napi_env env, napi_callback_info cbinfo)
+{
+ napi_value thisVar = nullptr;
+ napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr);
+ Worker* worker = nullptr;
+ napi_unwrap(env, thisVar, (void**)&worker);
+ if (worker == nullptr) {
+ HILOG_ERROR("worker:: worker is nullptr when Terminate, maybe worker is terminated");
+ return nullptr;
+ }
+ if (worker->IsTerminated() || worker->IsTerminating()) {
+ HILOG_INFO("worker:: worker is not in running");
+ return nullptr;
+ }
+ worker->TerminateInner();
+ return NapiValueHelp::GetUndefinedValue(env);
+}
+
+void Worker::TerminateInner()
+{
+ // 1. send null signal
+ PostMessageInner(NULL);
+ UpdateWorkerState(TERMINATEING);
+}
+
+Worker::~Worker()
+{
+ CloseHelp::DeletePointer(script_, true);
+ script_ = nullptr;
+ CloseHelp::DeletePointer(name_, true);
+ name_ = nullptr;
+ napi_env env = reinterpret_cast(mainEngine_);
+ workerMessageQueue_.Clear(env);
+ mainMessageQueue_.Clear(env);
+ // set thisVar's nativepointer is null
+ napi_value thisVar = nullptr;
+ napi_get_reference_value(env, workerWrapper_, &thisVar);
+ Worker* worker = nullptr;
+ napi_remove_wrap(env, thisVar, (void**)&worker);
+
+ napi_delete_reference(env, workerWrapper_);
+ workerWrapper_ = nullptr;
+
+ napi_delete_reference(env, parentPort_);
+ parentPort_ = nullptr;
+
+ CloseHelp::DeletePointer(runner_, false);
+ runner_ = nullptr;
+
+ CloseHelp::DeletePointer(workerEngine_, false);
+ workerEngine_ = nullptr;
+
+ mainEngine_ = nullptr;
+ RemoveAllListenerInner();
+}
+
+napi_value Worker::WorkerConstructor(napi_env env, napi_callback_info cbinfo)
+{
+ // check argv count
+ size_t argc = NapiValueHelp::GetCallbackInfoArgc(env, cbinfo);
+ if (argc < 1) {
+ napi_throw_error(env, nullptr, "Worker param count must be more than 1 with new");
+ return nullptr;
+ }
+
+ // check 1st param is string
+ napi_value thisVar = nullptr;
+ void* data = nullptr;
+ napi_value* args = new napi_value[argc];
+ [[maybe_unused]] ObjectScope scope(args, true);
+ napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, &data);
+ if (!NapiValueHelp::IsString(args[0])) {
+ napi_throw_error(env, nullptr, "Worker 1st param must be string with new");
+ return nullptr;
+ }
+
+ std::lock_guard lock(g_workersMutex);
+ if (g_workers.size() >= MAXWORKERS) {
+ napi_throw_error(env, nullptr, "Too many workers, the number of workers exceeds the maximum.");
+ return nullptr;
+ }
+
+ // 2. new worker instance
+ NativeEngine* engine = reinterpret_cast(env);
+ Worker* worker = new Worker(engine, nullptr);
+ g_workers.push_back(worker);
+
+ if (argc > 1 && NapiValueHelp::IsObject(args[1])) {
+ napi_value nameValue = nullptr;
+ napi_get_named_property(env, args[1], "name", &nameValue);
+ if (NapiValueHelp::IsString(nameValue)) {
+ char* nameStr = NapiValueHelp::GetString(env, nameValue);
+ if (nameStr == nullptr) {
+ napi_throw_error(env, nullptr, "worker name create error, please check.");
+ return nullptr;
+ }
+ worker->name_ = strdup(nameStr);
+ CloseHelp::DeletePointer(nameStr, true);
+ }
+
+ napi_value typeValue = nullptr;
+ napi_get_named_property(env, args[1], "type", &typeValue);
+ if (NapiValueHelp::IsString(typeValue)) {
+ char* typeStr = NapiValueHelp::GetString(env, typeValue);
+ if (typeStr == nullptr) {
+ napi_throw_error(env, nullptr, "worker type create error, please check.");
+ return nullptr;
+ }
+ if (strcmp("classic", typeStr) == 0) {
+ worker->SetScriptMode(CLASSIC);
+ CloseHelp::DeletePointer(typeStr, true);
+ } else if (strcmp("module", typeStr) == 0) {
+ worker->SetScriptMode(MODULE);
+ napi_throw_error(env, nullptr, "unsupport module");
+ CloseHelp::DeletePointer(typeStr, true);
+ CloseHelp::DeletePointer(worker, false);
+ return nullptr;
+ } else {
+ worker->SetScriptMode(MODULE);
+ napi_throw_error(env, nullptr, "unsupport module");
+ CloseHelp::DeletePointer(typeStr, true);
+ CloseHelp::DeletePointer(worker, false);
+ return nullptr;
+ }
+ }
+ }
+
+ // 3. execute StartExecuteInThread;
+ char* script = NapiValueHelp::GetString(env, args[0]);
+ if (script == nullptr) {
+ napi_throw_error(env, nullptr, "worker script create error, please check.");
+ return nullptr;
+ }
+ HILOG_INFO("worker:: script is %{public}s", script);
+ worker->StartExecuteInThread(env, script);
+ napi_wrap(
+ env, thisVar, worker,
+ [](napi_env env, void* data, void* hint) {
+ Worker* worker = (Worker*)data;
+ auto iter = std::find(g_workers.begin(), g_workers.end(), worker);
+ if (iter == g_workers.end()) {
+ return;
+ }
+ if (worker->IsTerminated() || worker->IsTerminating()) {
+ HILOG_INFO("worker:: worker is not in running");
+ return;
+ }
+ worker->TerminateInner();
+ },
+ nullptr, nullptr);
+ napi_create_reference(env, thisVar, 1, &worker->workerWrapper_);
+ return thisVar;
+}
+
+napi_value Worker::AddListener(napi_env env, napi_callback_info cbinfo, ListenerMode mode)
+{
+ size_t argc = NapiValueHelp::GetCallbackInfoArgc(env, cbinfo);
+ if (argc < WORKERPARAMNUM) {
+ napi_throw_error(env, nullptr, "Worker param count must be more than WORKPARAMNUM with on");
+ return nullptr;
+ }
+ // check 1st param is string
+ napi_value thisVar = nullptr;
+ void* data = nullptr;
+ napi_value* args = new napi_value[argc];
+ [[maybe_unused]] ObjectScope scope(args, true);
+ napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, &data);
+ if (!NapiValueHelp::IsString(args[0])) {
+ napi_throw_error(env, nullptr, "Worker 1st param must be string with on");
+ return nullptr;
+ }
+ if (!NapiValueHelp::IsCallable(env, args[1])) {
+ napi_throw_error(env, nullptr, "Worker 2st param must be callable with on");
+ return nullptr;
+ }
+ Worker* worker = nullptr;
+ napi_unwrap(env, thisVar, (void**)&worker);
+ if (worker == nullptr) {
+ HILOG_ERROR("worker:: worker is nullptr when addListener, maybe worker is terminated");
+ return nullptr;
+ }
+
+ auto listener = new WorkerListener(worker, mode);
+ if (mode == ONCE && argc > WORKERPARAMNUM) {
+ if (NapiValueHelp::IsObject(args[2])) {
+ napi_value onceValue = nullptr;
+ napi_get_named_property(env, args[2], "once", &onceValue);
+ bool isOnce = false;
+ napi_get_value_bool(env, onceValue, &isOnce);
+ if (!isOnce) {
+ listener->SetMode(PERMANENT);
+ }
+ }
+ }
+ listener->SetCallable(env, args[1]);
+ char* typeStr = NapiValueHelp::GetString(env, args[0]);
+ if (typeStr == nullptr) {
+ CloseHelp::DeletePointer(listener, false);
+ napi_throw_error(env, nullptr, "worker listener type create error, please check.");
+ return nullptr;
+ }
+ worker->AddListenerInner(env, typeStr, listener);
+ CloseHelp::DeletePointer(typeStr, true);
+ return NapiValueHelp::GetUndefinedValue(env);
+}
+
+bool Worker::WorkerListener::operator==(const WorkerListener& listener) const
+{
+ if (listener.worker_ == nullptr) {
+ return false;
+ }
+ napi_env env = reinterpret_cast(const_cast(listener.worker_->GetMainEngine()));
+ napi_ref ref = listener.GetCallback();
+ napi_value obj = nullptr;
+ napi_get_reference_value(env, ref, &obj);
+
+ napi_value compareObj = nullptr;
+ napi_get_reference_value(env, callback_, &compareObj);
+ return obj == compareObj;
+}
+
+void Worker::AddListenerInner(napi_env env, const char* type, const WorkerListener* listener)
+{
+ std::string typestr(type);
+ auto iter = eventListeners_.find(typestr);
+ if (iter == eventListeners_.end()) {
+ std::list listeners;
+ listeners.emplace_back(const_cast(listener));
+ eventListeners_[typestr] = listeners;
+ } else {
+ std::list& listenerList = iter->second;
+ std::list::iterator it = std::find_if(
+ listenerList.begin(), listenerList.end(), Worker::FindWorkerListener(env, listener->GetCallback()));
+ if (it != listenerList.end()) {
+ return;
+ }
+ listenerList.emplace_back(const_cast(listener));
+ }
+}
+
+void Worker::RemoveListenerInner(napi_env env, const char* type, napi_ref callback)
+{
+ std::string typestr(type);
+ auto iter = eventListeners_.find(typestr);
+ if (iter == eventListeners_.end()) {
+ return;
+ }
+ std::list& listenerList = iter->second;
+ if (callback != nullptr) {
+ std::list::iterator it =
+ std::find_if(listenerList.begin(), listenerList.end(), Worker::FindWorkerListener(env, callback));
+ if (it != listenerList.end()) {
+ listenerList.erase(it);
+ CloseHelp::DeletePointer(*it, false);
+ }
+ } else {
+ for (auto it = listenerList.begin(); it != listenerList.end(); it++) {
+ CloseHelp::DeletePointer(*it, false);
+ }
+ eventListeners_.erase(typestr);
+ }
+}
+
+napi_value Worker::On(napi_env env, napi_callback_info cbinfo)
+{
+ return AddListener(env, cbinfo, PERMANENT);
+}
+
+napi_value Worker::Once(napi_env env, napi_callback_info cbinfo)
+{
+ return AddListener(env, cbinfo, ONCE);
+}
+
+napi_value Worker::RemoveListener(napi_env env, napi_callback_info cbinfo)
+{
+ size_t argc = NapiValueHelp::GetCallbackInfoArgc(env, cbinfo);
+ if (argc < 1) {
+ napi_throw_error(env, nullptr, "Worker param count must be more than 2 with on");
+ return nullptr;
+ }
+ // check 1st param is string
+ napi_value thisVar = nullptr;
+ void* data = nullptr;
+ napi_value* args = new napi_value[argc];
+ [[maybe_unused]] ObjectScope scope(args, true);
+ napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, &data);
+ if (!NapiValueHelp::IsString(args[0])) {
+ napi_throw_error(env, nullptr, "Worker 1st param must be string with on");
+ return nullptr;
+ }
+
+ Worker* worker = nullptr;
+ napi_unwrap(env, thisVar, (void**)&worker);
+ if (worker == nullptr) {
+ HILOG_ERROR("worker:: worker is nullptr when RemoveListener, maybe worker is terminated");
+ return nullptr;
+ }
+
+ napi_ref callback = nullptr;
+ if (argc > 1 && !NapiValueHelp::IsCallable(env, args[1])) {
+ napi_throw_error(env, nullptr, "Worker 2st param must be callable with on");
+ return nullptr;
+ }
+ if (argc > 1 && NapiValueHelp::IsCallable(env, args[1])) {
+ napi_create_reference(env, args[1], 1, &callback);
+ }
+
+ char* typeStr = NapiValueHelp::GetString(env, args[0]);
+ if (typeStr == nullptr) {
+ napi_throw_error(env, nullptr, "worker listener type create error, please check.");
+ return nullptr;
+ }
+ worker->RemoveListenerInner(env, typeStr, callback);
+ CloseHelp::DeletePointer(typeStr, true);
+ napi_delete_reference(env, callback);
+ return NapiValueHelp::GetUndefinedValue(env);
+}
+
+napi_value Worker::Off(napi_env env, napi_callback_info cbinfo)
+{
+ return RemoveListener(env, cbinfo);
+}
+
+napi_value Worker::AddEventListener(napi_env env, napi_callback_info cbinfo)
+{
+ return AddListener(env, cbinfo, PERMANENT);
+}
+
+napi_value Worker::DispatchEvent(napi_env env, napi_callback_info cbinfo)
+{
+ size_t argc = NapiValueHelp::GetCallbackInfoArgc(env, cbinfo);
+ if (argc < 1) {
+ napi_throw_error(env, nullptr, "worker:: DispatchEvent param count must be more than 1");
+ return NapiValueHelp::GetBooleanValue(env, false);
+ }
+
+ // check 1st param is string
+ napi_value thisVar = nullptr;
+ void* data = nullptr;
+ napi_value* args = new napi_value[argc];
+ [[maybe_unused]] ObjectScope scope(args, true);
+ napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, &data);
+
+ if (!NapiValueHelp::IsObject(args[0])) {
+ napi_throw_error(env, nullptr, "worker DispatchEvent 1st param must be Event");
+ return NapiValueHelp::GetBooleanValue(env, false);
+ }
+
+ Worker* worker = nullptr;
+ napi_unwrap(env, thisVar, (void**)&worker);
+ if (worker == nullptr) {
+ HILOG_ERROR("worker:: worker is nullptr when DispatchEvent, maybe worker is terminated");
+ return NapiValueHelp::GetBooleanValue(env, false);
+ }
+
+ napi_value typeValue = nullptr;
+ napi_get_named_property(env, args[0], "type", &typeValue);
+ if (!NapiValueHelp::IsString(typeValue)) {
+ napi_throw_error(env, nullptr, "worker event type must be string");
+ return NapiValueHelp::GetBooleanValue(env, false);
+ }
+
+ napi_value obj = nullptr;
+ napi_get_reference_value(env, worker->workerWrapper_, &obj);
+ napi_value argv[1] = { args[0] };
+
+ char* typeStr = NapiValueHelp::GetString(env, typeValue);
+ if (typeStr == nullptr) {
+ napi_throw_error(env, nullptr, "worker listener type create error, please check.");
+ return NapiValueHelp::GetBooleanValue(env, false);
+ }
+ if (strcmp(typeStr, "error") == 0) {
+ CallWorkCallback(env, obj, 1, argv, "onerror");
+ } else if (strcmp(typeStr, "messageerror") == 0) {
+ CallWorkCallback(env, obj, 1, argv, "onmessageerror");
+ } else if (strcmp(typeStr, "message") == 0) {
+ CallWorkCallback(env, obj, 1, argv, "onmessage");
+ }
+
+ worker->HandleEventListeners(env, obj, 1, argv, typeStr);
+
+ CloseHelp::DeletePointer(typeStr, true);
+ return NapiValueHelp::GetBooleanValue(env, true);
+}
+
+napi_value Worker::RemoveEventListener(napi_env env, napi_callback_info cbinfo)
+{
+ return RemoveListener(env, cbinfo);
+}
+
+void Worker::RemoveAllListenerInner()
+{
+ for (auto iter = eventListeners_.begin(); iter != eventListeners_.end(); iter++) {
+ std::list& listeners = iter->second;
+ for (auto item = listeners.begin(); item != listeners.end(); item++) {
+ WorkerListener* listener = *item;
+ CloseHelp::DeletePointer(listener, false);
+ }
+ }
+ eventListeners_.clear();
+}
+
+napi_value Worker::RemoveAllListener(napi_env env, napi_callback_info cbinfo)
+{
+ napi_value thisVar = nullptr;
+ napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr);
+ Worker* worker = nullptr;
+ napi_unwrap(env, thisVar, (void**)&worker);
+ if (worker == nullptr) {
+ HILOG_ERROR("worker:: worker is nullptr when RemoveAllListener, maybe worker is terminated");
+ return nullptr;
+ }
+
+ worker->RemoveAllListenerInner();
+ return NapiValueHelp::GetUndefinedValue(env);
+}
+
+napi_value Worker::InitWorker(napi_env env, napi_value exports)
+{
+ NativeEngine *engine = reinterpret_cast(env);
+ if (engine->IsMainThread()) {
+ const char className[] = "Worker";
+ napi_property_descriptor properties[] = {
+ DECLARE_NAPI_FUNCTION("postMessage", PostMessage),
+ DECLARE_NAPI_FUNCTION("terminate", Terminate),
+ DECLARE_NAPI_FUNCTION("on", On),
+ DECLARE_NAPI_FUNCTION("once", Once),
+ DECLARE_NAPI_FUNCTION("off", Off),
+ DECLARE_NAPI_FUNCTION("addEventListener", AddEventListener),
+ DECLARE_NAPI_FUNCTION("dispatchEvent", DispatchEvent),
+ DECLARE_NAPI_FUNCTION("removeEventListener", RemoveEventListener),
+ DECLARE_NAPI_FUNCTION("removeAllListener", RemoveAllListener),
+ };
+ napi_value workerClazz = nullptr;
+ napi_define_class(env, className, sizeof(className), Worker::WorkerConstructor, nullptr,
+ sizeof(properties) / sizeof(properties[0]), properties, &workerClazz);
+ napi_set_named_property(env, exports, "Worker", workerClazz);
+ } else {
+ NativeEngine *engine = reinterpret_cast(env);
+ Worker *worker = nullptr;
+ for (auto item = g_workers.begin(); item != g_workers.end(); item++) {
+ if ((*item)->GetWorkerEngine() == engine) {
+ worker = *item;
+ }
+ }
+ if (worker == nullptr) {
+ napi_throw_error(env, nullptr, "worker:: worker is null");
+ return exports;
+ }
+
+ napi_property_descriptor properties[] = {
+ DECLARE_NAPI_FUNCTION_WITH_DATA("postMessage", PostMessageToMain, worker),
+ DECLARE_NAPI_FUNCTION_WITH_DATA("close", CloseWorker, worker),
+ };
+ const char propertyName[] = "parentPort";
+ napi_value parentPortObj = nullptr;
+ napi_create_object(env, &parentPortObj);
+ napi_define_properties(env, parentPortObj, sizeof(properties) / sizeof(properties[0]), properties);
+ napi_set_named_property(env, exports, propertyName, parentPortObj);
+
+ // register worker parentPort.
+ napi_create_reference(env, parentPortObj, 1, &worker->parentPort_);
+ }
+ return exports;
+}
+
+void Worker::WorkerOnErrorInner(const NativeEngine* engine, napi_value error)
+{
+ napi_value argv[1] = { error };
+ CallWorkerFunction(engine, 1, argv, "onerror", false);
+}
+
+bool Worker::CallWorkerFunction(
+ const NativeEngine* engine, int argc, const napi_value* argv, const char* methodName, bool tryCatch)
+{
+ if (engine == nullptr) {
+ return false;
+ }
+ napi_env env = reinterpret_cast(const_cast(engine));
+ napi_value callback = NapiValueHelp::GetNamePropertyInParentPort(env, parentPort_, methodName);
+ bool isCallable = NapiValueHelp::IsCallable(env, callback);
+ if (!isCallable) {
+ HILOG_ERROR("worker:: WorkerGlobalScope %{public}s is not Callable", methodName);
+ return false;
+ }
+ napi_value undefinedValue = NapiValueHelp::GetUndefinedValue(env);
+ napi_value callbackResult = nullptr;
+ napi_call_function(env, undefinedValue, callback, argc, argv, &callbackResult);
+ if (tryCatch && callbackResult == nullptr) {
+ // handle exception
+ HandleException(GetWorkerEngine());
+ }
+ return true;
+}
+
+void Worker::CloseWorkerCallback()
+{
+ CallWorkerFunction(GetWorkerEngine(), 0, nullptr, "onclose", true);
+ // off worker inited environment
+ if (OHOS::CCRuntime::Worker::WorkerCore::offWorkerFunc != NULL) {
+ OHOS::CCRuntime::Worker::WorkerCore::offWorkerFunc(const_cast(GetWorkerEngine()));
+ }
+}
+
+void Worker::CallMainFunction(
+ const NativeEngine* engine, int argc, const napi_value* argv, const char* methodName) const
+{
+ if (engine == nullptr) {
+ return;
+ }
+ napi_env env = reinterpret_cast(const_cast(engine));
+ napi_value callback = nullptr;
+ napi_value obj = nullptr;
+ napi_get_reference_value(env, workerWrapper_, &obj);
+ napi_get_named_property(env, obj, methodName, &callback);
+ bool isCallable = NapiValueHelp::IsCallable(env, callback);
+ if (!isCallable) {
+ HILOG_ERROR("worker:: worker %{public}s is not Callable", methodName);
+ return;
+ }
+ napi_value callbackResult = nullptr;
+ napi_call_function(env, obj, callback, argc, argv, &callbackResult);
+}
+} // namespace OHOS::CCRuntime::Worker
diff --git a/jsapi/worker/worker.h b/jsapi/worker/worker.h
new file mode 100644
index 0000000000000000000000000000000000000000..61e7a7e6284c557c39eb0b2949cc2aeadb90841c
--- /dev/null
+++ b/jsapi/worker/worker.h
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FOUNDATION_CCRUNTIME_JSAPI_WORKER_H
+#define FOUNDATION_CCRUNTIME_JSAPI_WORKER_H
+
+#include
+#include