crash gracefully on fatal js errors (take two)
Reviewed By: AaaChiuuu Differential Revision: D2773513 fb-gh-sync-id: f8e50ad12e808caf1d85c6c7859c04fcabdaaeae
This commit is contained in:
parent
f2bdb79782
commit
4866ec2767
|
@ -19,6 +19,7 @@ import android.app.Application;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
|
||||||
import com.facebook.infer.annotation.Assertions;
|
import com.facebook.infer.annotation.Assertions;
|
||||||
|
import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
|
||||||
import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener;
|
import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener;
|
||||||
import com.facebook.react.bridge.ReactApplicationContext;
|
import com.facebook.react.bridge.ReactApplicationContext;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
|
@ -159,6 +160,7 @@ public abstract class ReactInstanceManager {
|
||||||
protected boolean mUseDeveloperSupport;
|
protected boolean mUseDeveloperSupport;
|
||||||
protected @Nullable LifecycleState mInitialLifecycleState;
|
protected @Nullable LifecycleState mInitialLifecycleState;
|
||||||
protected @Nullable UIImplementationProvider mUIImplementationProvider;
|
protected @Nullable UIImplementationProvider mUIImplementationProvider;
|
||||||
|
protected @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
|
||||||
|
|
||||||
protected Builder() {
|
protected Builder() {
|
||||||
}
|
}
|
||||||
|
@ -242,6 +244,16 @@ public abstract class ReactInstanceManager {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the exception handler for all native module calls. If not set, the default
|
||||||
|
* {@link DevSupportManager} will be used, which shows a redbox in dev mode and rethrows
|
||||||
|
* (crashes the app) in prod mode.
|
||||||
|
*/
|
||||||
|
public Builder setNativeModuleCallExceptionHandler(NativeModuleCallExceptionHandler handler) {
|
||||||
|
mNativeModuleCallExceptionHandler = handler;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a new {@link ReactInstanceManagerImpl}.
|
* Instantiates a new {@link ReactInstanceManagerImpl}.
|
||||||
* Before calling {@code build}, the following must be called:
|
* Before calling {@code build}, the following must be called:
|
||||||
|
@ -274,7 +286,8 @@ public abstract class ReactInstanceManager {
|
||||||
mUseDeveloperSupport,
|
mUseDeveloperSupport,
|
||||||
mBridgeIdleDebugListener,
|
mBridgeIdleDebugListener,
|
||||||
Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"),
|
Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"),
|
||||||
mUIImplementationProvider);
|
mUIImplementationProvider,
|
||||||
|
mNativeModuleCallExceptionHandler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ import com.facebook.react.bridge.JavaScriptExecutor;
|
||||||
import com.facebook.react.bridge.JavaScriptModule;
|
import com.facebook.react.bridge.JavaScriptModule;
|
||||||
import com.facebook.react.bridge.JavaScriptModulesConfig;
|
import com.facebook.react.bridge.JavaScriptModulesConfig;
|
||||||
import com.facebook.react.bridge.NativeModule;
|
import com.facebook.react.bridge.NativeModule;
|
||||||
|
import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
|
||||||
import com.facebook.react.bridge.NativeModuleRegistry;
|
import com.facebook.react.bridge.NativeModuleRegistry;
|
||||||
import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener;
|
import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener;
|
||||||
import com.facebook.react.bridge.ProxyJavaScriptExecutor;
|
import com.facebook.react.bridge.ProxyJavaScriptExecutor;
|
||||||
|
@ -103,6 +104,7 @@ import com.facebook.systrace.Systrace;
|
||||||
private volatile boolean mHasStartedCreatingInitialContext = false;
|
private volatile boolean mHasStartedCreatingInitialContext = false;
|
||||||
private final UIImplementationProvider mUIImplementationProvider;
|
private final UIImplementationProvider mUIImplementationProvider;
|
||||||
private final MemoryPressureRouter mMemoryPressureRouter;
|
private final MemoryPressureRouter mMemoryPressureRouter;
|
||||||
|
private final @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
|
||||||
|
|
||||||
private final ReactInstanceDevCommandsHandler mDevInterface =
|
private final ReactInstanceDevCommandsHandler mDevInterface =
|
||||||
new ReactInstanceDevCommandsHandler() {
|
new ReactInstanceDevCommandsHandler() {
|
||||||
|
@ -198,7 +200,8 @@ import com.facebook.systrace.Systrace;
|
||||||
boolean useDeveloperSupport,
|
boolean useDeveloperSupport,
|
||||||
@Nullable NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener,
|
@Nullable NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener,
|
||||||
LifecycleState initialLifecycleState,
|
LifecycleState initialLifecycleState,
|
||||||
UIImplementationProvider uiImplementationProvider) {
|
UIImplementationProvider uiImplementationProvider,
|
||||||
|
NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
|
||||||
initializeSoLoaderIfNecessary(applicationContext);
|
initializeSoLoaderIfNecessary(applicationContext);
|
||||||
|
|
||||||
// TODO(9577825): remove this
|
// TODO(9577825): remove this
|
||||||
|
@ -222,6 +225,7 @@ import com.facebook.systrace.Systrace;
|
||||||
mLifecycleState = initialLifecycleState;
|
mLifecycleState = initialLifecycleState;
|
||||||
mUIImplementationProvider = uiImplementationProvider;
|
mUIImplementationProvider = uiImplementationProvider;
|
||||||
mMemoryPressureRouter = new MemoryPressureRouter(applicationContext);
|
mMemoryPressureRouter = new MemoryPressureRouter(applicationContext);
|
||||||
|
mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -660,13 +664,16 @@ import com.facebook.systrace.Systrace;
|
||||||
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
|
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null
|
||||||
|
? mNativeModuleCallExceptionHandler
|
||||||
|
: mDevSupportManager;
|
||||||
CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()
|
CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()
|
||||||
.setCatalystQueueConfigurationSpec(CatalystQueueConfigurationSpec.createDefault())
|
.setCatalystQueueConfigurationSpec(CatalystQueueConfigurationSpec.createDefault())
|
||||||
.setJSExecutor(jsExecutor)
|
.setJSExecutor(jsExecutor)
|
||||||
.setRegistry(nativeModuleRegistry)
|
.setRegistry(nativeModuleRegistry)
|
||||||
.setJSModulesConfig(javaScriptModulesConfig)
|
.setJSModulesConfig(javaScriptModulesConfig)
|
||||||
.setJSBundleLoader(jsBundleLoader)
|
.setJSBundleLoader(jsBundleLoader)
|
||||||
.setNativeModuleCallExceptionHandler(mDevSupportManager);
|
.setNativeModuleCallExceptionHandler(exceptionHandler);
|
||||||
|
|
||||||
Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstance");
|
Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstance");
|
||||||
CatalystInstance catalystInstance;
|
CatalystInstance catalystInstance;
|
||||||
|
|
|
@ -155,7 +155,7 @@ public class DevSupportManager implements NativeModuleCallExceptionHandler {
|
||||||
public void handleException(Exception e) {
|
public void handleException(Exception e) {
|
||||||
if (mIsDevSupportEnabled) {
|
if (mIsDevSupportEnabled) {
|
||||||
FLog.e(ReactConstants.TAG, "Exception in native call from JS", e);
|
FLog.e(ReactConstants.TAG, "Exception in native call from JS", e);
|
||||||
showNewError(e.getMessage(), StackTraceHelper.convertJavaStackTrace(e), JAVA_ERROR_COOKIE);
|
showNewJavaError(e.getMessage(), e);
|
||||||
} else {
|
} else {
|
||||||
if (e instanceof RuntimeException) {
|
if (e instanceof RuntimeException) {
|
||||||
// Because we are rethrowing the original exception, the original stacktrace will be
|
// Because we are rethrowing the original exception, the original stacktrace will be
|
||||||
|
@ -167,6 +167,10 @@ public class DevSupportManager implements NativeModuleCallExceptionHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void showNewJavaError(String message, Throwable e) {
|
||||||
|
showNewError(message, StackTraceHelper.convertJavaStackTrace(e), JAVA_ERROR_COOKIE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add option item to dev settings dialog displayed by this manager. In the case user select given
|
* Add option item to dev settings dialog displayed by this manager. In the case user select given
|
||||||
* option from that dialog, the appropriate handler passed as {@param optionHandler} will be
|
* option from that dialog, the appropriate handler passed as {@param optionHandler} will be
|
||||||
|
@ -555,10 +559,9 @@ public class DevSupportManager implements NativeModuleCallExceptionHandler {
|
||||||
new Runnable() {
|
new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
showNewError(
|
showNewJavaError(
|
||||||
mApplicationContext.getString(R.string.catalyst_remotedbg_error),
|
mApplicationContext.getString(R.string.catalyst_remotedbg_error),
|
||||||
StackTraceHelper.convertJavaStackTrace(cause),
|
cause);
|
||||||
JAVA_ERROR_COOKIE);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -590,15 +593,11 @@ public class DevSupportManager implements NativeModuleCallExceptionHandler {
|
||||||
public void run() {
|
public void run() {
|
||||||
if (cause instanceof DebugServerException) {
|
if (cause instanceof DebugServerException) {
|
||||||
DebugServerException debugServerException = (DebugServerException) cause;
|
DebugServerException debugServerException = (DebugServerException) cause;
|
||||||
showNewError(
|
showNewJavaError(debugServerException.description, cause);
|
||||||
debugServerException.description,
|
|
||||||
StackTraceHelper.convertJavaStackTrace(cause),
|
|
||||||
JAVA_ERROR_COOKIE);
|
|
||||||
} else {
|
} else {
|
||||||
showNewError(
|
showNewJavaError(
|
||||||
mApplicationContext.getString(R.string.catalyst_jsload_error),
|
mApplicationContext.getString(R.string.catalyst_jsload_error),
|
||||||
StackTraceHelper.convertJavaStackTrace(cause),
|
cause);
|
||||||
JAVA_ERROR_COOKIE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue