Detect recoverable cases where SendAccessibilityEvent exceptions don't need to hard-crash the app

Summary:
See T53113342, view command retry logic, and comment explanation in code.

Changelog: [Internal] fabric

Reviewed By: mdvacca

Differential Revision: D21606911

fbshipit-source-id: 503f52400beb98a19840c67896e0a7a519f30573
This commit is contained in:
Joshua Gross
2020-05-15 20:05:55 -07:00
committed by Facebook GitHub Bot
parent eb2a561ecb
commit 1a218e561c
2 changed files with 21 additions and 4 deletions
@@ -138,7 +138,7 @@ public class MountingManager {
private @NonNull ViewState getViewState(int tag) {
ViewState viewState = mTagToViewState.get(tag);
if (viewState == null) {
throw new IllegalStateException("Unable to find viewState view for tag " + tag);
throw new RetryableMountingLayerException("Unable to find viewState view for tag " + tag);
}
return viewState;
}
@@ -202,11 +202,13 @@ public class MountingManager {
ViewState viewState = getViewState(reactTag);
if (viewState.mViewManager == null) {
throw new IllegalStateException("Unable to find viewState manager for tag " + reactTag);
throw new RetryableMountingLayerException(
"Unable to find viewState manager for tag " + reactTag);
}
if (viewState.mView == null) {
throw new IllegalStateException("Unable to find viewState view for tag " + reactTag);
throw new RetryableMountingLayerException(
"Unable to find viewState view for tag " + reactTag);
}
viewState.mView.sendAccessibilityEvent(eventType);
@@ -8,10 +8,14 @@
package com.facebook.react.fabric.mounting.mountitems;
import androidx.annotation.NonNull;
import com.facebook.react.bridge.ReactSoftException;
import com.facebook.react.bridge.RetryableMountingLayerException;
import com.facebook.react.fabric.mounting.MountingManager;
public class SendAccessibilityEvent implements MountItem {
private final String TAG = "Fabric.SendAccessibilityEvent";
private final int mReactTag;
private final int mEventType;
@@ -22,7 +26,18 @@ public class SendAccessibilityEvent implements MountItem {
@Override
public void execute(@NonNull MountingManager mountingManager) {
mountingManager.sendAccessibilityEvent(mReactTag, mEventType);
try {
mountingManager.sendAccessibilityEvent(mReactTag, mEventType);
} catch (RetryableMountingLayerException e) {
// Accessibility events are similar to commands in that they're imperative
// calls from JS, disconnected from the commit lifecycle, and therefore
// inherently unpredictable and dangerous. If we encounter a "retryable"
// error, that is, a known category of errors that this is likely to hit
// due to race conditions (like the view disappearing after the event is
// queued and before it executes), we log a soft exception and continue along.
// Other categories of errors will still cause a hard crash.
ReactSoftException.logSoftException(TAG, e);
}
}
@Override