• 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 // [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