mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-26 05:15:49 +08:00
Delete old bridge
Reviewed By: astreet Differential Revision: D3510660 fbshipit-source-id: 031b9dcf19dd4e6677a6c9417917930bcbbe3219
This commit is contained in:
committed by
Facebook Github Bot 3
parent
5617d41327
commit
1a690d5674
@@ -1,568 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
import com.facebook.react.bridge.queue.ReactQueueConfiguration;
|
||||
import com.facebook.react.bridge.queue.ReactQueueConfigurationImpl;
|
||||
import com.facebook.react.bridge.queue.ReactQueueConfigurationSpec;
|
||||
import com.facebook.react.bridge.queue.QueueThreadExceptionHandler;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.common.annotations.VisibleForTesting;
|
||||
import com.facebook.react.common.futures.SimpleSettableFuture;
|
||||
import com.facebook.systrace.Systrace;
|
||||
import com.facebook.systrace.TraceListener;
|
||||
|
||||
/**
|
||||
* This provides an implementation of the public CatalystInstance instance. It is public because
|
||||
* it is built by ReactInstanceManager which is in a different package.
|
||||
*/
|
||||
@DoNotStrip
|
||||
public class CatalystInstanceImpl implements CatalystInstance {
|
||||
|
||||
private static final AtomicInteger sNextInstanceIdForTrace = new AtomicInteger(1);
|
||||
|
||||
// Access from any thread
|
||||
private final ReactQueueConfigurationImpl mReactQueueConfiguration;
|
||||
private final CopyOnWriteArrayList<NotThreadSafeBridgeIdleDebugListener> mBridgeIdleListeners;
|
||||
private final AtomicInteger mPendingJSCalls = new AtomicInteger(0);
|
||||
private final String mJsPendingCallsTitleForTrace =
|
||||
"pending_js_calls_instance" + sNextInstanceIdForTrace.getAndIncrement();
|
||||
private volatile boolean mIsBeingDestroyed = false;
|
||||
private volatile boolean mDestroyed = false;
|
||||
private final TraceListener mTraceListener;
|
||||
private final JavaScriptModuleRegistry mJSModuleRegistry;
|
||||
private final JSBundleLoader mJSBundleLoader;
|
||||
private @Nullable ExecutorToken mMainExecutorToken;
|
||||
|
||||
// These locks prevent additional calls from going JS<->Java after the bridge has been torn down.
|
||||
// There are separate ones for each direction because a JS to Java call can trigger a Java to JS
|
||||
// call: this would cause a deadlock with a traditional mutex (maybe we should be using a reader-
|
||||
// writer lock but then we'd have to worry about starving the destroy call).
|
||||
private final Object mJSToJavaCallsTeardownLock = new Object();
|
||||
private final Object mJavaToJSCallsTeardownLock = new Object();
|
||||
|
||||
// Access from native modules thread
|
||||
private final NativeModuleRegistry mJavaRegistry;
|
||||
private final NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
|
||||
private boolean mInitialized = false;
|
||||
|
||||
// Access from JS thread
|
||||
private final ReactBridge mBridge;
|
||||
private boolean mJSBundleHasLoaded;
|
||||
|
||||
private CatalystInstanceImpl(
|
||||
final ReactQueueConfigurationSpec ReactQueueConfigurationSpec,
|
||||
final JavaScriptExecutor jsExecutor,
|
||||
final NativeModuleRegistry registry,
|
||||
final JavaScriptModuleRegistry jsModuleRegistry,
|
||||
final JSBundleLoader jsBundleLoader,
|
||||
NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
|
||||
FLog.d(ReactConstants.TAG, "Initializing React Bridge.");
|
||||
mReactQueueConfiguration = ReactQueueConfigurationImpl.create(
|
||||
ReactQueueConfigurationSpec,
|
||||
new NativeExceptionHandler());
|
||||
mBridgeIdleListeners = new CopyOnWriteArrayList<>();
|
||||
mJavaRegistry = registry;
|
||||
mJSModuleRegistry = jsModuleRegistry;
|
||||
mJSBundleLoader = jsBundleLoader;
|
||||
mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
|
||||
mTraceListener = new JSProfilerTraceListener();
|
||||
|
||||
try {
|
||||
mBridge = mReactQueueConfiguration.getJSQueueThread().callOnQueue(
|
||||
new Callable<ReactBridge>() {
|
||||
@Override
|
||||
public ReactBridge call() throws Exception {
|
||||
Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "initializeBridge");
|
||||
try {
|
||||
return initializeBridge(jsExecutor);
|
||||
} finally {
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
|
||||
}
|
||||
}
|
||||
}).get();
|
||||
} catch (Exception t) {
|
||||
throw new RuntimeException("Failed to initialize bridge", t);
|
||||
}
|
||||
}
|
||||
|
||||
private ReactBridge initializeBridge(JavaScriptExecutor jsExecutor) {
|
||||
mReactQueueConfiguration.getJSQueueThread().assertIsOnThread();
|
||||
Assertions.assertCondition(mBridge == null, "initializeBridge should be called once");
|
||||
|
||||
Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ReactBridgeCtor");
|
||||
ReactBridge bridge;
|
||||
try {
|
||||
bridge = new ReactBridge(
|
||||
jsExecutor,
|
||||
new NativeModulesReactCallback(),
|
||||
mReactQueueConfiguration.getNativeModulesQueueThread());
|
||||
mMainExecutorToken = bridge.getMainExecutorToken();
|
||||
} finally {
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
|
||||
}
|
||||
|
||||
Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "setBatchedBridgeConfig");
|
||||
try {
|
||||
bridge.setGlobalVariable(
|
||||
"__fbBatchedBridgeConfig",
|
||||
buildModulesConfigJSONProperty(mJavaRegistry));
|
||||
bridge.setGlobalVariable(
|
||||
"__RCTProfileIsProfiling",
|
||||
Systrace.isTracing(Systrace.TRACE_TAG_REACT_APPS) ? "true" : "false");
|
||||
} finally {
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
|
||||
}
|
||||
|
||||
mJavaRegistry.notifyReactBridgeInitialized(bridge);
|
||||
return bridge;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runJSBundle() {
|
||||
mReactQueueConfiguration.getJSQueueThread().assertIsOnThread();
|
||||
Assertions.assertCondition(!mJSBundleHasLoaded, "JS bundle was already loaded!");
|
||||
|
||||
incrementPendingJSCalls();
|
||||
|
||||
Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "loadJSScript");
|
||||
try {
|
||||
mJSBundleLoader.loadScript(mBridge);
|
||||
|
||||
// This is registered after JS starts since it makes a JS call
|
||||
Systrace.registerListener(mTraceListener);
|
||||
} catch (JSExecutionException e) {
|
||||
mNativeModuleCallExceptionHandler.handleException(e);
|
||||
} finally {
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
|
||||
}
|
||||
|
||||
mJSBundleHasLoaded = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callFunction(
|
||||
ExecutorToken executorToken,
|
||||
String module,
|
||||
String method,
|
||||
NativeArray arguments) {
|
||||
if (mIsBeingDestroyed) {
|
||||
FLog.w(ReactConstants.TAG, "Calling JS function after bridge has been destroyed.");
|
||||
return;
|
||||
}
|
||||
synchronized (mJavaToJSCallsTeardownLock) {
|
||||
if (mDestroyed) {
|
||||
FLog.w(ReactConstants.TAG, "Calling JS function after bridge has been destroyed.");
|
||||
return;
|
||||
}
|
||||
|
||||
incrementPendingJSCalls();
|
||||
|
||||
Assertions.assertNotNull(mBridge).callFunction(
|
||||
executorToken,
|
||||
module,
|
||||
method, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
// This is called from java code, so it won't be stripped anyway, but proguard will rename it,
|
||||
// which this prevents.
|
||||
@DoNotStrip
|
||||
@Override
|
||||
public void invokeCallback(ExecutorToken executorToken, int callbackID, NativeArray arguments) {
|
||||
if (mIsBeingDestroyed) {
|
||||
FLog.w(ReactConstants.TAG, "Invoking JS callback after bridge has been destroyed.");
|
||||
return;
|
||||
}
|
||||
synchronized (mJavaToJSCallsTeardownLock) {
|
||||
if (mDestroyed) {
|
||||
FLog.w(ReactConstants.TAG, "Invoking JS callback after bridge has been destroyed.");
|
||||
return;
|
||||
}
|
||||
|
||||
incrementPendingJSCalls();
|
||||
|
||||
Assertions.assertNotNull(mBridge).invokeCallback(executorToken, callbackID, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys this catalyst instance, waiting for any other threads in ReactQueueConfiguration
|
||||
* (besides the UI thread) to finish running. Must be called from the UI thread so that we can
|
||||
* fully shut down other threads.
|
||||
*/
|
||||
@Override
|
||||
public void destroy() {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
|
||||
// This ordering is important. A JS to Java call that triggers a Java to JS call will also
|
||||
// acquire these locks in the same order
|
||||
mIsBeingDestroyed = true;
|
||||
synchronized (mJSToJavaCallsTeardownLock) {
|
||||
synchronized (mJavaToJSCallsTeardownLock) {
|
||||
if (mDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: tell all APIs to shut down
|
||||
mDestroyed = true;
|
||||
mJavaRegistry.notifyCatalystInstanceDestroy();
|
||||
|
||||
Systrace.unregisterListener(mTraceListener);
|
||||
|
||||
synchronouslyDisposeBridgeOnJSThread();
|
||||
}
|
||||
}
|
||||
|
||||
mReactQueueConfiguration.destroy();
|
||||
|
||||
boolean wasIdle = (mPendingJSCalls.getAndSet(0) == 0);
|
||||
if (!wasIdle && !mBridgeIdleListeners.isEmpty()) {
|
||||
for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) {
|
||||
listener.onTransitionToBridgeIdle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void synchronouslyDisposeBridgeOnJSThread() {
|
||||
final SimpleSettableFuture<Void> bridgeDisposeFuture = new SimpleSettableFuture<>();
|
||||
mReactQueueConfiguration.getJSQueueThread().runOnQueue(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mBridge.destroy();
|
||||
mBridge.dispose();
|
||||
bridgeDisposeFuture.set(null);
|
||||
}
|
||||
});
|
||||
bridgeDisposeFuture.getOrThrow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDestroyed() {
|
||||
return mDestroyed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize all the native modules
|
||||
*/
|
||||
@VisibleForTesting
|
||||
@Override
|
||||
public void initialize() {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
Assertions.assertCondition(
|
||||
!mInitialized,
|
||||
"This catalyst instance has already been initialized");
|
||||
mInitialized = true;
|
||||
mJavaRegistry.notifyCatalystInstanceInitialized();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReactQueueConfiguration getReactQueueConfiguration() {
|
||||
return mReactQueueConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends JavaScriptModule> T getJSModule(Class<T> jsInterface) {
|
||||
return getJSModule(Assertions.assertNotNull(mMainExecutorToken), jsInterface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends JavaScriptModule> T getJSModule(ExecutorToken executorToken, Class<T> jsInterface) {
|
||||
return Assertions.assertNotNull(mJSModuleRegistry)
|
||||
.getJavaScriptModule(this, executorToken, jsInterface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends NativeModule> boolean hasNativeModule(Class<T> nativeModuleInterface) {
|
||||
return mJavaRegistry.hasModule(nativeModuleInterface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends NativeModule> T getNativeModule(Class<T> nativeModuleInterface) {
|
||||
return mJavaRegistry.getModule(nativeModuleInterface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<NativeModule> getNativeModules() {
|
||||
return mJavaRegistry.getAllModules();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMemoryPressure(final MemoryPressure level) {
|
||||
mReactQueueConfiguration.getJSQueueThread().runOnQueue(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Assertions.assertNotNull(mBridge).handleMemoryPressure(level);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a idle listener for this Catalyst instance. The listener will receive notifications
|
||||
* whenever the bridge transitions from idle to busy and vice-versa, where the busy state is
|
||||
* defined as there being some non-zero number of calls to JS that haven't resolved via a
|
||||
* onBatchCompleted call. The listener should be purely passive and not affect application logic.
|
||||
*/
|
||||
@Override
|
||||
public void addBridgeIdleDebugListener(NotThreadSafeBridgeIdleDebugListener listener) {
|
||||
mBridgeIdleListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a NotThreadSafeBridgeIdleDebugListener previously added with
|
||||
* {@link #addBridgeIdleDebugListener}
|
||||
*/
|
||||
@Override
|
||||
public void removeBridgeIdleDebugListener(NotThreadSafeBridgeIdleDebugListener listener) {
|
||||
mBridgeIdleListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsProfiling() {
|
||||
return mBridge.supportsProfiling();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startProfiler(String title) {
|
||||
mBridge.startProfiler(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopProfiler(String title, String filename) {
|
||||
mBridge.stopProfiler(title, filename);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@Override
|
||||
public void setGlobalVariable(String propName, String jsonValue) {
|
||||
mBridge.setGlobalVariable(propName, jsonValue);
|
||||
}
|
||||
|
||||
private String buildModulesConfigJSONProperty(NativeModuleRegistry nativeModuleRegistry) {
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
JsonWriter writer = new JsonWriter(stringWriter);
|
||||
try {
|
||||
writer.beginObject();
|
||||
writer.name("remoteModuleConfig");
|
||||
nativeModuleRegistry.writeModuleDescriptions(writer);
|
||||
writer.endObject();
|
||||
return stringWriter.toString();
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException("Unable to serialize JavaScript module declaration", ioe);
|
||||
} finally {
|
||||
try {
|
||||
writer.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void incrementPendingJSCalls() {
|
||||
int oldPendingCalls = mPendingJSCalls.getAndIncrement();
|
||||
boolean wasIdle = oldPendingCalls == 0;
|
||||
Systrace.traceCounter(
|
||||
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
|
||||
mJsPendingCallsTitleForTrace,
|
||||
oldPendingCalls + 1);
|
||||
if (wasIdle && !mBridgeIdleListeners.isEmpty()) {
|
||||
for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) {
|
||||
listener.onTransitionToBridgeBusy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void decrementPendingJSCalls() {
|
||||
int newPendingCalls = mPendingJSCalls.decrementAndGet();
|
||||
// TODO(9604406): handle case of web workers injecting messages to main thread
|
||||
//Assertions.assertCondition(newPendingCalls >= 0);
|
||||
boolean isNowIdle = newPendingCalls == 0;
|
||||
Systrace.traceCounter(
|
||||
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
|
||||
mJsPendingCallsTitleForTrace,
|
||||
newPendingCalls);
|
||||
|
||||
if (isNowIdle && !mBridgeIdleListeners.isEmpty()) {
|
||||
for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) {
|
||||
listener.onTransitionToBridgeIdle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
Assertions.assertCondition(mDestroyed, "Bridge was not destroyed before finalizer!");
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
private class NativeModulesReactCallback implements ReactCallback {
|
||||
|
||||
@Override
|
||||
public void call(ExecutorToken executorToken, int moduleId, int methodId, ReadableNativeArray parameters) {
|
||||
mReactQueueConfiguration.getNativeModulesQueueThread().assertIsOnThread();
|
||||
|
||||
if (mIsBeingDestroyed) {
|
||||
return;
|
||||
}
|
||||
synchronized (mJSToJavaCallsTeardownLock) {
|
||||
// Suppress any callbacks if destroyed - will only lead to sadness.
|
||||
if (mDestroyed) {
|
||||
return;
|
||||
}
|
||||
mJavaRegistry.call(CatalystInstanceImpl.this, executorToken, moduleId, methodId, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBatchComplete() {
|
||||
mReactQueueConfiguration.getNativeModulesQueueThread().assertIsOnThread();
|
||||
|
||||
// The bridge may have been destroyed due to an exception during the batch. In that case
|
||||
// native modules could be in a bad state so we don't want to call anything on them. We
|
||||
// still want to trigger the debug listener since it allows instrumentation tests to end and
|
||||
// check their assertions without waiting for a timeout.
|
||||
if (mIsBeingDestroyed) {
|
||||
return;
|
||||
}
|
||||
synchronized (mJSToJavaCallsTeardownLock) {
|
||||
if (mDestroyed) {
|
||||
return;
|
||||
}
|
||||
Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "onBatchComplete");
|
||||
try {
|
||||
mJavaRegistry.onBatchComplete();
|
||||
} finally {
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
|
||||
}
|
||||
}
|
||||
|
||||
decrementPendingJSCalls();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExecutorUnregistered(ExecutorToken executorToken) {
|
||||
mReactQueueConfiguration.getNativeModulesQueueThread().assertIsOnThread();
|
||||
|
||||
// Since onCatalystInstanceDestroy happens on the UI thread, we don't want to also execute
|
||||
// this callback on the native modules thread at the same time. Longer term, onCatalystInstanceDestroy
|
||||
// should probably be executed on the native modules thread as well instead.
|
||||
if (mIsBeingDestroyed) {
|
||||
return;
|
||||
}
|
||||
synchronized (mJSToJavaCallsTeardownLock) {
|
||||
if (mDestroyed) {
|
||||
return;
|
||||
}
|
||||
Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "onExecutorUnregistered");
|
||||
try {
|
||||
mJavaRegistry.onExecutorUnregistered(executorToken);
|
||||
} finally {
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class NativeExceptionHandler implements QueueThreadExceptionHandler {
|
||||
|
||||
@Override
|
||||
public void handleException(Exception e) {
|
||||
// Any Exception caught here is because of something in JS. Even if it's a bug in the
|
||||
// framework/native code, it was triggered by JS and theoretically since we were able
|
||||
// to set up the bridge, JS could change its logic, reload, and not trigger that crash.
|
||||
mNativeModuleCallExceptionHandler.handleException(e);
|
||||
mReactQueueConfiguration.getUIQueueThread().runOnQueue(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
destroy();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private class JSProfilerTraceListener implements TraceListener {
|
||||
@Override
|
||||
public void onTraceStarted() {
|
||||
getJSModule(Assertions.assertNotNull(mMainExecutorToken), com.facebook.react.bridge.Systrace.class).setEnabled(
|
||||
true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTraceStopped() {
|
||||
getJSModule(Assertions.assertNotNull(mMainExecutorToken), com.facebook.react.bridge.Systrace.class).setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private @Nullable ReactQueueConfigurationSpec mReactQueueConfigurationSpec;
|
||||
private @Nullable JSBundleLoader mJSBundleLoader;
|
||||
private @Nullable NativeModuleRegistry mRegistry;
|
||||
private @Nullable JavaScriptModuleRegistry mJSModuleRegistry;
|
||||
private @Nullable JavaScriptExecutor mJSExecutor;
|
||||
private @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
|
||||
|
||||
public Builder setReactQueueConfigurationSpec(
|
||||
ReactQueueConfigurationSpec ReactQueueConfigurationSpec) {
|
||||
mReactQueueConfigurationSpec = ReactQueueConfigurationSpec;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setRegistry(NativeModuleRegistry registry) {
|
||||
mRegistry = registry;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setJSModuleRegistry(JavaScriptModuleRegistry jsModuleRegistry) {
|
||||
mJSModuleRegistry = jsModuleRegistry;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setJSBundleLoader(JSBundleLoader jsBundleLoader) {
|
||||
mJSBundleLoader = jsBundleLoader;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setJSExecutor(JavaScriptExecutor jsExecutor) {
|
||||
mJSExecutor = jsExecutor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setNativeModuleCallExceptionHandler(
|
||||
NativeModuleCallExceptionHandler handler) {
|
||||
mNativeModuleCallExceptionHandler = handler;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CatalystInstanceImpl build() {
|
||||
return new CatalystInstanceImpl(
|
||||
Assertions.assertNotNull(mReactQueueConfigurationSpec),
|
||||
Assertions.assertNotNull(mJSExecutor),
|
||||
Assertions.assertNotNull(mRegistry),
|
||||
Assertions.assertNotNull(mJSModuleRegistry),
|
||||
Assertions.assertNotNull(mJSBundleLoader),
|
||||
Assertions.assertNotNull(mNativeModuleCallExceptionHandler));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* A class that stores JS bundle information and allows {@link CatalystInstance} to load a correct
|
||||
* bundle through {@link ReactBridge}.
|
||||
*/
|
||||
public abstract class JSBundleLoader {
|
||||
|
||||
/**
|
||||
* This loader is recommended one for release version of your app. In that case local JS executor
|
||||
* should be used. JS bundle will be read from assets directory in native code to save on passing
|
||||
* large strings from java to native memory.
|
||||
*/
|
||||
public static JSBundleLoader createFileLoader(
|
||||
final Context context,
|
||||
final String fileName) {
|
||||
return new JSBundleLoader() {
|
||||
@Override
|
||||
public void loadScript(ReactBridge bridge) {
|
||||
if (fileName.startsWith("assets://")) {
|
||||
bridge.loadScriptFromAssets(context.getAssets(), fileName.replaceFirst("assets://", ""));
|
||||
} else {
|
||||
bridge.loadScriptFromFile(fileName, "file://" + fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceUrl() {
|
||||
return (fileName.startsWith("assets://") ? "" : "file://") + fileName;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* This loader is used when bundle gets reloaded from dev server. In that case loader expect JS
|
||||
* bundle to be prefetched and stored in local file. We do that to avoid passing large strings
|
||||
* between java and native code and avoid allocating memory in java to fit whole JS bundle in it.
|
||||
* Providing correct {@param sourceURL} of downloaded bundle is required for JS stacktraces to
|
||||
* work correctly and allows for source maps to correctly symbolize those.
|
||||
*/
|
||||
public static JSBundleLoader createCachedBundleFromNetworkLoader(
|
||||
final String sourceURL,
|
||||
final String cachedFileLocation) {
|
||||
return new JSBundleLoader() {
|
||||
@Override
|
||||
public void loadScript(ReactBridge bridge) {
|
||||
bridge.loadScriptFromFile(cachedFileLocation, sourceURL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceUrl() {
|
||||
return sourceURL;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* This loader is used when proxy debugging is enabled. In that case there is no point in fetching
|
||||
* the bundle from device as remote executor will have to do it anyway.
|
||||
*
|
||||
* @param proxySourceURL the URL to load the JS bundle from in the JavaScript proxy
|
||||
* @param realSourceURL the URL to report as the source URL, e.g. for asset loading
|
||||
*/
|
||||
public static JSBundleLoader createRemoteDebuggerBundleLoader(
|
||||
final String proxySourceURL,
|
||||
final String realSourceURL) {
|
||||
return new JSBundleLoader() {
|
||||
@Override
|
||||
public void loadScript(ReactBridge bridge) {
|
||||
bridge.loadScriptFromFile(null, proxySourceURL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceUrl() {
|
||||
return realSourceURL;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public abstract void loadScript(ReactBridge bridge);
|
||||
public abstract String getSourceUrl();
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge;
|
||||
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
|
||||
@DoNotStrip
|
||||
public class JSCJavaScriptExecutor extends JavaScriptExecutor {
|
||||
static {
|
||||
ReactBridge.staticInit();
|
||||
}
|
||||
|
||||
public static class Factory implements JavaScriptExecutor.Factory {
|
||||
@Override
|
||||
public JavaScriptExecutor create(WritableNativeMap jscConfig) throws Exception {
|
||||
return new JSCJavaScriptExecutor(jscConfig);
|
||||
}
|
||||
}
|
||||
|
||||
public JSCJavaScriptExecutor(WritableNativeMap jscConfig) {
|
||||
initialize(jscConfig);
|
||||
}
|
||||
|
||||
private native void initialize(WritableNativeMap jscConfig);
|
||||
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
package com.facebook.react.bridge;
|
||||
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
|
||||
/**
|
||||
* Exception thrown when there is an error evaluating JS, e.g. a syntax error.
|
||||
*/
|
||||
@DoNotStrip
|
||||
public class JSExecutionException extends RuntimeException {
|
||||
|
||||
@DoNotStrip
|
||||
public JSExecutionException(String detailMessage) {
|
||||
super(detailMessage);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge;
|
||||
|
||||
import com.facebook.jni.Countable;
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
|
||||
@DoNotStrip
|
||||
public abstract class JavaScriptExecutor extends Countable {
|
||||
public interface Factory {
|
||||
JavaScriptExecutor create(WritableNativeMap jscConfig) throws Exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close this executor and cleanup any resources that it was using. No further calls are
|
||||
* expected after this.
|
||||
*/
|
||||
public void close() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,235 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.facebook.react.common.MapBuilder;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.systrace.Systrace;
|
||||
|
||||
/**
|
||||
* A set of Java APIs to expose to a particular JavaScript instance.
|
||||
*/
|
||||
public class NativeModuleRegistry {
|
||||
|
||||
private final List<ModuleDefinition> mModuleTable;
|
||||
private final Map<Class<? extends NativeModule>, NativeModule> mModuleInstances;
|
||||
private final ArrayList<OnBatchCompleteListener> mBatchCompleteListenerModules;
|
||||
private final ArrayList<OnExecutorUnregisteredListener> mOnExecutorUnregisteredListenerModules;
|
||||
|
||||
private NativeModuleRegistry(
|
||||
List<ModuleDefinition> moduleTable,
|
||||
Map<Class<? extends NativeModule>, NativeModule> moduleInstances) {
|
||||
mModuleTable = moduleTable;
|
||||
mModuleInstances = moduleInstances;
|
||||
|
||||
mBatchCompleteListenerModules = new ArrayList<>(mModuleTable.size());
|
||||
mOnExecutorUnregisteredListenerModules = new ArrayList<>(mModuleTable.size());
|
||||
for (int i = 0; i < mModuleTable.size(); i++) {
|
||||
ModuleDefinition definition = mModuleTable.get(i);
|
||||
if (definition.target instanceof OnBatchCompleteListener) {
|
||||
mBatchCompleteListenerModules.add((OnBatchCompleteListener) definition.target);
|
||||
}
|
||||
if (definition.target instanceof OnExecutorUnregisteredListener) {
|
||||
mOnExecutorUnregisteredListenerModules.add((OnExecutorUnregisteredListener) definition.target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ void call(
|
||||
CatalystInstance catalystInstance,
|
||||
ExecutorToken executorToken,
|
||||
int moduleId,
|
||||
int methodId,
|
||||
ReadableNativeArray parameters) {
|
||||
ModuleDefinition definition = mModuleTable.get(moduleId);
|
||||
if (definition == null) {
|
||||
throw new RuntimeException("Call to unknown module: " + moduleId);
|
||||
}
|
||||
definition.call(catalystInstance, executorToken, methodId, parameters);
|
||||
}
|
||||
|
||||
/* package */ void writeModuleDescriptions(JsonWriter writer) throws IOException {
|
||||
Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "CreateJSON");
|
||||
try {
|
||||
writer.beginObject();
|
||||
for (ModuleDefinition moduleDef : mModuleTable) {
|
||||
writer.name(moduleDef.name).beginObject();
|
||||
writer.name("moduleID").value(moduleDef.id);
|
||||
writer.name("supportsWebWorkers").value(moduleDef.target.supportsWebWorkers());
|
||||
writer.name("methods").beginObject();
|
||||
for (int i = 0; i < moduleDef.methods.size(); i++) {
|
||||
MethodRegistration method = moduleDef.methods.get(i);
|
||||
writer.name(method.name).beginObject();
|
||||
writer.name("methodID").value(i);
|
||||
writer.name("type").value(method.method.getType());
|
||||
writer.endObject();
|
||||
}
|
||||
writer.endObject();
|
||||
moduleDef.target.writeConstantsField(writer, "constants");
|
||||
writer.endObject();
|
||||
}
|
||||
writer.endObject();
|
||||
} finally {
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ void notifyCatalystInstanceDestroy() {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
Systrace.beginSection(
|
||||
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
|
||||
"NativeModuleRegistry_notifyCatalystInstanceDestroy");
|
||||
try {
|
||||
for (NativeModule nativeModule : mModuleInstances.values()) {
|
||||
nativeModule.onCatalystInstanceDestroy();
|
||||
}
|
||||
} finally {
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ void notifyCatalystInstanceInitialized() {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
|
||||
ReactMarker.logMarker("NativeModule_start");
|
||||
Systrace.beginSection(
|
||||
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
|
||||
"NativeModuleRegistry_notifyCatalystInstanceInitialized");
|
||||
try {
|
||||
for (NativeModule nativeModule : mModuleInstances.values()) {
|
||||
nativeModule.initialize();
|
||||
}
|
||||
} finally {
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
|
||||
ReactMarker.logMarker("NativeModule_end");
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ void notifyReactBridgeInitialized(ReactBridge bridge) {
|
||||
Systrace.beginSection(
|
||||
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
|
||||
"NativeModuleRegistry_notifyReactBridgeInitialized");
|
||||
try {
|
||||
for (NativeModule nativeModule : mModuleInstances.values()) {
|
||||
nativeModule.onReactBridgeInitialized(bridge);
|
||||
}
|
||||
} finally {
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
|
||||
}
|
||||
}
|
||||
|
||||
public void onBatchComplete() {
|
||||
for (int i = 0; i < mBatchCompleteListenerModules.size(); i++) {
|
||||
mBatchCompleteListenerModules.get(i).onBatchComplete();
|
||||
}
|
||||
}
|
||||
|
||||
public void onExecutorUnregistered(ExecutorToken executorToken) {
|
||||
for (int i = 0; i < mOnExecutorUnregisteredListenerModules.size(); i++) {
|
||||
mOnExecutorUnregisteredListenerModules.get(i).onExecutorDestroyed(executorToken);
|
||||
}
|
||||
}
|
||||
|
||||
public <T extends NativeModule> boolean hasModule(Class<T> moduleInterface) {
|
||||
return mModuleInstances.containsKey(moduleInterface);
|
||||
}
|
||||
|
||||
public <T extends NativeModule> T getModule(Class<T> moduleInterface) {
|
||||
return (T) Assertions.assertNotNull(mModuleInstances.get(moduleInterface));
|
||||
}
|
||||
|
||||
public Collection<NativeModule> getAllModules() {
|
||||
return mModuleInstances.values();
|
||||
}
|
||||
|
||||
private static class ModuleDefinition {
|
||||
public final int id;
|
||||
public final String name;
|
||||
public final NativeModule target;
|
||||
public final ArrayList<MethodRegistration> methods;
|
||||
|
||||
public ModuleDefinition(int id, String name, NativeModule target) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.target = target;
|
||||
this.methods = new ArrayList<MethodRegistration>();
|
||||
|
||||
for (Map.Entry<String, NativeModule.NativeMethod> entry : target.getMethods().entrySet()) {
|
||||
this.methods.add(
|
||||
new MethodRegistration(
|
||||
entry.getKey(), "NativeCall__" + target.getName() + "_" + entry.getKey(),
|
||||
entry.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
public void call(
|
||||
CatalystInstance catalystInstance,
|
||||
ExecutorToken executorToken,
|
||||
int methodId,
|
||||
ReadableNativeArray parameters) {
|
||||
MethodRegistration method = this.methods.get(methodId);
|
||||
Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, method.tracingName);
|
||||
try {
|
||||
this.methods.get(methodId).method.invoke(catalystInstance, executorToken, parameters);
|
||||
} finally {
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class MethodRegistration {
|
||||
public MethodRegistration(String name, String tracingName, NativeModule.NativeMethod method) {
|
||||
this.name = name;
|
||||
this.tracingName = tracingName;
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public String name;
|
||||
public String tracingName;
|
||||
public NativeModule.NativeMethod method;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private final HashMap<String, NativeModule> mModules = MapBuilder.newHashMap();
|
||||
|
||||
public Builder add(NativeModule module) {
|
||||
NativeModule existing = mModules.get(module.getName());
|
||||
if (existing != null && !module.canOverrideExistingModule()) {
|
||||
throw new IllegalStateException("Native module " + module.getClass().getSimpleName() +
|
||||
" tried to override " + existing.getClass().getSimpleName() + " for module name " +
|
||||
module.getName() + ". If this was your intention, return true from " +
|
||||
module.getClass().getSimpleName() + "#canOverrideExistingModule()");
|
||||
}
|
||||
mModules.put(module.getName(), module);
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeModuleRegistry build() {
|
||||
List<ModuleDefinition> moduleTable = new ArrayList<>();
|
||||
Map<Class<? extends NativeModule>, NativeModule> moduleInstances = new HashMap<>();
|
||||
|
||||
int idx = 0;
|
||||
for (NativeModule module : mModules.values()) {
|
||||
ModuleDefinition moduleDef = new ModuleDefinition(idx++, module.getName(), module);
|
||||
moduleTable.add(moduleDef);
|
||||
moduleInstances.put(module.getClass(), module);
|
||||
}
|
||||
return new NativeModuleRegistry(moduleTable, moduleInstances);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.facebook.soloader.SoLoader;
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
|
||||
/**
|
||||
* JavaScript executor that delegates JS calls processed by native code back to a java version
|
||||
* of the native executor interface.
|
||||
*
|
||||
* When set as a executor with {@link CatalystInstance.Builder}, catalyst native code will delegate
|
||||
* low level javascript calls to the implementation of {@link JavaJSExecutor} interface provided
|
||||
* with the constructor of this class.
|
||||
*/
|
||||
@DoNotStrip
|
||||
public class ProxyJavaScriptExecutor extends JavaScriptExecutor {
|
||||
static {
|
||||
ReactBridge.staticInit();
|
||||
}
|
||||
|
||||
public static class Factory implements JavaScriptExecutor.Factory {
|
||||
private final JavaJSExecutor.Factory mJavaJSExecutorFactory;
|
||||
|
||||
public Factory(JavaJSExecutor.Factory javaJSExecutorFactory) {
|
||||
mJavaJSExecutorFactory = javaJSExecutorFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaScriptExecutor create(WritableNativeMap jscConfig) throws Exception {
|
||||
return new ProxyJavaScriptExecutor(mJavaJSExecutorFactory.create());
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable JavaJSExecutor mJavaJSExecutor;
|
||||
|
||||
/**
|
||||
* Create {@link ProxyJavaScriptExecutor} instance
|
||||
* @param executor implementation of {@link JavaJSExecutor} which will be responsible for handling
|
||||
* javascript calls
|
||||
*/
|
||||
public ProxyJavaScriptExecutor(JavaJSExecutor executor) {
|
||||
mJavaJSExecutor = executor;
|
||||
initialize(executor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (mJavaJSExecutor != null) {
|
||||
mJavaJSExecutor.close();
|
||||
mJavaJSExecutor = null;
|
||||
}
|
||||
}
|
||||
|
||||
private native void initialize(JavaJSExecutor executor);
|
||||
|
||||
}
|
||||
@@ -9,20 +9,9 @@
|
||||
|
||||
package com.facebook.react.bridge;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import android.content.res.AssetManager;
|
||||
|
||||
import com.facebook.react.bridge.queue.MessageQueueThread;
|
||||
import com.facebook.jni.Countable;
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
|
||||
/**
|
||||
* Interface to the JS execution environment and means of transport for messages Java<->JS.
|
||||
*/
|
||||
@DoNotStrip
|
||||
public class ReactBridge extends Countable {
|
||||
public class ReactBridge {
|
||||
|
||||
private static final String REACT_NATIVE_LIB = "reactnativejni";
|
||||
private static final String XREACT_NATIVE_LIB = "reactnativejnifb";
|
||||
@@ -31,81 +20,8 @@ public class ReactBridge extends Countable {
|
||||
staticInit();
|
||||
}
|
||||
|
||||
private final ReactCallback mCallback;
|
||||
private final JavaScriptExecutor mJSExecutor;
|
||||
private final MessageQueueThread mNativeModulesQueueThread;
|
||||
|
||||
public static void staticInit() {
|
||||
SoLoader.loadLibrary(REACT_NATIVE_LIB);
|
||||
SoLoader.loadLibrary(XREACT_NATIVE_LIB);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jsExecutor the JS executor to use to run JS
|
||||
* @param callback the callback class used to invoke native modules
|
||||
* @param nativeModulesQueueThread the MessageQueueThread the callbacks should be invoked on
|
||||
*/
|
||||
public ReactBridge(
|
||||
JavaScriptExecutor jsExecutor,
|
||||
ReactCallback callback,
|
||||
MessageQueueThread nativeModulesQueueThread) {
|
||||
mJSExecutor = jsExecutor;
|
||||
mCallback = callback;
|
||||
mNativeModulesQueueThread = nativeModulesQueueThread;
|
||||
initialize(jsExecutor, callback, mNativeModulesQueueThread);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
mJSExecutor.close();
|
||||
mJSExecutor.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
public void handleMemoryPressure(MemoryPressure level) {
|
||||
switch (level) {
|
||||
case UI_HIDDEN:
|
||||
handleMemoryPressureUiHidden();
|
||||
break;
|
||||
case MODERATE:
|
||||
handleMemoryPressureModerate();
|
||||
break;
|
||||
case CRITICAL:
|
||||
handleMemoryPressureCritical();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown level: " + level);
|
||||
}
|
||||
}
|
||||
|
||||
private native void initialize(
|
||||
JavaScriptExecutor jsExecutor,
|
||||
ReactCallback callback,
|
||||
MessageQueueThread nativeModulesQueueThread);
|
||||
|
||||
/**
|
||||
* All native functions are not thread safe and appropriate queues should be used
|
||||
*/
|
||||
public native void loadScriptFromAssets(AssetManager assetManager, String assetName);
|
||||
public native void loadScriptFromFile(@Nullable String fileName, @Nullable String sourceURL);
|
||||
public native void callFunction(ExecutorToken executorToken, String module, String method, NativeArray arguments);
|
||||
public native void invokeCallback(ExecutorToken executorToken, int callbackID, NativeArray arguments);
|
||||
public native void setGlobalVariable(String propertyName, String jsonEncodedArgument);
|
||||
public native boolean supportsProfiling();
|
||||
public native void startProfiler(String title);
|
||||
public native void stopProfiler(String title, String filename);
|
||||
public native ExecutorToken getMainExecutorToken();
|
||||
private native void handleMemoryPressureUiHidden();
|
||||
private native void handleMemoryPressureModerate();
|
||||
private native void handleMemoryPressureCritical();
|
||||
public native void destroy();
|
||||
|
||||
/**
|
||||
* This method will return a long representing the underlying JSGlobalContextRef pointer or
|
||||
* 0 (representing NULL) when in Chrome debug mode, and is only useful if passed back through
|
||||
* the JNI to native code that will use it with the JavaScriptCore C API.
|
||||
* **WARNING:** This method is *experimental* and should only be used when no other option is
|
||||
* available. It will likely change in a future release!
|
||||
*/
|
||||
public native long getJavaScriptContextNativePtrExperimental();
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge;
|
||||
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
|
||||
@DoNotStrip
|
||||
public interface ReactCallback {
|
||||
|
||||
@DoNotStrip
|
||||
void call(ExecutorToken executorToken, int moduleId, int methodId, ReadableNativeArray parameters);
|
||||
|
||||
@DoNotStrip
|
||||
void onBatchComplete();
|
||||
|
||||
@DoNotStrip
|
||||
void onExecutorUnregistered(ExecutorToken executorToken);
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge.webworkers;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
import com.facebook.react.bridge.queue.MessageQueueThread;
|
||||
import com.facebook.react.bridge.queue.MessageQueueThreadImpl;
|
||||
import com.facebook.react.bridge.queue.ProxyQueueThreadExceptionHandler;
|
||||
import com.facebook.react.common.build.ReactBuildConfig;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okio.Okio;
|
||||
import okio.Sink;
|
||||
|
||||
@DoNotStrip
|
||||
public class WebWorkers {
|
||||
|
||||
/**
|
||||
* Creates a new MessageQueueThread for a background web worker owned by the JS thread with the
|
||||
* given MessageQueueThread.
|
||||
*/
|
||||
@DoNotStrip
|
||||
public static MessageQueueThread createWebWorkerThread(int id, MessageQueueThread ownerThread) {
|
||||
return MessageQueueThreadImpl.startNewBackgroundThread(
|
||||
"web-worker-" + id,
|
||||
new ProxyQueueThreadExceptionHandler(ownerThread));
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method used to help develop web workers on debug builds. In release builds, worker
|
||||
* scripts need to be packaged with the app, but in dev mode we want to fetch/reload the worker
|
||||
* script on the fly from the packager. This method fetches the given URL *synchronously* and
|
||||
* writes it to the specified temp file.
|
||||
*
|
||||
* This is exposed from Java only because we don't want to add a C++ networking library dependency
|
||||
*
|
||||
* NB: The caller is responsible for deleting the file specified by outFileName when they're done
|
||||
* with it.
|
||||
* NB: We write to a temp file instead of returning a String because, depending on the size of the
|
||||
* worker script, allocating the full script string on the Java heap can cause an OOM.
|
||||
*/
|
||||
public static void downloadScriptToFileSync(String url, String outFileName) {
|
||||
if (!ReactBuildConfig.DEBUG) {
|
||||
throw new RuntimeException(
|
||||
"For security reasons, downloading scripts is only allowed in debug builds.");
|
||||
}
|
||||
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
final File out = new File(outFileName);
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
try {
|
||||
Response response = client.newCall(request).execute();
|
||||
|
||||
Sink output = Okio.sink(out);
|
||||
Okio.buffer(response.body().source()).readAll(output);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Exception downloading web worker script to file", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user