@ThreadSafe
public final class JavaScriptIsolate implements AutoCloseable

Environment within a JavaScriptSandbox where JavaScript is executed.

A single JavaScriptSandbox process can contain any number of JavaScriptIsolate instances where JS can be evaluated independently and in parallel.

Each isolate has its own state and JS global object, and cannot interact with any other isolate through JS APIs. There is only a moderate security boundary between isolates in a single JavaScriptSandbox. If the code in one JavaScriptIsolate is able to compromise the security of the JS engine then it may be able to observe or manipulate other isolates, since they run in the same process. For strong isolation multiple JavaScriptSandbox processes should be used, but it is not supported at the moment. Please find the feature request here.

This class is thread-safe.

Summary

Public methods

void

Add a callback to listen for isolate crashes.

void

Add a callback to listen for isolate crashes.

void
@RequiresFeature(name = JavaScriptSandbox.JS_FEATURE_CONSOLE_MESSAGING, enforcement = "androidx.javascriptengine.JavaScriptSandbox#isFeatureSupported")
clearConsoleCallback()

Clear any JavaScriptConsoleCallback set via setConsoleCallback.

void

Closes the JavaScriptIsolate object and renders it unusable.

@NonNull ListenableFuture<String>
@RequiresFeature(name = JavaScriptSandbox.JS_FEATURE_EVALUATE_FROM_FD, enforcement = "androidx.javascriptengine.JavaScriptSandbox#isFeatureSupported")
evaluateJavaScriptAsync(@NonNull AssetFileDescriptor afd)

Reads and evaluates the JavaScript code in the file described by the given AssetFileDescriptor.

@NonNull ListenableFuture<String>

Evaluates the given JavaScript code and returns the result.

@NonNull ListenableFuture<String>
@RequiresFeature(name = JavaScriptSandbox.JS_FEATURE_EVALUATE_FROM_FD, enforcement = "androidx.javascriptengine.JavaScriptSandbox#isFeatureSupported")
evaluateJavaScriptAsync(@NonNull ParcelFileDescriptor pfd)

Reads and evaluates the JavaScript code in the file described by the given ParcelFileDescriptor.

void
@RequiresFeature(name = JavaScriptSandbox.JS_FEATURE_PROVIDE_CONSUME_ARRAY_BUFFER, enforcement = "androidx.javascriptengine.JavaScriptSandbox#isFeatureSupported")
provideNamedData(@NonNull String name, @NonNull byte[] inputBytes)

Provides a byte array for consumption from the JavaScript environment.

void

Remove a callback previously registered with addOnTerminatedCallback.

void
@RequiresFeature(name = JavaScriptSandbox.JS_FEATURE_CONSOLE_MESSAGING, enforcement = "androidx.javascriptengine.JavaScriptSandbox#isFeatureSupported")
setConsoleCallback(@NonNull JavaScriptConsoleCallback callback)

Set a JavaScriptConsoleCallback to process console messages from the isolate.

void
@RequiresFeature(name = JavaScriptSandbox.JS_FEATURE_CONSOLE_MESSAGING, enforcement = "androidx.javascriptengine.JavaScriptSandbox#isFeatureSupported")
setConsoleCallback(
    @NonNull Executor executor,
    @NonNull JavaScriptConsoleCallback callback
)

Set a JavaScriptConsoleCallback to process console messages from the isolate.

Protected methods

void

Public methods

addOnTerminatedCallback

Added in 1.0.0-rc01
public void addOnTerminatedCallback(@NonNull Consumer<TerminationInfo> callback)

Add a callback to listen for isolate crashes.

This is the same as calling addOnTerminatedCallback using the main executor of the context used to create the JavaScriptSandbox object.

Parameters
@NonNull Consumer<TerminationInfo> callback

the consumer to be called with TerminationInfo when a crash occurs

Throws
java.lang.IllegalStateException

if the callback is already registered (using any executor)

addOnTerminatedCallback

