From bc986d0ff05fe8cad047926789c9ff7231b3fdd6 Mon Sep 17 00:00:00 2001 From: Pieter De Baets Date: Mon, 28 Oct 2024 04:27:29 -0700 Subject: [PATCH] Add featureflag to not re-order mount items in FabricMountingManager (#46702) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/46702 In https://github.com/facebook/react-native/pull/44188, we've started combining multiple transactions in a single transaction, to meet React's atomicity requirements, while also dealing with the constraints of Android's Fabric implementation. This revealed a bug where in some scenarios (especially when using transitions), a node may be deleted and created during the same transaction. The current implementation of FabricMountingManager assumes it can safely reorder some operations, which it does to optimize the size of IntBufferBatch mount items. This is however incorrect and unsafe when multiple transactions are merged. **Example:** Differentiator output: ``` # Transaction 1 Remove #100 from #11 Delete #100 # Transaction 2 Create #100 Insert #100 into #11 ``` FabricMountingManager output ``` Remove #100 from #11 Insert #100 into #11 Delete #100 ``` Note that the create action is also skipped, because we only update `allocatedViewTags` after processing all mutations, leading FabricMountingManager to assume creation is not required. This leads to an invalid state in SurfaceMountingManager, which will be surfaced as a crash in `getViewState` on the next mutation that interacts with these views. Changelog: [Android][Fixed] Fix crash in getViewState when using suspense fallbacks. Reviewed By: sammy-SC Differential Revision: D63148523 --- .../featureflags/ReactNativeFeatureFlags.kt | 8 +- .../ReactNativeFeatureFlagsCxxAccessor.kt | 12 +- .../ReactNativeFeatureFlagsCxxInterop.kt | 4 +- .../ReactNativeFeatureFlagsDefaults.kt | 4 +- .../ReactNativeFeatureFlagsLocalAccessor.kt | 13 +- .../ReactNativeFeatureFlagsProvider.kt | 4 +- .../react/fabric/FabricMountingManager.cpp | 140 +++++++++++------- .../JReactNativeFeatureFlagsCxxInterop.cpp | 16 +- .../JReactNativeFeatureFlagsCxxInterop.h | 5 +- .../featureflags/ReactNativeFeatureFlags.cpp | 6 +- .../featureflags/ReactNativeFeatureFlags.h | 7 +- .../ReactNativeFeatureFlagsAccessor.cpp | 106 +++++++------ .../ReactNativeFeatureFlagsAccessor.h | 6 +- .../ReactNativeFeatureFlagsDefaults.h | 6 +- .../ReactNativeFeatureFlagsProvider.h | 3 +- .../NativeReactNativeFeatureFlags.cpp | 7 +- .../NativeReactNativeFeatureFlags.h | 4 +- .../ReactNativeFeatureFlags.config.js | 9 ++ .../featureflags/ReactNativeFeatureFlags.js | 7 +- .../specs/NativeReactNativeFeatureFlags.js | 3 +- 20 files changed, 257 insertions(+), 113 deletions(-) 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 cffb38e37ee343..1fb0daae189337 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<> + * @generated SignedSource<<575eeb1e291c1a372eba7aabcdd948e3>> */ /** @@ -52,6 +52,12 @@ public object ReactNativeFeatureFlags { @JvmStatic public fun disableEventLoopOnBridgeless(): Boolean = accessor.disableEventLoopOnBridgeless() + /** + * Prevent FabricMountingManager from reordering mountitems, which may lead to invalid state on the UI thread + */ + @JvmStatic + public fun disableMountItemReorderingAndroid(): Boolean = accessor.disableMountItemReorderingAndroid() + /** * Kill-switch to turn off support for aling-items:baseline on Fabric iOS. */ 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 6951d052b2f2ff..9ee03db25ef923 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<<6b3d3512d88c836dd809204cad636211>> + * @generated SignedSource<> */ /** @@ -24,6 +24,7 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso private var allowRecursiveCommitsWithSynchronousMountOnAndroidCache: Boolean? = null private var completeReactInstanceCreationOnBgThreadOnAndroidCache: Boolean? = null private var disableEventLoopOnBridgelessCache: Boolean? = null + private var disableMountItemReorderingAndroidCache: Boolean? = null private var enableAlignItemsBaselineOnFabricIOSCache: Boolean? = null private var enableAndroidLineHeightCenteringCache: Boolean? = null private var enableBridgelessArchitectureCache: Boolean? = null @@ -104,6 +105,15 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso return cached } + override fun disableMountItemReorderingAndroid(): Boolean { + var cached = disableMountItemReorderingAndroidCache + if (cached == null) { + cached = ReactNativeFeatureFlagsCxxInterop.disableMountItemReorderingAndroid() + disableMountItemReorderingAndroidCache = cached + } + return cached + } + override fun enableAlignItemsBaselineOnFabricIOS(): Boolean { var cached = enableAlignItemsBaselineOnFabricIOSCache 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 beb07351efe7be..5cfdfe9e060603 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<<0ef9a66ccabeb0357f4b15c3e897f8fb>> + * @generated SignedSource<<44d0fe9a36e5e51816e10b8799d451fe>> */ /** @@ -36,6 +36,8 @@ public object ReactNativeFeatureFlagsCxxInterop { @DoNotStrip @JvmStatic public external fun disableEventLoopOnBridgeless(): Boolean + @DoNotStrip @JvmStatic public external fun disableMountItemReorderingAndroid(): Boolean + @DoNotStrip @JvmStatic public external fun enableAlignItemsBaselineOnFabricIOS(): Boolean @DoNotStrip @JvmStatic public external fun enableAndroidLineHeightCentering(): 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 cd29e014259de9..f230cc33fdcfc5 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<> + * @generated SignedSource<<917a6effbfd0a476cc05d90abee3c80b>> */ /** @@ -31,6 +31,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun disableEventLoopOnBridgeless(): Boolean = false + override fun disableMountItemReorderingAndroid(): Boolean = false + override fun enableAlignItemsBaselineOnFabricIOS(): Boolean = true override fun enableAndroidLineHeightCentering(): 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 c8674af73cf3e3..8dd0f02fb5704c 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<<949f5cdf6d0a4015fbd680ba718dce6d>> + * @generated SignedSource<<2ad36465b1a411cb55d85416bd8ba823>> */ /** @@ -28,6 +28,7 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces private var allowRecursiveCommitsWithSynchronousMountOnAndroidCache: Boolean? = null private var completeReactInstanceCreationOnBgThreadOnAndroidCache: Boolean? = null private var disableEventLoopOnBridgelessCache: Boolean? = null + private var disableMountItemReorderingAndroidCache: Boolean? = null private var enableAlignItemsBaselineOnFabricIOSCache: Boolean? = null private var enableAndroidLineHeightCenteringCache: Boolean? = null private var enableBridgelessArchitectureCache: Boolean? = null @@ -112,6 +113,16 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces return cached } + override fun disableMountItemReorderingAndroid(): Boolean { + var cached = disableMountItemReorderingAndroidCache + if (cached == null) { + cached = currentProvider.disableMountItemReorderingAndroid() + accessedFeatureFlags.add("disableMountItemReorderingAndroid") + disableMountItemReorderingAndroidCache = cached + } + return cached + } + override fun enableAlignItemsBaselineOnFabricIOS(): Boolean { var cached = enableAlignItemsBaselineOnFabricIOSCache 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 36e8db344f06d1..32af144a3bdbdd 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<<4e42e76c98b7434273e4f11212f0527b>> + * @generated SignedSource<<9770a9f125b8bcb4b1daef9e3458433f>> */ /** @@ -31,6 +31,8 @@ public interface ReactNativeFeatureFlagsProvider { @DoNotStrip public fun disableEventLoopOnBridgeless(): Boolean + @DoNotStrip public fun disableMountItemReorderingAndroid(): Boolean + @DoNotStrip public fun enableAlignItemsBaselineOnFabricIOS(): Boolean @DoNotStrip public fun enableAndroidLineHeightCentering(): Boolean diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp index b5eb6c64bd238e..c6ae9d3c4ae328 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp @@ -37,7 +37,8 @@ FabricMountingManager::FabricMountingManager( void FabricMountingManager::onSurfaceStart(SurfaceId surfaceId) { std::lock_guard lock(allocatedViewsMutex_); - allocatedViewRegistry_.emplace(surfaceId, std::unordered_set{}); + allocatedViewRegistry_.emplace( + surfaceId, std::unordered_set({surfaceId})); } void FabricMountingManager::onSurfaceStop(SurfaceId surfaceId) { @@ -465,6 +466,9 @@ void FabricMountingManager::executeMount( auto surfaceId = transaction.getSurfaceId(); auto& mutations = transaction.getMutations(); + bool maintainMutationOrder = + ReactNativeFeatureFlags::disableMountItemReorderingAndroid(); + auto revisionNumber = telemetry.getRevisionNumber(); std::vector cppCommonMountItems; @@ -486,7 +490,7 @@ void FabricMountingManager::executeMount( // operand is a value type, the compiler will decide the expression to be a // value type, an unnecessary (sometimes expensive) copy will happen as a // result. - const auto& allocatedViewTags = + auto& allocatedViewTags = allocatedViewsIterator != allocatedViewRegistry_.end() ? allocatedViewsIterator->second : defaultAllocatedViews; @@ -510,6 +514,7 @@ void FabricMountingManager::executeMount( if (shouldCreateView) { cppCommonMountItems.push_back( CppMountItem::CreateMountItem(newChildShadowView)); + allocatedViewTags.insert(newChildShadowView.tag); } break; } @@ -521,20 +526,32 @@ void FabricMountingManager::executeMount( break; } case ShadowViewMutation::Delete: { - cppDeleteMountItems.push_back( - CppMountItem::DeleteMountItem(oldChildShadowView)); + (maintainMutationOrder ? cppCommonMountItems : cppDeleteMountItems) + .push_back(CppMountItem::DeleteMountItem(oldChildShadowView)); + if (allocatedViewTags.erase(oldChildShadowView.tag) != 1) { + LOG(ERROR) << "Emitting delete for unallocated view. " + << oldChildShadowView.tag; + } break; } case ShadowViewMutation::Update: { if (!isVirtual) { + if (!allocatedViewTags.contains(newChildShadowView.tag)) { + LOG(FATAL) << "Emitting update for unallocated view. " + << newChildShadowView.tag; + } + if (oldChildShadowView.props != newChildShadowView.props) { - cppUpdatePropsMountItems.push_back( - CppMountItem::UpdatePropsMountItem( + (maintainMutationOrder ? cppCommonMountItems + : cppUpdatePropsMountItems) + .push_back(CppMountItem::UpdatePropsMountItem( oldChildShadowView, newChildShadowView)); } if (oldChildShadowView.state != newChildShadowView.state) { - cppUpdateStateMountItems.push_back( - CppMountItem::UpdateStateMountItem(newChildShadowView)); + (maintainMutationOrder ? cppCommonMountItems + : cppUpdateStateMountItems) + .push_back( + CppMountItem::UpdateStateMountItem(newChildShadowView)); } // Padding: padding mountItems must be executed before layout props @@ -543,14 +560,17 @@ void FabricMountingManager::executeMount( // padding information. if (oldChildShadowView.layoutMetrics.contentInsets != newChildShadowView.layoutMetrics.contentInsets) { - cppUpdatePaddingMountItems.push_back( - CppMountItem::UpdatePaddingMountItem(newChildShadowView)); + (maintainMutationOrder ? cppCommonMountItems + : cppUpdatePaddingMountItems) + .push_back( + CppMountItem::UpdatePaddingMountItem(newChildShadowView)); } if (oldChildShadowView.layoutMetrics != newChildShadowView.layoutMetrics) { - cppUpdateLayoutMountItems.push_back( - CppMountItem::UpdateLayoutMountItem( + (maintainMutationOrder ? cppCommonMountItems + : cppUpdateLayoutMountItems) + .push_back(CppMountItem::UpdateLayoutMountItem( mutation.newChildShadowView, parentShadowView)); } @@ -560,16 +580,18 @@ void FabricMountingManager::executeMount( // pack too much data there. if ((oldChildShadowView.layoutMetrics.overflowInset != newChildShadowView.layoutMetrics.overflowInset)) { - cppUpdateOverflowInsetMountItems.push_back( - CppMountItem::UpdateOverflowInsetMountItem( + (maintainMutationOrder ? cppCommonMountItems + : cppUpdateOverflowInsetMountItems) + .push_back(CppMountItem::UpdateOverflowInsetMountItem( newChildShadowView)); } } if (oldChildShadowView.eventEmitter != newChildShadowView.eventEmitter) { - cppUpdateEventEmitterMountItems.push_back( - CppMountItem::UpdateEventEmitterMountItem( + (maintainMutationOrder ? cppCommonMountItems + : cppUpdatePropsMountItems) + .push_back(CppMountItem::UpdateEventEmitterMountItem( mutation.newChildShadowView)); } break; @@ -580,19 +602,23 @@ void FabricMountingManager::executeMount( cppCommonMountItems.push_back(CppMountItem::InsertMountItem( parentShadowView, newChildShadowView, index)); - bool allocationCheck = - allocatedViewTags.find(newChildShadowView.tag) == - allocatedViewTags.end(); - bool shouldCreateView = allocationCheck; + bool shouldCreateView = + !allocatedViewTags.contains(newChildShadowView.tag); if (shouldCreateView) { - cppUpdatePropsMountItems.push_back( - CppMountItem::UpdatePropsMountItem({}, newChildShadowView)); + LOG(ERROR) << "Emitting insert for unallocated view. " + << newChildShadowView.tag; + (maintainMutationOrder ? cppCommonMountItems + : cppUpdatePropsMountItems) + .push_back(CppMountItem::UpdatePropsMountItem( + {}, newChildShadowView)); } // State if (newChildShadowView.state) { - cppUpdateStateMountItems.push_back( - CppMountItem::UpdateStateMountItem(newChildShadowView)); + (maintainMutationOrder ? cppCommonMountItems + : cppUpdateStateMountItems) + .push_back( + CppMountItem::UpdateStateMountItem(newChildShadowView)); } // Padding: padding mountItems must be executed before layout props @@ -601,13 +627,16 @@ void FabricMountingManager::executeMount( // padding information. if (newChildShadowView.layoutMetrics.contentInsets != EdgeInsets::ZERO) { - cppUpdatePaddingMountItems.push_back( - CppMountItem::UpdatePaddingMountItem(newChildShadowView)); + (maintainMutationOrder ? cppCommonMountItems + : cppUpdatePaddingMountItems) + .push_back( + CppMountItem::UpdatePaddingMountItem(newChildShadowView)); } // Layout - cppUpdateLayoutMountItems.push_back( - CppMountItem::UpdateLayoutMountItem( + (maintainMutationOrder ? cppCommonMountItems + : cppUpdateLayoutMountItems) + .push_back(CppMountItem::UpdateLayoutMountItem( newChildShadowView, parentShadowView)); // OverflowInset: This is the values indicating boundaries including @@ -616,15 +645,19 @@ void FabricMountingManager::executeMount( // pack too much data there. if (newChildShadowView.layoutMetrics.overflowInset != EdgeInsets::ZERO) { - cppUpdateOverflowInsetMountItems.push_back( - CppMountItem::UpdateOverflowInsetMountItem( + (maintainMutationOrder ? cppCommonMountItems + : cppUpdateOverflowInsetMountItems) + .push_back(CppMountItem::UpdateOverflowInsetMountItem( newChildShadowView)); } } // EventEmitter - cppUpdateEventEmitterMountItems.push_back( - CppMountItem::UpdateEventEmitterMountItem( + // On insert we always update the event emitter, as we do not pass + // it in when preallocating views + (maintainMutationOrder ? cppCommonMountItems + : cppUpdateEventEmitterMountItems) + .push_back(CppMountItem::UpdateEventEmitterMountItem( mutation.newChildShadowView)); break; @@ -634,22 +667,6 @@ void FabricMountingManager::executeMount( } } } - - if (allocatedViewsIterator != allocatedViewRegistry_.end()) { - auto& views = allocatedViewsIterator->second; - for (const auto& mutation : mutations) { - switch (mutation.type) { - case ShadowViewMutation::Create: - views.insert(mutation.newChildShadowView.tag); - break; - case ShadowViewMutation::Delete: - views.erase(mutation.oldChildShadowView.tag); - break; - default: - break; - } - } - } } // We now have all the information we need, including ordering of mount items, @@ -728,12 +745,33 @@ void FabricMountingManager::executeMount( case CppMountItem::Type::Create: writeCreateMountItem(buffer, mountItem); break; + case CppMountItem::Type::Delete: + writeDeleteMountItem(buffer, mountItem); + break; case CppMountItem::Type::Insert: writeInsertMountItem(buffer, mountItem); break; case CppMountItem::Type::Remove: writeRemoveMountItem(buffer, mountItem); break; + case CppMountItem::Type::UpdateProps: + writeUpdatePropsMountItem(buffer, mountItem); + break; + case CppMountItem::Type::UpdateState: + writeUpdateStateMountItem(buffer, mountItem); + break; + case CppMountItem::Type::UpdateLayout: + writeUpdateLayoutMountItem(buffer, mountItem); + break; + case CppMountItem::Type::UpdateEventEmitter: + writeUpdateEventEmitterMountItem(buffer, mountItem); + break; + case CppMountItem::Type::UpdatePadding: + writeUpdatePaddingMountItem(buffer, mountItem); + break; + case CppMountItem::Type::UpdateOverflowInset: + writeUpdateOverflowInsetMountItem(buffer, mountItem); + break; default: LOG(FATAL) << "Unexpected CppMountItem type: " << mountItemType; } @@ -906,11 +944,11 @@ void FabricMountingManager::preallocateShadowView( if (allocatedViewsIterator == allocatedViewRegistry_.end()) { return; } - auto& allocatedViews = allocatedViewsIterator->second; - if (allocatedViews.find(shadowView.tag) != allocatedViews.end()) { + const auto [_, inserted] = + allocatedViewsIterator->second.insert(shadowView.tag); + if (!inserted) { return; } - allocatedViews.insert(shadowView.tag); } bool isLayoutableShadowNode = shadowView.layoutMetrics != EmptyLayoutMetrics; 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 704015059f6d40..e95510f969b67d 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<<732d1ea726d8a08859bd153dc767ec7a>> + * @generated SignedSource<> */ /** @@ -63,6 +63,12 @@ class ReactNativeFeatureFlagsProviderHolder return method(javaProvider_); } + bool disableMountItemReorderingAndroid() override { + static const auto method = + getReactNativeFeatureFlagsProviderJavaClass()->getMethod("disableMountItemReorderingAndroid"); + return method(javaProvider_); + } + bool enableAlignItemsBaselineOnFabricIOS() override { static const auto method = getReactNativeFeatureFlagsProviderJavaClass()->getMethod("enableAlignItemsBaselineOnFabricIOS"); @@ -345,6 +351,11 @@ bool JReactNativeFeatureFlagsCxxInterop::disableEventLoopOnBridgeless( return ReactNativeFeatureFlags::disableEventLoopOnBridgeless(); } +bool JReactNativeFeatureFlagsCxxInterop::disableMountItemReorderingAndroid( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::disableMountItemReorderingAndroid(); +} + bool JReactNativeFeatureFlagsCxxInterop::enableAlignItemsBaselineOnFabricIOS( facebook::jni::alias_ref /*unused*/) { return ReactNativeFeatureFlags::enableAlignItemsBaselineOnFabricIOS(); @@ -603,6 +614,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() { makeNativeMethod( "disableEventLoopOnBridgeless", JReactNativeFeatureFlagsCxxInterop::disableEventLoopOnBridgeless), + makeNativeMethod( + "disableMountItemReorderingAndroid", + JReactNativeFeatureFlagsCxxInterop::disableMountItemReorderingAndroid), makeNativeMethod( "enableAlignItemsBaselineOnFabricIOS", JReactNativeFeatureFlagsCxxInterop::enableAlignItemsBaselineOnFabricIOS), 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 e480193163af18..0832d4b67e6a2a 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<<88fc1d08894dc2f774ed8c64b20bdaeb>> + * @generated SignedSource<> */ /** @@ -42,6 +42,9 @@ class JReactNativeFeatureFlagsCxxInterop static bool disableEventLoopOnBridgeless( facebook::jni::alias_ref); + static bool disableMountItemReorderingAndroid( + facebook::jni::alias_ref); + static bool enableAlignItemsBaselineOnFabricIOS( 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 696d000e77bb8a..8a7e60b3777695 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<> + * @generated SignedSource<> */ /** @@ -42,6 +42,10 @@ bool ReactNativeFeatureFlags::disableEventLoopOnBridgeless() { return getAccessor().disableEventLoopOnBridgeless(); } +bool ReactNativeFeatureFlags::disableMountItemReorderingAndroid() { + return getAccessor().disableMountItemReorderingAndroid(); +} + bool ReactNativeFeatureFlags::enableAlignItemsBaselineOnFabricIOS() { return getAccessor().enableAlignItemsBaselineOnFabricIOS(); } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h index 795a323ea19e2c..84169504a29a2c 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<<29b98e3d5daf7ad09cdee366ef38753e>> + * @generated SignedSource<> */ /** @@ -59,6 +59,11 @@ class ReactNativeFeatureFlags { */ RN_EXPORT static bool disableEventLoopOnBridgeless(); + /** + * Prevent FabricMountingManager from reordering mountitems, which may lead to invalid state on the UI thread + */ + RN_EXPORT static bool disableMountItemReorderingAndroid(); + /** * Kill-switch to turn off support for aling-items:baseline on Fabric iOS. */ diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp index 691e72052380f0..8bbec0e1742778 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<<59763b4423e81fbb2f99f78d12c9cca7>> + * @generated SignedSource<> */ /** @@ -101,6 +101,24 @@ bool ReactNativeFeatureFlagsAccessor::disableEventLoopOnBridgeless() { return flagValue.value(); } +bool ReactNativeFeatureFlagsAccessor::disableMountItemReorderingAndroid() { + auto flagValue = disableMountItemReorderingAndroid_.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(4, "disableMountItemReorderingAndroid"); + + flagValue = currentProvider_->disableMountItemReorderingAndroid(); + disableMountItemReorderingAndroid_ = flagValue; + } + + return flagValue.value(); +} + bool ReactNativeFeatureFlagsAccessor::enableAlignItemsBaselineOnFabricIOS() { auto flagValue = enableAlignItemsBaselineOnFabricIOS_.load(); @@ -110,7 +128,7 @@ bool ReactNativeFeatureFlagsAccessor::enableAlignItemsBaselineOnFabricIOS() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(4, "enableAlignItemsBaselineOnFabricIOS"); + markFlagAsAccessed(5, "enableAlignItemsBaselineOnFabricIOS"); flagValue = currentProvider_->enableAlignItemsBaselineOnFabricIOS(); enableAlignItemsBaselineOnFabricIOS_ = flagValue; @@ -128,7 +146,7 @@ bool ReactNativeFeatureFlagsAccessor::enableAndroidLineHeightCentering() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(5, "enableAndroidLineHeightCentering"); + markFlagAsAccessed(6, "enableAndroidLineHeightCentering"); flagValue = currentProvider_->enableAndroidLineHeightCentering(); enableAndroidLineHeightCentering_ = flagValue; @@ -146,7 +164,7 @@ bool ReactNativeFeatureFlagsAccessor::enableBridgelessArchitecture() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(6, "enableBridgelessArchitecture"); + markFlagAsAccessed(7, "enableBridgelessArchitecture"); flagValue = currentProvider_->enableBridgelessArchitecture(); enableBridgelessArchitecture_ = flagValue; @@ -164,7 +182,7 @@ bool ReactNativeFeatureFlagsAccessor::enableCleanTextInputYogaNode() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(7, "enableCleanTextInputYogaNode"); + markFlagAsAccessed(8, "enableCleanTextInputYogaNode"); flagValue = currentProvider_->enableCleanTextInputYogaNode(); enableCleanTextInputYogaNode_ = flagValue; @@ -182,7 +200,7 @@ bool ReactNativeFeatureFlagsAccessor::enableCppPropsIteratorSetter() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(8, "enableCppPropsIteratorSetter"); + markFlagAsAccessed(9, "enableCppPropsIteratorSetter"); flagValue = currentProvider_->enableCppPropsIteratorSetter(); enableCppPropsIteratorSetter_ = flagValue; @@ -200,7 +218,7 @@ bool ReactNativeFeatureFlagsAccessor::enableDeletionOfUnmountedViews() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(9, "enableDeletionOfUnmountedViews"); + markFlagAsAccessed(10, "enableDeletionOfUnmountedViews"); flagValue = currentProvider_->enableDeletionOfUnmountedViews(); enableDeletionOfUnmountedViews_ = flagValue; @@ -218,7 +236,7 @@ bool ReactNativeFeatureFlagsAccessor::enableEagerRootViewAttachment() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(10, "enableEagerRootViewAttachment"); + markFlagAsAccessed(11, "enableEagerRootViewAttachment"); flagValue = currentProvider_->enableEagerRootViewAttachment(); enableEagerRootViewAttachment_ = flagValue; @@ -236,7 +254,7 @@ bool ReactNativeFeatureFlagsAccessor::enableEventEmitterRetentionDuringGesturesO // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(11, "enableEventEmitterRetentionDuringGesturesOnAndroid"); + markFlagAsAccessed(12, "enableEventEmitterRetentionDuringGesturesOnAndroid"); flagValue = currentProvider_->enableEventEmitterRetentionDuringGesturesOnAndroid(); enableEventEmitterRetentionDuringGesturesOnAndroid_ = flagValue; @@ -254,7 +272,7 @@ bool ReactNativeFeatureFlagsAccessor::enableFabricLogs() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(12, "enableFabricLogs"); + markFlagAsAccessed(13, "enableFabricLogs"); flagValue = currentProvider_->enableFabricLogs(); enableFabricLogs_ = flagValue; @@ -272,7 +290,7 @@ bool ReactNativeFeatureFlagsAccessor::enableFabricRenderer() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(13, "enableFabricRenderer"); + markFlagAsAccessed(14, "enableFabricRenderer"); flagValue = currentProvider_->enableFabricRenderer(); enableFabricRenderer_ = flagValue; @@ -290,7 +308,7 @@ bool ReactNativeFeatureFlagsAccessor::enableFabricRendererExclusively() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(14, "enableFabricRendererExclusively"); + markFlagAsAccessed(15, "enableFabricRendererExclusively"); flagValue = currentProvider_->enableFabricRendererExclusively(); enableFabricRendererExclusively_ = flagValue; @@ -308,7 +326,7 @@ bool ReactNativeFeatureFlagsAccessor::enableGranularShadowTreeStateReconciliatio // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(15, "enableGranularShadowTreeStateReconciliation"); + markFlagAsAccessed(16, "enableGranularShadowTreeStateReconciliation"); flagValue = currentProvider_->enableGranularShadowTreeStateReconciliation(); enableGranularShadowTreeStateReconciliation_ = flagValue; @@ -326,7 +344,7 @@ bool ReactNativeFeatureFlagsAccessor::enableIOSViewClipToPaddingBox() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(16, "enableIOSViewClipToPaddingBox"); + markFlagAsAccessed(17, "enableIOSViewClipToPaddingBox"); flagValue = currentProvider_->enableIOSViewClipToPaddingBox(); enableIOSViewClipToPaddingBox_ = flagValue; @@ -344,7 +362,7 @@ bool ReactNativeFeatureFlagsAccessor::enableLayoutAnimationsOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(17, "enableLayoutAnimationsOnAndroid"); + markFlagAsAccessed(18, "enableLayoutAnimationsOnAndroid"); flagValue = currentProvider_->enableLayoutAnimationsOnAndroid(); enableLayoutAnimationsOnAndroid_ = flagValue; @@ -362,7 +380,7 @@ bool ReactNativeFeatureFlagsAccessor::enableLayoutAnimationsOnIOS() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(18, "enableLayoutAnimationsOnIOS"); + markFlagAsAccessed(19, "enableLayoutAnimationsOnIOS"); flagValue = currentProvider_->enableLayoutAnimationsOnIOS(); enableLayoutAnimationsOnIOS_ = flagValue; @@ -380,7 +398,7 @@ bool ReactNativeFeatureFlagsAccessor::enableLongTaskAPI() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(19, "enableLongTaskAPI"); + markFlagAsAccessed(20, "enableLongTaskAPI"); flagValue = currentProvider_->enableLongTaskAPI(); enableLongTaskAPI_ = flagValue; @@ -398,7 +416,7 @@ bool ReactNativeFeatureFlagsAccessor::enableNewBackgroundAndBorderDrawables() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(20, "enableNewBackgroundAndBorderDrawables"); + markFlagAsAccessed(21, "enableNewBackgroundAndBorderDrawables"); flagValue = currentProvider_->enableNewBackgroundAndBorderDrawables(); enableNewBackgroundAndBorderDrawables_ = flagValue; @@ -416,7 +434,7 @@ bool ReactNativeFeatureFlagsAccessor::enablePreciseSchedulingForPremountItemsOnA // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(21, "enablePreciseSchedulingForPremountItemsOnAndroid"); + markFlagAsAccessed(22, "enablePreciseSchedulingForPremountItemsOnAndroid"); flagValue = currentProvider_->enablePreciseSchedulingForPremountItemsOnAndroid(); enablePreciseSchedulingForPremountItemsOnAndroid_ = flagValue; @@ -434,7 +452,7 @@ bool ReactNativeFeatureFlagsAccessor::enablePropsUpdateReconciliationAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(22, "enablePropsUpdateReconciliationAndroid"); + markFlagAsAccessed(23, "enablePropsUpdateReconciliationAndroid"); flagValue = currentProvider_->enablePropsUpdateReconciliationAndroid(); enablePropsUpdateReconciliationAndroid_ = flagValue; @@ -452,7 +470,7 @@ bool ReactNativeFeatureFlagsAccessor::enableReportEventPaintTime() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(23, "enableReportEventPaintTime"); + markFlagAsAccessed(24, "enableReportEventPaintTime"); flagValue = currentProvider_->enableReportEventPaintTime(); enableReportEventPaintTime_ = flagValue; @@ -470,7 +488,7 @@ bool ReactNativeFeatureFlagsAccessor::enableSynchronousStateUpdates() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(24, "enableSynchronousStateUpdates"); + markFlagAsAccessed(25, "enableSynchronousStateUpdates"); flagValue = currentProvider_->enableSynchronousStateUpdates(); enableSynchronousStateUpdates_ = flagValue; @@ -488,7 +506,7 @@ bool ReactNativeFeatureFlagsAccessor::enableTextPreallocationOptimisation() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(25, "enableTextPreallocationOptimisation"); + markFlagAsAccessed(26, "enableTextPreallocationOptimisation"); flagValue = currentProvider_->enableTextPreallocationOptimisation(); enableTextPreallocationOptimisation_ = flagValue; @@ -506,7 +524,7 @@ bool ReactNativeFeatureFlagsAccessor::enableUIConsistency() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(26, "enableUIConsistency"); + markFlagAsAccessed(27, "enableUIConsistency"); flagValue = currentProvider_->enableUIConsistency(); enableUIConsistency_ = flagValue; @@ -524,7 +542,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecycling() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(27, "enableViewRecycling"); + markFlagAsAccessed(28, "enableViewRecycling"); flagValue = currentProvider_->enableViewRecycling(); enableViewRecycling_ = flagValue; @@ -542,7 +560,7 @@ bool ReactNativeFeatureFlagsAccessor::excludeYogaFromRawProps() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(28, "excludeYogaFromRawProps"); + markFlagAsAccessed(29, "excludeYogaFromRawProps"); flagValue = currentProvider_->excludeYogaFromRawProps(); excludeYogaFromRawProps_ = flagValue; @@ -560,7 +578,7 @@ bool ReactNativeFeatureFlagsAccessor::fixMappingOfEventPrioritiesBetweenFabricAn // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(29, "fixMappingOfEventPrioritiesBetweenFabricAndReact"); + markFlagAsAccessed(30, "fixMappingOfEventPrioritiesBetweenFabricAndReact"); flagValue = currentProvider_->fixMappingOfEventPrioritiesBetweenFabricAndReact(); fixMappingOfEventPrioritiesBetweenFabricAndReact_ = flagValue; @@ -578,7 +596,7 @@ bool ReactNativeFeatureFlagsAccessor::fixMountingCoordinatorReportedPendingTrans // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(30, "fixMountingCoordinatorReportedPendingTransactionsOnAndroid"); + markFlagAsAccessed(31, "fixMountingCoordinatorReportedPendingTransactionsOnAndroid"); flagValue = currentProvider_->fixMountingCoordinatorReportedPendingTransactionsOnAndroid(); fixMountingCoordinatorReportedPendingTransactionsOnAndroid_ = flagValue; @@ -596,7 +614,7 @@ bool ReactNativeFeatureFlagsAccessor::forceBatchingMountItemsOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(31, "forceBatchingMountItemsOnAndroid"); + markFlagAsAccessed(32, "forceBatchingMountItemsOnAndroid"); flagValue = currentProvider_->forceBatchingMountItemsOnAndroid(); forceBatchingMountItemsOnAndroid_ = flagValue; @@ -614,7 +632,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxEnabledDebug() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(32, "fuseboxEnabledDebug"); + markFlagAsAccessed(33, "fuseboxEnabledDebug"); flagValue = currentProvider_->fuseboxEnabledDebug(); fuseboxEnabledDebug_ = flagValue; @@ -632,7 +650,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxEnabledRelease() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(33, "fuseboxEnabledRelease"); + markFlagAsAccessed(34, "fuseboxEnabledRelease"); flagValue = currentProvider_->fuseboxEnabledRelease(); fuseboxEnabledRelease_ = flagValue; @@ -650,7 +668,7 @@ bool ReactNativeFeatureFlagsAccessor::initEagerTurboModulesOnNativeModulesQueueA // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(34, "initEagerTurboModulesOnNativeModulesQueueAndroid"); + markFlagAsAccessed(35, "initEagerTurboModulesOnNativeModulesQueueAndroid"); flagValue = currentProvider_->initEagerTurboModulesOnNativeModulesQueueAndroid(); initEagerTurboModulesOnNativeModulesQueueAndroid_ = flagValue; @@ -668,7 +686,7 @@ bool ReactNativeFeatureFlagsAccessor::lazyAnimationCallbacks() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(35, "lazyAnimationCallbacks"); + markFlagAsAccessed(36, "lazyAnimationCallbacks"); flagValue = currentProvider_->lazyAnimationCallbacks(); lazyAnimationCallbacks_ = flagValue; @@ -686,7 +704,7 @@ bool ReactNativeFeatureFlagsAccessor::loadVectorDrawablesOnImages() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(36, "loadVectorDrawablesOnImages"); + markFlagAsAccessed(37, "loadVectorDrawablesOnImages"); flagValue = currentProvider_->loadVectorDrawablesOnImages(); loadVectorDrawablesOnImages_ = flagValue; @@ -704,7 +722,7 @@ bool ReactNativeFeatureFlagsAccessor::setAndroidLayoutDirection() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(37, "setAndroidLayoutDirection"); + markFlagAsAccessed(38, "setAndroidLayoutDirection"); flagValue = currentProvider_->setAndroidLayoutDirection(); setAndroidLayoutDirection_ = flagValue; @@ -722,7 +740,7 @@ bool ReactNativeFeatureFlagsAccessor::traceTurboModulePromiseRejectionsOnAndroid // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(38, "traceTurboModulePromiseRejectionsOnAndroid"); + markFlagAsAccessed(39, "traceTurboModulePromiseRejectionsOnAndroid"); flagValue = currentProvider_->traceTurboModulePromiseRejectionsOnAndroid(); traceTurboModulePromiseRejectionsOnAndroid_ = flagValue; @@ -740,7 +758,7 @@ bool ReactNativeFeatureFlagsAccessor::useFabricInterop() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(39, "useFabricInterop"); + markFlagAsAccessed(40, "useFabricInterop"); flagValue = currentProvider_->useFabricInterop(); useFabricInterop_ = flagValue; @@ -758,7 +776,7 @@ bool ReactNativeFeatureFlagsAccessor::useImmediateExecutorInAndroidBridgeless() // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(40, "useImmediateExecutorInAndroidBridgeless"); + markFlagAsAccessed(41, "useImmediateExecutorInAndroidBridgeless"); flagValue = currentProvider_->useImmediateExecutorInAndroidBridgeless(); useImmediateExecutorInAndroidBridgeless_ = flagValue; @@ -776,7 +794,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(41, "useNativeViewConfigsInBridgelessMode"); + markFlagAsAccessed(42, "useNativeViewConfigsInBridgelessMode"); flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode(); useNativeViewConfigsInBridgelessMode_ = flagValue; @@ -794,7 +812,7 @@ bool ReactNativeFeatureFlagsAccessor::useOptimisedViewPreallocationOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(42, "useOptimisedViewPreallocationOnAndroid"); + markFlagAsAccessed(43, "useOptimisedViewPreallocationOnAndroid"); flagValue = currentProvider_->useOptimisedViewPreallocationOnAndroid(); useOptimisedViewPreallocationOnAndroid_ = flagValue; @@ -812,7 +830,7 @@ bool ReactNativeFeatureFlagsAccessor::useOptimizedEventBatchingOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(43, "useOptimizedEventBatchingOnAndroid"); + markFlagAsAccessed(44, "useOptimizedEventBatchingOnAndroid"); flagValue = currentProvider_->useOptimizedEventBatchingOnAndroid(); useOptimizedEventBatchingOnAndroid_ = flagValue; @@ -830,7 +848,7 @@ bool ReactNativeFeatureFlagsAccessor::useRuntimeShadowNodeReferenceUpdate() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(44, "useRuntimeShadowNodeReferenceUpdate"); + markFlagAsAccessed(45, "useRuntimeShadowNodeReferenceUpdate"); flagValue = currentProvider_->useRuntimeShadowNodeReferenceUpdate(); useRuntimeShadowNodeReferenceUpdate_ = flagValue; @@ -848,7 +866,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModuleInterop() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(45, "useTurboModuleInterop"); + markFlagAsAccessed(46, "useTurboModuleInterop"); flagValue = currentProvider_->useTurboModuleInterop(); useTurboModuleInterop_ = flagValue; @@ -866,7 +884,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModules() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(46, "useTurboModules"); + markFlagAsAccessed(47, "useTurboModules"); flagValue = currentProvider_->useTurboModules(); useTurboModules_ = flagValue; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h index 82934f3674d7af..d723765b1d4b13 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<> + * @generated SignedSource<> */ /** @@ -36,6 +36,7 @@ class ReactNativeFeatureFlagsAccessor { bool allowRecursiveCommitsWithSynchronousMountOnAndroid(); bool completeReactInstanceCreationOnBgThreadOnAndroid(); bool disableEventLoopOnBridgeless(); + bool disableMountItemReorderingAndroid(); bool enableAlignItemsBaselineOnFabricIOS(); bool enableAndroidLineHeightCentering(); bool enableBridgelessArchitecture(); @@ -90,12 +91,13 @@ class ReactNativeFeatureFlagsAccessor { std::unique_ptr currentProvider_; bool wasOverridden_; - std::array, 47> accessedFeatureFlags_; + std::array, 48> accessedFeatureFlags_; std::atomic> commonTestFlag_; std::atomic> allowRecursiveCommitsWithSynchronousMountOnAndroid_; std::atomic> completeReactInstanceCreationOnBgThreadOnAndroid_; std::atomic> disableEventLoopOnBridgeless_; + std::atomic> disableMountItemReorderingAndroid_; std::atomic> enableAlignItemsBaselineOnFabricIOS_; std::atomic> enableAndroidLineHeightCentering_; std::atomic> enableBridgelessArchitecture_; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index 1201da7752f220..199c44d34f845d 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<<116547f17bc1b3d16a8de7c92c5a9d53>> + * @generated SignedSource<<631c825e33e07674e19a084a33637a50>> */ /** @@ -43,6 +43,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { return false; } + bool disableMountItemReorderingAndroid() override { + return false; + } + bool enableAlignItemsBaselineOnFabricIOS() override { return true; } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h index 69f8d38a5c5cf7..8c4cf367780cbc 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<> + * @generated SignedSource<<18597e1e2a88be3d80b8747f72576d5f>> */ /** @@ -29,6 +29,7 @@ class ReactNativeFeatureFlagsProvider { virtual bool allowRecursiveCommitsWithSynchronousMountOnAndroid() = 0; virtual bool completeReactInstanceCreationOnBgThreadOnAndroid() = 0; virtual bool disableEventLoopOnBridgeless() = 0; + virtual bool disableMountItemReorderingAndroid() = 0; virtual bool enableAlignItemsBaselineOnFabricIOS() = 0; virtual bool enableAndroidLineHeightCentering() = 0; virtual bool enableBridgelessArchitecture() = 0; diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp index ace962fde67a43..1093afddc8a675 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<<77a440bf8f6221e90d5ab7a1d7ad638e>> + * @generated SignedSource<<43e3b8b18dec356b5121b581ab8ffa02>> */ /** @@ -71,6 +71,11 @@ bool NativeReactNativeFeatureFlags::disableEventLoopOnBridgeless( return ReactNativeFeatureFlags::disableEventLoopOnBridgeless(); } +bool NativeReactNativeFeatureFlags::disableMountItemReorderingAndroid( + jsi::Runtime& /*runtime*/) { + return ReactNativeFeatureFlags::disableMountItemReorderingAndroid(); +} + bool NativeReactNativeFeatureFlags::enableAlignItemsBaselineOnFabricIOS( jsi::Runtime& /*runtime*/) { return ReactNativeFeatureFlags::enableAlignItemsBaselineOnFabricIOS(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h index ddb938e89eb82e..e7356d78e46c02 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<<0885affcf6782a59b0f4a3d1370ffc90>> + * @generated SignedSource<> */ /** @@ -47,6 +47,8 @@ class NativeReactNativeFeatureFlags bool disableEventLoopOnBridgeless(jsi::Runtime& runtime); + bool disableMountItemReorderingAndroid(jsi::Runtime& runtime); + bool enableAlignItemsBaselineOnFabricIOS(jsi::Runtime& runtime); bool enableAndroidLineHeightCentering(jsi::Runtime& runtime); diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index fe6354d088be45..3a927575782d86 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -90,6 +90,15 @@ const definitions: FeatureFlagDefinitions = { purpose: 'release', }, }, + disableMountItemReorderingAndroid: { + defaultValue: false, + metadata: { + dateAdded: '2024-10-26', + description: + 'Prevent FabricMountingManager from reordering mountitems, which may lead to invalid state on the UI thread', + purpose: 'experimentation', + }, + }, enableAlignItemsBaselineOnFabricIOS: { defaultValue: true, metadata: { diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index 0f17ec52578f00..106d1232cc584d 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<> + * @generated SignedSource<<096ac17a630f7b29d3a029c704dbd8db>> * @flow strict */ @@ -56,6 +56,7 @@ export type ReactNativeFeatureFlags = { batchRenderingUpdatesInEventLoop: Getter, completeReactInstanceCreationOnBgThreadOnAndroid: Getter, disableEventLoopOnBridgeless: Getter, + disableMountItemReorderingAndroid: Getter, enableAlignItemsBaselineOnFabricIOS: Getter, enableAndroidLineHeightCentering: Getter, enableBridgelessArchitecture: Getter, @@ -212,6 +213,10 @@ export const completeReactInstanceCreationOnBgThreadOnAndroid: Getter = * The bridgeless architecture enables the event loop by default. This feature flag allows us to force disabling it in specific instances. */ export const disableEventLoopOnBridgeless: Getter = createNativeFlagGetter('disableEventLoopOnBridgeless', false); +/** + * Prevent FabricMountingManager from reordering mountitems, which may lead to invalid state on the UI thread + */ +export const disableMountItemReorderingAndroid: Getter = createNativeFlagGetter('disableMountItemReorderingAndroid', false); /** * Kill-switch to turn off support for aling-items:baseline on Fabric iOS. */ diff --git a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js index 1632204d2a9d1d..6265ddf78f9a1a 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<<8472e224a5a49da4d706820c89262b6b>> + * @generated SignedSource<> * @flow strict */ @@ -29,6 +29,7 @@ export interface Spec extends TurboModule { +batchRenderingUpdatesInEventLoop?: () => boolean; +completeReactInstanceCreationOnBgThreadOnAndroid?: () => boolean; +disableEventLoopOnBridgeless?: () => boolean; + +disableMountItemReorderingAndroid?: () => boolean; +enableAlignItemsBaselineOnFabricIOS?: () => boolean; +enableAndroidLineHeightCentering?: () => boolean; +enableBridgelessArchitecture?: () => boolean;