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 // [Start napi_remove_add_env_cleanup_hook]
17 #include <hilog/log.h>
18 #include <string>
19 #include <malloc.h>
20 #include "napi/native_api.h"
21 #include "uv.h"
22
23 // 定义内存结构,包含指向数据的指针和数据的大小
24 typedef struct {
25 char *data;
26 size_t size;
27 } Memory;
28
29 // 外部缓冲区清理回调函数,用于释放分配的内存
ExternalFinalize(napi_env env,void * finalizeData,void * finalizeHint)30 void ExternalFinalize(napi_env env, void *finalizeData, void *finalizeHint)
31 {
32 Memory *wrapper = (Memory *)finalizeHint;
33 // [StartExclude napi_remove_add_env_cleanup_hook]
34 if (wrapper == nullptr) {
35 //处理内存分配失败的情况
36 return;
37 }
38 // [EndExclude napi_remove_add_env_cleanup_hook]
39 free(wrapper->data);
40 free(wrapper);
41 OH_LOG_INFO(LOG_APP, "Node-API napi_add_env_cleanup_hook ExternalFinalize");
42 }
43
44 // 在环境关闭时执行一些清理操作,如清理全局变量或其他需要在环境关闭时处理的资源
Cleanup(void * arg)45 static void Cleanup(void *arg)
46 {
47 // 执行清理操作
48 OH_LOG_INFO(LOG_APP, "Node-API napi_add_env_cleanup_hook cleanuped: %{public}d", *(int *)(arg));
49 }
50
51 // 创建外部缓冲区并注册环境清理钩子函数
NapiEnvCleanUpHook(napi_env env,napi_callback_info info)52 static napi_value NapiEnvCleanUpHook(napi_env env, napi_callback_info info)
53 {
54 // 分配内存并复制字符串数据到内存中
55 std::string str("Hello from Node-API!");
56 Memory *wrapper = (Memory *)malloc(sizeof(Memory));
57 // [StartExclude napi_remove_add_env_cleanup_hook]
58 if (wrapper == nullptr) {
59 //处理内存分配失败的情况
60 return nullptr;
61 }
62 // [End napi_remove_add_env_cleanup_hook]
63 wrapper->data = static_cast<char *>(malloc(str.size()));
64 strcpy(wrapper->data, str.c_str());
65 wrapper->size = str.size();
66 // 创建外部缓冲区对象,并指定清理回调函数
67 napi_value buffer = nullptr;
68 napi_create_external_buffer(env, wrapper->size, (void *)wrapper->data, ExternalFinalize, wrapper, &buffer);
69 // 静态变量作为钩子函数参数
70 static int hookArg = 42;
71 static int hookParameter = 1;
72 // 注册环境清理钩子函数
73 napi_status status = napi_add_env_cleanup_hook(env, Cleanup, &hookArg);
74 if (status != napi_ok) {
75 napi_throw_error(env, nullptr, "Test Node-API napi_add_env_cleanup_hook failed.");
76 return nullptr;
77 }
78 // 注册环境清理钩子函数,此处不移除环境清理钩子,为了在Java环境被销毁时,这个钩子函数被调用,用来模拟执行一些清理操作,例如释放资源、关闭文件等。
79 status = napi_add_env_cleanup_hook(env, Cleanup, &hookParameter);
80 if (status != napi_ok) {
81 napi_throw_error(env, nullptr, "Test Node-API napi_add_env_cleanup_hook failed.");
82 return nullptr;
83 }
84 // 立即移除环境清理钩子函数,确保不会在后续环境清理时被调用
85 // 通常,当为其添加此钩子的资源无论如何都被拆除时调用这个接口
86 napi_remove_env_cleanup_hook(env, Cleanup, &hookArg);
87 // 返回创建的外部缓冲区对象
88 return buffer;
89 }
90 // [End napi_remove_add_env_cleanup_hook]
91
92 // [Start napi_add_remove_async_cleanup_hook]
93 typedef struct {
94 napi_env env;
95 void *testData;
96 uv_async_s asyncUv;
97 napi_async_cleanup_hook_handle cleanupHandle;
98 } AsyncContent;
99
100 // 删除异步工作对象并注销钩子函数
FinalizeWork(uv_handle_s * handle)101 static void FinalizeWork(uv_handle_s *handle)
102 {
103 AsyncContent *asyncData = reinterpret_cast<AsyncContent *>(handle->data);
104 // 不再需要异步清理钩子函数的情况下,尝试将其从环境中移除
105 napi_status result = napi_remove_async_cleanup_hook(asyncData->cleanupHandle);
106 if (result != napi_ok) {
107 napi_throw_error(asyncData->env, nullptr, "Test Node-API napi_remove_async_cleanup_hook failed");
108 }
109 // 释放AsyncContent
110 free(asyncData);
111 }
112
113 // 异步执行环境清理工作
AsyncWork(uv_async_s * async)114 static void AsyncWork(uv_async_s *async)
115 {
116 // 执行一些清理工作,比如释放动态分配的内存
117 AsyncContent *asyncData = reinterpret_cast<AsyncContent *>(async->data);
118 if (asyncData->testData != nullptr) {
119 free(asyncData->testData);
120 asyncData->testData = nullptr;
121 }
122 // 关闭libuv句柄,并触发FinalizeWork回调清理
123 uv_close((uv_handle_s *)async, FinalizeWork);
124 }
125
126 // 异步清理钩子函数,创建异步工作对象并执行
AsyncCleanup(napi_async_cleanup_hook_handle handle,void * info)127 static void AsyncCleanup(napi_async_cleanup_hook_handle handle, void *info)
128 {
129 AsyncContent *data = reinterpret_cast<AsyncContent *>(info);
130 // 获取libUv循环实例并初始化一个异步句柄,以便后续执行异步工作
131 uv_loop_s *uvLoop;
132 napi_get_uv_event_loop(data->env, &uvLoop);
133 uv_async_init(uvLoop, &data->asyncUv, AsyncWork);
134
135 data->asyncUv.data = data;
136 data->cleanupHandle = handle;
137 // 发送异步信号触发AsyncWork函数执行清理工作
138 uv_async_send(&data->asyncUv);
139 }
140
NapiAsyncCleanUpHook(napi_env env,napi_callback_info info)141 static napi_value NapiAsyncCleanUpHook(napi_env env, napi_callback_info info)
142 {
143 // 分配AsyncContent内存
144 AsyncContent *data = reinterpret_cast<AsyncContent *>(malloc(sizeof(AsyncContent)));
145 // StartExclude napi_add_remove_async_cleanup_hook]
146 if (data == nullptr) {
147 //处理内存分配失败的情况
148 return nullptr;
149 }
150 // [EndExclude napi_add_remove_async_cleanup_hook]
151 data->env = env;
152 data->cleanupHandle = nullptr;
153 // 分配内存并复制字符串数据
154 const char *testDataStr = "TestNapiAsyncCleanUpHook";
155 data->testData = strdup(testDataStr);
156 if (data->testData == nullptr) {
157 napi_throw_error(env, nullptr, "Test Node-API data->testData is nullptr");
158 }
159 // 添加异步清理钩子函数
160 napi_status status = napi_add_async_cleanup_hook(env, AsyncCleanup, data, &data->cleanupHandle);
161 if (status != napi_ok) {
162 napi_throw_error(env, nullptr, "Test Node-API napi_add_async_cleanup_hook failed");
163 }
164 napi_value result = nullptr;
165 napi_get_boolean(env, true, &result);
166 return result;
167 }
168 // [End napi_add_remove_async_cleanup_hook]
169
170 EXTERN_C_START
Init(napi_env env,napi_value exports)171 static napi_value Init(napi_env env, napi_value exports)
172 {
173 napi_property_descriptor desc[] = {
174 {"napiEnvCleanUpHook", nullptr, NapiEnvCleanUpHook, nullptr, nullptr, nullptr, napi_default, nullptr},
175 {"napiAsyncCleanUpHook", nullptr, NapiAsyncCleanUpHook, nullptr, nullptr, nullptr, napi_default, nullptr}};
176 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
177 return exports;
178 }
179 EXTERN_C_END
180
181 static napi_module demoModule = {
182 .nm_version = 1,
183 .nm_flags = 0,
184 .nm_filename = nullptr,
185 .nm_register_func = Init,
186 .nm_modname = "entry",
187 .nm_priv = ((void *)0),
188 .reserved = {0},
189 };
190
RegisterEntryModule(void)191 extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
192