Implement potential fix for mounting errors during synchronous state updates (#44015)

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

Changelog: [internal]

## Context

When we introduced synchronous state updates in Fabric, we saw some crashes on coming from the mounting layer on Android.

It seems some of these crashes are caused by nested mount operations. When we're mounting some views, like [scroll views](https://github.com/facebook/react-native/blob/881c0bc8970b9e402df6b4f87e1759b238b24735/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java#L383), we dispatch state updates that end up doing more mutations. When we were doing these state updates asynchronously, all the original mutations were processed before these updates, but now that we do them synchronously, the mutations are interleaved causing errors.

## Changes

This introduces a new flag that will force all the mutations going through `MountItemExecutor` in `FabricUIManager` to be batched instead of executed synchronously. This fixes the issues I saw locally and I'm expecting this will unblock synchronous state updates in production.

Potentially, this might fix other crashes we've been seeing with a low frequency.

Reviewed By: sammy-SC

Differential Revision: D55942125

fbshipit-source-id: b8d9c145ec307de7318dbbed14880bc9a84fdb2a
This commit is contained in:
Rubén Norte
2024-04-10 07:44:11 -07:00
committed by Facebook GitHub Bot
parent 54757ca017
commit b9a2249fff
21 changed files with 138 additions and 24 deletions
@@ -208,7 +208,14 @@ public class FabricUIManager implements UIManager, LifecycleEventListener, UIBlo
public void executeItems(Queue<MountItem> items) {
// This executor can be technically accessed before the dispatcher is created,
// but if that happens, something is terribly wrong
mMountItemDispatcher.dispatchMountItems(items);
if (ReactNativeFeatureFlags.forceBatchingMountItemsOnAndroid()) {
for (MountItem mountItem : items) {
mMountItemDispatcher.addMountItem(mountItem);
}
mMountItemDispatcher.tryDispatchMountItems();
} else {
mMountItemDispatcher.dispatchMountItems(items);
}
}
};
@@ -24,6 +24,7 @@ import com.facebook.react.bridge.ReactSoftExceptionLogger;
import com.facebook.react.bridge.RetryableMountingLayerException;
import com.facebook.react.fabric.mounting.mountitems.DispatchCommandMountItem;
import com.facebook.react.fabric.mounting.mountitems.MountItem;
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags;
import com.facebook.systrace.Systrace;
import java.util.ArrayList;
import java.util.Collection;
@@ -102,6 +103,10 @@ public class MountItemDispatcher {
return;
}
if (ReactNativeFeatureFlags.forceBatchingMountItemsOnAndroid()) {
mInDispatch = true;
}
final boolean didDispatchItems;
try {
didDispatchItems = dispatchMountItems();
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<4c0ede4fa927bc8361d0355bc7cddb10>>
* @generated SignedSource<<a9793334f77cea07b88a74103da09f72>>
*/
/**
@@ -88,6 +88,12 @@ public object ReactNativeFeatureFlags {
@JvmStatic
public fun enableUIConsistency(): Boolean = accessor.enableUIConsistency()
/**
* Forces the mounting layer on Android to always batch mount items instead of dispatching them immediately. This might fix some crashes related to synchronous state updates, where some views dispatch state updates during mount.
*/
@JvmStatic
public fun forceBatchingMountItemsOnAndroid(): Boolean = accessor.forceBatchingMountItemsOnAndroid()
/**
* Flag determining if the C++ implementation of InspectorPackagerConnection should be used instead of the per-platform one. This flag is global and should not be changed across React Host lifetimes.
*/
@@ -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<<aa5b9eac9da720ff1a1bc44325a92c46>>
* @generated SignedSource<<51d66e841a09638375b1849043c9886a>>
*/
/**
@@ -30,6 +30,7 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso
private var enableSpannableBuildingUnificationCache: Boolean? = null
private var enableSynchronousStateUpdatesCache: Boolean? = null
private var enableUIConsistencyCache: Boolean? = null
private var forceBatchingMountItemsOnAndroidCache: Boolean? = null
private var inspectorEnableCxxInspectorPackagerConnectionCache: Boolean? = null
private var inspectorEnableModernCDPRegistryCache: Boolean? = null
private var useModernRuntimeSchedulerCache: Boolean? = null
@@ -125,6 +126,15 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso
return cached
}
override fun forceBatchingMountItemsOnAndroid(): Boolean {
var cached = forceBatchingMountItemsOnAndroidCache
if (cached == null) {
cached = ReactNativeFeatureFlagsCxxInterop.forceBatchingMountItemsOnAndroid()
forceBatchingMountItemsOnAndroidCache = cached
}
return cached
}
override fun inspectorEnableCxxInspectorPackagerConnection(): Boolean {
var cached = inspectorEnableCxxInspectorPackagerConnectionCache
if (cached == null) {
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<69c4a4aa9621adfe02c15f5f011b3804>>
* @generated SignedSource<<4422f7984f27638cc2fb18230a6d042e>>
*/
/**
@@ -48,6 +48,8 @@ public object ReactNativeFeatureFlagsCxxInterop {
@DoNotStrip @JvmStatic public external fun enableUIConsistency(): Boolean
@DoNotStrip @JvmStatic public external fun forceBatchingMountItemsOnAndroid(): Boolean
@DoNotStrip @JvmStatic public external fun inspectorEnableCxxInspectorPackagerConnection(): Boolean
@DoNotStrip @JvmStatic public external fun inspectorEnableModernCDPRegistry(): Boolean
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<299901489d5059ed7124f6738be0e48d>>
* @generated SignedSource<<acf4e79f18c3b33bcca452a99265dfcf>>
*/
/**
@@ -43,6 +43,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
override fun enableUIConsistency(): Boolean = false
override fun forceBatchingMountItemsOnAndroid(): Boolean = false
override fun inspectorEnableCxxInspectorPackagerConnection(): Boolean = false
override fun inspectorEnableModernCDPRegistry(): Boolean = false
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<1c5e5d965ec746a3d06748ef922b8460>>
* @generated SignedSource<<46793ec55ed15661090a9b9998806bcc>>
*/
/**
@@ -34,6 +34,7 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces
private var enableSpannableBuildingUnificationCache: Boolean? = null
private var enableSynchronousStateUpdatesCache: Boolean? = null
private var enableUIConsistencyCache: Boolean? = null
private var forceBatchingMountItemsOnAndroidCache: Boolean? = null
private var inspectorEnableCxxInspectorPackagerConnectionCache: Boolean? = null
private var inspectorEnableModernCDPRegistryCache: Boolean? = null
private var useModernRuntimeSchedulerCache: Boolean? = null
@@ -139,6 +140,16 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces
return cached
}
override fun forceBatchingMountItemsOnAndroid(): Boolean {
var cached = forceBatchingMountItemsOnAndroidCache
if (cached == null) {
cached = currentProvider.forceBatchingMountItemsOnAndroid()
accessedFeatureFlags.add("forceBatchingMountItemsOnAndroid")
forceBatchingMountItemsOnAndroidCache = cached
}
return cached
}
override fun inspectorEnableCxxInspectorPackagerConnection(): Boolean {
var cached = inspectorEnableCxxInspectorPackagerConnectionCache
if (cached == null) {
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<2412f7c99bf424397e091a529ac05f32>>
* @generated SignedSource<<dd6d7b39eb1dc066dd6801b22846e431>>
*/
/**
@@ -43,6 +43,8 @@ public interface ReactNativeFeatureFlagsProvider {
@DoNotStrip public fun enableUIConsistency(): Boolean
@DoNotStrip public fun forceBatchingMountItemsOnAndroid(): Boolean
@DoNotStrip public fun inspectorEnableCxxInspectorPackagerConnection(): Boolean
@DoNotStrip public fun inspectorEnableModernCDPRegistry(): Boolean
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<0756d56ae2ce45f020ac9a87e9a3d1c3>>
* @generated SignedSource<<3a7d633de9e6fd6862864c202d56523a>>
*/
/**
@@ -99,6 +99,12 @@ class ReactNativeFeatureFlagsProviderHolder
return method(javaProvider_);
}
bool forceBatchingMountItemsOnAndroid() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("forceBatchingMountItemsOnAndroid");
return method(javaProvider_);
}
bool inspectorEnableCxxInspectorPackagerConnection() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("inspectorEnableCxxInspectorPackagerConnection");
@@ -177,6 +183,11 @@ bool JReactNativeFeatureFlagsCxxInterop::enableUIConsistency(
return ReactNativeFeatureFlags::enableUIConsistency();
}
bool JReactNativeFeatureFlagsCxxInterop::forceBatchingMountItemsOnAndroid(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::forceBatchingMountItemsOnAndroid();
}
bool JReactNativeFeatureFlagsCxxInterop::inspectorEnableCxxInspectorPackagerConnection(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::inspectorEnableCxxInspectorPackagerConnection();
@@ -244,6 +255,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
makeNativeMethod(
"enableUIConsistency",
JReactNativeFeatureFlagsCxxInterop::enableUIConsistency),
makeNativeMethod(
"forceBatchingMountItemsOnAndroid",
JReactNativeFeatureFlagsCxxInterop::forceBatchingMountItemsOnAndroid),
makeNativeMethod(
"inspectorEnableCxxInspectorPackagerConnection",
JReactNativeFeatureFlagsCxxInterop::inspectorEnableCxxInspectorPackagerConnection),
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<1ae5c51e5b1c1725565e57a02d19c3a7>>
* @generated SignedSource<<7237412cb02dad9468f144a050bd78e3>>
*/
/**
@@ -60,6 +60,9 @@ class JReactNativeFeatureFlagsCxxInterop
static bool enableUIConsistency(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
static bool forceBatchingMountItemsOnAndroid(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
static bool inspectorEnableCxxInspectorPackagerConnection(
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<<520ae882fb57dec58ededd47411c0b1d>>
* @generated SignedSource<<e589683db0f9a9fbf812fefd4a1c3f96>>
*/
/**
@@ -61,6 +61,10 @@ bool ReactNativeFeatureFlags::enableUIConsistency() {
return getAccessor().enableUIConsistency();
}
bool ReactNativeFeatureFlags::forceBatchingMountItemsOnAndroid() {
return getAccessor().forceBatchingMountItemsOnAndroid();
}
bool ReactNativeFeatureFlags::inspectorEnableCxxInspectorPackagerConnection() {
return getAccessor().inspectorEnableCxxInspectorPackagerConnection();
}
@@ -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<<e9fbc07cb8f1c50e015e34035d50b8d1>>
* @generated SignedSource<<38881afec04f45eff46edd99ce9443da>>
*/
/**
@@ -87,6 +87,11 @@ class ReactNativeFeatureFlags {
*/
RN_EXPORT static bool enableUIConsistency();
/**
* Forces the mounting layer on Android to always batch mount items instead of dispatching them immediately. This might fix some crashes related to synchronous state updates, where some views dispatch state updates during mount.
*/
RN_EXPORT static bool forceBatchingMountItemsOnAndroid();
/**
* Flag determining if the C++ implementation of InspectorPackagerConnection should be used instead of the per-platform one. This flag is global and should not be changed across React Host lifetimes.
*/
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<65cbd0e1b92ee06da3f466386c516dbc>>
* @generated SignedSource<<21980ab4688bc93c5573012a228e3997>>
*/
/**
@@ -209,6 +209,24 @@ bool ReactNativeFeatureFlagsAccessor::enableUIConsistency() {
return flagValue.value();
}
bool ReactNativeFeatureFlagsAccessor::forceBatchingMountItemsOnAndroid() {
auto flagValue = forceBatchingMountItemsOnAndroid_.load();
if (!flagValue.has_value()) {
// This block is not exclusive but it is not necessary.
// If multiple threads try to initialize the feature flag, we would only
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(10, "forceBatchingMountItemsOnAndroid");
flagValue = currentProvider_->forceBatchingMountItemsOnAndroid();
forceBatchingMountItemsOnAndroid_ = flagValue;
}
return flagValue.value();
}
bool ReactNativeFeatureFlagsAccessor::inspectorEnableCxxInspectorPackagerConnection() {
auto flagValue = inspectorEnableCxxInspectorPackagerConnection_.load();
@@ -218,7 +236,7 @@ bool ReactNativeFeatureFlagsAccessor::inspectorEnableCxxInspectorPackagerConnect
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(10, "inspectorEnableCxxInspectorPackagerConnection");
markFlagAsAccessed(11, "inspectorEnableCxxInspectorPackagerConnection");
flagValue = currentProvider_->inspectorEnableCxxInspectorPackagerConnection();
inspectorEnableCxxInspectorPackagerConnection_ = flagValue;
@@ -236,7 +254,7 @@ bool ReactNativeFeatureFlagsAccessor::inspectorEnableModernCDPRegistry() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(11, "inspectorEnableModernCDPRegistry");
markFlagAsAccessed(12, "inspectorEnableModernCDPRegistry");
flagValue = currentProvider_->inspectorEnableModernCDPRegistry();
inspectorEnableModernCDPRegistry_ = flagValue;
@@ -254,7 +272,7 @@ bool ReactNativeFeatureFlagsAccessor::useModernRuntimeScheduler() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(12, "useModernRuntimeScheduler");
markFlagAsAccessed(13, "useModernRuntimeScheduler");
flagValue = currentProvider_->useModernRuntimeScheduler();
useModernRuntimeScheduler_ = flagValue;
@@ -272,7 +290,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeViewConfigsInBridgelessMode() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(13, "useNativeViewConfigsInBridgelessMode");
markFlagAsAccessed(14, "useNativeViewConfigsInBridgelessMode");
flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode();
useNativeViewConfigsInBridgelessMode_ = flagValue;
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<00e1c8f5c451c9744257e0b3fc566949>>
* @generated SignedSource<<fe45466cd2b60fe856aa811ccc2365bd>>
*/
/**
@@ -41,6 +41,7 @@ class ReactNativeFeatureFlagsAccessor {
bool enableSpannableBuildingUnification();
bool enableSynchronousStateUpdates();
bool enableUIConsistency();
bool forceBatchingMountItemsOnAndroid();
bool inspectorEnableCxxInspectorPackagerConnection();
bool inspectorEnableModernCDPRegistry();
bool useModernRuntimeScheduler();
@@ -55,7 +56,7 @@ class ReactNativeFeatureFlagsAccessor {
std::unique_ptr<ReactNativeFeatureFlagsProvider> currentProvider_;
bool wasOverridden_;
std::array<std::atomic<const char*>, 14> accessedFeatureFlags_;
std::array<std::atomic<const char*>, 15> accessedFeatureFlags_;
std::atomic<std::optional<bool>> commonTestFlag_;
std::atomic<std::optional<bool>> batchRenderingUpdatesInEventLoop_;
@@ -67,6 +68,7 @@ class ReactNativeFeatureFlagsAccessor {
std::atomic<std::optional<bool>> enableSpannableBuildingUnification_;
std::atomic<std::optional<bool>> enableSynchronousStateUpdates_;
std::atomic<std::optional<bool>> enableUIConsistency_;
std::atomic<std::optional<bool>> forceBatchingMountItemsOnAndroid_;
std::atomic<std::optional<bool>> inspectorEnableCxxInspectorPackagerConnection_;
std::atomic<std::optional<bool>> inspectorEnableModernCDPRegistry_;
std::atomic<std::optional<bool>> useModernRuntimeScheduler_;
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<57c83d1855f16d4c3ffdd5cb98d57571>>
* @generated SignedSource<<72058f22fd21f03e66136929306d5974>>
*/
/**
@@ -67,6 +67,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
return false;
}
bool forceBatchingMountItemsOnAndroid() override {
return false;
}
bool inspectorEnableCxxInspectorPackagerConnection() override {
return false;
}
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<664351a329e558acf1923baeafe35e9d>>
* @generated SignedSource<<21fb3f2ea9db49ea4710a13807c7512a>>
*/
/**
@@ -35,6 +35,7 @@ class ReactNativeFeatureFlagsProvider {
virtual bool enableSpannableBuildingUnification() = 0;
virtual bool enableSynchronousStateUpdates() = 0;
virtual bool enableUIConsistency() = 0;
virtual bool forceBatchingMountItemsOnAndroid() = 0;
virtual bool inspectorEnableCxxInspectorPackagerConnection() = 0;
virtual bool inspectorEnableModernCDPRegistry() = 0;
virtual bool useModernRuntimeScheduler() = 0;
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<8c7e1d8afe1bc2068c94148a258c2ed0>>
* @generated SignedSource<<55ee96b1902071c987c70b5f07f670e4>>
*/
/**
@@ -87,6 +87,11 @@ bool NativeReactNativeFeatureFlags::enableUIConsistency(
return ReactNativeFeatureFlags::enableUIConsistency();
}
bool NativeReactNativeFeatureFlags::forceBatchingMountItemsOnAndroid(
jsi::Runtime& /*runtime*/) {
return ReactNativeFeatureFlags::forceBatchingMountItemsOnAndroid();
}
bool NativeReactNativeFeatureFlags::inspectorEnableCxxInspectorPackagerConnection(
jsi::Runtime& /*runtime*/) {
return ReactNativeFeatureFlags::inspectorEnableCxxInspectorPackagerConnection();
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<9d8d8fd8a9da981fd35c9f134f575e57>>
* @generated SignedSource<<f8f1ff1a05b772b861856d027659848a>>
*/
/**
@@ -55,6 +55,8 @@ class NativeReactNativeFeatureFlags
bool enableUIConsistency(jsi::Runtime& runtime);
bool forceBatchingMountItemsOnAndroid(jsi::Runtime& runtime);
bool inspectorEnableCxxInspectorPackagerConnection(jsi::Runtime& runtime);
bool inspectorEnableModernCDPRegistry(jsi::Runtime& runtime);
@@ -76,6 +76,11 @@ const definitions: FeatureFlagDefinitions = {
description:
'Ensures that JavaScript always has a consistent view of the state of the UI (e.g.: commits done in other threads are not immediately propagated to JS during its execution).',
},
forceBatchingMountItemsOnAndroid: {
defaultValue: false,
description:
'Forces the mounting layer on Android to always batch mount items instead of dispatching them immediately. This might fix some crashes related to synchronous state updates, where some views dispatch state updates during mount.',
},
inspectorEnableCxxInspectorPackagerConnection: {
defaultValue: false,
description:
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<9286e5fc6398d839d271af4f4a8ae94b>>
* @generated SignedSource<<45969617730126d45f35820ee3bd5853>>
* @flow strict-local
*/
@@ -50,6 +50,7 @@ export type ReactNativeFeatureFlags = {
enableSpannableBuildingUnification: Getter<boolean>,
enableSynchronousStateUpdates: Getter<boolean>,
enableUIConsistency: Getter<boolean>,
forceBatchingMountItemsOnAndroid: Getter<boolean>,
inspectorEnableCxxInspectorPackagerConnection: Getter<boolean>,
inspectorEnableModernCDPRegistry: Getter<boolean>,
useModernRuntimeScheduler: Getter<boolean>,
@@ -136,6 +137,10 @@ export const enableSynchronousStateUpdates: Getter<boolean> = createNativeFlagGe
* Ensures that JavaScript always has a consistent view of the state of the UI (e.g.: commits done in other threads are not immediately propagated to JS during its execution).
*/
export const enableUIConsistency: Getter<boolean> = createNativeFlagGetter('enableUIConsistency', false);
/**
* Forces the mounting layer on Android to always batch mount items instead of dispatching them immediately. This might fix some crashes related to synchronous state updates, where some views dispatch state updates during mount.
*/
export const forceBatchingMountItemsOnAndroid: Getter<boolean> = createNativeFlagGetter('forceBatchingMountItemsOnAndroid', false);
/**
* Flag determining if the C++ implementation of InspectorPackagerConnection should be used instead of the per-platform one. This flag is global and should not be changed across React Host lifetimes.
*/
@@ -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<<ac87a6f3de21bd3dd244b99322cb2d2c>>
* @generated SignedSource<<22dd9936df00ce7a53a5aa4a2c331279>>
* @flow strict-local
*/
@@ -33,6 +33,7 @@ export interface Spec extends TurboModule {
+enableSpannableBuildingUnification?: () => boolean;
+enableSynchronousStateUpdates?: () => boolean;
+enableUIConsistency?: () => boolean;
+forceBatchingMountItemsOnAndroid?: () => boolean;
+inspectorEnableCxxInspectorPackagerConnection?: () => boolean;
+inspectorEnableModernCDPRegistry?: () => boolean;
+useModernRuntimeScheduler?: () => boolean;