1e41f4b71Sopenharmony_ci# Node-API FAQs
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci## What should I do when "undefined/not callable" or specific error message is reported for xxx after "import xxx from libxxx.so" is executed?
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ci1. Check whether the module name in the .cpp file used in module registration is the same as that in the .so file name.
6e41f4b71Sopenharmony_ci   If the module name is **entry**, the .so file name must be **libentry.so**, and the **nm_modname** field in **napi_module** must be **entry**. The module names must be of the same case.
7e41f4b71Sopenharmony_ci
8e41f4b71Sopenharmony_ci2. Check whether the .so file is successfully loaded.
9e41f4b71Sopenharmony_ci   
10e41f4b71Sopenharmony_ci   Check the log related to module loading during the application startup. Search for the keyword "dlopen" and check for error information. Possible causes include the following:
11e41f4b71Sopenharmony_ci   
12e41f4b71Sopenharmony_ci   - The file to be loaded does not exist or is in a blocklist.
13e41f4b71Sopenharmony_ci   - The application does not have the required permission. 
14e41f4b71Sopenharmony_ci   - The **nm_modname** value does not match the module name in multi-thread scenarios (such as worker threads and taskpool). The module names must be of the same case.
15e41f4b71Sopenharmony_ci3. Check whether the dependency .so files are successfully loaded.
16e41f4b71Sopenharmony_ci   Check that all the dependency .so files are packaged into the application and the application has the permission to open them.  
17e41f4b71Sopenharmony_ci
18e41f4b71Sopenharmony_ci4. Check whether the module import mode matches the .so file path.
19e41f4b71Sopenharmony_ci   If the module is imported by using **import xxx from '\@ohos.yyy.zzz'**, you may find **libzzz.z.so** or **libzzz_napi.z.so** in **/system/lib/module/yyy** (for a 32-bit system) or **/system/lib64/module/yyy** (for a 64-bit system). If the .so file does not exist or the file names do not match, an error containing the keyword "dlopen" will be reported.
20e41f4b71Sopenharmony_ci
21e41f4b71Sopenharmony_ci    
22e41f4b71Sopenharmony_ci
23e41f4b71Sopenharmony_ci| **Error Log**| **Solution**|
24e41f4b71Sopenharmony_ci| -------- | -------- |
25e41f4b71Sopenharmony_ci| module $SO is not allowed to load in restricted runtime | The module, identified by **$SO**, is not allowed for the worker thread running in a restricted environment and cannot be loaded. You are advised to delete the module.|
26e41f4b71Sopenharmony_ci| module $SO is in blocklist, loading prohibited | The module, identified by **$SO**, is in a blocklist due to the control of the widget or Extension, and cannot be loaded. You are advised to delete the module.|
27e41f4b71Sopenharmony_ci| load module failed. $ERRMSG | The dynamic library fails to be loaded. **$ERRMSG** indicates the cause of the loading failure. Possible causes include the following:<br>- The .so file to be loaded does not exist.<br>- The dependency .so file does not exist. <br>- Undefined symbol is found. <br>Locate the cause based on the error message.|
28e41f4b71Sopenharmony_ci| try to load abc file from $FILEPATH failed. | You can load either a dynamic library or an .abc file. If this log information is displayed when you attempt to load a dynamic library, ignore this message. If it is displayed when you attempt to load an .abc file, the .abc file does not exist. **$FILEPATH** indicates the module path.|
29e41f4b71Sopenharmony_ci
30e41f4b71Sopenharmony_ci5. If specific error message is reported, identify the fault based on the error message.
31e41f4b71Sopenharmony_ci
32e41f4b71Sopenharmony_ci| **Error message** | **Fault Analysis & Solution**|
33e41f4b71Sopenharmony_ci| -------- | -------- |
34e41f4b71Sopenharmony_ci| First attempt: $ERRMSG | Loading the .so file with the module name of "xxx" fails. *$ERRMSG* indicates the error information.|
35e41f4b71Sopenharmony_ci| Second attempt: $ERRMSG | Loading the .so file with the module name of "xxx_napi" fails. *$ERRMSG* indicates the error information.|
36e41f4b71Sopenharmony_ci| try to load abc file from xxx failed | Loading the .abc file fails. *xxx* indicates the name of the .abc file.|
37e41f4b71Sopenharmony_ci| module xxx is not allowed to load in restricted runtime. | This module cannot be used in restricted runtime. *xxx* indicates the module name. You are advised to delete the module.|
38e41f4b71Sopenharmony_ci| module xxx is in blocklist, loading prohibited. | The module cannot be used in the current extension. *xxx* indicates the module name. You are advised to delete the module.|
39e41f4b71Sopenharmony_ci
40e41f4b71Sopenharmony_ci## What should I do when an unexpected value is returned by an API and "occur exception need return" is reported?
41e41f4b71Sopenharmony_ci
42e41f4b71Sopenharmony_ciBefore the call is complete, some Node-API interfaces are checked for JavaScript (JS) exceptions in the VM. If an exception is detected, "occur exception need return" will be reported, with the line number of the code and the Node-API interface name.
43e41f4b71Sopenharmony_ci
44e41f4b71Sopenharmony_ciYou can solve this problem as follows:
45e41f4b71Sopenharmony_ci
46e41f4b71Sopenharmony_ci- If the exception does not matter, clear the exception.
47e41f4b71Sopenharmony_ci  Call **napi_get_and_clear_last_exception** before "occur exception need return" is printed to clear the exception.
48e41f4b71Sopenharmony_ci
49e41f4b71Sopenharmony_ci- Throw the exception to the ArkTS layer for capture.
50e41f4b71Sopenharmony_ci  Throw the exception directly to the ArkTS layer without going through the native logic.
51e41f4b71Sopenharmony_ci
52e41f4b71Sopenharmony_ci## What are the differences between the lifecycle of napi_value and napi_ref?
53e41f4b71Sopenharmony_ci
54e41f4b71Sopenharmony_ci- **native_value** is managed by **HandleScope**. Generally, you do not need to add **HandleScope** for **native_value** (except for **complete callback** of **uv_queue_work**).
55e41f4b71Sopenharmony_ci
56e41f4b71Sopenharmony_ci- **napi_ref** must be deleted manually.
57e41f4b71Sopenharmony_ci
58e41f4b71Sopenharmony_ci## How do I locate the fault if the return value of a Node-API interface is not "napi_ok"?
59e41f4b71Sopenharmony_ci
60e41f4b71Sopenharmony_ciWhen a Node-API interface is successfully executed, **napi_ok** is returned. If the return value is not **napi_ok**, locate the fault as follows:
61e41f4b71Sopenharmony_ci
62e41f4b71Sopenharmony_ci- Check the result of the input parameter null check, which is performed first before a Node-API interface is executed. The code is as follows:
63e41f4b71Sopenharmony_ci
64e41f4b71Sopenharmony_ci  ```cpp
65e41f4b71Sopenharmony_ci  CHECK_ENV: null check for env.
66e41f4b71Sopenharmony_ci  CHECK_ARG: null check for other input parameters.
67e41f4b71Sopenharmony_ci  ```
68e41f4b71Sopenharmony_ci
69e41f4b71Sopenharmony_ci- Check the result of the input parameter type check, which is performed for certain Node-API interfaces. For example, **napi_get_value_double** is used to obtain a C double value from a JS number, and the type of the JS value passed in must be number. The parameter type check is as follows:
70e41f4b71Sopenharmony_ci
71e41f4b71Sopenharmony_ci  ```cpp
72e41f4b71Sopenharmony_ci  RETURN_STATUS_IF_FALSE(env, nativeValue->TypeOf() == NATIVE_NUMBER, napi_number_expected);
73e41f4b71Sopenharmony_ci  ```
74e41f4b71Sopenharmony_ci
75e41f4b71Sopenharmony_ci- Check the return value, which contains the verification result of certain interfaces. For example, **napi_call_function** is used to execute a JS function. If an exception occurs in the JS function, Node-API returns **napi_pending_exception**.
76e41f4b71Sopenharmony_ci
77e41f4b71Sopenharmony_ci  ```cpp
78e41f4b71Sopenharmony_ci  auto resultValue = engine->CallFunction(nativeRecv, nativeFunc, nativeArgv, argc);
79e41f4b71Sopenharmony_ci  RETURN_STATUS_IF_FALSE(env, resultValue != nullptr, napi_pending_exception)
80e41f4b71Sopenharmony_ci  ```
81e41f4b71Sopenharmony_ci
82e41f4b71Sopenharmony_ci- Determine the status value returned, and analyze the situation in which the status value is returned.
83e41f4b71Sopenharmony_ci
84e41f4b71Sopenharmony_ci## What should I do if memory leaks when napi_threadsafe_function is used?
85e41f4b71Sopenharmony_ci
86e41f4b71Sopenharmony_ciWhen **napi_threadsafe_function** (**tsfn** for short) is used, **napi_acquire_threadsafe_function** is often called to change the reference count of **tsfn** to ensure that **tsfn** is not released unexpectedly. When all the **tsfn** calls are complete, **napi_release_threadsafe_function** should be called in **napi_tsfn_release** mode in a timely manner to ensure that the reference count returns to the value before **napi_acquire_threadsafe_function** is called. **tsfn** can be correctly released only when the reference count is **0**.
87e41f4b71Sopenharmony_ci
88e41f4b71Sopenharmony_ciWhen **env** is about to exit but the reference count of **tsfn** is not **0**, **napi_release_threadsafe_function** should be called in **napi_tsfn_abort** mode to ensure that **tsfn** is not held or used by **env** after **env** is released. If **env** continues to hold and use **tsfn** after exiting, the application may crash.
89e41f4b71Sopenharmony_ci
90e41f4b71Sopenharmony_ciThe following code shows how to register **env_cleanup** to ensure that **tsfn** is no longer held by **env** after **env** exits.
91e41f4b71Sopenharmony_ci
92e41f4b71Sopenharmony_ci```cpp
93e41f4b71Sopenharmony_ci#include <hilog/log.h> // To output logs, link libhilog_ndk.z.so.
94e41f4b71Sopenharmony_ci#include <thread> // Include the thread module to create and mange threads.
95e41f4b71Sopenharmony_ci#include <unistd.h> // Include unistd.h to suspend the execution of the calling thread.
96e41f4b71Sopenharmony_ci
97e41f4b71Sopenharmony_ci// Define the log domain and tag.
98e41f4b71Sopenharmony_ci#undef LOG_DOMAIN
99e41f4b71Sopenharmony_ci#undef LOG_TAG
100e41f4b71Sopenharmony_ci#define LOG_DOMAIN 0x2342
101e41f4b71Sopenharmony_ci#define LOG_TAG "MY_TSFN_DEMO"
102e41f4b71Sopenharmony_ci
103e41f4b71Sopenharmony_ci/*
104e41f4b71Sopenharmony_ci  To construct a scenario in which the env lifecycle is shorter than the native lifecycle,
105e41f4b71Sopenharmony_ci  the following uses worker, taskpool, and napi_create_ark_runtime to create an ArkTS
106e41f4b71Sopenharmony_ci  running environment for a worker thread and manually stop the thread in advance.
107e41f4b71Sopenharmony_ci*/
108e41f4b71Sopenharmony_ci
109e41f4b71Sopenharmony_ci
110e41f4b71Sopenharmony_ci// Define a struct to simulate the scenario where tsfn is stored.
111e41f4b71Sopenharmony_ciclass MyTsfnContext {
112e41f4b71Sopenharmony_cipublic:
113e41f4b71Sopenharmony_ci// MyTsfnContext is constructed only in a JS thread because Node-API is used.
114e41f4b71Sopenharmony_ciMyTsfnContext(napi_env env, napi_value workName) {
115e41f4b71Sopenharmony_ci    // Register the env_cleanup_hook function.
116e41f4b71Sopenharmony_ci    napi_add_env_cleanup_hook(env, Cleanup, this);
117e41f4b71Sopenharmony_ci    // Create a thread-safe function.
118e41f4b71Sopenharmony_ci    if (napi_create_threadsafe_function(env, nullptr, nullptr, workName, 1, 1, this,
119e41f4b71Sopenharmony_ci            TsfnFinalize, this, TsfnCallJs, &tsfn_) != napi_ok) {
120e41f4b71Sopenharmony_ci        OH_LOG_INFO(LOG_APP, "tsfn is created faild");
121e41f4b71Sopenharmony_ci        return;
122e41f4b71Sopenharmony_ci    };
123e41f4b71Sopenharmony_ci};
124e41f4b71Sopenharmony_ci
125e41f4b71Sopenharmony_ci~MyTsfnContext() { OH_LOG_INFO(LOG_APP, "MyTsfnContext is deconstructed"); };
126e41f4b71Sopenharmony_ci
127e41f4b71Sopenharmony_cinapi_threadsafe_function GetTsfn() {
128e41f4b71Sopenharmony_ci    std::unique_lock<std::mutex> lock(mutex_);
129e41f4b71Sopenharmony_ci    return tsfn_;
130e41f4b71Sopenharmony_ci}
131e41f4b71Sopenharmony_ci
132e41f4b71Sopenharmony_cibool Acquire() {
133e41f4b71Sopenharmony_ci    if (GetTsfn() == nullptr) {
134e41f4b71Sopenharmony_ci        return false;
135e41f4b71Sopenharmony_ci    };
136e41f4b71Sopenharmony_ci    return (napi_acquire_threadsafe_function(GetTsfn()) == napi_ok);
137e41f4b71Sopenharmony_ci};
138e41f4b71Sopenharmony_ci
139e41f4b71Sopenharmony_cibool Release() {
140e41f4b71Sopenharmony_ci    if (GetTsfn() == nullptr) {
141e41f4b71Sopenharmony_ci        return false;
142e41f4b71Sopenharmony_ci    };
143e41f4b71Sopenharmony_ci    return (napi_release_threadsafe_function(GetTsfn(), napi_tsfn_release) == napi_ok);
144e41f4b71Sopenharmony_ci};
145e41f4b71Sopenharmony_ci
146e41f4b71Sopenharmony_cibool Call(void *data) {
147e41f4b71Sopenharmony_ci    if (GetTsfn() == nullptr) {
148e41f4b71Sopenharmony_ci        return false;
149e41f4b71Sopenharmony_ci    };
150e41f4b71Sopenharmony_ci    return (napi_call_threadsafe_function(GetTsfn(), data, napi_tsfn_blocking) == napi_ok);
151e41f4b71Sopenharmony_ci};
152e41f4b71Sopenharmony_ci
153e41f4b71Sopenharmony_ciprivate:
154e41f4b71Sopenharmony_ci// Ensure correct read and write of tsfn by multiple threads.
155e41f4b71Sopenharmony_cistd::mutex mutex_;
156e41f4b71Sopenharmony_cinapi_threadsafe_function tsfn_ = nullptr;
157e41f4b71Sopenharmony_ci
158e41f4b71Sopenharmony_ci// Call napi_add_env_cleanup_hook.
159e41f4b71Sopenharmony_cistatic void Cleanup(void *data) {
160e41f4b71Sopenharmony_ci    MyTsfnContext *that = reinterpret_cast<MyTsfnContext *>(data);
161e41f4b71Sopenharmony_ci    napi_threadsafe_function tsfn = that->GetTsfn();
162e41f4b71Sopenharmony_ci    std::unique_lock<std::mutex> lock(that->mutex_);
163e41f4b71Sopenharmony_ci    that->tsfn_ = nullptr;
164e41f4b71Sopenharmony_ci    lock.unlock();
165e41f4b71Sopenharmony_ci    OH_LOG_WARN(LOG_APP, "cleanup is called");
166e41f4b71Sopenharmony_ci    napi_release_threadsafe_function(tsfn, napi_tsfn_abort);
167e41f4b71Sopenharmony_ci};
168e41f4b71Sopenharmony_ci
169e41f4b71Sopenharmony_ci// Callback to be invoked when tsfn is released.
170e41f4b71Sopenharmony_cistatic void TsfnFinalize(napi_env env, void *data, void *hint) {
171e41f4b71Sopenharmony_ci    MyTsfnContext *ctx = reinterpret_cast<MyTsfnContext *>(data);
172e41f4b71Sopenharmony_ci    OH_LOG_INFO(LOG_APP, "tsfn is released");
173e41f4b71Sopenharmony_ci    napi_remove_env_cleanup_hook(env, MyTsfnContext::Cleanup, ctx);
174e41f4b71Sopenharmony_ci    // Cleanup releases the thread-safe function in advance. To avoid UAF, enable the caller to trigger the release.
175e41f4b71Sopenharmony_ci    if (ctx->GetTsfn() != nullptr) {
176e41f4b71Sopenharmony_ci        OH_LOG_INFO(LOG_APP, "ctx is released");
177e41f4b71Sopenharmony_ci        delete ctx;
178e41f4b71Sopenharmony_ci    }
179e41f4b71Sopenharmony_ci};
180e41f4b71Sopenharmony_ci
181e41f4b71Sopenharmony_ci// Callback sent by tsfn to the JS thread for execution.
182e41f4b71Sopenharmony_cistatic void TsfnCallJs(napi_env env, napi_value func, void *context, void *data) {
183e41f4b71Sopenharmony_ci    MyTsfnContext *ctx = reinterpret_cast<MyTsfnContext *>(context);
184e41f4b71Sopenharmony_ci    char *str = reinterpret_cast<char *>(data);
185e41f4b71Sopenharmony_ci    OH_LOG_INFO(LOG_APP, "tsfn is called, data is: \"%{public}s\"", str);
186e41f4b71Sopenharmony_ci    // The service logic is omitted here.
187e41f4b71Sopenharmony_ci};
188e41f4b71Sopenharmony_ci};
189e41f4b71Sopenharmony_ci
190e41f4b71Sopenharmony_ci// Register the myTsfnDemo method with the module. The myTsfnDemo method is defined as follows:
191e41f4b71Sopenharmony_ci// export const myTsfnDemo: () => void;
192e41f4b71Sopenharmony_cinapi_value MyTsfnDemo(napi_env env, napi_callback_info info) {
193e41f4b71Sopenharmony_ci    OH_LOG_ERROR(LOG_APP, "MyTsfnDemo is called");
194e41f4b71Sopenharmony_ci    napi_value workName = nullptr;
195e41f4b71Sopenharmony_ci    napi_create_string_utf8(env, "MyTsfnWork", NAPI_AUTO_LENGTH, &workName);
196e41f4b71Sopenharmony_ci    MyTsfnContext *myContext = new MyTsfnContext(env, workName);
197e41f4b71Sopenharmony_ci    if (myContext->GetTsfn() == nullptr) {
198e41f4b71Sopenharmony_ci        OH_LOG_ERROR(LOG_APP, "faild to create tsfn");
199e41f4b71Sopenharmony_ci        delete myContext;
200e41f4b71Sopenharmony_ci        return nullptr;
201e41f4b71Sopenharmony_ci    };
202e41f4b71Sopenharmony_ci    char *data0 = "Im call in ArkTS Thread";
203e41f4b71Sopenharmony_ci    if (!myContext->Call(data0)) {
204e41f4b71Sopenharmony_ci        OH_LOG_INFO(LOG_APP, "call tsfn failed");
205e41f4b71Sopenharmony_ci    };
206e41f4b71Sopenharmony_ci
207e41f4b71Sopenharmony_ci    // Create a thread to simulate an asynchronous operation.
208e41f4b71Sopenharmony_ci    std::thread(
209e41f4b71Sopenharmony_ci        [](MyTsfnContext *myCtx) {
210e41f4b71Sopenharmony_ci            if (!myCtx->Acquire()) {
211e41f4b71Sopenharmony_ci                OH_LOG_ERROR(LOG_APP, "acquire tsfn faild");
212e41f4b71Sopenharmony_ci                return;
213e41f4b71Sopenharmony_ci            };
214e41f4b71Sopenharmony_ci            char *data1 = "Im call in std::thread";
215e41f4b71Sopenharmony_ci            // This operation is optional and used only to check whether the asynchronous tsfn is still valid.
216e41f4b71Sopenharmony_ci            if (!myCtx->Call(data1)) {
217e41f4b71Sopenharmony_ci                OH_LOG_ERROR(LOG_APP, "call tsfn failed");
218e41f4b71Sopenharmony_ci            };
219e41f4b71Sopenharmony_ci            // Suspend the thread for 5 seconds to simulate a time-consuming operation, which is not complete when env exits.
220e41f4b71Sopenharmony_ci            sleep(5);
221e41f4b71Sopenharmony_ci            // When the asynchronous operation is complete, tsfn has been released and set to nullptr.
222e41f4b71Sopenharmony_ci            char *data2 = "Im call after work";
223e41f4b71Sopenharmony_ci            if (!myCtx->Call(data2) && !myCtx->Release()) {
224e41f4b71Sopenharmony_ci                OH_LOG_ERROR(LOG_APP, "call and release tsfn failed");
225e41f4b71Sopenharmony_ci                delete myCtx;
226e41f4b71Sopenharmony_ci            }
227e41f4b71Sopenharmony_ci        }, myContext).detach();
228e41f4b71Sopenharmony_ci    return nullptr;
229e41f4b71Sopenharmony_ci};
230e41f4b71Sopenharmony_ci
231e41f4b71Sopenharmony_ci```
232e41f4b71Sopenharmony_ci
233e41f4b71Sopenharmony_ciThe following is the main thread logic, which creates worker threads and instruct workers to execute tasks.
234e41f4b71Sopenharmony_ci
235e41f4b71Sopenharmony_ci```ts
236e41f4b71Sopenharmony_ci// Main thread.
237e41f4b71Sopenharmony_ciimport worker, { MessageEvents } from '@ohos.worker';
238e41f4b71Sopenharmony_ci
239e41f4b71Sopenharmony_ciconst mWorker = new worker.ThreadWorker('../workers/Worker');
240e41f4b71Sopenharmony_cimWorker.onmessage = (e: MessageEvents) => {
241e41f4b71Sopenharmony_ci    const action: string | undefined = e.data?.action;
242e41f4b71Sopenharmony_ci    if (action === 'kill') {
243e41f4b71Sopenharmony_ci        mWorker.terminate();
244e41f4b71Sopenharmony_ci    }
245e41f4b71Sopenharmony_ci}
246e41f4b71Sopenharmony_ci
247e41f4b71Sopenharmony_ci// The registration of the triggering mode is omitted.
248e41f4b71Sopenharmony_cimWorker.postMessage({action: 'tsfn-demo'})
249e41f4b71Sopenharmony_ci
250e41f4b71Sopenharmony_ci```
251e41f4b71Sopenharmony_ci
252e41f4b71Sopenharmony_ciThe following is the worker thread logic, which triggers native tasks.
253e41f4b71Sopenharmony_ci
254e41f4b71Sopenharmony_ci```ts
255e41f4b71Sopenharmony_ci// worker.ets
256e41f4b71Sopenharmony_ciimport worker, { ThreadWorkerGlobalScope, MessageEvents, ErrorEvent } from '@ohos.worker';
257e41f4b71Sopenharmony_ciimport napiModule from 'libentry.so'; // libentry.so is the module name of the Node-API library.
258e41f4b71Sopenharmony_ci
259e41f4b71Sopenharmony_ciconst workerPort: ThreadWorkerGlobalScope = worker.workerPort;
260e41f4b71Sopenharmony_ci
261e41f4b71Sopenharmony_ciworkerPort.onmessage = (e: MessageEvents) => {
262e41f4b71Sopenharmony_ci    const action: string | undefined = e.data?.action;
263e41f4b71Sopenharmony_ci    if (action === 'tsfn-demo') {
264e41f4b71Sopenharmony_ci        // Trigger the tsfn demo in C++.
265e41f4b71Sopenharmony_ci        napiModule.myTsfnDemo();
266e41f4b71Sopenharmony_ci        // Instruct the main thread to terminate the worker.
267e41f4b71Sopenharmony_ci        workerPort.postMessage({action: 'kill'});
268e41f4b71Sopenharmony_ci    };
269e41f4b71Sopenharmony_ci}
270e41f4b71Sopenharmony_ci```
271