rdkNativeScript is a JavaScript runtime component in the RDK middleware that enables native execution of JavaScript applications directly on RDKE/RDKV devices, outside of a full browser environment. It provides a lightweight, embeddable runtime that exposes device capabilities — such as media playback, networking, and display — to JavaScript applications through a set of controlled API bindings. The component is deployed as a Thunder plugin with the callsign org.rdk.jsruntime and can be cloned to create multiple independent runtime instances.

At the device level, rdkNativeScript allows non-browser JavaScript applications such as lightweight widgets and streaming clients to run with native-level access to media pipelines, WebSocket communication, and the Wayland display stack. It bridges the gap between JavaScript application logic and low-level device capabilities without requiring a full web engine.

At the module level, rdkNativeScript manages the complete lifecycle of JavaScript execution contexts: it initializes the JavaScript engine, creates per-application contexts, loads and evaluates scripts (from local paths or remote URLs), manages optional module bindings per context, and provides a WebSocket-based IPC channel for external control.

```mermaid
flowchart LR

%% Styles
classDef Apps stroke:#00B9F1,fill:#E6F7FD,stroke-width:2px;
classDef RDKMW stroke:#75D701,fill:#F1FFE6,stroke-width:2px;
classDef VL stroke:#808080,fill:#F2F2F2,stroke-width:2px;

%% Apps Layer
    subgraph Apps["Apps & Runtimes"]
        WPE_RT["WPEFramework / Thunder"]
    end

%% Middleware
    subgraph RDKMW["RDK Core Middleware"]
        JSRuntime["rdkNativeScript\n(org.rdk.jsruntime)"]
        AAMP["AAMP Media Player"]
        Westeros["Westeros / Wayland"]
        Thunder["Thunder Core"]
    end

%% Vendor Layer
    subgraph VL["Vendor Layer"]
        Essos["Essos (Wayland Compositor Abstraction)"]
        GST["GStreamer Pipeline"]
        EGL["EGL / GPU"]
    end

    %% Connections
    WPE_RT -->|JSON-RPC: launchApplication| Thunder
    Thunder -->|Dispatch| JSRuntime
    JSRuntime -->|Media playback bindings| AAMP
    JSRuntime -->|Wayland display + key input| Westeros
    AAMP -->|Pipeline control| GST
    Westeros -->|Compositor abstraction| Essos
    Essos -->|EGL rendering| EGL
```

Key Features & Responsibilities:


Design

rdkNativeScript is structured around a layered separation between engine management, context lifecycle, and application dispatch. The runtime is initialized once per process through NativeJSRenderer, which owns the IJavaScriptEngine instance and manages the map of active application contexts. Each application is represented by a numeric identifier mapped to a JavaScriptContext instance. The JavaScriptContextBase class provides engine-agnostic operations — file loading, script evaluation delegation, key event routing, and ThunderJS / RDK WebBridge code injection — while engine-specific implementations extend it for JSC or QuickJS.

Northbound, the component exposes its API through the Thunder plugin mechanism: clients issue a JSON-RPC launchApplication call to a cloned plugin instance. The server path, when enabled, accepts a similar command set over a WebSocket connection on the port defined by WS_SERVER_PORT using messages of the form { "method": "…", "params": { … } } (module tokens are passed as moduleSettings). The JSRuntimeServer dispatches incoming messages to the same NativeJSRenderer methods used by the Thunder plugin path. Southbound, the component consumes the JavaScriptCore C API for script evaluation, GStreamer for media pipeline initialization, libcurl for script download from remote URLs, and the Essos API for Wayland compositor setup and keyboard event delivery.

The design isolates per-application state (URL, JS context, module flags, performance metrics) inside JavaScriptContext and uses a shared JSContextGroupRef across all contexts in the process. This allows garbage collection to be coordinated globally through a periodic GLib timer while individual contexts can be released independently. The main GLib event loop processes both JSC internal events and timer callbacks on the main thread; applications are created and run from separate per-application threads that call into the renderer.

