diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactIgnorableMountingException.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactIgnorableMountingException.java new file mode 100644 index 00000000000..4dbf939817c --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactIgnorableMountingException.java @@ -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; + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index 2cbaa95bf3e..df44999e0c7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -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);