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 29bf8fb06bdd..9044ba47c6d6 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<<9646ebeba75ec903be5ade7e2333f0c8>> + * @generated SignedSource<<248d4e5e599c3af43dc352c8bb1a2c13>> */ /** @@ -360,6 +360,12 @@ public object ReactNativeFeatureFlags { @JvmStatic public fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean = accessor.fixMappingOfEventPrioritiesBetweenFabricAndReact() + /** + * Enable system assertion validating that Fusebox is configured with a single host. When set, the CDP backend will dynamically disable features (Perf and Network) in the event that multiple hosts are registered (undefined behaviour), and broadcast this over `ReactNativeApplication.systemStateChanged`. + */ + @JvmStatic + public fun fuseboxAssertSingleHostState(): Boolean = accessor.fuseboxAssertSingleHostState() + /** * Flag determining if the React Native DevTools (Fusebox) CDP backend should be enabled in release builds. This flag is global and should not be changed across React Host lifetimes. */ diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt index ec42740a8754..fd4e49d5ff9d 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<<9d6ccbe6d02608901fc18ad88baab176>> + * @generated SignedSource<> */ /** @@ -75,6 +75,7 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces private var enableVirtualViewWindowFocusDetectionCache: Boolean? = null private var enableWebPerformanceAPIsByDefaultCache: Boolean? = null private var fixMappingOfEventPrioritiesBetweenFabricAndReactCache: Boolean? = null + private var fuseboxAssertSingleHostStateCache: Boolean? = null private var fuseboxEnabledReleaseCache: Boolean? = null private var fuseboxNetworkInspectionEnabledCache: Boolean? = null private var hideOffscreenVirtualViewsOnIOSCache: Boolean? = null @@ -598,6 +599,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces return cached } + override fun fuseboxAssertSingleHostState(): Boolean { + var cached = fuseboxAssertSingleHostStateCache + if (cached == null) { + cached = ReactNativeFeatureFlagsCxxInterop.fuseboxAssertSingleHostState() + fuseboxAssertSingleHostStateCache = cached + } + return cached + } + override fun fuseboxEnabledRelease(): Boolean { var cached = fuseboxEnabledReleaseCache 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 d49354281fdd..e09b5830fda0 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<> + * @generated SignedSource<> */ /** @@ -138,6 +138,8 @@ public object ReactNativeFeatureFlagsCxxInterop { @DoNotStrip @JvmStatic public external fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean + @DoNotStrip @JvmStatic public external fun fuseboxAssertSingleHostState(): Boolean + @DoNotStrip @JvmStatic public external fun fuseboxEnabledRelease(): Boolean @DoNotStrip @JvmStatic public external fun fuseboxNetworkInspectionEnabled(): 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 fdd3b815149e..42bd104b71cc 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<<7b8a5ad9a3353ea32a39bd139e9174f7>> + * @generated SignedSource<<30041179508b76146b4a6ff70f7d2090>> */ /** @@ -133,6 +133,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean = false + override fun fuseboxAssertSingleHostState(): Boolean = true + override fun fuseboxEnabledRelease(): Boolean = false override fun fuseboxNetworkInspectionEnabled(): 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 ec66c76e0c87..085d26c6e576 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<<9bb9a7cf89c92f5a397b2328fa983dc6>> + * @generated SignedSource<<78f60952fc7a5cd0efbf8ba8478251a7>> */ /** @@ -79,6 +79,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc private var enableVirtualViewWindowFocusDetectionCache: Boolean? = null private var enableWebPerformanceAPIsByDefaultCache: Boolean? = null private var fixMappingOfEventPrioritiesBetweenFabricAndReactCache: Boolean? = null + private var fuseboxAssertSingleHostStateCache: Boolean? = null private var fuseboxEnabledReleaseCache: Boolean? = null private var fuseboxNetworkInspectionEnabledCache: Boolean? = null private var hideOffscreenVirtualViewsOnIOSCache: Boolean? = null @@ -657,6 +658,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc return cached } + override fun fuseboxAssertSingleHostState(): Boolean { + var cached = fuseboxAssertSingleHostStateCache + if (cached == null) { + cached = currentProvider.fuseboxAssertSingleHostState() + accessedFeatureFlags.add("fuseboxAssertSingleHostState") + fuseboxAssertSingleHostStateCache = cached + } + return cached + } + override fun fuseboxEnabledRelease(): Boolean { var cached = fuseboxEnabledReleaseCache 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 cd76bc3df19c..1c6a0883a6d3 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<> + * @generated SignedSource<<865a11fa77d36e33d3bb6548cce01e66>> */ /** @@ -133,6 +133,8 @@ public interface ReactNativeFeatureFlagsProvider { @DoNotStrip public fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean + @DoNotStrip public fun fuseboxAssertSingleHostState(): Boolean + @DoNotStrip public fun fuseboxEnabledRelease(): Boolean @DoNotStrip public fun fuseboxNetworkInspectionEnabled(): Boolean diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp index df06cc588264..944f0319d208 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<<0527dbb4a838be34b80d76b11d18cea0>> + * @generated SignedSource<<975dfce969af2eda791cd6dc37d6ccc2>> */ /** @@ -369,6 +369,12 @@ class ReactNativeFeatureFlagsJavaProvider return method(javaProvider_); } + bool fuseboxAssertSingleHostState() override { + static const auto method = + getReactNativeFeatureFlagsProviderJavaClass()->getMethod("fuseboxAssertSingleHostState"); + return method(javaProvider_); + } + bool fuseboxEnabledRelease() override { static const auto method = getReactNativeFeatureFlagsProviderJavaClass()->getMethod("fuseboxEnabledRelease"); @@ -810,6 +816,11 @@ bool JReactNativeFeatureFlagsCxxInterop::fixMappingOfEventPrioritiesBetweenFabri return ReactNativeFeatureFlags::fixMappingOfEventPrioritiesBetweenFabricAndReact(); } +bool JReactNativeFeatureFlagsCxxInterop::fuseboxAssertSingleHostState( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::fuseboxAssertSingleHostState(); +} + bool JReactNativeFeatureFlagsCxxInterop::fuseboxEnabledRelease( facebook::jni::alias_ref /*unused*/) { return ReactNativeFeatureFlags::fuseboxEnabledRelease(); @@ -1141,6 +1152,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() { makeNativeMethod( "fixMappingOfEventPrioritiesBetweenFabricAndReact", JReactNativeFeatureFlagsCxxInterop::fixMappingOfEventPrioritiesBetweenFabricAndReact), + makeNativeMethod( + "fuseboxAssertSingleHostState", + JReactNativeFeatureFlagsCxxInterop::fuseboxAssertSingleHostState), makeNativeMethod( "fuseboxEnabledRelease", JReactNativeFeatureFlagsCxxInterop::fuseboxEnabledRelease), 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 64a4b5ec585d..5b66f4dcf5b2 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<> + * @generated SignedSource<<97c126a1763860d25ee216150156e200>> */ /** @@ -195,6 +195,9 @@ class JReactNativeFeatureFlagsCxxInterop static bool fixMappingOfEventPrioritiesBetweenFabricAndReact( facebook::jni::alias_ref); + static bool fuseboxAssertSingleHostState( + facebook::jni::alias_ref); + static bool fuseboxEnabledRelease( facebook::jni::alias_ref); diff --git a/packages/react-native/ReactCommon/jsinspector-modern/HostAgent.cpp b/packages/react-native/ReactCommon/jsinspector-modern/HostAgent.cpp index 60a33116bd15..813770d51ad5 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/HostAgent.cpp +++ b/packages/react-native/ReactCommon/jsinspector-modern/HostAgent.cpp @@ -10,6 +10,7 @@ #ifdef REACT_NATIVE_DEBUGGER_ENABLED #include "InspectorFlags.h" +#include "InspectorInterfaces.h" #include "NetworkIOAgent.h" #include "SessionState.h" #include "TracingAgent.h" @@ -145,6 +146,19 @@ class HostAgent::Impl final { } if (InspectorFlags::getInstance().getNetworkInspectionEnabled()) { if (req.method == "Network.enable") { + auto& inspector = getInspectorInstance(); + if (inspector.getSystemState().registeredPagesCount > 1) { + frontendChannel_( + cdp::jsonError( + req.id, + cdp::ErrorCode::InternalError, + "The Network domain is unavailable when multiple React Native hosts are registered.")); + return { + .isFinishedHandlingRequest = true, + .shouldSendOKResponse = false, + }; + } + sessionState_.isNetworkDomainEnabled = true; return { @@ -216,6 +230,11 @@ class HostAgent::Impl final { cdp::jsonNotification( "ReactNativeApplication.metadataUpdated", createHostMetadataPayload(hostMetadata_))); + auto& inspector = getInspectorInstance(); + bool isSingleHost = inspector.getSystemState().registeredPagesCount <= 1; + if (!isSingleHost) { + emitSystemStateChanged(isSingleHost); + } auto stashedTraceRecording = targetController_.getDelegate() @@ -374,6 +393,15 @@ class HostAgent::Impl final { tracingAgent_.emitExternalTraceRecording(std::move(traceRecording)); } + void emitSystemStateChanged(bool isSingleHost) { + frontendChannel_( + cdp::jsonNotification( + "ReactNativeApplication.systemStateChanged", + folly::dynamic::object("isSingleHost", isSingleHost))); + + frontendChannel_(cdp::jsonNotification("Network.disable")); + } + private: enum class FuseboxClientType { Unknown, Fusebox, NonFusebox }; @@ -480,6 +508,7 @@ class HostAgent::Impl final { } void emitExternalTraceRecording(tracing::TraceRecordingState traceRecording) { } + void emitSystemStateChanged(bool isSingleHost) {} }; #endif // REACT_NATIVE_DEBUGGER_ENABLED @@ -519,6 +548,10 @@ void HostAgent::emitExternalTraceRecording( impl_->emitExternalTraceRecording(std::move(traceRecording)); } +void HostAgent::emitSystemStateChanged(bool isSingleHost) const { + impl_->emitSystemStateChanged(isSingleHost); +} + #pragma mark - Tracing HostTracingAgent::HostTracingAgent(tracing::TraceRecordingState& state) diff --git a/packages/react-native/ReactCommon/jsinspector-modern/HostAgent.h b/packages/react-native/ReactCommon/jsinspector-modern/HostAgent.h index afb8bf44ad40..ab4478816562 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/HostAgent.h +++ b/packages/react-native/ReactCommon/jsinspector-modern/HostAgent.h @@ -79,6 +79,12 @@ class HostAgent final { */ void emitExternalTraceRecording(tracing::TraceRecordingState traceRecording) const; + /** + * Emits a system state changed event when the number of ReactHost instances + * changes. + */ + void emitSystemStateChanged(bool isSingleHost) const; + private: // We use the private implementation idiom to ensure this class has the same // layout regardless of whether REACT_NATIVE_DEBUGGER_ENABLED is defined. The diff --git a/packages/react-native/ReactCommon/jsinspector-modern/HostTarget.h b/packages/react-native/ReactCommon/jsinspector-modern/HostTarget.h index e315893e8e11..72929a95a205 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/HostTarget.h +++ b/packages/react-native/ReactCommon/jsinspector-modern/HostTarget.h @@ -326,6 +326,11 @@ class JSINSPECTOR_EXPORT HostTarget : public EnableExecutorFromThis */ void emitTraceRecordingForFirstFuseboxClient(tracing::TraceRecordingState traceRecording) const; + /** + * Emits a system state changed event to all active sessions. + */ + void emitSystemStateChanged(bool isSingleHost) const; + private: /** * Constructs a new HostTarget. diff --git a/packages/react-native/ReactCommon/jsinspector-modern/InspectorFlags.cpp b/packages/react-native/ReactCommon/jsinspector-modern/InspectorFlags.cpp index 35092ec4e6f5..010813a24264 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/InspectorFlags.cpp +++ b/packages/react-native/ReactCommon/jsinspector-modern/InspectorFlags.cpp @@ -17,6 +17,10 @@ InspectorFlags& InspectorFlags::getInstance() { return instance; } +bool InspectorFlags::getAssertSingleHostState() const { + return loadFlagsAndAssertUnchanged().assertSingleHostState; +} + bool InspectorFlags::getFuseboxEnabled() const { if (fuseboxDisabledForTest_) { return false; @@ -48,6 +52,8 @@ void InspectorFlags::dangerouslyDisableFuseboxForTest() { const InspectorFlags::Values& InspectorFlags::loadFlagsAndAssertUnchanged() const { InspectorFlags::Values newValues = { + .assertSingleHostState = + ReactNativeFeatureFlags::fuseboxAssertSingleHostState(), .fuseboxEnabled = #if defined(REACT_NATIVE_DEBUGGER_ENABLED) true, diff --git a/packages/react-native/ReactCommon/jsinspector-modern/InspectorFlags.h b/packages/react-native/ReactCommon/jsinspector-modern/InspectorFlags.h index 60e260ea19bf..5e245d482eed 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/InspectorFlags.h +++ b/packages/react-native/ReactCommon/jsinspector-modern/InspectorFlags.h @@ -19,6 +19,12 @@ class InspectorFlags { public: static InspectorFlags &getInstance(); + /** + * Flag determining if the inspector backend should strictly assert that only + * a single host is registered. + */ + bool getAssertSingleHostState() const; + /** * Flag determining if the modern CDP backend should be enabled. */ @@ -54,6 +60,7 @@ class InspectorFlags { private: struct Values { + bool assertSingleHostState; bool fuseboxEnabled; bool isProfilingBuild; bool networkInspectionEnabled; diff --git a/packages/react-native/ReactCommon/jsinspector-modern/InspectorInterfaces.cpp b/packages/react-native/ReactCommon/jsinspector-modern/InspectorInterfaces.cpp index d660504a84d7..b0d2f7a5ffd4 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/InspectorInterfaces.cpp +++ b/packages/react-native/ReactCommon/jsinspector-modern/InspectorInterfaces.cpp @@ -7,6 +7,8 @@ #include "InspectorInterfaces.h" +#include "InspectorFlags.h" + #include #include #include @@ -35,6 +37,14 @@ namespace { class InspectorImpl : public IInspector { public: + InspectorImpl() { + systemStateListener_ = std::make_shared(systemState_); + auto& inspectorFlags = InspectorFlags::getInstance(); + if (inspectorFlags.getAssertSingleHostState()) { + registerPageStatusListener(systemStateListener_); + } + } + int addPage( const std::string& description, const std::string& vm, @@ -50,7 +60,21 @@ class InspectorImpl : public IInspector { void registerPageStatusListener( std::weak_ptr listener) override; + InspectorSystemState getSystemState() const override; + private: + class SystemStateListener : public IPageStatusListener { + public: + explicit SystemStateListener(InspectorSystemState& state) : state_(state) {} + + void onPageAdded(int /*pageId*/) override { + state_.registeredPagesCount++; + } + + private: + InspectorSystemState& state_; + }; + class Page { public: Page( @@ -74,6 +98,8 @@ class InspectorImpl : public IInspector { int nextPageId_{1}; std::map pages_; std::list> listeners_; + InspectorSystemState systemState_{0}; + std::shared_ptr systemStateListener_; }; InspectorImpl::Page::Page( @@ -116,6 +142,12 @@ int InspectorImpl::addPage( pageId, Page{pageId, description, vm, std::move(connectFunc), capabilities}); + for (const auto& listenerWeak : listeners_) { + if (auto listener = listenerWeak.lock()) { + listener->onPageAdded(pageId); + } + } + return pageId; } @@ -175,6 +207,11 @@ void InspectorImpl::registerPageStatusListener( } listeners_.push_back(listener); } + +InspectorSystemState InspectorImpl::getSystemState() const { + std::scoped_lock lock(mutex_); + return systemState_; +} } // namespace IInspector& getInspectorInstance() { diff --git a/packages/react-native/ReactCommon/jsinspector-modern/InspectorInterfaces.h b/packages/react-native/ReactCommon/jsinspector-modern/InspectorInterfaces.h index 04e45131e5e7..3117b216ac2d 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/InspectorInterfaces.h +++ b/packages/react-native/ReactCommon/jsinspector-modern/InspectorInterfaces.h @@ -51,6 +51,11 @@ struct InspectorPageDescription { // Alias for backwards compatibility. using InspectorPage = InspectorPageDescription; +struct InspectorSystemState { + /** The total count of pages registered during the app lifetime. */ + int registeredPagesCount; +}; + /// IRemoteConnection allows the VM to send debugger messages to the client. /// IRemoteConnection's methods are safe to call from any thread *if* /// InspectorPackagerConnection.cpp is in use. @@ -78,7 +83,8 @@ class JSINSPECTOR_EXPORT ILocalConnection : public IDestructible { class JSINSPECTOR_EXPORT IPageStatusListener : public IDestructible { public: virtual ~IPageStatusListener() = 0; - virtual void onPageRemoved(int pageId) = 0; + virtual void onPageAdded(int /*pageId*/) {} + virtual void onPageRemoved(int /*pageId*/) {} }; /// IInspector tracks debuggable JavaScript targets (pages). @@ -127,6 +133,11 @@ class JSINSPECTOR_EXPORT IInspector : public IDestructible { * when pages are removed. */ virtual void registerPageStatusListener(std::weak_ptr listener) = 0; + + /** + * Get the current \c InspectorSystemState object. + */ + virtual InspectorSystemState getSystemState() const = 0; }; class NotImplementedException : public std::exception { diff --git a/packages/react-native/ReactCommon/jsinspector-modern/TracingAgent.cpp b/packages/react-native/ReactCommon/jsinspector-modern/TracingAgent.cpp index ee4942bc02c5..9ed49254f63d 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/TracingAgent.cpp +++ b/packages/react-native/ReactCommon/jsinspector-modern/TracingAgent.cpp @@ -49,6 +49,17 @@ TracingAgent::~TracingAgent() { bool TracingAgent::handleRequest(const cdp::PreparsedRequest& req) { if (req.method == "Tracing.start") { + auto& inspector = getInspectorInstance(); + if (inspector.getSystemState().registeredPagesCount > 1) { + frontendChannel_( + cdp::jsonError( + req.id, + cdp::ErrorCode::InternalError, + "The Tracing domain is unavailable when multiple React Native hosts are registered.")); + + return true; + } + if (sessionState_.isDebuggerDomainEnabled) { frontendChannel_( cdp::jsonError( diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp index c3adaa661754..eab3bf4e14f3 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<> */ /** @@ -246,6 +246,10 @@ bool ReactNativeFeatureFlags::fixMappingOfEventPrioritiesBetweenFabricAndReact() return getAccessor().fixMappingOfEventPrioritiesBetweenFabricAndReact(); } +bool ReactNativeFeatureFlags::fuseboxAssertSingleHostState() { + return getAccessor().fuseboxAssertSingleHostState(); +} + bool ReactNativeFeatureFlags::fuseboxEnabledRelease() { return getAccessor().fuseboxEnabledRelease(); } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h index 5a46288842e9..b4c4eadcdaa9 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<<467f48f2231ceb6772a9a9da9e3badb9>> + * @generated SignedSource<<6fdcfc50aba88a432b35083ab96c3844>> */ /** @@ -314,6 +314,11 @@ class ReactNativeFeatureFlags { */ RN_EXPORT static bool fixMappingOfEventPrioritiesBetweenFabricAndReact(); + /** + * Enable system assertion validating that Fusebox is configured with a single host. When set, the CDP backend will dynamically disable features (Perf and Network) in the event that multiple hosts are registered (undefined behaviour), and broadcast this over `ReactNativeApplication.systemStateChanged`. + */ + RN_EXPORT static bool fuseboxAssertSingleHostState(); + /** * Flag determining if the React Native DevTools (Fusebox) CDP backend should be enabled in release builds. This flag is global and should not be changed across React Host lifetimes. */ diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp index 7093ce280a74..0da7a8c891b0 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<<8f6640b5dc86a3f50b14ba9d222de89c>> + * @generated SignedSource<<2c76b98618bad8b17782632dc0fa1b46>> */ /** @@ -1019,6 +1019,24 @@ bool ReactNativeFeatureFlagsAccessor::fixMappingOfEventPrioritiesBetweenFabricAn return flagValue.value(); } +bool ReactNativeFeatureFlagsAccessor::fuseboxAssertSingleHostState() { + auto flagValue = fuseboxAssertSingleHostState_.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(55, "fuseboxAssertSingleHostState"); + + flagValue = currentProvider_->fuseboxAssertSingleHostState(); + fuseboxAssertSingleHostState_ = flagValue; + } + + return flagValue.value(); +} + bool ReactNativeFeatureFlagsAccessor::fuseboxEnabledRelease() { auto flagValue = fuseboxEnabledRelease_.load(); @@ -1028,7 +1046,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(55, "fuseboxEnabledRelease"); + markFlagAsAccessed(56, "fuseboxEnabledRelease"); flagValue = currentProvider_->fuseboxEnabledRelease(); fuseboxEnabledRelease_ = flagValue; @@ -1046,7 +1064,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(56, "fuseboxNetworkInspectionEnabled"); + markFlagAsAccessed(57, "fuseboxNetworkInspectionEnabled"); flagValue = currentProvider_->fuseboxNetworkInspectionEnabled(); fuseboxNetworkInspectionEnabled_ = flagValue; @@ -1064,7 +1082,7 @@ bool ReactNativeFeatureFlagsAccessor::hideOffscreenVirtualViewsOnIOS() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(57, "hideOffscreenVirtualViewsOnIOS"); + markFlagAsAccessed(58, "hideOffscreenVirtualViewsOnIOS"); flagValue = currentProvider_->hideOffscreenVirtualViewsOnIOS(); hideOffscreenVirtualViewsOnIOS_ = flagValue; @@ -1082,7 +1100,7 @@ bool ReactNativeFeatureFlagsAccessor::overrideBySynchronousMountPropsAtMountingA // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(58, "overrideBySynchronousMountPropsAtMountingAndroid"); + markFlagAsAccessed(59, "overrideBySynchronousMountPropsAtMountingAndroid"); flagValue = currentProvider_->overrideBySynchronousMountPropsAtMountingAndroid(); overrideBySynchronousMountPropsAtMountingAndroid_ = flagValue; @@ -1100,7 +1118,7 @@ bool ReactNativeFeatureFlagsAccessor::perfIssuesEnabled() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(59, "perfIssuesEnabled"); + markFlagAsAccessed(60, "perfIssuesEnabled"); flagValue = currentProvider_->perfIssuesEnabled(); perfIssuesEnabled_ = flagValue; @@ -1118,7 +1136,7 @@ bool ReactNativeFeatureFlagsAccessor::perfMonitorV2Enabled() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(60, "perfMonitorV2Enabled"); + markFlagAsAccessed(61, "perfMonitorV2Enabled"); flagValue = currentProvider_->perfMonitorV2Enabled(); perfMonitorV2Enabled_ = flagValue; @@ -1136,7 +1154,7 @@ double ReactNativeFeatureFlagsAccessor::preparedTextCacheSize() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(61, "preparedTextCacheSize"); + markFlagAsAccessed(62, "preparedTextCacheSize"); flagValue = currentProvider_->preparedTextCacheSize(); preparedTextCacheSize_ = flagValue; @@ -1154,7 +1172,7 @@ bool ReactNativeFeatureFlagsAccessor::preventShadowTreeCommitExhaustion() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(62, "preventShadowTreeCommitExhaustion"); + markFlagAsAccessed(63, "preventShadowTreeCommitExhaustion"); flagValue = currentProvider_->preventShadowTreeCommitExhaustion(); preventShadowTreeCommitExhaustion_ = flagValue; @@ -1172,7 +1190,7 @@ bool ReactNativeFeatureFlagsAccessor::shouldPressibilityUseW3CPointerEventsForHo // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(63, "shouldPressibilityUseW3CPointerEventsForHover"); + markFlagAsAccessed(64, "shouldPressibilityUseW3CPointerEventsForHover"); flagValue = currentProvider_->shouldPressibilityUseW3CPointerEventsForHover(); shouldPressibilityUseW3CPointerEventsForHover_ = flagValue; @@ -1190,7 +1208,7 @@ bool ReactNativeFeatureFlagsAccessor::shouldTriggerResponderTransferOnScrollAndr // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(64, "shouldTriggerResponderTransferOnScrollAndroid"); + markFlagAsAccessed(65, "shouldTriggerResponderTransferOnScrollAndroid"); flagValue = currentProvider_->shouldTriggerResponderTransferOnScrollAndroid(); shouldTriggerResponderTransferOnScrollAndroid_ = flagValue; @@ -1208,7 +1226,7 @@ bool ReactNativeFeatureFlagsAccessor::skipActivityIdentityAssertionOnHostPause() // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(65, "skipActivityIdentityAssertionOnHostPause"); + markFlagAsAccessed(66, "skipActivityIdentityAssertionOnHostPause"); flagValue = currentProvider_->skipActivityIdentityAssertionOnHostPause(); skipActivityIdentityAssertionOnHostPause_ = flagValue; @@ -1226,7 +1244,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(66, "traceTurboModulePromiseRejectionsOnAndroid"); + markFlagAsAccessed(67, "traceTurboModulePromiseRejectionsOnAndroid"); flagValue = currentProvider_->traceTurboModulePromiseRejectionsOnAndroid(); traceTurboModulePromiseRejectionsOnAndroid_ = flagValue; @@ -1244,7 +1262,7 @@ bool ReactNativeFeatureFlagsAccessor::updateRuntimeShadowNodeReferencesOnCommit( // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(67, "updateRuntimeShadowNodeReferencesOnCommit"); + markFlagAsAccessed(68, "updateRuntimeShadowNodeReferencesOnCommit"); flagValue = currentProvider_->updateRuntimeShadowNodeReferencesOnCommit(); updateRuntimeShadowNodeReferencesOnCommit_ = flagValue; @@ -1262,7 +1280,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(68, "useAlwaysAvailableJSErrorHandling"); + markFlagAsAccessed(69, "useAlwaysAvailableJSErrorHandling"); flagValue = currentProvider_->useAlwaysAvailableJSErrorHandling(); useAlwaysAvailableJSErrorHandling_ = flagValue; @@ -1280,7 +1298,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(69, "useFabricInterop"); + markFlagAsAccessed(70, "useFabricInterop"); flagValue = currentProvider_->useFabricInterop(); useFabricInterop_ = flagValue; @@ -1298,7 +1316,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeEqualsInNativeReadableArrayAndroi // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(70, "useNativeEqualsInNativeReadableArrayAndroid"); + markFlagAsAccessed(71, "useNativeEqualsInNativeReadableArrayAndroid"); flagValue = currentProvider_->useNativeEqualsInNativeReadableArrayAndroid(); useNativeEqualsInNativeReadableArrayAndroid_ = flagValue; @@ -1316,7 +1334,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeTransformHelperAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(71, "useNativeTransformHelperAndroid"); + markFlagAsAccessed(72, "useNativeTransformHelperAndroid"); flagValue = currentProvider_->useNativeTransformHelperAndroid(); useNativeTransformHelperAndroid_ = flagValue; @@ -1334,7 +1352,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(72, "useNativeViewConfigsInBridgelessMode"); + markFlagAsAccessed(73, "useNativeViewConfigsInBridgelessMode"); flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode(); useNativeViewConfigsInBridgelessMode_ = flagValue; @@ -1352,7 +1370,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(73, "useRawPropsJsiValue"); + markFlagAsAccessed(74, "useRawPropsJsiValue"); flagValue = currentProvider_->useRawPropsJsiValue(); useRawPropsJsiValue_ = flagValue; @@ -1370,7 +1388,7 @@ bool ReactNativeFeatureFlagsAccessor::useShadowNodeStateOnClone() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(74, "useShadowNodeStateOnClone"); + markFlagAsAccessed(75, "useShadowNodeStateOnClone"); flagValue = currentProvider_->useShadowNodeStateOnClone(); useShadowNodeStateOnClone_ = flagValue; @@ -1388,7 +1406,7 @@ bool ReactNativeFeatureFlagsAccessor::useSharedAnimatedBackend() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(75, "useSharedAnimatedBackend"); + markFlagAsAccessed(76, "useSharedAnimatedBackend"); flagValue = currentProvider_->useSharedAnimatedBackend(); useSharedAnimatedBackend_ = flagValue; @@ -1406,7 +1424,7 @@ bool ReactNativeFeatureFlagsAccessor::useTraitHiddenOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(76, "useTraitHiddenOnAndroid"); + markFlagAsAccessed(77, "useTraitHiddenOnAndroid"); flagValue = currentProvider_->useTraitHiddenOnAndroid(); useTraitHiddenOnAndroid_ = flagValue; @@ -1424,7 +1442,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(77, "useTurboModuleInterop"); + markFlagAsAccessed(78, "useTurboModuleInterop"); flagValue = currentProvider_->useTurboModuleInterop(); useTurboModuleInterop_ = flagValue; @@ -1442,7 +1460,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(78, "useTurboModules"); + markFlagAsAccessed(79, "useTurboModules"); flagValue = currentProvider_->useTurboModules(); useTurboModules_ = flagValue; @@ -1460,7 +1478,7 @@ double ReactNativeFeatureFlagsAccessor::viewCullingOutsetRatio() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(79, "viewCullingOutsetRatio"); + markFlagAsAccessed(80, "viewCullingOutsetRatio"); flagValue = currentProvider_->viewCullingOutsetRatio(); viewCullingOutsetRatio_ = flagValue; @@ -1478,7 +1496,7 @@ double ReactNativeFeatureFlagsAccessor::virtualViewHysteresisRatio() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(80, "virtualViewHysteresisRatio"); + markFlagAsAccessed(81, "virtualViewHysteresisRatio"); flagValue = currentProvider_->virtualViewHysteresisRatio(); virtualViewHysteresisRatio_ = flagValue; @@ -1496,7 +1514,7 @@ double ReactNativeFeatureFlagsAccessor::virtualViewPrerenderRatio() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(81, "virtualViewPrerenderRatio"); + markFlagAsAccessed(82, "virtualViewPrerenderRatio"); flagValue = currentProvider_->virtualViewPrerenderRatio(); virtualViewPrerenderRatio_ = flagValue; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h index b626cc49c70c..35e35c0efaeb 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<> */ /** @@ -87,6 +87,7 @@ class ReactNativeFeatureFlagsAccessor { bool enableVirtualViewWindowFocusDetection(); bool enableWebPerformanceAPIsByDefault(); bool fixMappingOfEventPrioritiesBetweenFabricAndReact(); + bool fuseboxAssertSingleHostState(); bool fuseboxEnabledRelease(); bool fuseboxNetworkInspectionEnabled(); bool hideOffscreenVirtualViewsOnIOS(); @@ -125,7 +126,7 @@ class ReactNativeFeatureFlagsAccessor { std::unique_ptr currentProvider_; bool wasOverridden_; - std::array, 82> accessedFeatureFlags_; + std::array, 83> accessedFeatureFlags_; std::atomic> commonTestFlag_; std::atomic> cdpInteractionMetricsEnabled_; @@ -182,6 +183,7 @@ class ReactNativeFeatureFlagsAccessor { std::atomic> enableVirtualViewWindowFocusDetection_; std::atomic> enableWebPerformanceAPIsByDefault_; std::atomic> fixMappingOfEventPrioritiesBetweenFabricAndReact_; + std::atomic> fuseboxAssertSingleHostState_; std::atomic> fuseboxEnabledRelease_; std::atomic> fuseboxNetworkInspectionEnabled_; std::atomic> hideOffscreenVirtualViewsOnIOS_; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index 32aecdc212e3..56364605fe2a 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<<85c260dcb8eb9209a53207c3c54183f0>> + * @generated SignedSource<> */ /** @@ -247,6 +247,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { return false; } + bool fuseboxAssertSingleHostState() override { + return true; + } + bool fuseboxEnabledRelease() override { return false; } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h index 34ce8c68d0c7..a0a9bb21a870 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.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<<0224a638fbec556a62c58f5d84c4c662>> + * @generated SignedSource<> */ /** @@ -540,6 +540,15 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef return ReactNativeFeatureFlagsDefaults::fixMappingOfEventPrioritiesBetweenFabricAndReact(); } + bool fuseboxAssertSingleHostState() override { + auto value = values_["fuseboxAssertSingleHostState"]; + if (!value.isNull()) { + return value.getBool(); + } + + return ReactNativeFeatureFlagsDefaults::fuseboxAssertSingleHostState(); + } + bool fuseboxEnabledRelease() override { auto value = values_["fuseboxEnabledRelease"]; if (!value.isNull()) { diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h index f2dcc71af4ec..3105f8e2bacf 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<> */ /** @@ -80,6 +80,7 @@ class ReactNativeFeatureFlagsProvider { virtual bool enableVirtualViewWindowFocusDetection() = 0; virtual bool enableWebPerformanceAPIsByDefault() = 0; virtual bool fixMappingOfEventPrioritiesBetweenFabricAndReact() = 0; + virtual bool fuseboxAssertSingleHostState() = 0; virtual bool fuseboxEnabledRelease() = 0; virtual bool fuseboxNetworkInspectionEnabled() = 0; virtual bool hideOffscreenVirtualViewsOnIOS() = 0; diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp index 05c867b7f714..3599dac5daf3 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<> + * @generated SignedSource<> */ /** @@ -319,6 +319,11 @@ bool NativeReactNativeFeatureFlags::fixMappingOfEventPrioritiesBetweenFabricAndR return ReactNativeFeatureFlags::fixMappingOfEventPrioritiesBetweenFabricAndReact(); } +bool NativeReactNativeFeatureFlags::fuseboxAssertSingleHostState( + jsi::Runtime& /*runtime*/) { + return ReactNativeFeatureFlags::fuseboxAssertSingleHostState(); +} + bool NativeReactNativeFeatureFlags::fuseboxEnabledRelease( jsi::Runtime& /*runtime*/) { return ReactNativeFeatureFlags::fuseboxEnabledRelease(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h index cd406e004de4..6b4e0a48dadd 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<<0d898a94decb43e191a343676c8afb91>> + * @generated SignedSource<> */ /** @@ -146,6 +146,8 @@ class NativeReactNativeFeatureFlags bool fixMappingOfEventPrioritiesBetweenFabricAndReact(jsi::Runtime& runtime); + bool fuseboxAssertSingleHostState(jsi::Runtime& runtime); + bool fuseboxEnabledRelease(jsi::Runtime& runtime); bool fuseboxNetworkInspectionEnabled(jsi::Runtime& runtime); diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index 6388b73719a7..e875eb561b89 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -634,6 +634,16 @@ const definitions: FeatureFlagDefinitions = { }, ossReleaseStage: 'none', }, + fuseboxAssertSingleHostState: { + defaultValue: true, + metadata: { + description: + 'Enable system assertion validating that Fusebox is configured with a single host. When set, the CDP backend will dynamically disable features (Perf and Network) in the event that multiple hosts are registered (undefined behaviour), and broadcast this over `ReactNativeApplication.systemStateChanged`.', + expectedReleaseValue: true, + purpose: 'operational', + }, + ossReleaseStage: 'stable', + }, fuseboxEnabledRelease: { defaultValue: false, metadata: { diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index aa7c52f4a1b2..3334c3766952 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 * @noformat */ @@ -105,6 +105,7 @@ export type ReactNativeFeatureFlags = $ReadOnly<{ enableVirtualViewWindowFocusDetection: Getter, enableWebPerformanceAPIsByDefault: Getter, fixMappingOfEventPrioritiesBetweenFabricAndReact: Getter, + fuseboxAssertSingleHostState: Getter, fuseboxEnabledRelease: Getter, fuseboxNetworkInspectionEnabled: Getter, hideOffscreenVirtualViewsOnIOS: Getter, @@ -433,6 +434,10 @@ export const enableWebPerformanceAPIsByDefault: Getter = createNativeFl * Uses the default event priority instead of the discreet event priority by default when dispatching events from Fabric to React. */ export const fixMappingOfEventPrioritiesBetweenFabricAndReact: Getter = createNativeFlagGetter('fixMappingOfEventPrioritiesBetweenFabricAndReact', false); +/** + * Enable system assertion validating that Fusebox is configured with a single host. When set, the CDP backend will dynamically disable features (Perf and Network) in the event that multiple hosts are registered (undefined behaviour), and broadcast this over `ReactNativeApplication.systemStateChanged`. + */ +export const fuseboxAssertSingleHostState: Getter = createNativeFlagGetter('fuseboxAssertSingleHostState', true); /** * Flag determining if the React Native DevTools (Fusebox) CDP backend should be enabled in release builds. This flag is global and should not be changed across React Host lifetimes. */ diff --git a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js index 218586e3e244..8858f48afdf6 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<<53fc9aca82f76eb0519b03187993359a>> + * @generated SignedSource<<0bd1151b93fcc3a7ab6572f48d31b3cf>> * @flow strict * @noformat */ @@ -80,6 +80,7 @@ export interface Spec extends TurboModule { +enableVirtualViewWindowFocusDetection?: () => boolean; +enableWebPerformanceAPIsByDefault?: () => boolean; +fixMappingOfEventPrioritiesBetweenFabricAndReact?: () => boolean; + +fuseboxAssertSingleHostState?: () => boolean; +fuseboxEnabledRelease?: () => boolean; +fuseboxNetworkInspectionEnabled?: () => boolean; +hideOffscreenVirtualViewsOnIOS?: () => boolean;