IPC is handled through two mechanisms. Within the device, Thunder JSON-RPC is the primary channel for application control. The WebSocket server and client provide an alternative channel used for remote control and container-bridged delivery. Container-side delivery is implemented in JSRuntimeContainer, which reads the container process PID from the cgroup filesystem, enters the container's network namespace using setns, and connects a WebSocket client to the in-container server endpoint.

Module settings, application URLs, and runtime flags are held in memory for the lifetime of the process. Runtime configuration is managed through environment variables or sentinel files in /tmp.

```mermaid
graph TD

    subgraph JSRuntime ["rdkNativeScript Process"]

        subgraph RendererLayer ["NativeJSRenderer (Application Manager)"]
            NR["NativeJSRenderer\nManages context map, pending requests,\napplication lifecycle (create/run/terminate)"]
        end

        subgraph EngineLayer ["JavaScript Engine"]
            JSE["JavaScriptEngine (JSC)\nGLib main loop, GStreamer init,\nperiodic GC, remote inspector setup"]
        end

        subgraph ContextLayer ["Per-Application Contexts"]
            CTX1["JavaScriptContext (App 1)\nJSC global context, module bindings,\nAAMP player, network metrics"]
            CTX2["JavaScriptContext (App N)\nJSC global context, module bindings"]
        end

        subgraph BaseLayer ["JavaScriptContextBase"]
            BASE["Engine-agnostic ops:\nfile load, runScript, runFile,\nThunderJS injection, key routing"]
        end

        subgraph SupportLayer ["Support Modules"]
            ES["EssosInstance\nWayland display init,\nkeyboard event callbacks"]
            MS["ModuleSettings\nPer-app feature flags parsed\nfrom options string"]
            LOG["NativeJSLogger\nLevel-filtered logging,\noptional EthanLog output"]
        end

    end

    NR --> JSE
    NR --> CTX1
    NR --> CTX2
    CTX1 --> BASE
    CTX2 --> BASE
    NR --> ES
    NR --> MS
```

Threading Model

RDKE/RDKV Platform and Integration Requirements

Module Settings

ModuleSettings is a plain data structure that controls which JavaScript binding modules are registered for a given application context. Each application receives its own ModuleSettings instance populated at launch time; the settings are fixed for the lifetime of that context.

Available Modules:

Option TokenFieldWhat It Enables
httpenableHttpHTTP client bindings in the JavaScript context
xhrenableXHRXMLHttpRequest (XHR) bindings
wsenableWebSocketWebSocket client bindings
wsenhancedenableWebSocketEnhancedEnhanced WebSocket bindings with additional event support
fetchenableFetchFetch API bindings
jsdomenableJSDOMFull JSDOM bindings for DOM API emulation
minijsdomenableMiniJSDOMLightweight JSDOM subset; takes precedence over jsdom when both tokens are specified
windowenableWindowWindow object bindings
playerenablePlayerAAMP media player bindings; exposes AAMPMediaPlayer as a JavaScript global

Population Mechanisms:

All flags default to false; only tokens present in the options string activate the corresponding module. minijsdom and jsdom are mutually exclusive — minijsdom takes precedence when both tokens appear.


Component State Flow

Initialization to Active State

```mermaid
sequenceDiagram
    participant System as System / PluginActivator
    participant Thunder as Thunder
    participant NR as NativeJSRenderer
    participant JSE as JavaScriptEngine-JSC
    participant Essos as EssosInstance
    participant GST as GStreamer

    System->>Thunder: Controller.1.clone org.rdk.jsruntime to jsruntime1
    System->>Thunder: Controller.1.activate jsruntime1
    Thunder->>NR: Construct NativeJSRenderer with waylandDisplay
    Note over NR: Read NATIVEJS_LOG_LEVEL env var
    NR->>Essos: EssosInstance.initialize useWayland
    Essos-->>NR: Essos context ready
    NR->>JSE: new JavaScriptEngine and initialize
    JSE->>GST: gst_init when player support is compiled and NATIVEJS_GST_START_DISABLE is unset
    JSE->>JSE: WTF.initializeMainThread
    JSE->>JSE: g_main_loop_new and install GC timer
    Note over JSE: Remote inspector started if NATIVEJS_INSPECTOR_SERVER set
    JSE-->>NR: Engine initialized
    Note over NR: Check /tmp sentinel files for ThunderJS, WebBridge, WS server
    NR-->>Thunder: Ready

    loop Runtime
        Note over NR: State: Active - awaiting launchApplication calls
    end
```

