Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid crash by handling missing views in dispatchViewManagerCommand #33795

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.common.ReactConstants;
import com.facebook.react.common.build.ReactBuildConfig;
import com.facebook.react.modules.i18nmanager.I18nUtil;
import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
import com.facebook.react.uimanager.events.EventDispatcher;
Expand Down Expand Up @@ -742,13 +743,21 @@ public void clearJSResponder() {
@Deprecated
public void dispatchViewManagerCommand(
int reactTag, int commandId, @Nullable ReadableArray commandArgs) {
assertViewExists(reactTag, "dispatchViewManagerCommand: " + commandId);
boolean viewExists = checkOrAssertViewExists(reactTag, "dispatchViewManagerCommand: " + commandId);
if (!viewExists) {
return;
}

mOperationsQueue.enqueueDispatchCommand(reactTag, commandId, commandArgs);
}

public void dispatchViewManagerCommand(
int reactTag, String commandId, @Nullable ReadableArray commandArgs) {
assertViewExists(reactTag, "dispatchViewManagerCommand: " + commandId);
boolean viewExists = checkOrAssertViewExists(reactTag, "dispatchViewManagerCommand: " + commandId);
if (!viewExists) {
return;
}

mOperationsQueue.enqueueDispatchCommand(reactTag, commandId, commandArgs);
}

Expand All @@ -763,7 +772,11 @@ public void dispatchViewManagerCommand(
* no arguments if the menu is dismissed
*/
public void showPopupMenu(int reactTag, ReadableArray items, Callback error, Callback success) {
assertViewExists(reactTag, "showPopupMenu");
boolean viewExists = checkOrAssertViewExists(reactTag, "showPopupMenu");
if (!viewExists) {
return;
}

mOperationsQueue.enqueueShowPopupMenu(reactTag, items, error, success);
}

Expand Down Expand Up @@ -867,15 +880,30 @@ private void measureLayoutRelativeToVerifiedAncestor(
outputBuffer[3] = node.getScreenHeight();
}

private void assertViewExists(int reactTag, String operationNameForExceptionMessage) {
if (mShadowNodeRegistry.getNode(reactTag) == null) {
throw new IllegalViewOperationException(
"Unable to execute operation "
+ operationNameForExceptionMessage
+ " on view with "
+ "tag: "
+ reactTag
+ ", since the view does not exists");
/**
* Returns whether a view identified by the tag exists. In debug mode, this
* will throw whenever the view doesn't exist. In production, it'll log a
* warning. Callers should use this and just return if the view doesn't exist
* to avoid crashing.
*/
private boolean checkOrAssertViewExists(int reactTag, String operationNameForExceptionMessage) {
boolean viewExists = mShadowNodeRegistry.getNode(reactTag) != null;
if (viewExists) {
return true;
}

String message = "Unable to execute operation "
+ operationNameForExceptionMessage
+ " on view with "
+ "tag: "
+ reactTag
+ ", since the view does not exist";

if (ReactBuildConfig.DEBUG) {
throw new IllegalViewOperationException(message);
} else {
FLog.w(ReactConstants.TAG, message);
return false;
}
}

Expand Down