Skip to content

Commit d1944f1

Browse files
huntiemeta-codesync[bot]
authored andcommitted
Add single host inspector state assertion over CDP (#54407)
Summary: Pull Request resolved: #54407 Introduces a new `InspectorSystemState` object and `ReactNativeApplication.systemStateChanged` CDP event, used to assert whether more than one React Native Host has been registered for the current app lifetime. This will be used to disable the Performance and Network features in React Native DevTools when the debugger backend is in this currently unsupported state. We intend to implement host lifecycle correctness across all features soon. Changelog: [Internal] Reviewed By: cipolleschi Differential Revision: D86201689 fbshipit-source-id: b8525359fc01eb7ae666879f2c0fd4c94f0af81a
1 parent 45024a5 commit d1944f1

27 files changed

+258
-48
lines changed

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<01feab16132bc07b79b359178e322327>>
7+
* @generated SignedSource<<862c5a78fec94408ca78ef2349627a02>>
88
*/
99

1010
/**
@@ -372,6 +372,12 @@ public object ReactNativeFeatureFlags {
372372
@JvmStatic
373373
public fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean = accessor.fixMappingOfEventPrioritiesBetweenFabricAndReact()
374374

375+
/**
376+
* 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`.
377+
*/
378+
@JvmStatic
379+
public fun fuseboxAssertSingleHostState(): Boolean = accessor.fuseboxAssertSingleHostState()
380+
375381
/**
376382
* 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.
377383
*/

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<405bf283e4631e166cd57f5dfe30d5f9>>
7+
* @generated SignedSource<<67b008ecdc29278a7019f60e24673fc1>>
88
*/
99

1010
/**
@@ -77,6 +77,7 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
7777
private var enableVirtualViewWindowFocusDetectionCache: Boolean? = null
7878
private var enableWebPerformanceAPIsByDefaultCache: Boolean? = null
7979
private var fixMappingOfEventPrioritiesBetweenFabricAndReactCache: Boolean? = null
80+
private var fuseboxAssertSingleHostStateCache: Boolean? = null
8081
private var fuseboxEnabledReleaseCache: Boolean? = null
8182
private var fuseboxNetworkInspectionEnabledCache: Boolean? = null
8283
private var hideOffscreenVirtualViewsOnIOSCache: Boolean? = null
@@ -618,6 +619,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
618619
return cached
619620
}
620621

622+
override fun fuseboxAssertSingleHostState(): Boolean {
623+
var cached = fuseboxAssertSingleHostStateCache
624+
if (cached == null) {
625+
cached = ReactNativeFeatureFlagsCxxInterop.fuseboxAssertSingleHostState()
626+
fuseboxAssertSingleHostStateCache = cached
627+
}
628+
return cached
629+
}
630+
621631
override fun fuseboxEnabledRelease(): Boolean {
622632
var cached = fuseboxEnabledReleaseCache
623633
if (cached == null) {

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<bffd645aa55b941acff92ca4efe6192a>>
7+
* @generated SignedSource<<553d71b2c9e8e89b2e5d48723f3009b4>>
88
*/
99

1010
/**
@@ -142,6 +142,8 @@ public object ReactNativeFeatureFlagsCxxInterop {
142142

143143
@DoNotStrip @JvmStatic public external fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean
144144

145+
@DoNotStrip @JvmStatic public external fun fuseboxAssertSingleHostState(): Boolean
146+
145147
@DoNotStrip @JvmStatic public external fun fuseboxEnabledRelease(): Boolean
146148

147149
@DoNotStrip @JvmStatic public external fun fuseboxNetworkInspectionEnabled(): Boolean

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<a25d191472f7777804175ef9f56521d6>>
7+
* @generated SignedSource<<bf1a3a96ae311f186f7fffacc466407e>>
88
*/
99

1010
/**
@@ -137,6 +137,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
137137

138138
override fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean = false
139139

140+
override fun fuseboxAssertSingleHostState(): Boolean = true
141+
140142
override fun fuseboxEnabledRelease(): Boolean = false
141143

142144
override fun fuseboxNetworkInspectionEnabled(): Boolean = false

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<e8531e8c374d0ea1e604a2f3d5000078>>
7+
* @generated SignedSource<<7a2517498558f2c0f69831d5466ddec3>>
88
*/
99

1010
/**
@@ -81,6 +81,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
8181
private var enableVirtualViewWindowFocusDetectionCache: Boolean? = null
8282
private var enableWebPerformanceAPIsByDefaultCache: Boolean? = null
8383
private var fixMappingOfEventPrioritiesBetweenFabricAndReactCache: Boolean? = null
84+
private var fuseboxAssertSingleHostStateCache: Boolean? = null
8485
private var fuseboxEnabledReleaseCache: Boolean? = null
8586
private var fuseboxNetworkInspectionEnabledCache: Boolean? = null
8687
private var hideOffscreenVirtualViewsOnIOSCache: Boolean? = null
@@ -679,6 +680,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
679680
return cached
680681
}
681682

683+
override fun fuseboxAssertSingleHostState(): Boolean {
684+
var cached = fuseboxAssertSingleHostStateCache
685+
if (cached == null) {
686+
cached = currentProvider.fuseboxAssertSingleHostState()
687+
accessedFeatureFlags.add("fuseboxAssertSingleHostState")
688+
fuseboxAssertSingleHostStateCache = cached
689+
}
690+
return cached
691+
}
692+
682693
override fun fuseboxEnabledRelease(): Boolean {
683694
var cached = fuseboxEnabledReleaseCache
684695
if (cached == null) {

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<2325f5410537941e25998ca8c59bf51d>>
7+
* @generated SignedSource<<0efef5db3ded62f312486ac2fb04bcdb>>
88
*/
99

1010
/**
@@ -137,6 +137,8 @@ public interface ReactNativeFeatureFlagsProvider {
137137

138138
@DoNotStrip public fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean
139139

140+
@DoNotStrip public fun fuseboxAssertSingleHostState(): Boolean
141+
140142
@DoNotStrip public fun fuseboxEnabledRelease(): Boolean
141143

142144
@DoNotStrip public fun fuseboxNetworkInspectionEnabled(): Boolean

packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<95ebd4929bf0f98aa059ad4b8139f7b3>>
7+
* @generated SignedSource<<09f32ad880a470e45d3e5ba67a6e5831>>
88
*/
99

1010
/**
@@ -381,6 +381,12 @@ class ReactNativeFeatureFlagsJavaProvider
381381
return method(javaProvider_);
382382
}
383383

384+
bool fuseboxAssertSingleHostState() override {
385+
static const auto method =
386+
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("fuseboxAssertSingleHostState");
387+
return method(javaProvider_);
388+
}
389+
384390
bool fuseboxEnabledRelease() override {
385391
static const auto method =
386392
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("fuseboxEnabledRelease");
@@ -832,6 +838,11 @@ bool JReactNativeFeatureFlagsCxxInterop::fixMappingOfEventPrioritiesBetweenFabri
832838
return ReactNativeFeatureFlags::fixMappingOfEventPrioritiesBetweenFabricAndReact();
833839
}
834840

841+
bool JReactNativeFeatureFlagsCxxInterop::fuseboxAssertSingleHostState(
842+
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
843+
return ReactNativeFeatureFlags::fuseboxAssertSingleHostState();
844+
}
845+
835846
bool JReactNativeFeatureFlagsCxxInterop::fuseboxEnabledRelease(
836847
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
837848
return ReactNativeFeatureFlags::fuseboxEnabledRelease();
@@ -1169,6 +1180,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
11691180
makeNativeMethod(
11701181
"fixMappingOfEventPrioritiesBetweenFabricAndReact",
11711182
JReactNativeFeatureFlagsCxxInterop::fixMappingOfEventPrioritiesBetweenFabricAndReact),
1183+
makeNativeMethod(
1184+
"fuseboxAssertSingleHostState",
1185+
JReactNativeFeatureFlagsCxxInterop::fuseboxAssertSingleHostState),
11721186
makeNativeMethod(
11731187
"fuseboxEnabledRelease",
11741188
JReactNativeFeatureFlagsCxxInterop::fuseboxEnabledRelease),

packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<155f615584a7738dc5b89205c2ecad8b>>
7+
* @generated SignedSource<<414ebc294bc434bdf5f9eca094eac268>>
88
*/
99

1010
/**
@@ -201,6 +201,9 @@ class JReactNativeFeatureFlagsCxxInterop
201201
static bool fixMappingOfEventPrioritiesBetweenFabricAndReact(
202202
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
203203

204+
static bool fuseboxAssertSingleHostState(
205+
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
206+
204207
static bool fuseboxEnabledRelease(
205208
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
206209

packages/react-native/ReactCommon/jsinspector-modern/HostAgent.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
1212
#include "InspectorFlags.h"
13+
#include "InspectorInterfaces.h"
1314
#include "NetworkIOAgent.h"
1415
#include "SessionState.h"
1516
#include "TracingAgent.h"
@@ -216,6 +217,11 @@ class HostAgent::Impl final {
216217
cdp::jsonNotification(
217218
"ReactNativeApplication.metadataUpdated",
218219
createHostMetadataPayload(hostMetadata_)));
220+
auto& inspector = getInspectorInstance();
221+
bool isSingleHost = inspector.getSystemState().registeredPagesCount <= 1;
222+
if (!isSingleHost) {
223+
emitSystemStateChanged(isSingleHost);
224+
}
219225

220226
auto stashedTraceRecording =
221227
targetController_.getDelegate()
@@ -374,6 +380,17 @@ class HostAgent::Impl final {
374380
tracingAgent_.emitExternalTraceRecording(std::move(traceRecording));
375381
}
376382

383+
void emitSystemStateChanged(bool isSingleHost) {
384+
frontendChannel_(
385+
cdp::jsonNotification(
386+
"ReactNativeApplication.systemStateChanged",
387+
folly::dynamic::object("isSingleHost", isSingleHost)));
388+
389+
if (!isSingleHost) {
390+
frontendChannel_(cdp::jsonNotification("Network.disable"));
391+
}
392+
}
393+
377394
private:
378395
enum class FuseboxClientType { Unknown, Fusebox, NonFusebox };
379396

@@ -480,6 +497,7 @@ class HostAgent::Impl final {
480497
}
481498
void emitExternalTraceRecording(tracing::TraceRecordingState traceRecording) {
482499
}
500+
void emitSystemStateChanged(bool isSingleHost) {}
483501
};
484502

485503
#endif // REACT_NATIVE_DEBUGGER_ENABLED
@@ -519,6 +537,10 @@ void HostAgent::emitExternalTraceRecording(
519537
impl_->emitExternalTraceRecording(std::move(traceRecording));
520538
}
521539

540+
void HostAgent::emitSystemStateChanged(bool isSingleHost) const {
541+
impl_->emitSystemStateChanged(isSingleHost);
542+
}
543+
522544
#pragma mark - Tracing
523545

524546
HostTracingAgent::HostTracingAgent(tracing::TraceRecordingState& state)

packages/react-native/ReactCommon/jsinspector-modern/HostAgent.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ class HostAgent final {
7979
*/
8080
void emitExternalTraceRecording(tracing::TraceRecordingState traceRecording) const;
8181

82+
/**
83+
* Emits a system state changed event when the number of ReactHost instances
84+
* changes.
85+
*/
86+
void emitSystemStateChanged(bool isSingleHost) const;
87+
8288
private:
8389
// We use the private implementation idiom to ensure this class has the same
8490
// layout regardless of whether REACT_NATIVE_DEBUGGER_ENABLED is defined. The

0 commit comments

Comments
 (0)