You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: Tests/NodeApi/NAPI_VERSION_ROADMAP.md
+14-7Lines changed: 14 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -11,7 +11,11 @@ This is a multi-PR effort. Keep the boundaries strict:
11
11
-**Bug fixes** against the current N-API implementation that the tests surface → *quarantine* the failing test via the allow-list and open a separate fix PR. Do not fix impl bugs in the test-suite PR.
12
12
-**Any `NAPI_VERSION` bump** (6 → 7 → 8 → …) and the per-engine native work it requires.
13
13
-**jsc-android engine bump** (v6 enabler — see below).
14
-
-**Android in-process addon loading** — building `napi` as a shared library so `dlopen`'d test addons can resolve `napi_*` from the host (see *Platform status* below). Affects every Android consumer's packaging → separate PR.
14
+
15
+
> **Android packaging note:** to run the suite in-process the addons are `dlopen`'d as standalone
16
+
> `.node` modules, which requires `napi` to ship as a shared library (`libnapi.so`) on Android (see
17
+
> *Platform status*). That is a deliberate packaging change for all Android consumers; if upstream
18
+
> prefers it isolated, it can land as a small precursor commit/PR that this suite depends on.
15
19
16
20
## Current state (2026-06-04)
17
21
@@ -35,11 +39,13 @@ This is a multi-PR effort. Keep the boundaries strict:
35
39
| Platform | Engine | v5 suite | Runner | Notes |
36
40
|---|---|---|---|---|
37
41
|**macOS**| JavaScriptCore | ✅ **12/12** (plain + ASan/UBSan + TSan) | child-process | Full v5 reference. |
**Android in-process addon loading (dynamic `.node` + shared `libnapi.so`).** The app sandbox can't `fork`/`exec`, so the conformance suite runs the addons *in-process*. The addons are built as standalone SHARED `lib<name>.so` modules (matching nodejs/node-api-cts's `add_node_api_cts_addon`), packaged by AGP into `nativeLibraryDir`, and `dlopen`'d by `node_lite_android` by soname. For their `napi_*` imports to bind at load, **`napi` is built as a shared library (`libnapi.so`) on Android** — a real `DT_NEEDED` of both the host and every addon, so there is a single napi instance. This is the IoC / dynamic-self-registration model: `dlopen` the addon → its `DT_NEEDED libnapi.so` resolves the `napi_*` → `dlsym("napi_register_module_v1")` → call it. Verified on device: `lib2_function_arguments.so` carries `DT_NEEDED [libnapi.so]`, its 8 `napi_*` are imports (`U`), `libnapi.so` exports all 106 `napi_*` (`T`), and the 4 v5 tests pass. The harness also needs the `noexcept`-removal fix (`38864e4`) so a failing test surfaces as a `ProcessResult` rather than `std::terminate`, and native stdout/stderr is pumped to logcat (tag `NodeApiTests`) for visible gtest output.
39
45
40
-
**Android in-process addon loading (statically linked).** The app sandbox can't `fork`/`exec`, so the conformance suite runs the addons *in-process*. Dynamic `.node` loading there is a dead end — and is never shipped to the Play/Quest stores anyway: the host (`libUnitTestsJNI.so`) is loaded RTLD_LOCAL by `System.loadLibrary`, and bionic won't surface its (exported) `napi_*` to a `dlopen`'d module; post-hoc `RTLD_GLOBAL` promotion is a no-op on bionic (verified on device: the module `dlopen` returns NULL; the addon carries no `DT_NEEDED` for napi). So the addons are **statically linked into the host** instead: `node_api.h` makes the registrar/version entry-point names overridable, `entry_point.h` (under `JSR_NODE_API_STATIC_LINK`) gives `Init` internal linkage and emits a per-addon load-time constructor that self-registers its uniquely-suffixed entry points, the Android CMake compiles each addon as an OBJECT library, and `node_lite_android` resolves them from an in-process registry instead of `dlopen`+`dlsym`. The 4 v5 js-native-api tests now execute in-process and **pass** (commits `f32130e`, `f0d1c2e`; the harness also needed the `noexcept`-removal fix `38864e4` so a failing test surfaces as a `ProcessResult` rather than `std::terminate`). Native stdout/stderr is pumped to logcat (tag `NodeApiTests`) so gtest results are visible (`adb logcat -s NodeApiTests`). Building `napi` as a shared library (task #9) would also work and is the only option if real external `.node` addons ever need `dlopen` on Android, but it ripples to every consumer's packaging and is not needed for the conformance suite.
46
+
> Why shared `napi` rather than static-linking the addons into the host: bionic will not surface a `System.loadLibrary`-loaded (RTLD_LOCAL) host's `napi_*` to a `dlopen`'d module, and post-hoc `RTLD_GLOBAL` host promotion is a no-op on bionic — so a `dlopen`'d addon can only resolve `napi` via a real shared-library `DT_NEEDED`. (An earlier iteration statically linked the addons into the host and passed too; the shared-lib model was adopted to align with node-api-cts's dynamic `.node` addons, easing a future migration.)
41
47
42
-
> Emulator note: the unrelated `JavaScript.All` UnitTest (XMLHttpRequest/WebSocket/HTTP mocha tests) fails in an offline emulator (status 0 vs 200/404, socket timeouts); it runs before and is independent of the js-native-api suite.
48
+
> Emulator note: the unrelated `JavaScript.All` UnitTest (XMLHttpRequest/WebSocket/HTTP mocha tests) can fail in an offline emulator (status 0 vs 200/404, socket timeouts); it runs before and is independent of the js-native-api suite.
43
49
44
50
## Chakra N-API ceiling
45
51
@@ -97,9 +103,10 @@ run the suite per engine → implement the JSC/(Chakra) gaps → green.
97
103
`amaro` for TS-strip); the only implementor is `node`. Adopting it means authoring an `implementors/jsruntimehost/`
0 commit comments