Runtime State Changes

State Change Triggers:

Context Switching Scenarios:


Call Flows

Initialization Call Flow

```mermaid
sequenceDiagram
    participant Client as ThunderJS / curl
    participant Thunder as Thunder
    participant NR as NativeJSRenderer
    participant JSE as JavaScriptEngine

    Client->>Thunder: Controller.1.clone {callsign: "org.rdk.jsruntime", newcallsign: "jsruntime1"}
    Thunder-->>Client: Clone acknowledged
    Client->>Thunder: Controller.1.activate {callsign: "jsruntime1"}
    Thunder->>NR: Construct and initialize
    NR->>JSE: initialize()
    JSE-->>NR: Engine ready
    NR-->>Thunder: Plugin active
    Thunder-->>Client: Activation success
```

Request Processing Call Flow

```mermaid
sequenceDiagram
    participant Client as ThunderJS / curl
    participant Thunder as Thunder
    participant NR as NativeJSRenderer
    participant CTX as JavaScriptContext
    participant CURL as libcurl
    participant AAMP as AAMP JS Bindings

    Client->>Thunder: JSON-RPC: jsruntime1.1.launchApplication {url, options}
    Thunder->>NR: Dispatch launchApplication
    NR->>NR: createApplicationIdentifier()
    NR->>CTX: new JavaScriptContext(moduleSettings, url, engine)
    Note over CTX: Register bindings for enabled modules\n(XHR, WebSocket, Player, Fetch, JSDOM…)
    alt Player module enabled
        CTX->>AAMP: Static AAMPPlayer_LoadJS(context), or dynamic dlopen(libaampjsbindings.so) / aamp_LoadJSController(context)
    end
    NR->>CURL: downloadFile(url) [if remote URL]
    CURL-->>NR: Script content
    NR->>CTX: runFile(scriptPath, args, isApplication=true)
    CTX-->>NR: Execution complete
    NR-->>Thunder: JSON-RPC response {success: true}
    Thunder-->>Client: Response
```

Internal Modules

