Add feature flag for universal calls to start|finishOperationBatch (#49908)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/49908

There are various batching mechanisms across react-native platforms. The NativeAnimated startOperationBatch and finishOperationBatch methods are a useful way to signal that complete animation graphs are established for atomic flushes to the UI thread.

Setting up this feature flag for use across non-Android React Native platforms.

## Changelog

[Internal]

Reviewed By: javache

Differential Revision: D70827938

fbshipit-source-id: 4c4a74e9a11f75090152637d6195092f5af866a0
This commit is contained in:
Eric Rozell
2025-03-12 11:55:15 -07:00
committed by Facebook GitHub Bot
parent 91d034533e
commit 05e720adfb
23 changed files with 199 additions and 64 deletions
@@ -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<<e5e17b9d0c91c979f09cbdc0314f4cf2>>
* @generated SignedSource<<df008a78acc9b0104c54e06849d5e9b9>>
*/
/**
@@ -34,6 +34,12 @@ public object ReactNativeFeatureFlags {
@JvmStatic
public fun commonTestFlag(): Boolean = accessor.commonTestFlag()
/**
* Enables start- and finishOperationBatch on any platform.
*/
@JvmStatic
public fun animatedShouldSignalBatch(): Boolean = accessor.animatedShouldSignalBatch()
/**
* Prevent FabricMountingManager from reordering mountitems, which may lead to invalid state on the UI thread
*/
@@ -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<<e567bf1ac6ec5d0381deed1245b22a3f>>
* @generated SignedSource<<9813fd15c7f54d69d3de6084f733c3a6>>
*/
/**
@@ -21,6 +21,7 @@ package com.facebook.react.internal.featureflags
internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccessor {
private var commonTestFlagCache: Boolean? = null
private var animatedShouldSignalBatchCache: Boolean? = null
private var disableMountItemReorderingAndroidCache: Boolean? = null
private var enableAccumulatedUpdatesInRawPropsAndroidCache: Boolean? = null
private var enableBridgelessArchitectureCache: Boolean? = null
@@ -71,6 +72,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
return cached
}
override fun animatedShouldSignalBatch(): Boolean {
var cached = animatedShouldSignalBatchCache
if (cached == null) {
cached = ReactNativeFeatureFlagsCxxInterop.animatedShouldSignalBatch()
animatedShouldSignalBatchCache = cached
}
return cached
}
override fun disableMountItemReorderingAndroid(): Boolean {
var cached = disableMountItemReorderingAndroidCache
if (cached == null) {
@@ -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<<1e7421f38e1dd6629e42492b2c7a4ee1>>
* @generated SignedSource<<06c5ef75b624d953e7a8d9297feaf816>>
*/
/**
@@ -30,6 +30,8 @@ public object ReactNativeFeatureFlagsCxxInterop {
@DoNotStrip @JvmStatic public external fun commonTestFlag(): Boolean
@DoNotStrip @JvmStatic public external fun animatedShouldSignalBatch(): Boolean
@DoNotStrip @JvmStatic public external fun disableMountItemReorderingAndroid(): Boolean
@DoNotStrip @JvmStatic public external fun enableAccumulatedUpdatesInRawPropsAndroid(): Boolean
@@ -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<<0f22538afea52085aaf605e8608eaff8>>
* @generated SignedSource<<cbe1d77424b561149b0bda39955dffac>>
*/
/**
@@ -25,6 +25,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
override fun commonTestFlag(): Boolean = false
override fun animatedShouldSignalBatch(): Boolean = false
override fun disableMountItemReorderingAndroid(): Boolean = false
override fun enableAccumulatedUpdatesInRawPropsAndroid(): Boolean = false
@@ -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<<1693dced312625bbfedce5f2dfa9816c>>
* @generated SignedSource<<0fb76e329360157ea9772a0d8bebc873>>
*/
/**
@@ -25,6 +25,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
private val accessedFeatureFlags = mutableSetOf<String>()
private var commonTestFlagCache: Boolean? = null
private var animatedShouldSignalBatchCache: Boolean? = null
private var disableMountItemReorderingAndroidCache: Boolean? = null
private var enableAccumulatedUpdatesInRawPropsAndroidCache: Boolean? = null
private var enableBridgelessArchitectureCache: Boolean? = null
@@ -76,6 +77,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
return cached
}
override fun animatedShouldSignalBatch(): Boolean {
var cached = animatedShouldSignalBatchCache
if (cached == null) {
cached = currentProvider.animatedShouldSignalBatch()
accessedFeatureFlags.add("animatedShouldSignalBatch")
animatedShouldSignalBatchCache = cached
}
return cached
}
override fun disableMountItemReorderingAndroid(): Boolean {
var cached = disableMountItemReorderingAndroidCache
if (cached == null) {
@@ -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<<2f2bbf0a92c3af728de6ea38dc374b94>>
* @generated SignedSource<<0c16f7af743a6c4d7aaabf010c1c7327>>
*/
/**
@@ -25,6 +25,8 @@ import com.facebook.proguard.annotations.DoNotStrip
public interface ReactNativeFeatureFlagsProvider {
@DoNotStrip public fun commonTestFlag(): Boolean
@DoNotStrip public fun animatedShouldSignalBatch(): Boolean
@DoNotStrip public fun disableMountItemReorderingAndroid(): Boolean
@DoNotStrip public fun enableAccumulatedUpdatesInRawPropsAndroid(): Boolean
@@ -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<<14c3186a1395a23befb73fc9da972de7>>
* @generated SignedSource<<c866e69278d249dd79cb2fc193d1a7e2>>
*/
/**
@@ -45,6 +45,12 @@ class ReactNativeFeatureFlagsProviderHolder
return method(javaProvider_);
}
bool animatedShouldSignalBatch() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("animatedShouldSignalBatch");
return method(javaProvider_);
}
bool disableMountItemReorderingAndroid() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("disableMountItemReorderingAndroid");
@@ -294,6 +300,11 @@ bool JReactNativeFeatureFlagsCxxInterop::commonTestFlag(
return ReactNativeFeatureFlags::commonTestFlag();
}
bool JReactNativeFeatureFlagsCxxInterop::animatedShouldSignalBatch(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::animatedShouldSignalBatch();
}
bool JReactNativeFeatureFlagsCxxInterop::disableMountItemReorderingAndroid(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::disableMountItemReorderingAndroid();
@@ -528,6 +539,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
makeNativeMethod(
"commonTestFlag",
JReactNativeFeatureFlagsCxxInterop::commonTestFlag),
makeNativeMethod(
"animatedShouldSignalBatch",
JReactNativeFeatureFlagsCxxInterop::animatedShouldSignalBatch),
makeNativeMethod(
"disableMountItemReorderingAndroid",
JReactNativeFeatureFlagsCxxInterop::disableMountItemReorderingAndroid),
@@ -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<<5edcb3baccc7a27525ba6ca43b2aab8a>>
* @generated SignedSource<<ee83dc14463351d400cd75624c803176>>
*/
/**
@@ -33,6 +33,9 @@ class JReactNativeFeatureFlagsCxxInterop
static bool commonTestFlag(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
static bool animatedShouldSignalBatch(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
static bool disableMountItemReorderingAndroid(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
@@ -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<<98c62bb40ef9c03af6e3e2d758cef7ec>>
* @generated SignedSource<<4d47f61435ba3a74e84752a02def81c2>>
*/
/**
@@ -30,6 +30,10 @@ bool ReactNativeFeatureFlags::commonTestFlag() {
return getAccessor().commonTestFlag();
}
bool ReactNativeFeatureFlags::animatedShouldSignalBatch() {
return getAccessor().animatedShouldSignalBatch();
}
bool ReactNativeFeatureFlags::disableMountItemReorderingAndroid() {
return getAccessor().disableMountItemReorderingAndroid();
}
@@ -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<<452dc78526d49a23c5052bd1ecd130d2>>
* @generated SignedSource<<29cdbefbe02064df4fb65388e64f95a4>>
*/
/**
@@ -44,6 +44,11 @@ class ReactNativeFeatureFlags {
*/
RN_EXPORT static bool commonTestFlag();
/**
* Enables start- and finishOperationBatch on any platform.
*/
RN_EXPORT static bool animatedShouldSignalBatch();
/**
* Prevent FabricMountingManager from reordering mountitems, which may lead to invalid state on the UI thread
*/
@@ -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<<dd3a65bc7f16b0d774237c21c21d048a>>
* @generated SignedSource<<353677101629176192534f1f234e2de4>>
*/
/**
@@ -47,6 +47,24 @@ bool ReactNativeFeatureFlagsAccessor::commonTestFlag() {
return flagValue.value();
}
bool ReactNativeFeatureFlagsAccessor::animatedShouldSignalBatch() {
auto flagValue = animatedShouldSignalBatch_.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(1, "animatedShouldSignalBatch");
flagValue = currentProvider_->animatedShouldSignalBatch();
animatedShouldSignalBatch_ = flagValue;
}
return flagValue.value();
}
bool ReactNativeFeatureFlagsAccessor::disableMountItemReorderingAndroid() {
auto flagValue = disableMountItemReorderingAndroid_.load();
@@ -56,7 +74,7 @@ bool ReactNativeFeatureFlagsAccessor::disableMountItemReorderingAndroid() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(1, "disableMountItemReorderingAndroid");
markFlagAsAccessed(2, "disableMountItemReorderingAndroid");
flagValue = currentProvider_->disableMountItemReorderingAndroid();
disableMountItemReorderingAndroid_ = flagValue;
@@ -74,7 +92,7 @@ bool ReactNativeFeatureFlagsAccessor::enableAccumulatedUpdatesInRawPropsAndroid(
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(2, "enableAccumulatedUpdatesInRawPropsAndroid");
markFlagAsAccessed(3, "enableAccumulatedUpdatesInRawPropsAndroid");
flagValue = currentProvider_->enableAccumulatedUpdatesInRawPropsAndroid();
enableAccumulatedUpdatesInRawPropsAndroid_ = flagValue;
@@ -92,7 +110,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(3, "enableBridgelessArchitecture");
markFlagAsAccessed(4, "enableBridgelessArchitecture");
flagValue = currentProvider_->enableBridgelessArchitecture();
enableBridgelessArchitecture_ = flagValue;
@@ -110,7 +128,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(4, "enableCppPropsIteratorSetter");
markFlagAsAccessed(5, "enableCppPropsIteratorSetter");
flagValue = currentProvider_->enableCppPropsIteratorSetter();
enableCppPropsIteratorSetter_ = flagValue;
@@ -128,7 +146,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(5, "enableEagerRootViewAttachment");
markFlagAsAccessed(6, "enableEagerRootViewAttachment");
flagValue = currentProvider_->enableEagerRootViewAttachment();
enableEagerRootViewAttachment_ = flagValue;
@@ -146,7 +164,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(6, "enableFabricLogs");
markFlagAsAccessed(7, "enableFabricLogs");
flagValue = currentProvider_->enableFabricLogs();
enableFabricLogs_ = flagValue;
@@ -164,7 +182,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(7, "enableFabricRenderer");
markFlagAsAccessed(8, "enableFabricRenderer");
flagValue = currentProvider_->enableFabricRenderer();
enableFabricRenderer_ = flagValue;
@@ -182,7 +200,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(8, "enableIOSViewClipToPaddingBox");
markFlagAsAccessed(9, "enableIOSViewClipToPaddingBox");
flagValue = currentProvider_->enableIOSViewClipToPaddingBox();
enableIOSViewClipToPaddingBox_ = flagValue;
@@ -200,7 +218,7 @@ bool ReactNativeFeatureFlagsAccessor::enableImagePrefetchingAndroid() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(9, "enableImagePrefetchingAndroid");
markFlagAsAccessed(10, "enableImagePrefetchingAndroid");
flagValue = currentProvider_->enableImagePrefetchingAndroid();
enableImagePrefetchingAndroid_ = flagValue;
@@ -218,7 +236,7 @@ bool ReactNativeFeatureFlagsAccessor::enableJSRuntimeGCOnMemoryPressureOnIOS() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(10, "enableJSRuntimeGCOnMemoryPressureOnIOS");
markFlagAsAccessed(11, "enableJSRuntimeGCOnMemoryPressureOnIOS");
flagValue = currentProvider_->enableJSRuntimeGCOnMemoryPressureOnIOS();
enableJSRuntimeGCOnMemoryPressureOnIOS_ = flagValue;
@@ -236,7 +254,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(11, "enableLayoutAnimationsOnAndroid");
markFlagAsAccessed(12, "enableLayoutAnimationsOnAndroid");
flagValue = currentProvider_->enableLayoutAnimationsOnAndroid();
enableLayoutAnimationsOnAndroid_ = flagValue;
@@ -254,7 +272,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(12, "enableLayoutAnimationsOnIOS");
markFlagAsAccessed(13, "enableLayoutAnimationsOnIOS");
flagValue = currentProvider_->enableLayoutAnimationsOnIOS();
enableLayoutAnimationsOnIOS_ = flagValue;
@@ -272,7 +290,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(13, "enableLongTaskAPI");
markFlagAsAccessed(14, "enableLongTaskAPI");
flagValue = currentProvider_->enableLongTaskAPI();
enableLongTaskAPI_ = flagValue;
@@ -290,7 +308,7 @@ bool ReactNativeFeatureFlagsAccessor::enableNativeCSSParsing() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(14, "enableNativeCSSParsing");
markFlagAsAccessed(15, "enableNativeCSSParsing");
flagValue = currentProvider_->enableNativeCSSParsing();
enableNativeCSSParsing_ = flagValue;
@@ -308,7 +326,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(15, "enableNewBackgroundAndBorderDrawables");
markFlagAsAccessed(16, "enableNewBackgroundAndBorderDrawables");
flagValue = currentProvider_->enableNewBackgroundAndBorderDrawables();
enableNewBackgroundAndBorderDrawables_ = flagValue;
@@ -326,7 +344,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(16, "enablePropsUpdateReconciliationAndroid");
markFlagAsAccessed(17, "enablePropsUpdateReconciliationAndroid");
flagValue = currentProvider_->enablePropsUpdateReconciliationAndroid();
enablePropsUpdateReconciliationAndroid_ = flagValue;
@@ -344,7 +362,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(17, "enableReportEventPaintTime");
markFlagAsAccessed(18, "enableReportEventPaintTime");
flagValue = currentProvider_->enableReportEventPaintTime();
enableReportEventPaintTime_ = flagValue;
@@ -362,7 +380,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(18, "enableSynchronousStateUpdates");
markFlagAsAccessed(19, "enableSynchronousStateUpdates");
flagValue = currentProvider_->enableSynchronousStateUpdates();
enableSynchronousStateUpdates_ = flagValue;
@@ -380,7 +398,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(19, "enableUIConsistency");
markFlagAsAccessed(20, "enableUIConsistency");
flagValue = currentProvider_->enableUIConsistency();
enableUIConsistency_ = flagValue;
@@ -398,7 +416,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewCulling() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(20, "enableViewCulling");
markFlagAsAccessed(21, "enableViewCulling");
flagValue = currentProvider_->enableViewCulling();
enableViewCulling_ = flagValue;
@@ -416,7 +434,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(21, "enableViewRecycling");
markFlagAsAccessed(22, "enableViewRecycling");
flagValue = currentProvider_->enableViewRecycling();
enableViewRecycling_ = flagValue;
@@ -434,7 +452,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecyclingForText() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(22, "enableViewRecyclingForText");
markFlagAsAccessed(23, "enableViewRecyclingForText");
flagValue = currentProvider_->enableViewRecyclingForText();
enableViewRecyclingForText_ = flagValue;
@@ -452,7 +470,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecyclingForView() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(23, "enableViewRecyclingForView");
markFlagAsAccessed(24, "enableViewRecyclingForView");
flagValue = currentProvider_->enableViewRecyclingForView();
enableViewRecyclingForView_ = flagValue;
@@ -470,7 +488,7 @@ bool ReactNativeFeatureFlagsAccessor::fixDifferentiatorEmittingUpdatesWithWrongP
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(24, "fixDifferentiatorEmittingUpdatesWithWrongParentTag");
markFlagAsAccessed(25, "fixDifferentiatorEmittingUpdatesWithWrongParentTag");
flagValue = currentProvider_->fixDifferentiatorEmittingUpdatesWithWrongParentTag();
fixDifferentiatorEmittingUpdatesWithWrongParentTag_ = flagValue;
@@ -488,7 +506,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(25, "fixMappingOfEventPrioritiesBetweenFabricAndReact");
markFlagAsAccessed(26, "fixMappingOfEventPrioritiesBetweenFabricAndReact");
flagValue = currentProvider_->fixMappingOfEventPrioritiesBetweenFabricAndReact();
fixMappingOfEventPrioritiesBetweenFabricAndReact_ = flagValue;
@@ -506,7 +524,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(26, "fixMountingCoordinatorReportedPendingTransactionsOnAndroid");
markFlagAsAccessed(27, "fixMountingCoordinatorReportedPendingTransactionsOnAndroid");
flagValue = currentProvider_->fixMountingCoordinatorReportedPendingTransactionsOnAndroid();
fixMountingCoordinatorReportedPendingTransactionsOnAndroid_ = flagValue;
@@ -524,7 +542,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(27, "fuseboxEnabledRelease");
markFlagAsAccessed(28, "fuseboxEnabledRelease");
flagValue = currentProvider_->fuseboxEnabledRelease();
fuseboxEnabledRelease_ = flagValue;
@@ -542,7 +560,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxNetworkInspectionEnabled() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(28, "fuseboxNetworkInspectionEnabled");
markFlagAsAccessed(29, "fuseboxNetworkInspectionEnabled");
flagValue = currentProvider_->fuseboxNetworkInspectionEnabled();
fuseboxNetworkInspectionEnabled_ = flagValue;
@@ -560,7 +578,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(29, "lazyAnimationCallbacks");
markFlagAsAccessed(30, "lazyAnimationCallbacks");
flagValue = currentProvider_->lazyAnimationCallbacks();
lazyAnimationCallbacks_ = flagValue;
@@ -578,7 +596,7 @@ bool ReactNativeFeatureFlagsAccessor::removeTurboModuleManagerDelegateMutex() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(30, "removeTurboModuleManagerDelegateMutex");
markFlagAsAccessed(31, "removeTurboModuleManagerDelegateMutex");
flagValue = currentProvider_->removeTurboModuleManagerDelegateMutex();
removeTurboModuleManagerDelegateMutex_ = flagValue;
@@ -596,7 +614,7 @@ bool ReactNativeFeatureFlagsAccessor::throwExceptionInsteadOfDeadlockOnTurboModu
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(31, "throwExceptionInsteadOfDeadlockOnTurboModuleSetupDuringSyncRenderIOS");
markFlagAsAccessed(32, "throwExceptionInsteadOfDeadlockOnTurboModuleSetupDuringSyncRenderIOS");
flagValue = currentProvider_->throwExceptionInsteadOfDeadlockOnTurboModuleSetupDuringSyncRenderIOS();
throwExceptionInsteadOfDeadlockOnTurboModuleSetupDuringSyncRenderIOS_ = flagValue;
@@ -614,7 +632,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(32, "traceTurboModulePromiseRejectionsOnAndroid");
markFlagAsAccessed(33, "traceTurboModulePromiseRejectionsOnAndroid");
flagValue = currentProvider_->traceTurboModulePromiseRejectionsOnAndroid();
traceTurboModulePromiseRejectionsOnAndroid_ = flagValue;
@@ -632,7 +650,7 @@ bool ReactNativeFeatureFlagsAccessor::useAlwaysAvailableJSErrorHandling() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(33, "useAlwaysAvailableJSErrorHandling");
markFlagAsAccessed(34, "useAlwaysAvailableJSErrorHandling");
flagValue = currentProvider_->useAlwaysAvailableJSErrorHandling();
useAlwaysAvailableJSErrorHandling_ = flagValue;
@@ -650,7 +668,7 @@ bool ReactNativeFeatureFlagsAccessor::useEditTextStockAndroidFocusBehavior() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(34, "useEditTextStockAndroidFocusBehavior");
markFlagAsAccessed(35, "useEditTextStockAndroidFocusBehavior");
flagValue = currentProvider_->useEditTextStockAndroidFocusBehavior();
useEditTextStockAndroidFocusBehavior_ = flagValue;
@@ -668,7 +686,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(35, "useFabricInterop");
markFlagAsAccessed(36, "useFabricInterop");
flagValue = currentProvider_->useFabricInterop();
useFabricInterop_ = flagValue;
@@ -686,7 +704,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(36, "useNativeViewConfigsInBridgelessMode");
markFlagAsAccessed(37, "useNativeViewConfigsInBridgelessMode");
flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode();
useNativeViewConfigsInBridgelessMode_ = flagValue;
@@ -704,7 +722,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(37, "useOptimizedEventBatchingOnAndroid");
markFlagAsAccessed(38, "useOptimizedEventBatchingOnAndroid");
flagValue = currentProvider_->useOptimizedEventBatchingOnAndroid();
useOptimizedEventBatchingOnAndroid_ = flagValue;
@@ -722,7 +740,7 @@ bool ReactNativeFeatureFlagsAccessor::useRawPropsJsiValue() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(38, "useRawPropsJsiValue");
markFlagAsAccessed(39, "useRawPropsJsiValue");
flagValue = currentProvider_->useRawPropsJsiValue();
useRawPropsJsiValue_ = flagValue;
@@ -740,7 +758,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(39, "useTurboModuleInterop");
markFlagAsAccessed(40, "useTurboModuleInterop");
flagValue = currentProvider_->useTurboModuleInterop();
useTurboModuleInterop_ = flagValue;
@@ -758,7 +776,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(40, "useTurboModules");
markFlagAsAccessed(41, "useTurboModules");
flagValue = currentProvider_->useTurboModules();
useTurboModules_ = flagValue;
@@ -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<<c526b54707d066c3883f5209b597ec83>>
* @generated SignedSource<<00f623d5f3920895eb2c1b530dce6a7d>>
*/
/**
@@ -33,6 +33,7 @@ class ReactNativeFeatureFlagsAccessor {
ReactNativeFeatureFlagsAccessor();
bool commonTestFlag();
bool animatedShouldSignalBatch();
bool disableMountItemReorderingAndroid();
bool enableAccumulatedUpdatesInRawPropsAndroid();
bool enableBridgelessArchitecture();
@@ -84,9 +85,10 @@ class ReactNativeFeatureFlagsAccessor {
std::unique_ptr<ReactNativeFeatureFlagsProvider> currentProvider_;
bool wasOverridden_;
std::array<std::atomic<const char*>, 41> accessedFeatureFlags_;
std::array<std::atomic<const char*>, 42> accessedFeatureFlags_;
std::atomic<std::optional<bool>> commonTestFlag_;
std::atomic<std::optional<bool>> animatedShouldSignalBatch_;
std::atomic<std::optional<bool>> disableMountItemReorderingAndroid_;
std::atomic<std::optional<bool>> enableAccumulatedUpdatesInRawPropsAndroid_;
std::atomic<std::optional<bool>> enableBridgelessArchitecture_;
@@ -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<<132471a831b3041cc6cae8915de33982>>
* @generated SignedSource<<140e6580100dab5806194e780610f122>>
*/
/**
@@ -31,6 +31,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
return false;
}
bool animatedShouldSignalBatch() override {
return false;
}
bool disableMountItemReorderingAndroid() override {
return false;
}
@@ -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<<b4b4f1a34fa94b88dae41b0f14c96cc8>>
* @generated SignedSource<<b8be2ef692b468cdfee6d88c091abec3>>
*/
/**
@@ -54,6 +54,15 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef
return ReactNativeFeatureFlagsDefaults::commonTestFlag();
}
bool animatedShouldSignalBatch() override {
auto value = values_["animatedShouldSignalBatch"];
if (!value.isNull()) {
return value.getBool();
}
return ReactNativeFeatureFlagsDefaults::animatedShouldSignalBatch();
}
bool disableMountItemReorderingAndroid() override {
auto value = values_["disableMountItemReorderingAndroid"];
if (!value.isNull()) {
@@ -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<<7bd8ef01ed492807df85a3d4a7f6a55c>>
* @generated SignedSource<<f694a97b02b01d4b56b5eac7f2a348e5>>
*/
/**
@@ -33,6 +33,8 @@ class ReactNativeFeatureFlagsOverridesOSSCanary : public ReactNativeFeatureFlags
bool enableBridgelessArchitecture() override {
return true;
}
@@ -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<<25f75edcfc62e5ce24c2d1bd10244e40>>
* @generated SignedSource<<ddf338308d0390152ddbec172c0ad40e>>
*/
/**
@@ -105,6 +105,8 @@ class ReactNativeFeatureFlagsOverridesOSSExperimental : public ReactNativeFeatur
@@ -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<<abf61ee3c9ef2363a04899dda2920fdc>>
* @generated SignedSource<<0845c9b1618ac1e18ce4aeb5d03a70f5>>
*/
/**
@@ -26,6 +26,7 @@ class ReactNativeFeatureFlagsProvider {
virtual ~ReactNativeFeatureFlagsProvider() = default;
virtual bool commonTestFlag() = 0;
virtual bool animatedShouldSignalBatch() = 0;
virtual bool disableMountItemReorderingAndroid() = 0;
virtual bool enableAccumulatedUpdatesInRawPropsAndroid() = 0;
virtual bool enableBridgelessArchitecture() = 0;
@@ -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<<2e88c46eee92923e11e44bc63a297f91>>
* @generated SignedSource<<7493403280d2ac7ec348eb3d78d915c2>>
*/
/**
@@ -49,6 +49,11 @@ bool NativeReactNativeFeatureFlags::commonTestFlagWithoutNativeImplementation(
return false;
}
bool NativeReactNativeFeatureFlags::animatedShouldSignalBatch(
jsi::Runtime& /*runtime*/) {
return ReactNativeFeatureFlags::animatedShouldSignalBatch();
}
bool NativeReactNativeFeatureFlags::disableMountItemReorderingAndroid(
jsi::Runtime& /*runtime*/) {
return ReactNativeFeatureFlags::disableMountItemReorderingAndroid();
@@ -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<<976dc1d9e9df5d843d796ba71fab2e27>>
* @generated SignedSource<<36b55f5cfd86d9aaad26c760dec7c875>>
*/
/**
@@ -39,6 +39,8 @@ class NativeReactNativeFeatureFlags
bool commonTestFlagWithoutNativeImplementation(jsi::Runtime& runtime);
bool animatedShouldSignalBatch(jsi::Runtime& runtime);
bool disableMountItemReorderingAndroid(jsi::Runtime& runtime);
bool enableAccumulatedUpdatesInRawPropsAndroid(jsi::Runtime& runtime);
@@ -60,6 +60,16 @@ const testDefinitions: FeatureFlagDefinitions = {
const definitions: FeatureFlagDefinitions = {
common: {
...testDefinitions.common,
animatedShouldSignalBatch: {
defaultValue: false,
metadata: {
dateAdded: '2025-03-07',
description: 'Enables start- and finishOperationBatch on any platform.',
expectedReleaseValue: true,
purpose: 'experimentation',
},
ossReleaseStage: 'none',
},
disableMountItemReorderingAndroid: {
defaultValue: false,
metadata: {
@@ -57,6 +57,8 @@ const eventListenerAnimationFinishedCallbacks: {
let globalEventEmitterGetValueListener: ?EventSubscription = null;
let globalEventEmitterAnimationFinishedListener: ?EventSubscription = null;
const shouldSignalBatch = ReactNativeFeatureFlags.animatedShouldSignalBatch();
function createNativeOperations(): $NonMaybeType<typeof NativeAnimatedModule> {
const methodNames = [
'createAnimatedNode', // 1
@@ -106,6 +108,11 @@ function createNativeOperations(): $NonMaybeType<typeof NativeAnimatedModule> {
if (queueOperations || queue.length !== 0) {
// $FlowExpectedError[incompatible-call] - Dynamism.
queue.push(() => method(...args));
} else if (shouldSignalBatch) {
// $FlowExpectedError[incompatible-call] - Dynamism.
queue.push(() => method(...args));
clearImmediate(flushQueueImmediate);
flushQueueImmediate = setImmediate(API.flushQueue);
} else {
// $FlowExpectedError[incompatible-call] - Dynamism.
method(...args);
@@ -138,6 +145,10 @@ const API = {
}) as $NonMaybeType<typeof NativeAnimatedModule>['getValue'],
setWaitingForIdentifier(id: string): void {
if (shouldSignalBatch) {
return;
}
waitingForQueuedOperations.add(id);
queueOperations = true;
if (
@@ -149,6 +160,10 @@ const API = {
},
unsetWaitingForIdentifier(id: string): void {
if (shouldSignalBatch) {
return;
}
waitingForQueuedOperations.delete(id);
if (waitingForQueuedOperations.size === 0) {
@@ -202,7 +217,7 @@ const API = {
return;
}
if (Platform.OS === 'android') {
if (Platform.OS === 'android' || shouldSignalBatch) {
NativeAnimatedModule?.startOperationBatch?.();
}
@@ -211,7 +226,7 @@ const API = {
}
queue.length = 0;
if (Platform.OS === 'android') {
if (Platform.OS === 'android' || shouldSignalBatch) {
NativeAnimatedModule?.finishOperationBatch?.();
}
}) as () => void,
@@ -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<<4f1befe0cec24eeb531d7ecca6bc451b>>
* @generated SignedSource<<99bbe1c87a7620b6381705db9795fd77>>
* @flow strict
*/
@@ -49,6 +49,7 @@ export type ReactNativeFeatureFlags = $ReadOnly<{
...ReactNativeFeatureFlagsJsOnly,
commonTestFlag: Getter<boolean>,
commonTestFlagWithoutNativeImplementation: Getter<boolean>,
animatedShouldSignalBatch: Getter<boolean>,
disableMountItemReorderingAndroid: Getter<boolean>,
enableAccumulatedUpdatesInRawPropsAndroid: Getter<boolean>,
enableBridgelessArchitecture: Getter<boolean>,
@@ -169,6 +170,10 @@ export const commonTestFlag: Getter<boolean> = createNativeFlagGetter('commonTes
* Common flag for testing (without native implementation). Do NOT modify.
*/
export const commonTestFlagWithoutNativeImplementation: Getter<boolean> = createNativeFlagGetter('commonTestFlagWithoutNativeImplementation', false);
/**
* Enables start- and finishOperationBatch on any platform.
*/
export const animatedShouldSignalBatch: Getter<boolean> = createNativeFlagGetter('animatedShouldSignalBatch', false);
/**
* Prevent FabricMountingManager from reordering mountitems, which may lead to invalid state on the UI thread
*/
@@ -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<<f8e0c44bed98b686fd2964aae598ad67>>
* @generated SignedSource<<22d8e7623a2eee5182c786f2ec914401>>
* @flow strict
*/
@@ -25,6 +25,7 @@ import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboMod
export interface Spec extends TurboModule {
+commonTestFlag?: () => boolean;
+commonTestFlagWithoutNativeImplementation?: () => boolean;
+animatedShouldSignalBatch?: () => boolean;
+disableMountItemReorderingAndroid?: () => boolean;
+enableAccumulatedUpdatesInRawPropsAndroid?: () => boolean;
+enableBridgelessArchitecture?: () => boolean;