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