• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
16 #include "napi/native_api.h"
17 #include "hilog/log.h"
18 #include <future>
19 
20 static constexpr int INT_ARG_2 = 2; // 入参索引
21 static constexpr int INT_BUF_32 = 32; // 入参索引
22 
23 struct CallbackData {
24     napi_threadsafe_function tsfn;
25     napi_async_work work;
26 };
27 
ExecuteWork(napi_env env,void * data)28 static void ExecuteWork(napi_env env, void *data)
29 {
30     CallbackData *callbackData = reinterpret_cast<CallbackData *>(data);
31     std::promise<std::string> promise;
32     auto future = promise.get_future();
33     napi_call_threadsafe_function(callbackData->tsfn, &promise, napi_tsfn_nonblocking);
34     try {
35         auto result = future.get();
36         OH_LOG_INFO(LOG_APP, "XXX, Result from JS %{public}s", result.c_str());
37     } catch (const std::exception &e) {
38         OH_LOG_INFO(LOG_APP, "XXX, Result from JS %{public}s", e.what());
39     }
40 }
41 
ResolvedCallback(napi_env env,napi_callback_info info)42 static napi_value ResolvedCallback(napi_env env, napi_callback_info info)
43 {
44     void *data = nullptr;
45     size_t argc = 1;
46     napi_value argv[1];
47     if (napi_get_cb_info(env, info, &argc, argv, nullptr, &data) != napi_ok) {
48         return nullptr;
49     }
50     size_t result = 0;
51     char buf[32] = {0};
52     napi_get_value_string_utf8(env, argv[0], buf, INT_BUF_32, &result);
53     reinterpret_cast<std::promise<std::string> *>(data)->set_value(std::string(buf));
54     return nullptr;
55 }
56 
RejectedCallback(napi_env env,napi_callback_info info)57 static napi_value RejectedCallback(napi_env env, napi_callback_info info)
58 {
59     void *data = nullptr;
60     if (napi_get_cb_info(env, info, nullptr, nullptr, nullptr, &data) != napi_ok) {
61         return nullptr;
62     }
63     reinterpret_cast<std::promise<std::string> *>(data)->set_exception(
64         std::make_exception_ptr(std::runtime_error("Error in jsCallback")));
65     return nullptr;
66 }
67 
CallJs(napi_env env,napi_value jsCb,void * context,void * data)68 static void CallJs(napi_env env, napi_value jsCb, void *context, void *data)
69 {
70     if (env == nullptr) {
71         return;
72     }
73     napi_value undefined = nullptr;
74     napi_value promise = nullptr;
75     napi_get_undefined(env, &undefined);
76     napi_call_function(env, undefined, jsCb, 0, nullptr, &promise);
77     napi_value thenFunc = nullptr;
78     if (napi_get_named_property(env, promise, "then", &thenFunc) != napi_ok) {
79         return;
80     }
81     napi_value resolvedCallback;
82     napi_value rejectedCallback;
83     napi_create_function(env, "resolvedCallback", NAPI_AUTO_LENGTH, ResolvedCallback, data, &resolvedCallback);
84     napi_create_function(env, "rejectedCallback", NAPI_AUTO_LENGTH, RejectedCallback, data, &rejectedCallback);
85     napi_value argv[2] = {resolvedCallback, rejectedCallback};
86     napi_call_function(env, promise, thenFunc, INT_ARG_2, argv, nullptr);
87 }
88 
WorkComplete(napi_env env,napi_status status,void * data)89 static void WorkComplete(napi_env env, napi_status status, void *data)
90 {
91     CallbackData *callbackData = reinterpret_cast<CallbackData *>(data);
92     napi_release_threadsafe_function(callbackData->tsfn, napi_tsfn_release);
93     napi_delete_async_work(env, callbackData->work);
94     callbackData->tsfn = nullptr;
95     callbackData->work = nullptr;
96 }
97 
98 
StartThread(napi_env env,napi_callback_info info)99 static napi_value StartThread(napi_env env, napi_callback_info info)
100 {
101     size_t argc = 1;
102     napi_value jsCb = nullptr;
103     CallbackData *callbackData = nullptr;
104     napi_get_cb_info(env, info, &argc, &jsCb, nullptr, reinterpret_cast<void **>(&callbackData));
105 
106     // 创建一个线程安全函数
107     napi_value resourceName = nullptr;
108     napi_create_string_utf8(env, "Thread-safe Function Demo", NAPI_AUTO_LENGTH, &resourceName);
109     napi_create_threadsafe_function(env, jsCb, nullptr, resourceName, 0, 1, callbackData, nullptr, callbackData, CallJs,
110                                     &callbackData->tsfn);
111 
112     // 创建一个异步任务
113     // ExecuteWork会执行在一个由libuv创建的非JS线程上
114     // 此处使用napi_create_async_work是为了模拟在非JS线程场景使用napi_call_threadsafe_function接口向JS线程提交任务
115     napi_create_async_work(env, nullptr, resourceName, ExecuteWork, WorkComplete, callbackData, &callbackData->work);
116 
117     // 将异步任务加入到异步队列中
118     napi_queue_async_work(env, callbackData->work);
119     return nullptr;
120 }
121 
122 
123 EXTERN_C_START
Init(napi_env env,napi_value exports)124 static napi_value Init(napi_env env, napi_value exports)
125 {
126     CallbackData *callbackData = new CallbackData(); // 可在线程退出时释放
127     napi_property_descriptor desc[] = {
128         {"startThread", nullptr, StartThread, nullptr, nullptr, nullptr, napi_default, callbackData},
129     };
130     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
131     return exports;
132 }
133 EXTERN_C_END
134 
135 static napi_module demoModule = {
136     .nm_version = 1,
137     .nm_flags = 0,
138     .nm_filename = nullptr,
139     .nm_register_func = Init,
140     .nm_modname = "entry1",
141     .nm_priv = ((void *)0),
142     .reserved = {0},
143 };
144 
RegisterEntryModule(void)145 extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
146