Mechanisms to workaround certain Fabric crashes in prod

Summary:
New mechanism to soft-crash, or crash, and collect diagnostics in the mounting layer.

Changelog: [Internal]

Reviewed By: sammy-SC

Differential Revision: D22971260

fbshipit-source-id: 860cde3effa4a187f10f5dd1488dd41ace65e363
This commit is contained in:
Joshua Gross
2020-08-06 11:18:05 -07:00
committed by Facebook GitHub Bot
parent 5f03e7ef41
commit cd372b1b06
2 changed files with 55 additions and 16 deletions
@@ -0,0 +1,36 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.bridge;
/**
* If thrown during a MountItem execution, FabricUIManager will print diagnostics and ignore the
* error. Use this carefully and sparingly!
*/
public class ReactIgnorableMountingException extends RuntimeException {
public ReactIgnorableMountingException(String m) {
super(m);
}
public ReactIgnorableMountingException(String m, Throwable e) {
super(m, e);
}
public ReactIgnorableMountingException(Throwable e) {
super(e);
}
public static boolean isIgnorable(Throwable e) {
while (e != null) {
if (e instanceof ReactIgnorableMountingException) {
return true;
}
e = e.getCause();
}
return false;
}
}
@@ -38,6 +38,7 @@ import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.NativeMap;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactIgnorableMountingException;
import com.facebook.react.bridge.ReactMarker;
import com.facebook.react.bridge.ReactMarkerConstants;
import com.facebook.react.bridge.ReactNoCrashSoftException;
@@ -857,12 +858,12 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
long batchedExecutionStartTime = SystemClock.uptimeMillis();
try {
for (MountItem mountItem : mountItemsToDispatch) {
if (ENABLE_FABRIC_LOGS) {
printMountItem(mountItem, "dispatchMountItems: Executing mountItem");
}
for (MountItem mountItem : mountItemsToDispatch) {
if (ENABLE_FABRIC_LOGS) {
printMountItem(mountItem, "dispatchMountItems: Executing mountItem");
}
try {
// Make sure surface associated with this MountItem has been started, and not stopped.
// TODO T68118357: clean up this logic and simplify this method overall
if (mountItem instanceof BatchMountItem) {
@@ -875,19 +876,21 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
}
mountItem.execute(mMountingManager);
}
mBatchedExecutionTime += SystemClock.uptimeMillis() - batchedExecutionStartTime;
} catch (Throwable e) {
// If there's an exception, we want to log diagnostics in prod and rethrow
// If a MountItem description is split across multiple lines, it's because it's a compound
// MountItem. Log each line separately.
FLog.e(TAG, "dispatchMountItems: caught exception, displaying all MountItems");
for (MountItem mountItem : mountItemsToDispatch) {
printMountItem(mountItem, "dispatchMountItems: mountItem");
}
} catch (Throwable e) {
// If there's an exception, we want to log diagnostics in prod and rethrow.
FLog.e(TAG, "dispatchMountItems: caught exception, displaying all MountItems", e);
for (MountItem m : mountItemsToDispatch) {
printMountItem(m, "dispatchMountItems: mountItem");
}
throw e;
if (ReactIgnorableMountingException.isIgnorable(e)) {
ReactSoftException.logSoftException(TAG, e);
} else {
throw e;
}
}
}
mBatchedExecutionTime += SystemClock.uptimeMillis() - batchedExecutionStartTime;
}
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);