1e41f4b71Sopenharmony_ci# Working with Cleanup Hooks Using Node-API
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci## Introduction
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ciNode-API provides APIs for adding and removing cleanup hooks, which are called to release resources when the environment exits.
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ci## Basic Concepts
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ciBefore using Node-API to add or remove cleanup hooks, understand the following concepts:
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ci- Resource management<br>In ArkTS, you need to manage system resources, such as memory, file handles, and network connections. Properly creating, using, and releasing these resources during the lifecycle of the Node-API module can prevent resource leaks and application breakdown. Resource management usually includes initializing resources, clearing resources when required, and performing necessary operations when clearing resources, such as closing a file or disconnecting from the network.
12e41f4b71Sopenharmony_ci- Hook function<br>A hook function is a callback that is automatically executed at the specified time or upon a specific event. When an environment or a process exits, not all the resources can be automatically reclaimed immediately. In the context of the Node-API module, the cleanup hooks are a supplement that ensures release of all the resources occupied.
13e41f4b71Sopenharmony_ci
14e41f4b71Sopenharmony_ciSo far, you've learnt resource management in ArkTS and cleanup hook functions. Read on to learn the Node-API interfaces that you can use to perform resource management with cleanup hooks.
15e41f4b71Sopenharmony_ci
16e41f4b71Sopenharmony_ci## Available APIs
17e41f4b71Sopenharmony_ci
18e41f4b71Sopenharmony_ciThe following table lists the APIs for using different types of cleanup hooks.  
19e41f4b71Sopenharmony_ci| API| Description|
20e41f4b71Sopenharmony_ci| -------- | -------- |
21e41f4b71Sopenharmony_ci| napi_add_env_cleanup_hook | Adds an environment cleanup hook function, which will be called when the Node-API environment exits.|
22e41f4b71Sopenharmony_ci| napi_remove_env_cleanup_hook | Removes an environment cleanup hook function.|
23e41f4b71Sopenharmony_ci| napi_add_async_cleanup_hook | Adds an async cleanup hook function, which will be executed asynchronously when the Node-API process exits.|
24e41f4b71Sopenharmony_ci| napi_remove_async_cleanup_hook | Removes an async cleanup hook function.|
25e41f4b71Sopenharmony_ci
26e41f4b71Sopenharmony_ci## Example
27e41f4b71Sopenharmony_ci
28e41f4b71Sopenharmony_ciIf you are just starting out with Node-API, see [Node-API Development Process](use-napi-process.md). The following demonstrates only the C++ and ArkTS code involved in the APIs for cleanup hooks.
29e41f4b71Sopenharmony_ci
30e41f4b71Sopenharmony_ci### napi_add_env_cleanup_hook
31e41f4b71Sopenharmony_ci
32e41f4b71Sopenharmony_ciUse **napi_add_env_cleanup_hook** to add an environment cleanup hook function, which will be executed when the environment exits. This ensures that resources are released before the environment is destroyed.
33e41f4b71Sopenharmony_ci
34e41f4b71Sopenharmony_ci### napi_remove_env_cleanup_hook
35e41f4b71Sopenharmony_ci
36e41f4b71Sopenharmony_ciUse **napi_remove_env_cleanup_hook** to remove the previously added environment cleanup hook function. You may need to use this API when an addon is uninstalled or resources are reallocated.
37e41f4b71Sopenharmony_ci
38e41f4b71Sopenharmony_ciCPP code:
39e41f4b71Sopenharmony_ci
40e41f4b71Sopenharmony_ci```cpp
41e41f4b71Sopenharmony_ci#include <hilog/log.h>
42e41f4b71Sopenharmony_ci#include <string>
43e41f4b71Sopenharmony_ci#include "napi/native_api.h"
44e41f4b71Sopenharmony_ci// Define the memory struct, including the pointer to the data and the data size.
45e41f4b71Sopenharmony_citypedef struct {
46e41f4b71Sopenharmony_ci    char *data;
47e41f4b71Sopenharmony_ci    size_t size;
48e41f4b71Sopenharmony_ci} Memory;
49e41f4b71Sopenharmony_ci// Callback for clearing the external buffer. It is used to release the allocated memory.
50e41f4b71Sopenharmony_civoid ExternalFinalize(napi_env env, void *finalize_data, void *finalize_hint) 
51e41f4b71Sopenharmony_ci{
52e41f4b71Sopenharmony_ci    Memory *wrapper = (Memory *)finalize_hint;
53e41f4b71Sopenharmony_ci    free(wrapper->data);
54e41f4b71Sopenharmony_ci    free(wrapper);
55e41f4b71Sopenharmony_ci    OH_LOG_INFO(LOG_APP, "Node-API napi_add_env_cleanup_hook ExternalFinalize");
56e41f4b71Sopenharmony_ci}
57e41f4b71Sopenharmony_ci// Perform cleanup operations when the environment is closed, for example, clear global variables or other resources.
58e41f4b71Sopenharmony_cistatic void Cleanup(void *arg)
59e41f4b71Sopenharmony_ci{
60e41f4b71Sopenharmony_ci    // Perform the cleanup operation.
61e41f4b71Sopenharmony_ci    OH_LOG_INFO(LOG_APP, "Node-API napi_add_env_cleanup_hook cleanuped: %{public}d", *(int *)(arg));
62e41f4b71Sopenharmony_ci}
63e41f4b71Sopenharmony_ci// Create an external buffer and add the environment cleanup hook function.
64e41f4b71Sopenharmony_cistatic napi_value NapiEnvCleanUpHook(napi_env env, napi_callback_info info) 
65e41f4b71Sopenharmony_ci{
66e41f4b71Sopenharmony_ci    // Allocate memory and copy the string to the memory.
67e41f4b71Sopenharmony_ci    std::string str("Hello from Node-API!");
68e41f4b71Sopenharmony_ci    Memory *wrapper = (Memory *)malloc(sizeof(Memory));
69e41f4b71Sopenharmony_ci    wrapper->data = (char *)malloc(str.size());
70e41f4b71Sopenharmony_ci    strcpy(wrapper->data, str.c_str());
71e41f4b71Sopenharmony_ci    wrapper->size = str.size();
72e41f4b71Sopenharmony_ci    // Create an external buffer object and specify the cleanup callback function.
73e41f4b71Sopenharmony_ci    napi_value buffer = nullptr;
74e41f4b71Sopenharmony_ci    napi_create_external_buffer(env, wrapper->size, (void *)wrapper->data, ExternalFinalize, wrapper, &buffer);
75e41f4b71Sopenharmony_ci    // Use static variables as hook function parameters.
76e41f4b71Sopenharmony_ci    static int hookArg = 42;
77e41f4b71Sopenharmony_ci    static int hookParameter = 1;
78e41f4b71Sopenharmony_ci    // Add a cleanup hook function for releasing resources when the environment exits.
79e41f4b71Sopenharmony_ci    napi_status status = napi_add_env_cleanup_hook(env, Cleanup, &hookArg);
80e41f4b71Sopenharmony_ci    if (status != napi_ok) {
81e41f4b71Sopenharmony_ci        napi_throw_error(env, nullptr, "Test Node-API napi_add_env_cleanup_hook failed.");
82e41f4b71Sopenharmony_ci        return nullptr;
83e41f4b71Sopenharmony_ci    }
84e41f4b71Sopenharmony_ci    // Add the environment cleanup hook function. The hook function is not removed here to make it called to simulate some cleanup operations, such as releasing resources and closing files, when the Javas environment is destroyed.
85e41f4b71Sopenharmony_ci    status = napi_add_env_cleanup_hook(env, Cleanup, &hookParameter);
86e41f4b71Sopenharmony_ci    if (status != napi_ok) {
87e41f4b71Sopenharmony_ci        napi_throw_error(env, nullptr, "Test Node-API napi_add_env_cleanup_hook failed.");
88e41f4b71Sopenharmony_ci        return nullptr;
89e41f4b71Sopenharmony_ci    }
90e41f4b71Sopenharmony_ci    // Remove the environment cleanup hook function immediately.
91e41f4b71Sopenharmony_ci    // Generally, use this API when the resource associated with the hook must be released.
92e41f4b71Sopenharmony_ci    napi_remove_env_cleanup_hook(env, Cleanup, &hookArg);
93e41f4b71Sopenharmony_ci    // Return the created external buffer object.
94e41f4b71Sopenharmony_ci    return buffer;
95e41f4b71Sopenharmony_ci}
96e41f4b71Sopenharmony_ci```
97e41f4b71Sopenharmony_ci
98e41f4b71Sopenharmony_ciAPI declaration:
99e41f4b71Sopenharmony_ci
100e41f4b71Sopenharmony_ci```ts
101e41f4b71Sopenharmony_ci// index.d.ts
102e41f4b71Sopenharmony_ciexport const napiEnvCleanUpHook: () => Object | void;
103e41f4b71Sopenharmony_ci```
104e41f4b71Sopenharmony_ci
105e41f4b71Sopenharmony_ciArkTS code:
106e41f4b71Sopenharmony_ci
107e41f4b71Sopenharmony_ci```ts
108e41f4b71Sopenharmony_ci// index.ets
109e41f4b71Sopenharmony_ciimport hilog from '@ohos.hilog'
110e41f4b71Sopenharmony_ciimport worker from '@ohos.worker'
111e41f4b71Sopenharmony_ci
112e41f4b71Sopenharmony_cilet wk = new worker.ThreadWorker("entry/ets/workers/worker.ts");
113e41f4b71Sopenharmony_ci// Send a message to the worker thread.
114e41f4b71Sopenharmony_ciwk.postMessage("test NapiEnvCleanUpHook");
115e41f4b71Sopenharmony_ci// Process the message from the worker thread.
116e41f4b71Sopenharmony_ciwk.onmessage = (message) => {
117e41f4b71Sopenharmony_ci  hilog.info(0x0000, 'testTag', 'Test Node-API message from worker: %{public}s', JSON.stringify(message));
118e41f4b71Sopenharmony_ci  wk.terminate();
119e41f4b71Sopenharmony_ci};
120e41f4b71Sopenharmony_ci```
121e41f4b71Sopenharmony_ci
122e41f4b71Sopenharmony_ci```ts
123e41f4b71Sopenharmony_ci// worker.ts
124e41f4b71Sopenharmony_ciimport hilog from '@ohos.hilog'
125e41f4b71Sopenharmony_ciimport worker from '@ohos.worker'
126e41f4b71Sopenharmony_ciimport testNapi from 'libentry.so'
127e41f4b71Sopenharmony_ci
128e41f4b71Sopenharmony_cilet parent = worker.workerPort;
129e41f4b71Sopenharmony_ci// Process messages from the main thread.
130e41f4b71Sopenharmony_ciparent.onmessage = function(message) {
131e41f4b71Sopenharmony_ci  hilog.info(0x0000, 'testTag', 'Test Node-API message from main thread: %{public}s', JSON.stringify(message));
132e41f4b71Sopenharmony_ci  // Send a message to the main thread.
133e41f4b71Sopenharmony_ci  parent.postMessage('Test Node-API worker:' + testNapi.napiEnvCleanUpHook());
134e41f4b71Sopenharmony_ci}
135e41f4b71Sopenharmony_ci```
136e41f4b71Sopenharmony_ci
137e41f4b71Sopenharmony_ciFor details about the worker development, see [Worker Introduction](../arkts-utils/worker-introduction.md).
138e41f4b71Sopenharmony_ci
139e41f4b71Sopenharmony_ci### napi_add_async_cleanup_hook
140e41f4b71Sopenharmony_ci
141e41f4b71Sopenharmony_ciUse **napi_add_async_cleanup_hook** to add an async cleanup hook function, which will be executed asynchronously when the environment exits. Unlike a sync hook, an async hook allows a longer operation without blocking the process exit.
142e41f4b71Sopenharmony_ci
143e41f4b71Sopenharmony_ci### napi_remove_async_cleanup_hook
144e41f4b71Sopenharmony_ci
145e41f4b71Sopenharmony_ciUse **napi_remove_async_cleanup_hook** to remove an async cleanup hook function that is no longer required.
146e41f4b71Sopenharmony_ci
147e41f4b71Sopenharmony_ciCPP code:
148e41f4b71Sopenharmony_ci
149e41f4b71Sopenharmony_ci```cpp
150e41f4b71Sopenharmony_ci#include <malloc.h>
151e41f4b71Sopenharmony_ci#include <string.h>
152e41f4b71Sopenharmony_ci#include "napi/native_api.h"
153e41f4b71Sopenharmony_ci#include "uv.h"
154e41f4b71Sopenharmony_ci
155e41f4b71Sopenharmony_ci// Async operation content.
156e41f4b71Sopenharmony_citypedef struct {
157e41f4b71Sopenharmony_ci    napi_env env;
158e41f4b71Sopenharmony_ci    void *testData;
159e41f4b71Sopenharmony_ci    uv_async_s asyncUv;
160e41f4b71Sopenharmony_ci    napi_async_cleanup_hook_handle cleanupHandle;
161e41f4b71Sopenharmony_ci} AsyncContent;
162e41f4b71Sopenharmony_ci// Delete the async work object and remove the hook function.
163e41f4b71Sopenharmony_cistatic void FinalizeWork(uv_handle_s *handle)
164e41f4b71Sopenharmony_ci{
165e41f4b71Sopenharmony_ci    AsyncContent *asyncData = reinterpret_cast<AsyncContent *>(handle->data);
166e41f4b71Sopenharmony_ci    // Remove the hook function from the environment when it is no longer required.
167e41f4b71Sopenharmony_ci    napi_status result = napi_remove_async_cleanup_hook(asyncData->cleanupHandle);
168e41f4b71Sopenharmony_ci    if (result != napi_ok) {
169e41f4b71Sopenharmony_ci        napi_throw_error(asyncData->env, nullptr, "Test Node-API napi_remove_async_cleanup_hook failed");
170e41f4b71Sopenharmony_ci    }
171e41f4b71Sopenharmony_ci    // Release AsyncContent.
172e41f4b71Sopenharmony_ci    free(asyncData);
173e41f4b71Sopenharmony_ci}
174e41f4b71Sopenharmony_ci// Asynchronously clear the environment.
175e41f4b71Sopenharmony_cistatic void AsyncWork(uv_async_s *async)
176e41f4b71Sopenharmony_ci{
177e41f4b71Sopenharmony_ci    // Perform cleanup operations, for example, release the dynamically allocated memory.
178e41f4b71Sopenharmony_ci    AsyncContent *asyncData = reinterpret_cast<AsyncContent *>(async->data);
179e41f4b71Sopenharmony_ci    if (asyncData->testData != nullptr) {
180e41f4b71Sopenharmony_ci        free(asyncData->testData);
181e41f4b71Sopenharmony_ci        asyncData->testData = nullptr;
182e41f4b71Sopenharmony_ci    }
183e41f4b71Sopenharmony_ci    // Close the libuv handle and trigger the FinalizeWork callback to clear the handle.
184e41f4b71Sopenharmony_ci    uv_close((uv_handle_s *)async, FinalizeWork);
185e41f4b71Sopenharmony_ci}
186e41f4b71Sopenharmony_ci// Create and trigger an async cleanup operation in an event loop.
187e41f4b71Sopenharmony_cistatic void AsyncCleanup(napi_async_cleanup_hook_handle handle, void *info)
188e41f4b71Sopenharmony_ci{
189e41f4b71Sopenharmony_ci    AsyncContent *data = reinterpret_cast<AsyncContent *>(info);
190e41f4b71Sopenharmony_ci    // Obtain a libuv loop instance and initialize a handle for subsequent async work.
191e41f4b71Sopenharmony_ci    uv_loop_s *uvLoop;
192e41f4b71Sopenharmony_ci    napi_get_uv_event_loop(data->env, &uvLoop);
193e41f4b71Sopenharmony_ci    uv_async_init(uvLoop, &data->asyncUv, AsyncWork);
194e41f4b71Sopenharmony_ci
195e41f4b71Sopenharmony_ci    data->asyncUv.data = data;
196e41f4b71Sopenharmony_ci    data->cleanupHandle = handle;
197e41f4b71Sopenharmony_ci    // Send an async signal to trigger the AsyncWork function to perform cleanup.
198e41f4b71Sopenharmony_ci    uv_async_send(&data->asyncUv);
199e41f4b71Sopenharmony_ci}
200e41f4b71Sopenharmony_ci
201e41f4b71Sopenharmony_cistatic napi_value NapiAsyncCleanUpHook(napi_env env, napi_callback_info info)
202e41f4b71Sopenharmony_ci{
203e41f4b71Sopenharmony_ci    // Allocate the AsyncContent memory.
204e41f4b71Sopenharmony_ci    AsyncContent *data = reinterpret_cast<AsyncContent *>(malloc(sizeof(AsyncContent)));
205e41f4b71Sopenharmony_ci    data->env = env;
206e41f4b71Sopenharmony_ci    data->cleanupHandle = nullptr;
207e41f4b71Sopenharmony_ci    // Allocate memory and copy string data.
208e41f4b71Sopenharmony_ci    const char *testDataStr = "TestNapiAsyncCleanUpHook";
209e41f4b71Sopenharmony_ci    data->testData = strdup(testDataStr);
210e41f4b71Sopenharmony_ci    if (data->testData == nullptr) {
211e41f4b71Sopenharmony_ci        napi_throw_error(env, nullptr, "Test Node-API data->testData is nullptr");
212e41f4b71Sopenharmony_ci    }
213e41f4b71Sopenharmony_ci    // Add an async cleanup hook function.
214e41f4b71Sopenharmony_ci    napi_status status = napi_add_async_cleanup_hook(env, AsyncCleanup, data, &data->cleanupHandle);
215e41f4b71Sopenharmony_ci    if (status != napi_ok) {
216e41f4b71Sopenharmony_ci        napi_throw_error(env, nullptr, "Test Node-API napi_add_async_cleanup_hook failed");
217e41f4b71Sopenharmony_ci    }
218e41f4b71Sopenharmony_ci    napi_value result = nullptr;
219e41f4b71Sopenharmony_ci    napi_get_boolean(env, true, &result);
220e41f4b71Sopenharmony_ci    return result;
221e41f4b71Sopenharmony_ci}
222e41f4b71Sopenharmony_ci```
223e41f4b71Sopenharmony_ci
224e41f4b71Sopenharmony_ciSince the uv.h library is used, add the following configuration to the CMakeLists file:
225e41f4b71Sopenharmony_ci```text
226e41f4b71Sopenharmony_ci// CMakeLists.txt
227e41f4b71Sopenharmony_citarget_link_libraries(entry PUBLIC libuv.so)
228e41f4b71Sopenharmony_ci```
229e41f4b71Sopenharmony_ci
230e41f4b71Sopenharmony_ciAPI declaration:
231e41f4b71Sopenharmony_ci
232e41f4b71Sopenharmony_ci```ts
233e41f4b71Sopenharmony_ci// index.d.ts
234e41f4b71Sopenharmony_ciexport const napiAsyncCleanUpHook: () => boolean | void;
235e41f4b71Sopenharmony_ci```
236e41f4b71Sopenharmony_ci
237e41f4b71Sopenharmony_ciArkTS code:
238e41f4b71Sopenharmony_ci
239e41f4b71Sopenharmony_ci```ts
240e41f4b71Sopenharmony_ciimport hilog from '@ohos.hilog'
241e41f4b71Sopenharmony_ciimport testNapi from 'libentry.so'
242e41f4b71Sopenharmony_citry {
243e41f4b71Sopenharmony_ci  hilog.info(0x0000, 'testTag', 'Test Node-API napi_add_async_cleanup_hook: %{public}s', testNapi.napiAsyncCleanUpHook());
244e41f4b71Sopenharmony_ci} catch (error) {
245e41f4b71Sopenharmony_ci  hilog.error(0x0000, 'testTag', 'Test Node-API napi_add_async_cleanup_hook error.message: %{public}s', error.message);
246e41f4b71Sopenharmony_ci}
247e41f4b71Sopenharmony_ci```
248e41f4b71Sopenharmony_ci
249e41f4b71Sopenharmony_ciTo print logs in the native CPP, add the following information to the **CMakeLists.txt** file and add the header file by using **#include "hilog/log.h"**.
250e41f4b71Sopenharmony_ci
251e41f4b71Sopenharmony_ci```text
252e41f4b71Sopenharmony_ci// CMakeLists.txt
253e41f4b71Sopenharmony_ciadd_definitions( "-DLOG_DOMAIN=0xd0d0" )
254e41f4b71Sopenharmony_ciadd_definitions( "-DLOG_TAG=\"testTag\"" )
255e41f4b71Sopenharmony_citarget_link_libraries(entry PUBLIC libhilog_ndk.z.so)
256e41f4b71Sopenharmony_ci```
257