Module / ClassDescriptionKey Files
NativeJSRendererCentral application manager. Owns the JavaScript engine instance and the map of active contexts. Exposes createApplication, runApplication, runJavaScript, and terminateApplication. Manages pending request queues, Essos initialization, and developer console thread.NativeJSRenderer.cpp, NativeJSRenderer.h
JavaScriptEngineConcrete JSC engine implementation. Initializes the WTF main thread, GLib event loop, GStreamer pipeline subsystem, remote inspector server, and the periodic garbage collection timer. Implements IJavaScriptEngine.src/jsc/JavaScriptEngine.cpp, include/jsc/JavaScriptEngine.h
JavaScriptContextPer-application JSC global context. Registers all enabled module bindings (setTimeout, XHR, WebSocket, HTTP, Fetch, JSDOM, crypto, player). Tracks performance metrics (context creation time, execution time, playback start time) and network metrics via NetworkMetricsListener. Implements IJavaScriptContext.src/jsc/JavaScriptContext.cpp, include/jsc/JavaScriptContext.h
JavaScriptContextBaseEngine-agnostic base class for JavaScript contexts. Implements file loading, runScript, runFile, key event routing to the active context, ThunderJS and RDK WebBridge code injection, and module path resolution.src/JavaScriptContextBase.cpp, include/JavaScriptContextBase.h
JSRuntimeServerWebSocket server (singleton) that listens on a configurable port and dispatches JSON-encoded launchApplication, createApplication, runApplication, runJavaScript, and destroyApplication commands to NativeJSRenderer. Uses websocketpp with Asio transport.src/JSRuntimeServer.cpp, include/JSRuntimeServer.h
JSRuntimeClientWebSocket client (singleton) that connects to a JSRuntimeServer instance and provides a synchronous sendCommand interface with a 5-second response timeout. Used by the standalone client executable to send commands to a runtime server.src/JSRuntimeClient.cpp, include/JSRuntimeClient.h
JSRuntimeContainerProvides utilities for entering Linux namespaces (network, mount, IPC) of a containerized process by resolving the container PID from the cgroup filesystem and calling setns on a temporary thread. Also builds and dispatches WebSocket launch messages to the in-container server.src/JSRuntimeContainer.cpp, include/JSRuntimeContainer.h
EssosInstanceSingleton wrapper around the Essos compositor abstraction API. Initializes an Essos context against the active Wayland display and translates raw Wayland key events into JavaScriptKeyDetails structures that are forwarded to the registered JavaScriptKeyListener.src/EssosInstance.cpp, include/EssosInstance.h
ModuleSettingsPlain data structure holding boolean flags for each optional JavaScript module. Populated either from command-line flags in standalone mode or by parsing a comma-separated options string passed to launchApplication.src/ModuleSettings.cpp, include/ModuleSettings.h
NativeJSLoggerComponent-level logger with five severity levels (DEBUG, INFO, WARN, ERROR, FATAL). Level is set via the NATIVEJS_LOG_LEVEL environment variable at startup. Supports output to either stdout or EthanLog when the ETHAN_LOGGING_PIPE environment variable is present.src/NativeJSLogger.cpp, include/NativeJSLogger.h
PlayerWrapperManages a PlayerInstanceAAMP player object within a JSC context. Initializes AAMP, registers JavaScript-callable player functions (load, play, pause, stop, seek, audio/text track selection, etc.), and routes player events back into the JS context via PlayerEventHandler.src/jsc/PlayerWrapper.cpp, include/jsc/PlayerWrapper.h

Component Interactions

Interaction Matrix

Target Component / LayerInteraction PurposeKey APIs / Topics
Plugins

ThunderPlugin activation, JSON-RPC method dispatch, plugin cloningController.1.clone, Controller.1.activate, launchApplication
HAL

EssosWayland display initialization and keyboard input routingEssContextCreate, EssContextSetKeyListener, EssContextStart
GStreamerMedia pipeline subsystem initialization required for AAMP playbackgst_init()
AAMP JS BindingsMedia playback control exposed as AAMPMediaPlayer in JavaScriptAAMPPlayer_LoadJS(), AAMPPlayer_UnloadJS() (dynamic: libaampjsbindings.so)
libcurlRemote script file download by URL before evaluationcurl_easy_perform, write callbacks
External Systems

WebSocket Server (self)External tools and container clients send application control commandsWebSocket JSON messages: launchApplication, createApplication, destroyApplication
Remote InspectorJavaScript debugger connection over networkJSRemoteInspectorStart(), env NATIVEJS_INSPECTOR_SERVER

Events Published

Event NameTopicTrigger ConditionSubscriber Components
Key press / releaseInternal JavaScriptKeyListener callbackWayland key event received by EssosInstanceJavaScriptContextBase registered as the current key listener (processes key event in JS engine)

IPC Flow Patterns

WebSocket Server Command Flow:

```mermaid
sequenceDiagram
    participant ExtTool as External Tool / Container Client
    participant SRV as JSRuntimeServer
    participant NR as NativeJSRenderer
    participant CTX as JavaScriptContext

    ExtTool->>SRV: WebSocket connect (WS_SERVER_PORT)
    ExtTool->>SRV: JSON: {"method": "launchApplication", "params": {"url": "...", "moduleSettings": "player,xhr"}}
    SRV->>NR: createApplication(moduleSettings)
    SRV->>NR: runApplication(id, url)
    NR->>CTX: Script execution
    CTX-->>NR: Done
    SRV-->>ExtTool: JSON response {"result":"ID : <id>"}
```

