1 /*
2 * Copyright (c) 2025 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 // [Start napi_call_threadsafe_function_with_priority_cpp]
16 // [Start napi_ark_runtime_cpp]
17 #include <pthread.h>
18 #include "napi/native_api.h"
19 // [StartExclute napi_ark_runtime_cpp]
20 #include <napi/common.h>
21 #include <pthread.h>
22 #include <future>
23
24 static constexpr int INT_ARG_2 = 2; // 入参索引
25 static constexpr int INT_ARG_12 = 12; // 入参索引
26 static constexpr int INT_ARG_15 = 15; // 入参索引
27 // [EndExclute napi_ark_runtime_cpp]
28 // [StartExclute napi_call_threadsafe_function_with_priority_cpp]
CreateArkRuntimeFunc(void * arg)29 static void *CreateArkRuntimeFunc(void *arg)
30 {
31 // 1. 创建基础运行环境
32 napi_env env;
33 napi_status ret = napi_create_ark_runtime(&env);
34 if (ret != napi_ok) {
35 return nullptr;
36 }
37
38 // 2. 加载自定义模块
39 napi_value objUtils;
40 ret = napi_load_module_with_info(env, "entry/src/main/ets/pages/ObjectUtils", "com.example.myapplication/entry",
41 &objUtils);
42 if (ret != napi_ok) {
43 return nullptr;
44 }
45
46 // 3. 使用ArkTS中的logger
47 napi_value logger;
48 ret = napi_get_named_property(env, objUtils, "Logger", &logger);
49 if (ret != napi_ok) {
50 return nullptr;
51 }
52 ret = napi_call_function(env, objUtils, logger, 0, nullptr, nullptr);
53
54 // 4. 销毁ArkTS环境
55 ret = napi_destroy_ark_runtime(&env);
56
57 return nullptr;
58 }
59
CreateArkRuntime(napi_env env,napi_callback_info info)60 static napi_value CreateArkRuntime(napi_env env, napi_callback_info info)
61 {
62 pthread_t tid;
63 pthread_create(&tid, nullptr, CreateArkRuntimeFunc, nullptr);
64 pthread_join(tid, nullptr);
65 return nullptr;
66 }
67 // [StartExclute napi_ark_runtime_cpp]
68 // [Start napi_event_loop_cpp]
ResolvedCallback(napi_env env,napi_callback_info info)69 static napi_value ResolvedCallback(napi_env env, napi_callback_info info)
70 {
71 napi_stop_event_loop(env);
72 return nullptr;
73 }
74
RejectedCallback(napi_env env,napi_callback_info info)75 static napi_value RejectedCallback(napi_env env, napi_callback_info info)
76 {
77 napi_stop_event_loop(env);
78 return nullptr;
79 }
80
RunEventLoopFunc(void * arg)81 static void *RunEventLoopFunc(void *arg)
82 {
83 // 1. 创建ArkTS实例
84 napi_env env;
85 napi_status ret = napi_create_ark_runtime(&env);
86 if (ret != napi_ok) {
87 return nullptr;
88 }
89
90 // 2. 加载自定义的模块
91 napi_value objectUtils;
92 // 'com.example.myapplication' 为当前应用的bundleName
93 ret = napi_load_module_with_info(env, "ets/pages/ObjectUtils", "com.example.myapplication/entry", &objectUtils);
94 if (ret != napi_ok) {
95 return nullptr;
96 }
97
98 // 3. 调用异步SetTimeout接口
99 napi_value setTimeout = nullptr;
100 napi_value promise = nullptr;
101
102 napi_get_named_property(env, objectUtils, "SetTimeout", &setTimeout);
103 napi_call_function(env, objectUtils, setTimeout, 0, nullptr, &promise);
104
105 napi_value theFunc = nullptr;
106 if (napi_get_named_property(env, promise, "then", &theFunc) != napi_ok) {
107 return nullptr;
108 }
109
110 napi_value resolvedCallback = nullptr;
111 napi_value rejectedCallback = nullptr;
112 napi_create_function(env, "resolvedCallback", NAPI_AUTO_LENGTH, ResolvedCallback, nullptr, &resolvedCallback);
113 napi_create_function(env, "rejectedCallback", NAPI_AUTO_LENGTH, RejectedCallback, nullptr, &rejectedCallback);
114 napi_value argv[2] = {resolvedCallback, rejectedCallback};
115 napi_call_function(env, promise, theFunc, INT_ARG_2, argv, nullptr);
116
117 auto flag = reinterpret_cast<bool *>(arg);
118 if (*flag == true) {
119 napi_run_event_loop(env, napi_event_mode_default);
120 } else {
121 // 非阻塞式的处理任务,有可能队列中还没有任务就已经返回了
122 napi_run_event_loop(env, napi_event_mode_nowait);
123 }
124 return nullptr;
125 }
126
RunEventLoop(napi_env env,napi_callback_info info)127 static napi_value RunEventLoop(napi_env env, napi_callback_info info)
128 {
129 pthread_t tid;
130 size_t argc = 1;
131 napi_value argv[1] = {nullptr};
132 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
133
134 bool flag = false;
135 napi_get_value_bool(env, argv[0], &flag);
136 // 创建异步线程
137 pthread_create(&tid, nullptr, RunEventLoopFunc, &flag);
138 pthread_join(tid, nullptr);
139
140 return nullptr;
141 }
142 // [StartExclute napi_event_loop_cpp]
143 // [EndExclute napi_call_threadsafe_function_with_priority_cpp]
144 struct CallbackData {
145 napi_threadsafe_function tsfn;
146 napi_async_work work;
147 };
148 // ArkTS线程的回调实现
CallJs(napi_env env,napi_value jsCb,void * context,void * data)149 static void CallJs(napi_env env, napi_value jsCb, void *context, void *data)
150 {
151 if (env == nullptr) {
152 return;
153 }
154 napi_value resultNumber = nullptr;
155 napi_value undefined = nullptr;
156 napi_get_undefined(env, &undefined);
157 napi_value number1 = nullptr;
158 napi_create_int32(env, INT_ARG_12, &number1);
159 napi_value number2 = nullptr;
160 napi_create_int32(env, INT_ARG_15, &number2);
161 napi_value argv[2] = {number1, number2};
162 napi_call_function(env, undefined, jsCb, INT_ARG_2, argv, &resultNumber);
163 int32_t res = 0;
164 napi_get_value_int32(env, resultNumber, &res);
165 }
166
167 // 异步线程中调用该接口向ArkTS线程投递指定优先级和入队方式的任务
ExecuteWork(napi_env env,void * data)168 static void ExecuteWork(napi_env env, void *data)
169 {
170 CallbackData *callbackData = reinterpret_cast<CallbackData *>(data);
171 // 执行任务为napi_priority_idle优先级,入队方式为队列尾部入队
172 napi_call_threadsafe_function_with_priority(callbackData->tsfn, nullptr, napi_priority_idle, true);
173 napi_call_threadsafe_function_with_priority(callbackData->tsfn, nullptr, napi_priority_low, true);
174 napi_call_threadsafe_function_with_priority(callbackData->tsfn, nullptr, napi_priority_high, true);
175 napi_call_threadsafe_function_with_priority(callbackData->tsfn, nullptr, napi_priority_immediate, true);
176 // 执行任务为napi_priority_high优先级,入队方式为队列头部入队
177 napi_call_threadsafe_function_with_priority(callbackData->tsfn, nullptr, napi_priority_high, false);
178 }
179
WorkComplete(napi_env env,napi_status status,void * data)180 static void WorkComplete(napi_env env, napi_status status, void *data)
181 {
182 CallbackData *callbackData = reinterpret_cast<CallbackData *>(data);
183 napi_release_threadsafe_function(callbackData->tsfn, napi_tsfn_release);
184 napi_delete_async_work(env, callbackData->work);
185 callbackData->work = nullptr;
186 callbackData->tsfn = nullptr;
187 }
188
CallThreadSafeWithPriority(napi_env env,napi_callback_info info)189 static napi_value CallThreadSafeWithPriority(napi_env env, napi_callback_info info)
190 {
191 size_t argc = 1;
192 napi_value jsCb = nullptr;
193 CallbackData *callbackData = nullptr;
194 napi_get_cb_info(env, info, &argc, &jsCb, nullptr, reinterpret_cast<void **>(&callbackData));
195 napi_value resourceName = nullptr;
196 napi_create_string_utf8(env, "Thread-safe Function Demo", NAPI_AUTO_LENGTH, &resourceName);
197 napi_create_threadsafe_function(env, jsCb, nullptr, resourceName, 0, 1, callbackData, nullptr, callbackData, CallJs,
198 &callbackData->tsfn);
199 napi_create_async_work(env, nullptr, resourceName, ExecuteWork, WorkComplete, callbackData, &callbackData->work);
200 napi_queue_async_work(env, callbackData->work);
201 return nullptr;
202 }
203 // [EndExclute napi_event_loop_cpp]
204 // [EndExclute napi_ark_runtime_cpp]
205 EXTERN_C_START
Init(napi_env env,napi_value exports)206 static napi_value Init(napi_env env, napi_value exports)
207 {
208 CallbackData *callbackData = new CallbackData();
209 napi_property_descriptor desc[] = {
210 {"createArkRuntime", nullptr, CreateArkRuntime, nullptr, nullptr, nullptr, napi_static, nullptr},
211 {"runEventLoop", nullptr, RunEventLoop, nullptr, nullptr, nullptr, napi_default, nullptr},
212 {"callThreadSafeWithPriority", nullptr, CallThreadSafeWithPriority, nullptr, nullptr, nullptr,
213 napi_default, callbackData}};
214 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
215 return exports;
216 }
217 EXTERN_C_END
218
219 static napi_module nativeModule = {
220 .nm_version = 1,
221 .nm_flags = 0,
222 .nm_filename = nullptr,
223 .nm_register_func = Init,
224 .nm_modname = "entry",
225 .nm_priv = nullptr,
226 .reserved = {0},
227 };
228
RegisterQueueWorkModule()229 extern "C" __attribute__((constructor)) void RegisterQueueWorkModule() { napi_module_register(&nativeModule); }
230 // [End napi_call_threadsafe_function_with_priority_cpp]
231 // [End napi_event_loop_cpp]
232 // [End napi_ark_runtime_cpp]
233