From 6e3d15f7e697f3d9ad8083234dde1049c6a3de24 Mon Sep 17 00:00:00 2001 From: Pieter De Baets Date: Fri, 27 Sep 2024 08:46:22 -0700 Subject: [PATCH] Add featureflag to not re-order mount items in FabricMountingManager Summary: 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. 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 | 143 +++++++++++------- .../JReactNativeFeatureFlagsCxxInterop.cpp | 16 +- .../JReactNativeFeatureFlagsCxxInterop.h | 5 +- .../featureflags/ReactNativeFeatureFlags.cpp | 6 +- .../featureflags/ReactNativeFeatureFlags.h | 7 +- .../ReactNativeFeatureFlagsAccessor.cpp | 118 +++++++++------ .../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, 263 insertions(+), 122 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 5fb42d9f9ef298..51d53b04c9a402 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<> */ /** @@ -58,6 +58,12 @@ public object ReactNativeFeatureFlags { @JvmStatic public fun destroyFabricSurfacesInReactInstanceManager(): Boolean = accessor.destroyFabricSurfacesInReactInstanceManager() + /** + * 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 68e4e60d24c70e..4b8c546bbc668d 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<<19dca512d93d689e927ee5988a43e646>> + * @generated SignedSource<<457a8f0213f00a9e074b8b735edbd421>> */ /** @@ -25,6 +25,7 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso private var batchRenderingUpdatesInEventLoopCache: Boolean? = null private var completeReactInstanceCreationOnBgThreadOnAndroidCache: Boolean? = null private var destroyFabricSurfacesInReactInstanceManagerCache: Boolean? = null + private var disableMountItemReorderingAndroidCache: Boolean? = null private var enableAlignItemsBaselineOnFabricIOSCache: Boolean? = null private var enableAndroidLineHeightCenteringCache: Boolean? = null private var enableAndroidMixBlendModePropCache: Boolean? = null @@ -120,6 +121,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 7bd8cfdc898324..10103738c00ed2 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<<76eebf045692e945d39a4ea27a63ae02>> + * @generated SignedSource<> */ /** @@ -38,6 +38,8 @@ public object ReactNativeFeatureFlagsCxxInterop { @DoNotStrip @JvmStatic public external fun destroyFabricSurfacesInReactInstanceManager(): 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 7a844d2e333707..4ed9be88bd54b1 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<<8155a9c1309145fefdb19feb33c241db>> + * @generated SignedSource<> */ /** @@ -33,6 +33,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun destroyFabricSurfacesInReactInstanceManager(): 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 c855a74f49e353..2599a0b76b40cd 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<<5e4e474b62996caec15bbf8af9622a0a>> + * @generated SignedSource<<3f5ada38e8e379f0a74ecbd9f7fe58c6>> */ /** @@ -29,6 +29,7 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces private var batchRenderingUpdatesInEventLoopCache: Boolean? = null private var completeReactInstanceCreationOnBgThreadOnAndroidCache: Boolean? = null private var destroyFabricSurfacesInReactInstanceManagerCache: Boolean? = null + private var disableMountItemReorderingAndroidCache: Boolean? = null private var enableAlignItemsBaselineOnFabricIOSCache: Boolean? = null private var enableAndroidLineHeightCenteringCache: Boolean? = null private var enableAndroidMixBlendModePropCache: Boolean? = null @@ -129,6 +130,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 2098020dd96e33..b7024a67d19007 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<<97eddbbd75ff7cfd0f1c905d72e9eafd>> + * @generated SignedSource<> */ /** @@ -33,6 +33,8 @@ public interface ReactNativeFeatureFlagsProvider { @DoNotStrip public fun destroyFabricSurfacesInReactInstanceManager(): 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 fc8bcd1eed05f4..613ab912785548 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 @@ -38,7 +38,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) { @@ -466,6 +467,9 @@ void FabricMountingManager::executeMount( auto surfaceId = transaction.getSurfaceId(); auto& mutations = transaction.getMutations(); + bool maintainMutationOrder = + true || ReactNativeFeatureFlags::disableMountItemReorderingAndroid(); + auto revisionNumber = telemetry.getRevisionNumber(); std::vector cppCommonMountItems; @@ -481,13 +485,13 @@ void FabricMountingManager::executeMount( std::lock_guard allocatedViewsLock(allocatedViewsMutex_); auto allocatedViewsIterator = allocatedViewRegistry_.find(surfaceId); - auto defaultAllocatedViews = std::unordered_set{}; + std::unordered_set defaultAllocatedViews; // Do not remove `defaultAllocatedViews` or initialize // `std::unordered_set{}` inline in below ternary expression - if falsy // 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; @@ -511,6 +515,7 @@ void FabricMountingManager::executeMount( if (shouldCreateView) { cppCommonMountItems.push_back( CppMountItem::CreateMountItem(newChildShadowView)); + allocatedViewTags.insert(newChildShadowView.tag); } break; } @@ -522,19 +527,29 @@ void FabricMountingManager::executeMount( break; } case ShadowViewMutation::Delete: { - cppDeleteMountItems.push_back( + cppCommonMountItems.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( + cppCommonMountItems.push_back( CppMountItem::UpdateStateMountItem(newChildShadowView)); } @@ -544,14 +559,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)); } @@ -561,39 +579,41 @@ 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; } case ShadowViewMutation::Insert: { if (!isVirtual) { - // Insert item - 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 @@ -602,13 +622,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 + : cppUpdatePropsMountItems) + .push_back(CppMountItem::UpdateLayoutMountItem( newChildShadowView, parentShadowView)); // OverflowInset: This is the values indicating boundaries including @@ -617,15 +640,22 @@ 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)); } + + // Insert item + cppCommonMountItems.push_back(CppMountItem::InsertMountItem( + parentShadowView, newChildShadowView, index)); } // EventEmitter - cppUpdateEventEmitterMountItems.push_back( - CppMountItem::UpdateEventEmitterMountItem( + // FIXME: is this still necessary if we already emitted in create? + (maintainMutationOrder ? cppCommonMountItems + : cppUpdateEventEmitterMountItems) + .push_back(CppMountItem::UpdateEventEmitterMountItem( mutation.newChildShadowView)); break; @@ -635,22 +665,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, @@ -729,12 +743,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; } @@ -907,11 +942,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 8fe3b974a72e78..32fd99624f0778 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<<383e9749c506bc2326455ef907e06a4c>> + * @generated SignedSource<> */ /** @@ -69,6 +69,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"); @@ -392,6 +398,11 @@ bool JReactNativeFeatureFlagsCxxInterop::destroyFabricSurfacesInReactInstanceMan return ReactNativeFeatureFlags::destroyFabricSurfacesInReactInstanceManager(); } +bool JReactNativeFeatureFlagsCxxInterop::disableMountItemReorderingAndroid( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::disableMountItemReorderingAndroid(); +} + bool JReactNativeFeatureFlagsCxxInterop::enableAlignItemsBaselineOnFabricIOS( facebook::jni::alias_ref /*unused*/) { return ReactNativeFeatureFlags::enableAlignItemsBaselineOnFabricIOS(); @@ -669,6 +680,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() { makeNativeMethod( "destroyFabricSurfacesInReactInstanceManager", JReactNativeFeatureFlagsCxxInterop::destroyFabricSurfacesInReactInstanceManager), + 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 c478530d81b695..315cf52981781f 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<<293ed423f770e7e0ba95b19eb5c28dc2>> + * @generated SignedSource<<6355b205740d69ca0694f361c3d970f1>> */ /** @@ -45,6 +45,9 @@ class JReactNativeFeatureFlagsCxxInterop static bool destroyFabricSurfacesInReactInstanceManager( 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 09d76c096ffaf7..543f21df281ae8 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<<85cdb5a41317e9671cc23b2c7345c04d>> + * @generated SignedSource<<4b58fe90530e3657245bcd0c3932a448>> */ /** @@ -41,6 +41,10 @@ bool ReactNativeFeatureFlags::destroyFabricSurfacesInReactInstanceManager() { return getAccessor().destroyFabricSurfacesInReactInstanceManager(); } +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 c844d4651574f6..6163adec89a8ff 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<<4699faf8e9d38d2abe407d3cf9fe8963>> */ /** @@ -62,6 +62,11 @@ class ReactNativeFeatureFlags { */ RN_EXPORT static bool destroyFabricSurfacesInReactInstanceManager(); + /** + * 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 09f80847d1fd2e..25252313e1d091 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<> + * @generated SignedSource<> */ /** @@ -119,6 +119,24 @@ bool ReactNativeFeatureFlagsAccessor::destroyFabricSurfacesInReactInstanceManage 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(5, "disableMountItemReorderingAndroid"); + + flagValue = currentProvider_->disableMountItemReorderingAndroid(); + disableMountItemReorderingAndroid_ = flagValue; + } + + return flagValue.value(); +} + bool ReactNativeFeatureFlagsAccessor::enableAlignItemsBaselineOnFabricIOS() { auto flagValue = enableAlignItemsBaselineOnFabricIOS_.load(); @@ -128,7 +146,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(5, "enableAlignItemsBaselineOnFabricIOS"); + markFlagAsAccessed(6, "enableAlignItemsBaselineOnFabricIOS"); flagValue = currentProvider_->enableAlignItemsBaselineOnFabricIOS(); enableAlignItemsBaselineOnFabricIOS_ = flagValue; @@ -146,7 +164,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(6, "enableAndroidLineHeightCentering"); + markFlagAsAccessed(7, "enableAndroidLineHeightCentering"); flagValue = currentProvider_->enableAndroidLineHeightCentering(); enableAndroidLineHeightCentering_ = flagValue; @@ -164,7 +182,7 @@ bool ReactNativeFeatureFlagsAccessor::enableAndroidMixBlendModeProp() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(7, "enableAndroidMixBlendModeProp"); + markFlagAsAccessed(8, "enableAndroidMixBlendModeProp"); flagValue = currentProvider_->enableAndroidMixBlendModeProp(); enableAndroidMixBlendModeProp_ = flagValue; @@ -182,7 +200,7 @@ bool ReactNativeFeatureFlagsAccessor::enableBackgroundStyleApplicator() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(8, "enableBackgroundStyleApplicator"); + markFlagAsAccessed(9, "enableBackgroundStyleApplicator"); flagValue = currentProvider_->enableBackgroundStyleApplicator(); enableBackgroundStyleApplicator_ = flagValue; @@ -200,7 +218,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(9, "enableBridgelessArchitecture"); + markFlagAsAccessed(10, "enableBridgelessArchitecture"); flagValue = currentProvider_->enableBridgelessArchitecture(); enableBridgelessArchitecture_ = flagValue; @@ -218,7 +236,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(10, "enableCleanTextInputYogaNode"); + markFlagAsAccessed(11, "enableCleanTextInputYogaNode"); flagValue = currentProvider_->enableCleanTextInputYogaNode(); enableCleanTextInputYogaNode_ = flagValue; @@ -236,7 +254,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(11, "enableDeletionOfUnmountedViews"); + markFlagAsAccessed(12, "enableDeletionOfUnmountedViews"); flagValue = currentProvider_->enableDeletionOfUnmountedViews(); enableDeletionOfUnmountedViews_ = flagValue; @@ -254,7 +272,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(12, "enableEagerRootViewAttachment"); + markFlagAsAccessed(13, "enableEagerRootViewAttachment"); flagValue = currentProvider_->enableEagerRootViewAttachment(); enableEagerRootViewAttachment_ = flagValue; @@ -272,7 +290,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(13, "enableEventEmitterRetentionDuringGesturesOnAndroid"); + markFlagAsAccessed(14, "enableEventEmitterRetentionDuringGesturesOnAndroid"); flagValue = currentProvider_->enableEventEmitterRetentionDuringGesturesOnAndroid(); enableEventEmitterRetentionDuringGesturesOnAndroid_ = flagValue; @@ -290,7 +308,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(14, "enableFabricLogs"); + markFlagAsAccessed(15, "enableFabricLogs"); flagValue = currentProvider_->enableFabricLogs(); enableFabricLogs_ = flagValue; @@ -308,7 +326,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(15, "enableFabricRenderer"); + markFlagAsAccessed(16, "enableFabricRenderer"); flagValue = currentProvider_->enableFabricRenderer(); enableFabricRenderer_ = flagValue; @@ -326,7 +344,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(16, "enableFabricRendererExclusively"); + markFlagAsAccessed(17, "enableFabricRendererExclusively"); flagValue = currentProvider_->enableFabricRendererExclusively(); enableFabricRendererExclusively_ = flagValue; @@ -344,7 +362,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(17, "enableGranularShadowTreeStateReconciliation"); + markFlagAsAccessed(18, "enableGranularShadowTreeStateReconciliation"); flagValue = currentProvider_->enableGranularShadowTreeStateReconciliation(); enableGranularShadowTreeStateReconciliation_ = flagValue; @@ -362,7 +380,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(18, "enableIOSViewClipToPaddingBox"); + markFlagAsAccessed(19, "enableIOSViewClipToPaddingBox"); flagValue = currentProvider_->enableIOSViewClipToPaddingBox(); enableIOSViewClipToPaddingBox_ = flagValue; @@ -380,7 +398,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(19, "enableLayoutAnimationsOnIOS"); + markFlagAsAccessed(20, "enableLayoutAnimationsOnIOS"); flagValue = currentProvider_->enableLayoutAnimationsOnIOS(); enableLayoutAnimationsOnIOS_ = flagValue; @@ -398,7 +416,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(20, "enableLongTaskAPI"); + markFlagAsAccessed(21, "enableLongTaskAPI"); flagValue = currentProvider_->enableLongTaskAPI(); enableLongTaskAPI_ = flagValue; @@ -416,7 +434,7 @@ bool ReactNativeFeatureFlagsAccessor::enableMicrotasks() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(21, "enableMicrotasks"); + markFlagAsAccessed(22, "enableMicrotasks"); flagValue = currentProvider_->enableMicrotasks(); enableMicrotasks_ = flagValue; @@ -434,7 +452,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(22, "enablePreciseSchedulingForPremountItemsOnAndroid"); + markFlagAsAccessed(23, "enablePreciseSchedulingForPremountItemsOnAndroid"); flagValue = currentProvider_->enablePreciseSchedulingForPremountItemsOnAndroid(); enablePreciseSchedulingForPremountItemsOnAndroid_ = flagValue; @@ -452,7 +470,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(23, "enablePropsUpdateReconciliationAndroid"); + markFlagAsAccessed(24, "enablePropsUpdateReconciliationAndroid"); flagValue = currentProvider_->enablePropsUpdateReconciliationAndroid(); enablePropsUpdateReconciliationAndroid_ = flagValue; @@ -470,7 +488,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(24, "enableReportEventPaintTime"); + markFlagAsAccessed(25, "enableReportEventPaintTime"); flagValue = currentProvider_->enableReportEventPaintTime(); enableReportEventPaintTime_ = flagValue; @@ -488,7 +506,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(25, "enableSynchronousStateUpdates"); + markFlagAsAccessed(26, "enableSynchronousStateUpdates"); flagValue = currentProvider_->enableSynchronousStateUpdates(); enableSynchronousStateUpdates_ = flagValue; @@ -506,7 +524,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(26, "enableTextPreallocationOptimisation"); + markFlagAsAccessed(27, "enableTextPreallocationOptimisation"); flagValue = currentProvider_->enableTextPreallocationOptimisation(); enableTextPreallocationOptimisation_ = flagValue; @@ -524,7 +542,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(27, "enableUIConsistency"); + markFlagAsAccessed(28, "enableUIConsistency"); flagValue = currentProvider_->enableUIConsistency(); enableUIConsistency_ = flagValue; @@ -542,7 +560,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(28, "enableViewRecycling"); + markFlagAsAccessed(29, "enableViewRecycling"); flagValue = currentProvider_->enableViewRecycling(); enableViewRecycling_ = flagValue; @@ -560,7 +578,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(29, "excludeYogaFromRawProps"); + markFlagAsAccessed(30, "excludeYogaFromRawProps"); flagValue = currentProvider_->excludeYogaFromRawProps(); excludeYogaFromRawProps_ = flagValue; @@ -578,7 +596,7 @@ bool ReactNativeFeatureFlagsAccessor::fetchImagesInViewPreallocation() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(30, "fetchImagesInViewPreallocation"); + markFlagAsAccessed(31, "fetchImagesInViewPreallocation"); flagValue = currentProvider_->fetchImagesInViewPreallocation(); fetchImagesInViewPreallocation_ = flagValue; @@ -596,7 +614,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(31, "fixMappingOfEventPrioritiesBetweenFabricAndReact"); + markFlagAsAccessed(32, "fixMappingOfEventPrioritiesBetweenFabricAndReact"); flagValue = currentProvider_->fixMappingOfEventPrioritiesBetweenFabricAndReact(); fixMappingOfEventPrioritiesBetweenFabricAndReact_ = flagValue; @@ -614,7 +632,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(32, "fixMountingCoordinatorReportedPendingTransactionsOnAndroid"); + markFlagAsAccessed(33, "fixMountingCoordinatorReportedPendingTransactionsOnAndroid"); flagValue = currentProvider_->fixMountingCoordinatorReportedPendingTransactionsOnAndroid(); fixMountingCoordinatorReportedPendingTransactionsOnAndroid_ = flagValue; @@ -632,7 +650,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(33, "forceBatchingMountItemsOnAndroid"); + markFlagAsAccessed(34, "forceBatchingMountItemsOnAndroid"); flagValue = currentProvider_->forceBatchingMountItemsOnAndroid(); forceBatchingMountItemsOnAndroid_ = flagValue; @@ -650,7 +668,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(34, "fuseboxEnabledDebug"); + markFlagAsAccessed(35, "fuseboxEnabledDebug"); flagValue = currentProvider_->fuseboxEnabledDebug(); fuseboxEnabledDebug_ = flagValue; @@ -668,7 +686,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(35, "fuseboxEnabledRelease"); + markFlagAsAccessed(36, "fuseboxEnabledRelease"); flagValue = currentProvider_->fuseboxEnabledRelease(); fuseboxEnabledRelease_ = flagValue; @@ -686,7 +704,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(36, "initEagerTurboModulesOnNativeModulesQueueAndroid"); + markFlagAsAccessed(37, "initEagerTurboModulesOnNativeModulesQueueAndroid"); flagValue = currentProvider_->initEagerTurboModulesOnNativeModulesQueueAndroid(); initEagerTurboModulesOnNativeModulesQueueAndroid_ = flagValue; @@ -704,7 +722,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(37, "lazyAnimationCallbacks"); + markFlagAsAccessed(38, "lazyAnimationCallbacks"); flagValue = currentProvider_->lazyAnimationCallbacks(); lazyAnimationCallbacks_ = flagValue; @@ -722,7 +740,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(38, "loadVectorDrawablesOnImages"); + markFlagAsAccessed(39, "loadVectorDrawablesOnImages"); flagValue = currentProvider_->loadVectorDrawablesOnImages(); loadVectorDrawablesOnImages_ = flagValue; @@ -740,7 +758,7 @@ bool ReactNativeFeatureFlagsAccessor::removeNestedCallsToDispatchMountItemsOnAnd // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(39, "removeNestedCallsToDispatchMountItemsOnAndroid"); + markFlagAsAccessed(40, "removeNestedCallsToDispatchMountItemsOnAndroid"); flagValue = currentProvider_->removeNestedCallsToDispatchMountItemsOnAndroid(); removeNestedCallsToDispatchMountItemsOnAndroid_ = flagValue; @@ -758,7 +776,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(40, "setAndroidLayoutDirection"); + markFlagAsAccessed(41, "setAndroidLayoutDirection"); flagValue = currentProvider_->setAndroidLayoutDirection(); setAndroidLayoutDirection_ = flagValue; @@ -776,7 +794,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(41, "traceTurboModulePromiseRejectionsOnAndroid"); + markFlagAsAccessed(42, "traceTurboModulePromiseRejectionsOnAndroid"); flagValue = currentProvider_->traceTurboModulePromiseRejectionsOnAndroid(); traceTurboModulePromiseRejectionsOnAndroid_ = flagValue; @@ -794,7 +812,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(42, "useFabricInterop"); + markFlagAsAccessed(43, "useFabricInterop"); flagValue = currentProvider_->useFabricInterop(); useFabricInterop_ = flagValue; @@ -812,7 +830,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(43, "useImmediateExecutorInAndroidBridgeless"); + markFlagAsAccessed(44, "useImmediateExecutorInAndroidBridgeless"); flagValue = currentProvider_->useImmediateExecutorInAndroidBridgeless(); useImmediateExecutorInAndroidBridgeless_ = flagValue; @@ -830,7 +848,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(44, "useModernRuntimeScheduler"); + markFlagAsAccessed(45, "useModernRuntimeScheduler"); flagValue = currentProvider_->useModernRuntimeScheduler(); useModernRuntimeScheduler_ = flagValue; @@ -848,7 +866,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(45, "useNativeViewConfigsInBridgelessMode"); + markFlagAsAccessed(46, "useNativeViewConfigsInBridgelessMode"); flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode(); useNativeViewConfigsInBridgelessMode_ = flagValue; @@ -866,7 +884,7 @@ bool ReactNativeFeatureFlagsAccessor::useNewReactImageViewBackgroundDrawing() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(46, "useNewReactImageViewBackgroundDrawing"); + markFlagAsAccessed(47, "useNewReactImageViewBackgroundDrawing"); flagValue = currentProvider_->useNewReactImageViewBackgroundDrawing(); useNewReactImageViewBackgroundDrawing_ = flagValue; @@ -884,7 +902,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(47, "useOptimisedViewPreallocationOnAndroid"); + markFlagAsAccessed(48, "useOptimisedViewPreallocationOnAndroid"); flagValue = currentProvider_->useOptimisedViewPreallocationOnAndroid(); useOptimisedViewPreallocationOnAndroid_ = flagValue; @@ -902,7 +920,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(48, "useOptimizedEventBatchingOnAndroid"); + markFlagAsAccessed(49, "useOptimizedEventBatchingOnAndroid"); flagValue = currentProvider_->useOptimizedEventBatchingOnAndroid(); useOptimizedEventBatchingOnAndroid_ = flagValue; @@ -920,7 +938,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(49, "useRuntimeShadowNodeReferenceUpdate"); + markFlagAsAccessed(50, "useRuntimeShadowNodeReferenceUpdate"); flagValue = currentProvider_->useRuntimeShadowNodeReferenceUpdate(); useRuntimeShadowNodeReferenceUpdate_ = flagValue; @@ -938,7 +956,7 @@ bool ReactNativeFeatureFlagsAccessor::useRuntimeShadowNodeReferenceUpdateOnLayou // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(50, "useRuntimeShadowNodeReferenceUpdateOnLayout"); + markFlagAsAccessed(51, "useRuntimeShadowNodeReferenceUpdateOnLayout"); flagValue = currentProvider_->useRuntimeShadowNodeReferenceUpdateOnLayout(); useRuntimeShadowNodeReferenceUpdateOnLayout_ = flagValue; @@ -956,7 +974,7 @@ bool ReactNativeFeatureFlagsAccessor::useStateAlignmentMechanism() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(51, "useStateAlignmentMechanism"); + markFlagAsAccessed(52, "useStateAlignmentMechanism"); flagValue = currentProvider_->useStateAlignmentMechanism(); useStateAlignmentMechanism_ = flagValue; @@ -974,7 +992,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(52, "useTurboModuleInterop"); + markFlagAsAccessed(53, "useTurboModuleInterop"); flagValue = currentProvider_->useTurboModuleInterop(); useTurboModuleInterop_ = flagValue; @@ -992,7 +1010,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(53, "useTurboModules"); + markFlagAsAccessed(54, "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 c7db3980bfcc49..d092aadef88ccb 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<<5f2c9b500fc26e68d56efae08b15575f>> + * @generated SignedSource<<84c298eb502f6962d386149fa0b2783e>> */ /** @@ -36,6 +36,7 @@ class ReactNativeFeatureFlagsAccessor { bool batchRenderingUpdatesInEventLoop(); bool completeReactInstanceCreationOnBgThreadOnAndroid(); bool destroyFabricSurfacesInReactInstanceManager(); + bool disableMountItemReorderingAndroid(); bool enableAlignItemsBaselineOnFabricIOS(); bool enableAndroidLineHeightCentering(); bool enableAndroidMixBlendModeProp(); @@ -95,13 +96,14 @@ class ReactNativeFeatureFlagsAccessor { std::unique_ptr currentProvider_; bool wasOverridden_; - std::array, 54> accessedFeatureFlags_; + std::array, 55> accessedFeatureFlags_; std::atomic> commonTestFlag_; std::atomic> allowRecursiveCommitsWithSynchronousMountOnAndroid_; std::atomic> batchRenderingUpdatesInEventLoop_; std::atomic> completeReactInstanceCreationOnBgThreadOnAndroid_; std::atomic> destroyFabricSurfacesInReactInstanceManager_; + std::atomic> disableMountItemReorderingAndroid_; std::atomic> enableAlignItemsBaselineOnFabricIOS_; std::atomic> enableAndroidLineHeightCentering_; std::atomic> enableAndroidMixBlendModeProp_; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index 5ce07698ba0d8a..8e557427c09680 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<> + * @generated SignedSource<<6be2ee3001db2fee84c216e5520131fe>> */ /** @@ -47,6 +47,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 9fd1367f2c1b36..a4a5adb1ca0551 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<<487fdb2eca1a5a12b12ac076d4a8f148>> */ /** @@ -30,6 +30,7 @@ class ReactNativeFeatureFlagsProvider { virtual bool batchRenderingUpdatesInEventLoop() = 0; virtual bool completeReactInstanceCreationOnBgThreadOnAndroid() = 0; virtual bool destroyFabricSurfacesInReactInstanceManager() = 0; + virtual bool disableMountItemReorderingAndroid() = 0; virtual bool enableAlignItemsBaselineOnFabricIOS() = 0; virtual bool enableAndroidLineHeightCentering() = 0; virtual bool enableAndroidMixBlendModeProp() = 0; diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp index 5316822e3b2d52..fb4b3a3d287360 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<<2b484558d552981e4ec0644d75849dde>> + * @generated SignedSource<<6a783825a3ee81f351c42df3a853edd3>> */ /** @@ -62,6 +62,11 @@ bool NativeReactNativeFeatureFlags::destroyFabricSurfacesInReactInstanceManager( return ReactNativeFeatureFlags::destroyFabricSurfacesInReactInstanceManager(); } +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 ded551e76c8665..cc72c1107be2d7 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<<94afee988401ba2af586ec8fe310cb8b>> + * @generated SignedSource<> */ /** @@ -45,6 +45,8 @@ class NativeReactNativeFeatureFlags bool destroyFabricSurfacesInReactInstanceManager(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 7dc63f49a76dde..ffa6be457c7b12 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -80,6 +80,15 @@ const definitions: FeatureFlagDefinitions = { purpose: 'experimentation', }, }, + disableMountItemReorderingAndroid: { + defaultValue: false, + metadata: { + dateAdded: '2024-09-24', + 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 577d22448e4750..720118f3403432 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<> * @flow strict */ @@ -54,6 +54,7 @@ export type ReactNativeFeatureFlags = { batchRenderingUpdatesInEventLoop: Getter, completeReactInstanceCreationOnBgThreadOnAndroid: Getter, destroyFabricSurfacesInReactInstanceManager: Getter, + disableMountItemReorderingAndroid: Getter, enableAlignItemsBaselineOnFabricIOS: Getter, enableAndroidLineHeightCentering: Getter, enableAndroidMixBlendModeProp: Getter, @@ -205,6 +206,10 @@ export const completeReactInstanceCreationOnBgThreadOnAndroid: Getter = * When enabled, ReactInstanceManager will clean up Fabric surfaces on destroy(). */ export const destroyFabricSurfacesInReactInstanceManager: Getter = createNativeFlagGetter('destroyFabricSurfacesInReactInstanceManager', 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 fb2d28bfff7d50..84109f6bd1a254 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<<0467a8715892bbeca0a08681c730aeab>> + * @generated SignedSource<> * @flow strict */ @@ -28,6 +28,7 @@ export interface Spec extends TurboModule { +batchRenderingUpdatesInEventLoop?: () => boolean; +completeReactInstanceCreationOnBgThreadOnAndroid?: () => boolean; +destroyFabricSurfacesInReactInstanceManager?: () => boolean; + +disableMountItemReorderingAndroid?: () => boolean; +enableAlignItemsBaselineOnFabricIOS?: () => boolean; +enableAndroidLineHeightCentering?: () => boolean; +enableAndroidMixBlendModeProp?: () => boolean;