Implementation Details

Key External API Integrations

APIPurposeImplementation File
EssContextCreate()Creates an Essos compositor contextsrc/EssosInstance.cpp
EssContextSetTerminateListener()Registers a termination callback with the compositorsrc/EssosInstance.cpp
EssContextSetKeyListener()Registers a keyboard input callback for key press and release eventssrc/EssosInstance.cpp
EssContextStart()Starts the Essos event loop, connecting to the Wayland displaysrc/EssosInstance.cpp
gst_init()Initializes the GStreamer framework before any pipeline creationsrc/jsc/JavaScriptEngine.cpp
AAMPPlayer_LoadJS()Loads AAMP JS bindings into a JSC global context (static mode)src/jsc/JavaScriptContext.cpp
AAMPPlayer_UnloadJS()Unloads AAMP JS bindings from a JSC global context (static mode)src/jsc/JavaScriptContext.cpp
dlopen("libaampjsbindings.so")Dynamically loads the AAMP JS bindings library at application creationsrc/jsc/JavaScriptContext.cpp
JSGlobalContextCreateInGroup()Creates a new JSC global context within the shared context groupsrc/jsc/JavaScriptContext.cpp
JSContextGroupCreate()Creates the shared JSC context group for the processsrc/jsc/JavaScriptContext.cpp
JSSynchronousGarbageCollectForDebugging()Forces synchronous GC on context releasesrc/jsc/JavaScriptContext.cpp
curl_easy_perform()Downloads remote script content before evaluationsrc/NativeJSRenderer.cpp

Key Implementation Logic


Configuration

Key Configuration Parameters

ParameterTypeDefaultDescription
NATIVEJS_LOG_LEVELstring (env)INFOSets the logging verbosity. Accepted values: debug, info, warn, error, fatal.
NATIVEJS_GC_INTERVALfloat (env)60000Garbage collection timer interval in milliseconds. Controls how frequently the JSC GC runs.
NATIVEJS_INSPECTOR_SERVERstring (env)(not set)Activates the custom remote JavaScript inspector only when built with REMOTE_INSPECTOR_ENABLE. The value supplies a port in host:port form, but the server listens on all interfaces; restrict access to a trusted network.
NATIVEJS_GST_START_DISABLEstring (env)(not set)When set to any value, suppresses gst_init() during engine initialization.
NATIVEJS_EMBED_THUNDERJSstring (env)(not set)When set, enables ThunderJS injection into all contexts. Equivalent to creating the /tmp/nativejsEmbedThunder sentinel file.
NATIVEJS_ENABLE_WEBSOCKET_SERVERstring (env)(not set)When set, or when the /tmp/nativejsEnableWebSocketServer sentinel exists, enables the JavaScript webSocketServer binding in contexts (when built with ENABLE_WEBSOCKET_SERVER). It does not start the external JSRuntimeServer, which is started with the standalone --server option.
/tmp/nativejsRdkWebBridgefile (sentinel)(not present)When present, enables RDK WebBridge injection into all contexts.
WAYLAND_DISPLAYstring (env)(not set)Set automatically from the --display argument to direct the runtime to a specific Wayland compositor socket.
WS_SERVER_PORTint (build)5000WebSocket server listen port. Defined at build time via -DWS_SERVER_PORT=5000.
NATIVEJS_DUMP_NETWORKMETRICstring (env)(not set)When set, collects network metrics and stores the output to a file in /tmp.

Runtime Configuration

The options string passed to launchApplication configures the module bindings for the created JavaScript context:

# Launch with player and XHR modules enabled
curl -H "Content-Type: application/json" \
  --request POST \
  --data '{"jsonrpc":"2.0","id":"1","method":"jsruntime1.1.launchApplication","params":{"url":"http://host/app.js","options":"player,xhr"}}' \
  http://127.0.0.1:9998/jsonrpc

Accepted option tokens: http, xhr, ws, wsenhanced, fetch, jsdom, minijsdom, window, player.

Configuration Persistence

Configuration changes are not persisted across reboots.