From aa75e94831df7ec94ee4cbc4df0de453c486022e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Tue, 18 Mar 2025 05:59:50 -0700 Subject: [PATCH] Avoid errors when dispatching mount operations within mount hooks (#50091) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/50091 Changelog: [internal] If a library uses mount hooks to perform mount operations, it's possible to get concurrent modifications of the list of pending surface IDs to report. This fixes that potential error by making a copy of the list before dispatching the mount notifications. Fixes https://github.com/facebook/react-native/issues/49783. Reviewed By: javache Differential Revision: D71387739 fbshipit-source-id: 96c723ef2d6bcc659c4452434b7a4d5af26117ef --- .../react/fabric/FabricUIManager.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index a7389a8b48f..2e8cab11087 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -173,7 +173,7 @@ public class FabricUIManager private final CopyOnWriteArrayList mListeners = new CopyOnWriteArrayList<>(); private boolean mMountNotificationScheduled = false; - private final List mMountedSurfaceIds = new ArrayList<>(); + private List mSurfaceIdsWithPendingMountNotification = new ArrayList<>(); @ThreadConfined(UI) @NonNull @@ -1250,12 +1250,13 @@ public class FabricUIManager // Collect surface IDs for all the mount items for (MountItem mountItem : mountItems) { - if (mountItem != null && !mMountedSurfaceIds.contains(mountItem.getSurfaceId())) { - mMountedSurfaceIds.add(mountItem.getSurfaceId()); + if (mountItem != null + && !mSurfaceIdsWithPendingMountNotification.contains(mountItem.getSurfaceId())) { + mSurfaceIdsWithPendingMountNotification.add(mountItem.getSurfaceId()); } } - if (!mMountNotificationScheduled && !mMountedSurfaceIds.isEmpty()) { + if (!mMountNotificationScheduled && !mSurfaceIdsWithPendingMountNotification.isEmpty()) { mMountNotificationScheduled = true; // Notify mount when the effects are visible and prevent mount hooks to @@ -1267,17 +1268,19 @@ public class FabricUIManager public void run() { mMountNotificationScheduled = false; + // Create a copy in case mount hooks trigger more mutations + final List surfaceIdsToReportMount = + mSurfaceIdsWithPendingMountNotification; + mSurfaceIdsWithPendingMountNotification = new ArrayList<>(); + final @Nullable FabricUIManagerBinding binding = mBinding; if (binding == null || mDestroyed) { - mMountedSurfaceIds.clear(); return; } - for (int surfaceId : mMountedSurfaceIds) { + for (int surfaceId : surfaceIdsToReportMount) { binding.reportMount(surfaceId); } - - mMountedSurfaceIds.clear(); } }); }