Added in 1.0.0-rc01
public void addOnTerminatedCallback(
    @NonNull Executor executor,
    @NonNull Consumer<TerminationInfo> callback
)

Add a callback to listen for isolate crashes.

There is no guaranteed order to when these callbacks are triggered and unfinished evaluations' futures are rejected.

Registering a callback after the isolate has crashed will result in it being executed immediately on the supplied executor with the isolate's TerminationInfo as an argument.

Closing an isolate via close is not considered a crash, even if there are unresolved evaluations, and will not trigger termination callbacks.

Parameters
@NonNull Executor executor

the executor with which to run callback

@NonNull Consumer<TerminationInfo> callback

the consumer to be called with TerminationInfo when a crash occurs

Throws
java.lang.IllegalStateException

if the callback is already registered (using any executor)

clearConsoleCallback

Added in 1.0.0-rc01
@RequiresFeature(name = JavaScriptSandbox.JS_FEATURE_CONSOLE_MESSAGING, enforcement = "androidx.javascriptengine.JavaScriptSandbox#isFeatureSupported")
public void clearConsoleCallback()

Clear any JavaScriptConsoleCallback set via setConsoleCallback.

Clearing a callback is not guaranteed to take effect for any already pending evaluations.

close

Added in 1.0.0-rc01
public void close()

Closes the JavaScriptIsolate object and renders it unusable.

Once closed, no more method calls should be made. Pending evaluations will reject with an IsolateTerminatedException immediately.

If isFeatureSupported is true for JS_FEATURE_ISOLATE_TERMINATION, then any pending evaluations are terminated. If it is false, the isolate will not get cleaned up until the pending evaluations have run to completion and will consume resources until then.

Closing an isolate via this method does not wait on the isolate to clean up. Resources held by the isolate may remain in use for a duration after this method returns.

evaluateJavaScriptAsync

Added in 1.0.0-rc01
@RequiresFeature(name = JavaScriptSandbox.JS_FEATURE_EVALUATE_FROM_FD, enforcement = "androidx.javascriptengine.JavaScriptSandbox#isFeatureSupported")
public @NonNull ListenableFuture<StringevaluateJavaScriptAsync(@NonNull AssetFileDescriptor afd)

Reads and evaluates the JavaScript code in the file described by the given AssetFileDescriptor.

Please refer to the documentation of evaluateJavaScriptAsync as the behavior of this method is similar other than for the input type.

This API exposes the underlying file to the service. In case the service process is compromised for unforeseen reasons, it might be able to read from the AssetFileDescriptor beyond the given length and offset. This API does not close the given AssetFileDescriptor.

Note: The underlying file data must be UTF-8 encoded.

This overload is useful when the source of the data is easily readable as an AssetFileDescriptor, e.g. an asset or raw resource.

Parameters
@NonNull AssetFileDescriptor afd

an AssetFileDescriptor for a file containing UTF-8 encoded JavaScript code to be evaluated

Returns
@NonNull ListenableFuture<String>

a Future that evaluates to the result String of the evaluation or an exception (see JavaScriptException and subclasses) if there is an error

evaluateJavaScriptAsync

Added in 1.0.0-rc01
public @NonNull ListenableFuture<StringevaluateJavaScriptAsync(@NonNull String code)

Evaluates the given JavaScript code and returns the result.

There are 3 possible behaviors based on the output of the expression:

  • If the JS expression evaluates to a JS String, then the Java Future resolves to a Java String.
  • If the JS expression evaluates to a JS Promise, and if isFeatureSupported for JS_FEATURE_PROMISE_RETURN returns true, the Java Future resolves to a Java String once the promise resolves. If it returns false, then the Future resolves to an empty Java string.
  • If the JS expression evaluates to another data type, then the Java Future resolves to an empty Java String.
The environment uses a single JS global object for all the calls to evaluateJavaScriptAsync(String) and provideNamedData methods. These calls are queued up and are run one at a time in sequence, using the single JS environment for the isolate. The global variables set by one evaluation are visible for later evaluations. This is similar to adding multiple