From b9a2249fff08c8e68d97e798e962dd51b011109a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Wed, 10 Apr 2024 07:44:11 -0700 Subject: [PATCH] Implement potential fix for mounting errors during synchronous state updates (#44015) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/44015 Changelog: [internal] ## Context When we introduced synchronous state updates in Fabric, we saw some crashes on coming from the mounting layer on Android. It seems some of these crashes are caused by nested mount operations. When we're mounting some views, like [scroll views](https://github.com/facebook/react-native/blob/881c0bc8970b9e402df6b4f87e1759b238b24735/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java#L383), we dispatch state updates that end up doing more mutations. When we were doing these state updates asynchronously, all the original mutations were processed before these updates, but now that we do them synchronously, the mutations are interleaved causing errors. ## Changes This introduces a new flag that will force all the mutations going through `MountItemExecutor` in `FabricUIManager` to be batched instead of executed synchronously. This fixes the issues I saw locally and I'm expecting this will unblock synchronous state updates in production. Potentially, this might fix other crashes we've been seeing with a low frequency. Reviewed By: sammy-SC Differential Revision: D55942125 fbshipit-source-id: b8d9c145ec307de7318dbbed14880bc9a84fdb2a --- .../react/fabric/FabricUIManager.java | 9 +++++- .../fabric/mounting/MountItemDispatcher.java | 5 ++++ .../featureflags/ReactNativeFeatureFlags.kt | 8 +++++- .../ReactNativeFeatureFlagsCxxAccessor.kt | 12 +++++++- .../ReactNativeFeatureFlagsCxxInterop.kt | 4 ++- .../ReactNativeFeatureFlagsDefaults.kt | 4 ++- .../ReactNativeFeatureFlagsLocalAccessor.kt | 13 ++++++++- .../ReactNativeFeatureFlagsProvider.kt | 4 ++- .../JReactNativeFeatureFlagsCxxInterop.cpp | 16 ++++++++++- .../JReactNativeFeatureFlagsCxxInterop.h | 5 +++- .../featureflags/ReactNativeFeatureFlags.cpp | 6 +++- .../featureflags/ReactNativeFeatureFlags.h | 7 ++++- .../ReactNativeFeatureFlagsAccessor.cpp | 28 +++++++++++++++---- .../ReactNativeFeatureFlagsAccessor.h | 6 ++-- .../ReactNativeFeatureFlagsDefaults.h | 6 +++- .../ReactNativeFeatureFlagsProvider.h | 3 +- .../NativeReactNativeFeatureFlags.cpp | 7 ++++- .../NativeReactNativeFeatureFlags.h | 4 ++- .../ReactNativeFeatureFlags.config.js | 5 ++++ .../featureflags/ReactNativeFeatureFlags.js | 7 ++++- .../specs/NativeReactNativeFeatureFlags.js | 3 +- 21 files changed, 138 insertions(+), 24 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 33c7934c9cb..8f257a95f8d 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 @@ -208,7 +208,14 @@ public class FabricUIManager implements UIManager, LifecycleEventListener, UIBlo public void executeItems(Queue items) { // This executor can be technically accessed before the dispatcher is created, // but if that happens, something is terribly wrong - mMountItemDispatcher.dispatchMountItems(items); + if (ReactNativeFeatureFlags.forceBatchingMountItemsOnAndroid()) { + for (MountItem mountItem : items) { + mMountItemDispatcher.addMountItem(mountItem); + } + mMountItemDispatcher.tryDispatchMountItems(); + } else { + mMountItemDispatcher.dispatchMountItems(items); + } } }; diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountItemDispatcher.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountItemDispatcher.java index 8cb3b4868ab..67e28885cea 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountItemDispatcher.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountItemDispatcher.java @@ -24,6 +24,7 @@ import com.facebook.react.bridge.ReactSoftExceptionLogger; import com.facebook.react.bridge.RetryableMountingLayerException; import com.facebook.react.fabric.mounting.mountitems.DispatchCommandMountItem; import com.facebook.react.fabric.mounting.mountitems.MountItem; +import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags; import com.facebook.systrace.Systrace; import java.util.ArrayList; import java.util.Collection; @@ -102,6 +103,10 @@ public class MountItemDispatcher { return; } + if (ReactNativeFeatureFlags.forceBatchingMountItemsOnAndroid()) { + mInDispatch = true; + } + final boolean didDispatchItems; try { didDispatchItems = dispatchMountItems(); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt index b6450cb4bca..fe7273bf077 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<4c0ede4fa927bc8361d0355bc7cddb10>> + * @generated SignedSource<> */ /** @@ -88,6 +88,12 @@ public object ReactNativeFeatureFlags { @JvmStatic public fun enableUIConsistency(): Boolean = accessor.enableUIConsistency() + /** + * Forces the mounting layer on Android to always batch mount items instead of dispatching them immediately. This might fix some crashes related to synchronous state updates, where some views dispatch state updates during mount. + */ + @JvmStatic + public fun forceBatchingMountItemsOnAndroid(): Boolean = accessor.forceBatchingMountItemsOnAndroid() + /** * Flag determining if the C++ implementation of InspectorPackagerConnection should be used instead of the per-platform one. This flag is global and should not be changed across React Host lifetimes. */ diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt index ad1b4bd50d6..48ce01995a3 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<51d66e841a09638375b1849043c9886a>> */ /** @@ -30,6 +30,7 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso private var enableSpannableBuildingUnificationCache: Boolean? = null private var enableSynchronousStateUpdatesCache: Boolean? = null private var enableUIConsistencyCache: Boolean? = null + private var forceBatchingMountItemsOnAndroidCache: Boolean? = null private var inspectorEnableCxxInspectorPackagerConnectionCache: Boolean? = null private var inspectorEnableModernCDPRegistryCache: Boolean? = null private var useModernRuntimeSchedulerCache: Boolean? = null @@ -125,6 +126,15 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso return cached } + override fun forceBatchingMountItemsOnAndroid(): Boolean { + var cached = forceBatchingMountItemsOnAndroidCache + if (cached == null) { + cached = ReactNativeFeatureFlagsCxxInterop.forceBatchingMountItemsOnAndroid() + forceBatchingMountItemsOnAndroidCache = cached + } + return cached + } + override fun inspectorEnableCxxInspectorPackagerConnection(): Boolean { var cached = inspectorEnableCxxInspectorPackagerConnectionCache if (cached == null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt index 75af0124187..0b6d013f751 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<69c4a4aa9621adfe02c15f5f011b3804>> + * @generated SignedSource<<4422f7984f27638cc2fb18230a6d042e>> */ /** @@ -48,6 +48,8 @@ public object ReactNativeFeatureFlagsCxxInterop { @DoNotStrip @JvmStatic public external fun enableUIConsistency(): Boolean + @DoNotStrip @JvmStatic public external fun forceBatchingMountItemsOnAndroid(): Boolean + @DoNotStrip @JvmStatic public external fun inspectorEnableCxxInspectorPackagerConnection(): Boolean @DoNotStrip @JvmStatic public external fun inspectorEnableModernCDPRegistry(): Boolean diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt index 324eac6805e..2c0cbcbd775 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<299901489d5059ed7124f6738be0e48d>> + * @generated SignedSource<> */ /** @@ -43,6 +43,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun enableUIConsistency(): Boolean = false + override fun forceBatchingMountItemsOnAndroid(): Boolean = false + override fun inspectorEnableCxxInspectorPackagerConnection(): Boolean = false override fun inspectorEnableModernCDPRegistry(): Boolean = false diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt index fda593afdcf..2f3ec5922e6 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<1c5e5d965ec746a3d06748ef922b8460>> + * @generated SignedSource<<46793ec55ed15661090a9b9998806bcc>> */ /** @@ -34,6 +34,7 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces private var enableSpannableBuildingUnificationCache: Boolean? = null private var enableSynchronousStateUpdatesCache: Boolean? = null private var enableUIConsistencyCache: Boolean? = null + private var forceBatchingMountItemsOnAndroidCache: Boolean? = null private var inspectorEnableCxxInspectorPackagerConnectionCache: Boolean? = null private var inspectorEnableModernCDPRegistryCache: Boolean? = null private var useModernRuntimeSchedulerCache: Boolean? = null @@ -139,6 +140,16 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces return cached } + override fun forceBatchingMountItemsOnAndroid(): Boolean { + var cached = forceBatchingMountItemsOnAndroidCache + if (cached == null) { + cached = currentProvider.forceBatchingMountItemsOnAndroid() + accessedFeatureFlags.add("forceBatchingMountItemsOnAndroid") + forceBatchingMountItemsOnAndroidCache = cached + } + return cached + } + override fun inspectorEnableCxxInspectorPackagerConnection(): Boolean { var cached = inspectorEnableCxxInspectorPackagerConnectionCache if (cached == null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt index 14f3eeb4cff..48c47e13263 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<2412f7c99bf424397e091a529ac05f32>> + * @generated SignedSource<> */ /** @@ -43,6 +43,8 @@ public interface ReactNativeFeatureFlagsProvider { @DoNotStrip public fun enableUIConsistency(): Boolean + @DoNotStrip public fun forceBatchingMountItemsOnAndroid(): Boolean + @DoNotStrip public fun inspectorEnableCxxInspectorPackagerConnection(): Boolean @DoNotStrip public fun inspectorEnableModernCDPRegistry(): Boolean diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp index f22e68be74e..6eefe64e4ff 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<0756d56ae2ce45f020ac9a87e9a3d1c3>> + * @generated SignedSource<<3a7d633de9e6fd6862864c202d56523a>> */ /** @@ -99,6 +99,12 @@ class ReactNativeFeatureFlagsProviderHolder return method(javaProvider_); } + bool forceBatchingMountItemsOnAndroid() override { + static const auto method = + getReactNativeFeatureFlagsProviderJavaClass()->getMethod("forceBatchingMountItemsOnAndroid"); + return method(javaProvider_); + } + bool inspectorEnableCxxInspectorPackagerConnection() override { static const auto method = getReactNativeFeatureFlagsProviderJavaClass()->getMethod("inspectorEnableCxxInspectorPackagerConnection"); @@ -177,6 +183,11 @@ bool JReactNativeFeatureFlagsCxxInterop::enableUIConsistency( return ReactNativeFeatureFlags::enableUIConsistency(); } +bool JReactNativeFeatureFlagsCxxInterop::forceBatchingMountItemsOnAndroid( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::forceBatchingMountItemsOnAndroid(); +} + bool JReactNativeFeatureFlagsCxxInterop::inspectorEnableCxxInspectorPackagerConnection( facebook::jni::alias_ref /*unused*/) { return ReactNativeFeatureFlags::inspectorEnableCxxInspectorPackagerConnection(); @@ -244,6 +255,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() { makeNativeMethod( "enableUIConsistency", JReactNativeFeatureFlagsCxxInterop::enableUIConsistency), + makeNativeMethod( + "forceBatchingMountItemsOnAndroid", + JReactNativeFeatureFlagsCxxInterop::forceBatchingMountItemsOnAndroid), makeNativeMethod( "inspectorEnableCxxInspectorPackagerConnection", JReactNativeFeatureFlagsCxxInterop::inspectorEnableCxxInspectorPackagerConnection), diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h index b1ff803c287..047cf2c8e30 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<1ae5c51e5b1c1725565e57a02d19c3a7>> + * @generated SignedSource<<7237412cb02dad9468f144a050bd78e3>> */ /** @@ -60,6 +60,9 @@ class JReactNativeFeatureFlagsCxxInterop static bool enableUIConsistency( facebook::jni::alias_ref); + static bool forceBatchingMountItemsOnAndroid( + facebook::jni::alias_ref); + static bool inspectorEnableCxxInspectorPackagerConnection( facebook::jni::alias_ref); diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp index fbedd28aff4..43864710f1b 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<520ae882fb57dec58ededd47411c0b1d>> + * @generated SignedSource<> */ /** @@ -61,6 +61,10 @@ bool ReactNativeFeatureFlags::enableUIConsistency() { return getAccessor().enableUIConsistency(); } +bool ReactNativeFeatureFlags::forceBatchingMountItemsOnAndroid() { + return getAccessor().forceBatchingMountItemsOnAndroid(); +} + bool ReactNativeFeatureFlags::inspectorEnableCxxInspectorPackagerConnection() { return getAccessor().inspectorEnableCxxInspectorPackagerConnection(); } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h index 9c58e99111d..736feebfd2d 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<38881afec04f45eff46edd99ce9443da>> */ /** @@ -87,6 +87,11 @@ class ReactNativeFeatureFlags { */ RN_EXPORT static bool enableUIConsistency(); + /** + * Forces the mounting layer on Android to always batch mount items instead of dispatching them immediately. This might fix some crashes related to synchronous state updates, where some views dispatch state updates during mount. + */ + RN_EXPORT static bool forceBatchingMountItemsOnAndroid(); + /** * Flag determining if the C++ implementation of InspectorPackagerConnection should be used instead of the per-platform one. This flag is global and should not be changed across React Host lifetimes. */ diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp index afeaa359a71..799111c21ba 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<65cbd0e1b92ee06da3f466386c516dbc>> + * @generated SignedSource<<21980ab4688bc93c5573012a228e3997>> */ /** @@ -209,6 +209,24 @@ bool ReactNativeFeatureFlagsAccessor::enableUIConsistency() { return flagValue.value(); } +bool ReactNativeFeatureFlagsAccessor::forceBatchingMountItemsOnAndroid() { + auto flagValue = forceBatchingMountItemsOnAndroid_.load(); + + if (!flagValue.has_value()) { + // This block is not exclusive but it is not necessary. + // If multiple threads try to initialize the feature flag, we would only + // be accessing the provider multiple times but the end state of this + // instance and the returned flag value would be the same. + + markFlagAsAccessed(10, "forceBatchingMountItemsOnAndroid"); + + flagValue = currentProvider_->forceBatchingMountItemsOnAndroid(); + forceBatchingMountItemsOnAndroid_ = flagValue; + } + + return flagValue.value(); +} + bool ReactNativeFeatureFlagsAccessor::inspectorEnableCxxInspectorPackagerConnection() { auto flagValue = inspectorEnableCxxInspectorPackagerConnection_.load(); @@ -218,7 +236,7 @@ bool ReactNativeFeatureFlagsAccessor::inspectorEnableCxxInspectorPackagerConnect // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(10, "inspectorEnableCxxInspectorPackagerConnection"); + markFlagAsAccessed(11, "inspectorEnableCxxInspectorPackagerConnection"); flagValue = currentProvider_->inspectorEnableCxxInspectorPackagerConnection(); inspectorEnableCxxInspectorPackagerConnection_ = flagValue; @@ -236,7 +254,7 @@ bool ReactNativeFeatureFlagsAccessor::inspectorEnableModernCDPRegistry() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(11, "inspectorEnableModernCDPRegistry"); + markFlagAsAccessed(12, "inspectorEnableModernCDPRegistry"); flagValue = currentProvider_->inspectorEnableModernCDPRegistry(); inspectorEnableModernCDPRegistry_ = flagValue; @@ -254,7 +272,7 @@ bool ReactNativeFeatureFlagsAccessor::useModernRuntimeScheduler() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(12, "useModernRuntimeScheduler"); + markFlagAsAccessed(13, "useModernRuntimeScheduler"); flagValue = currentProvider_->useModernRuntimeScheduler(); useModernRuntimeScheduler_ = flagValue; @@ -272,7 +290,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeViewConfigsInBridgelessMode() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(13, "useNativeViewConfigsInBridgelessMode"); + markFlagAsAccessed(14, "useNativeViewConfigsInBridgelessMode"); flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode(); useNativeViewConfigsInBridgelessMode_ = flagValue; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h index 3736fdc54f6..aab11cf3a90 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<00e1c8f5c451c9744257e0b3fc566949>> + * @generated SignedSource<> */ /** @@ -41,6 +41,7 @@ class ReactNativeFeatureFlagsAccessor { bool enableSpannableBuildingUnification(); bool enableSynchronousStateUpdates(); bool enableUIConsistency(); + bool forceBatchingMountItemsOnAndroid(); bool inspectorEnableCxxInspectorPackagerConnection(); bool inspectorEnableModernCDPRegistry(); bool useModernRuntimeScheduler(); @@ -55,7 +56,7 @@ class ReactNativeFeatureFlagsAccessor { std::unique_ptr currentProvider_; bool wasOverridden_; - std::array, 14> accessedFeatureFlags_; + std::array, 15> accessedFeatureFlags_; std::atomic> commonTestFlag_; std::atomic> batchRenderingUpdatesInEventLoop_; @@ -67,6 +68,7 @@ class ReactNativeFeatureFlagsAccessor { std::atomic> enableSpannableBuildingUnification_; std::atomic> enableSynchronousStateUpdates_; std::atomic> enableUIConsistency_; + std::atomic> forceBatchingMountItemsOnAndroid_; std::atomic> inspectorEnableCxxInspectorPackagerConnection_; std::atomic> inspectorEnableModernCDPRegistry_; std::atomic> useModernRuntimeScheduler_; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index c8feb9416c8..7dc384f8637 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<57c83d1855f16d4c3ffdd5cb98d57571>> + * @generated SignedSource<<72058f22fd21f03e66136929306d5974>> */ /** @@ -67,6 +67,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { return false; } + bool forceBatchingMountItemsOnAndroid() override { + return false; + } + bool inspectorEnableCxxInspectorPackagerConnection() override { return false; } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h index 72aee0dd8a6..7e1237ae370 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<664351a329e558acf1923baeafe35e9d>> + * @generated SignedSource<<21fb3f2ea9db49ea4710a13807c7512a>> */ /** @@ -35,6 +35,7 @@ class ReactNativeFeatureFlagsProvider { virtual bool enableSpannableBuildingUnification() = 0; virtual bool enableSynchronousStateUpdates() = 0; virtual bool enableUIConsistency() = 0; + virtual bool forceBatchingMountItemsOnAndroid() = 0; virtual bool inspectorEnableCxxInspectorPackagerConnection() = 0; virtual bool inspectorEnableModernCDPRegistry() = 0; virtual bool useModernRuntimeScheduler() = 0; diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp index 369d188b50f..2096238d12e 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp +++ b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<8c7e1d8afe1bc2068c94148a258c2ed0>> + * @generated SignedSource<<55ee96b1902071c987c70b5f07f670e4>> */ /** @@ -87,6 +87,11 @@ bool NativeReactNativeFeatureFlags::enableUIConsistency( return ReactNativeFeatureFlags::enableUIConsistency(); } +bool NativeReactNativeFeatureFlags::forceBatchingMountItemsOnAndroid( + jsi::Runtime& /*runtime*/) { + return ReactNativeFeatureFlags::forceBatchingMountItemsOnAndroid(); +} + bool NativeReactNativeFeatureFlags::inspectorEnableCxxInspectorPackagerConnection( jsi::Runtime& /*runtime*/) { return ReactNativeFeatureFlags::inspectorEnableCxxInspectorPackagerConnection(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h index 7682e88d53b..fc233e23a49 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h +++ b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<9d8d8fd8a9da981fd35c9f134f575e57>> + * @generated SignedSource<> */ /** @@ -55,6 +55,8 @@ class NativeReactNativeFeatureFlags bool enableUIConsistency(jsi::Runtime& runtime); + bool forceBatchingMountItemsOnAndroid(jsi::Runtime& runtime); + bool inspectorEnableCxxInspectorPackagerConnection(jsi::Runtime& runtime); bool inspectorEnableModernCDPRegistry(jsi::Runtime& runtime); diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index c4c4f378b39..54ad2c8aaf8 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -76,6 +76,11 @@ const definitions: FeatureFlagDefinitions = { description: 'Ensures that JavaScript always has a consistent view of the state of the UI (e.g.: commits done in other threads are not immediately propagated to JS during its execution).', }, + forceBatchingMountItemsOnAndroid: { + defaultValue: false, + description: + 'Forces the mounting layer on Android to always batch mount items instead of dispatching them immediately. This might fix some crashes related to synchronous state updates, where some views dispatch state updates during mount.', + }, inspectorEnableCxxInspectorPackagerConnection: { defaultValue: false, description: diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index caf5af53932..867f39004fb 100644 --- a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<9286e5fc6398d839d271af4f4a8ae94b>> + * @generated SignedSource<<45969617730126d45f35820ee3bd5853>> * @flow strict-local */ @@ -50,6 +50,7 @@ export type ReactNativeFeatureFlags = { enableSpannableBuildingUnification: Getter, enableSynchronousStateUpdates: Getter, enableUIConsistency: Getter, + forceBatchingMountItemsOnAndroid: Getter, inspectorEnableCxxInspectorPackagerConnection: Getter, inspectorEnableModernCDPRegistry: Getter, useModernRuntimeScheduler: Getter, @@ -136,6 +137,10 @@ export const enableSynchronousStateUpdates: Getter = createNativeFlagGe * Ensures that JavaScript always has a consistent view of the state of the UI (e.g.: commits done in other threads are not immediately propagated to JS during its execution). */ export const enableUIConsistency: Getter = createNativeFlagGetter('enableUIConsistency', false); +/** + * Forces the mounting layer on Android to always batch mount items instead of dispatching them immediately. This might fix some crashes related to synchronous state updates, where some views dispatch state updates during mount. + */ +export const forceBatchingMountItemsOnAndroid: Getter = createNativeFlagGetter('forceBatchingMountItemsOnAndroid', false); /** * Flag determining if the C++ implementation of InspectorPackagerConnection should be used instead of the per-platform one. This flag is global and should not be changed across React Host lifetimes. */ diff --git a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js index c38ed3a21fe..9331c6242fe 100644 --- a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<22dd9936df00ce7a53a5aa4a2c331279>> * @flow strict-local */ @@ -33,6 +33,7 @@ export interface Spec extends TurboModule { +enableSpannableBuildingUnification?: () => boolean; +enableSynchronousStateUpdates?: () => boolean; +enableUIConsistency?: () => boolean; + +forceBatchingMountItemsOnAndroid?: () => boolean; +inspectorEnableCxxInspectorPackagerConnection?: () => boolean; +inspectorEnableModernCDPRegistry?: () => boolean; +useModernRuntimeScheduler?: () => boolean;