react-native 0.83.4 → 0.83.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Libraries/Core/ReactNativeVersion.js +1 -1
- package/Libraries/Utilities/Appearance.js +6 -1
- package/Libraries/Utilities/HMRClient.js +28 -1
- package/React/Base/RCTVersion.m +1 -1
- package/React/CoreModules/RCTDevLoadingView.mm +17 -0
- package/React/DevSupport/RCTFrameTimingsObserver.h +24 -0
- package/React/DevSupport/RCTFrameTimingsObserver.mm +298 -0
- package/React/FBReactNativeSpec/FBReactNativeSpecJSI.h +16 -0
- package/ReactAndroid/api/ReactAndroid.api +0 -9
- package/ReactAndroid/gradle.properties +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/BridgelessDevSupportManager.kt +2 -2
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerBase.kt +7 -7
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/InspectorFlags.kt +4 -0
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/FrameTimingSequence.kt +16 -0
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/FrameTimingsObserver.kt +275 -0
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/TracingState.kt +17 -0
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/TracingStateListener.kt +15 -0
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/{interfaces → inspector}/TracingStateProvider.kt +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/perfmonitor/PerfMonitorInspectorTargetBinding.kt +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/perfmonitor/PerfMonitorOverlayManager.kt +4 -4
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/perfmonitor/PerfMonitorOverlayView.kt +3 -3
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/perfmonitor/PerfMonitorUpdateListener.kt +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt +13 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt +21 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt +5 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +5 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt +23 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt +5 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/tracing/PerformanceTracer.kt +39 -0
- package/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.kt +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkEventUtil.kt +20 -19
- package/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.kt +6 -12
- package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.kt +86 -4
- package/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImplDevHelper.kt +3 -3
- package/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostInspectorTarget.kt +10 -6
- package/ReactAndroid/src/main/jni/react/devsupport/JInspectorFlags.cpp +22 -0
- package/ReactAndroid/src/main/jni/react/devsupport/JInspectorFlags.h +2 -0
- package/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp +29 -1
- package/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h +7 -1
- package/ReactAndroid/src/main/jni/react/runtime/jni/JReactHostInspectorTarget.cpp +196 -17
- package/ReactAndroid/src/main/jni/react/runtime/jni/JReactHostInspectorTarget.h +168 -18
- package/ReactAndroid/src/main/jni/third-party/folly/CMakeLists.txt +1 -0
- package/ReactCommon/cxxreact/ReactNativeVersion.h +2 -2
- package/ReactCommon/hermes/inspector-modern/chrome/Registration.cpp +44 -2
- package/ReactCommon/jsinspector-modern/HostAgent.cpp +45 -10
- package/ReactCommon/jsinspector-modern/HostAgent.h +2 -2
- package/ReactCommon/jsinspector-modern/HostTarget.cpp +14 -7
- package/ReactCommon/jsinspector-modern/HostTarget.h +101 -14
- package/ReactCommon/jsinspector-modern/HostTargetTraceRecording.cpp +39 -8
- package/ReactCommon/jsinspector-modern/HostTargetTraceRecording.h +42 -5
- package/ReactCommon/jsinspector-modern/HostTargetTracing.cpp +54 -21
- package/ReactCommon/jsinspector-modern/HostTargetTracing.h +89 -0
- package/ReactCommon/jsinspector-modern/InspectorFlags.cpp +12 -0
- package/ReactCommon/jsinspector-modern/InspectorFlags.h +12 -0
- package/ReactCommon/jsinspector-modern/InspectorInterfaces.cpp +3 -7
- package/ReactCommon/jsinspector-modern/InstanceAgent.cpp +2 -11
- package/ReactCommon/jsinspector-modern/NetworkIOAgent.cpp +1 -1
- package/ReactCommon/jsinspector-modern/RuntimeAgent.cpp +19 -0
- package/ReactCommon/jsinspector-modern/RuntimeAgent.h +7 -0
- package/ReactCommon/jsinspector-modern/RuntimeTarget.cpp +33 -0
- package/ReactCommon/jsinspector-modern/RuntimeTarget.h +6 -0
- package/ReactCommon/jsinspector-modern/TracingAgent.cpp +29 -13
- package/ReactCommon/jsinspector-modern/TracingAgent.h +5 -4
- package/ReactCommon/jsinspector-modern/tests/HostTargetTest.cpp +65 -0
- package/ReactCommon/jsinspector-modern/tests/InspectorMocks.h +23 -2
- package/ReactCommon/jsinspector-modern/tests/JsiIntegrationTest.cpp +1 -0
- package/ReactCommon/jsinspector-modern/tests/NetworkReporterTest.cpp +1 -0
- package/ReactCommon/jsinspector-modern/tests/TracingTest.cpp +335 -0
- package/ReactCommon/jsinspector-modern/tests/TracingTest.h +95 -0
- package/ReactCommon/jsinspector-modern/tests/utils/InspectorFlagOverridesGuard.cpp +10 -0
- package/ReactCommon/jsinspector-modern/tests/utils/InspectorFlagOverridesGuard.h +3 -1
- package/ReactCommon/jsinspector-modern/tracing/CMakeLists.txt +1 -0
- package/ReactCommon/jsinspector-modern/tracing/FrameTimingSequence.h +61 -0
- package/ReactCommon/jsinspector-modern/tracing/HostTracingProfile.h +43 -0
- package/ReactCommon/jsinspector-modern/tracing/HostTracingProfileSerializer.cpp +165 -0
- package/ReactCommon/jsinspector-modern/tracing/HostTracingProfileSerializer.h +50 -0
- package/ReactCommon/jsinspector-modern/tracing/PerformanceTracer.cpp +16 -14
- package/ReactCommon/jsinspector-modern/tracing/PerformanceTracerSection.h +113 -0
- package/ReactCommon/jsinspector-modern/tracing/React-jsinspectortracing.podspec +1 -0
- package/ReactCommon/jsinspector-modern/tracing/TimeWindowedBuffer.h +158 -0
- package/ReactCommon/jsinspector-modern/tracing/TraceEvent.h +2 -1
- package/ReactCommon/jsinspector-modern/tracing/TraceEventGenerator.cpp +100 -0
- package/ReactCommon/jsinspector-modern/tracing/TraceEventGenerator.h +60 -0
- package/ReactCommon/jsinspector-modern/tracing/TraceEventSerializer.cpp +44 -1
- package/ReactCommon/jsinspector-modern/tracing/TraceEventSerializer.h +7 -0
- package/ReactCommon/jsinspector-modern/tracing/TraceRecordingState.h +18 -7
- package/ReactCommon/jsinspector-modern/tracing/TracingCategory.h +136 -0
- package/ReactCommon/jsinspector-modern/tracing/tests/TimeWindowedBufferTest.cpp +352 -0
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp +9 -1
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h +11 -1
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp +65 -29
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h +6 -2
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +9 -1
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h +19 -1
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h +3 -1
- package/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.mm +3 -1
- package/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp +11 -1
- package/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h +5 -1
- package/ReactCommon/react/performance/timeline/PerformanceObserver.cpp +18 -6
- package/ReactCommon/react/performance/timeline/PerformanceObserver.h +2 -0
- package/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm +115 -0
- package/ReactCommon/{jsinspector-modern → react/utils}/Base64.h +2 -2
- package/gradle/libs.versions.toml +1 -1
- package/package.json +10 -10
- package/scripts/cocoapods/utils.rb +1 -0
- package/src/private/featureflags/ReactNativeFeatureFlags.js +11 -1
- package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +3 -1
- package/third-party-podspecs/RCT-Folly.podspec +1 -1
- package/third-party-podspecs/fmt.podspec +2 -2
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/interfaces/TracingState.kt +0 -19
- package/ReactCommon/jsinspector-modern/tracing/TraceRecordingStateSerializer.cpp +0 -68
- package/ReactCommon/jsinspector-modern/tracing/TraceRecordingStateSerializer.h +0 -42
- package/ReactCommon/jsinspector-modern/tracing/TracingState.h +0 -24
|
@@ -74,10 +74,10 @@ class HostAgent final {
|
|
|
74
74
|
bool hasFuseboxClientConnected() const;
|
|
75
75
|
|
|
76
76
|
/**
|
|
77
|
-
* Emits the
|
|
77
|
+
* Emits the HostTracingProfile that was captured externally, not via the
|
|
78
78
|
* CDP-initiated request.
|
|
79
79
|
*/
|
|
80
|
-
void
|
|
80
|
+
void emitExternalTracingProfile(tracing::HostTracingProfile tracingProfile) const;
|
|
81
81
|
|
|
82
82
|
/**
|
|
83
83
|
* Emits a system state changed event when the number of ReactHost instances
|
|
@@ -111,8 +111,9 @@ class HostTargetSession {
|
|
|
111
111
|
return hostAgent_.hasFuseboxClientConnected();
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
void
|
|
115
|
-
|
|
114
|
+
void emitHostTracingProfile(
|
|
115
|
+
tracing::HostTracingProfile tracingProfile) const {
|
|
116
|
+
hostAgent_.emitExternalTracingProfile(std::move(tracingProfile));
|
|
116
117
|
}
|
|
117
118
|
|
|
118
119
|
private:
|
|
@@ -328,6 +329,7 @@ namespace {
|
|
|
328
329
|
struct StaticHostTargetMetadata {
|
|
329
330
|
std::optional<bool> isProfilingBuild;
|
|
330
331
|
std::optional<bool> networkInspectionEnabled;
|
|
332
|
+
std::optional<bool> frameRecordingEnabled;
|
|
331
333
|
};
|
|
332
334
|
|
|
333
335
|
StaticHostTargetMetadata getStaticHostMetadata() {
|
|
@@ -335,7 +337,8 @@ StaticHostTargetMetadata getStaticHostMetadata() {
|
|
|
335
337
|
|
|
336
338
|
return {
|
|
337
339
|
.isProfilingBuild = inspectorFlags.getIsProfilingBuild(),
|
|
338
|
-
.networkInspectionEnabled = inspectorFlags.getNetworkInspectionEnabled()
|
|
340
|
+
.networkInspectionEnabled = inspectorFlags.getNetworkInspectionEnabled(),
|
|
341
|
+
.frameRecordingEnabled = inspectorFlags.getFrameRecordingEnabled()};
|
|
339
342
|
}
|
|
340
343
|
|
|
341
344
|
} // namespace
|
|
@@ -370,6 +373,10 @@ folly::dynamic createHostMetadataPayload(const HostTargetMetadata& metadata) {
|
|
|
370
373
|
result["unstable_networkInspectionEnabled"] =
|
|
371
374
|
staticMetadata.networkInspectionEnabled.value();
|
|
372
375
|
}
|
|
376
|
+
if (staticMetadata.frameRecordingEnabled) {
|
|
377
|
+
result["unstable_frameRecordingEnabled"] =
|
|
378
|
+
staticMetadata.frameRecordingEnabled.value();
|
|
379
|
+
}
|
|
373
380
|
|
|
374
381
|
return result;
|
|
375
382
|
}
|
|
@@ -382,13 +389,13 @@ bool HostTarget::hasActiveSessionWithFuseboxClient() const {
|
|
|
382
389
|
return hasActiveFuseboxSession;
|
|
383
390
|
}
|
|
384
391
|
|
|
385
|
-
void HostTarget::
|
|
386
|
-
tracing::
|
|
392
|
+
void HostTarget::emitTracingProfileForFirstFuseboxClient(
|
|
393
|
+
tracing::HostTracingProfile tracingProfile) const {
|
|
387
394
|
bool emitted = false;
|
|
388
395
|
sessions_.forEach([&](HostTargetSession& session) {
|
|
389
396
|
if (emitted) {
|
|
390
397
|
/**
|
|
391
|
-
*
|
|
398
|
+
* HostTracingProfile object is not copiable for performance reasons,
|
|
392
399
|
* because it could contain large Runtime sampling profile object.
|
|
393
400
|
*
|
|
394
401
|
* This approach would not work with multi-client debugger setup.
|
|
@@ -396,7 +403,7 @@ void HostTarget::emitTraceRecordingForFirstFuseboxClient(
|
|
|
396
403
|
return;
|
|
397
404
|
}
|
|
398
405
|
if (session.hasFuseboxClient()) {
|
|
399
|
-
session.
|
|
406
|
+
session.emitHostTracingProfile(std::move(tracingProfile));
|
|
400
407
|
emitted = true;
|
|
401
408
|
}
|
|
402
409
|
});
|
|
@@ -16,11 +16,16 @@
|
|
|
16
16
|
#include "ScopedExecutor.h"
|
|
17
17
|
#include "WeakList.h"
|
|
18
18
|
|
|
19
|
+
#include <functional>
|
|
19
20
|
#include <optional>
|
|
21
|
+
#include <set>
|
|
20
22
|
#include <string>
|
|
21
23
|
|
|
24
|
+
#include <jsinspector-modern/tracing/FrameTimingSequence.h>
|
|
25
|
+
#include <jsinspector-modern/tracing/HostTracingProfile.h>
|
|
26
|
+
#include <jsinspector-modern/tracing/TraceRecordingState.h>
|
|
27
|
+
#include <jsinspector-modern/tracing/TracingCategory.h>
|
|
22
28
|
#include <jsinspector-modern/tracing/TracingMode.h>
|
|
23
|
-
#include <jsinspector-modern/tracing/TracingState.h>
|
|
24
29
|
|
|
25
30
|
#ifndef JSINSPECTOR_EXPORT
|
|
26
31
|
#ifdef _MSC_VER
|
|
@@ -53,6 +58,36 @@ struct HostTargetMetadata {
|
|
|
53
58
|
std::optional<std::string> reactNativeVersion{};
|
|
54
59
|
};
|
|
55
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Receives any performance-related events from a HostTarget: could be Tracing, Performance Monitor, etc.
|
|
63
|
+
*/
|
|
64
|
+
class HostTargetTracingDelegate {
|
|
65
|
+
public:
|
|
66
|
+
HostTargetTracingDelegate() = default;
|
|
67
|
+
virtual ~HostTargetTracingDelegate() = default;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Fired when the corresponding HostTarget started recording a tracing session.
|
|
71
|
+
* The tracing state is expected to be initialized at this point and the delegate should be able to record events
|
|
72
|
+
* through HostTarget.
|
|
73
|
+
*/
|
|
74
|
+
virtual void onTracingStarted(tracing::Mode /* tracingMode */, bool /* screenshotsCategoryEnabled */) {}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Fired when the corresponding HostTarget is about to end recording a tracing session.
|
|
78
|
+
* The tracing state is expected to be still initialized during the call and the delegate should be able to record
|
|
79
|
+
* events through HostTarget.
|
|
80
|
+
*
|
|
81
|
+
* Any attempts to record events after this callback is finished will fail.
|
|
82
|
+
*/
|
|
83
|
+
virtual void onTracingStopped() {}
|
|
84
|
+
|
|
85
|
+
HostTargetTracingDelegate(const HostTargetTracingDelegate &) = delete;
|
|
86
|
+
HostTargetTracingDelegate(HostTargetTracingDelegate &&) = delete;
|
|
87
|
+
HostTargetTracingDelegate &operator=(const HostTargetTracingDelegate &) = delete;
|
|
88
|
+
HostTargetTracingDelegate &operator=(HostTargetTracingDelegate &&) = delete;
|
|
89
|
+
};
|
|
90
|
+
|
|
56
91
|
/**
|
|
57
92
|
* Receives events from a HostTarget. This is a shared interface that each
|
|
58
93
|
* React Native platform needs to implement in order to integrate with the
|
|
@@ -100,6 +135,19 @@ class HostTargetDelegate : public LoadNetworkResourceDelegate {
|
|
|
100
135
|
}
|
|
101
136
|
};
|
|
102
137
|
|
|
138
|
+
struct PageCaptureScreenshotRequest {
|
|
139
|
+
/**
|
|
140
|
+
* Image compression format. Defaults to "png".
|
|
141
|
+
* Allowed values: "jpeg", "png", "webp".
|
|
142
|
+
*/
|
|
143
|
+
std::optional<std::string> format;
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Compression quality from range [0..100] (jpeg only).
|
|
147
|
+
*/
|
|
148
|
+
std::optional<int> quality;
|
|
149
|
+
};
|
|
150
|
+
|
|
103
151
|
virtual ~HostTargetDelegate() override;
|
|
104
152
|
|
|
105
153
|
/**
|
|
@@ -147,18 +195,37 @@ class HostTargetDelegate : public LoadNetworkResourceDelegate {
|
|
|
147
195
|
"LoadNetworkResourceDelegate.loadNetworkResource is not implemented by this host target delegate.");
|
|
148
196
|
}
|
|
149
197
|
|
|
198
|
+
/**
|
|
199
|
+
* Called when the debugger requests a screenshot of the current page via
|
|
200
|
+
* @cdp Page.captureScreenshot. The delegate should capture the current
|
|
201
|
+
* view, encode it to the requested format, and return base64-encoded
|
|
202
|
+
* image data. Return std::nullopt on failure.
|
|
203
|
+
*/
|
|
204
|
+
virtual std::optional<std::string> captureScreenshot(const PageCaptureScreenshotRequest & /*request*/)
|
|
205
|
+
{
|
|
206
|
+
return std::nullopt;
|
|
207
|
+
}
|
|
208
|
+
|
|
150
209
|
/**
|
|
151
210
|
* [Experimental] Will be called at the CDP session initialization to get the
|
|
152
211
|
* trace recording that may have been stashed by the Host from the previous
|
|
153
212
|
* background session.
|
|
154
213
|
*
|
|
155
|
-
* \return the
|
|
214
|
+
* \return the HostTracingProfile if there is one that needs to be
|
|
156
215
|
* displayed, otherwise std::nullopt.
|
|
157
216
|
*/
|
|
158
|
-
virtual std::optional<tracing::
|
|
217
|
+
virtual std::optional<tracing::HostTracingProfile> unstable_getHostTracingProfileThatWillBeEmittedOnInitialization()
|
|
159
218
|
{
|
|
160
219
|
return std::nullopt;
|
|
161
220
|
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* An optional delegate that will be used by HostTarget to notify about tracing-related events.
|
|
224
|
+
*/
|
|
225
|
+
virtual HostTargetTracingDelegate *getTracingDelegate()
|
|
226
|
+
{
|
|
227
|
+
return nullptr;
|
|
228
|
+
}
|
|
162
229
|
};
|
|
163
230
|
|
|
164
231
|
/**
|
|
@@ -203,14 +270,16 @@ class HostTargetController final {
|
|
|
203
270
|
* Starts trace recording for this HostTarget.
|
|
204
271
|
*
|
|
205
272
|
* \param mode In which mode to start the trace recording.
|
|
273
|
+
* \param enabledCategories The set of categories to enable.
|
|
274
|
+
*
|
|
206
275
|
* \return false if already tracing, true otherwise.
|
|
207
276
|
*/
|
|
208
|
-
bool startTracing(tracing::Mode mode);
|
|
277
|
+
bool startTracing(tracing::Mode mode, std::set<tracing::Category> enabledCategories);
|
|
209
278
|
|
|
210
279
|
/**
|
|
211
280
|
* Stops previously started trace recording.
|
|
212
281
|
*/
|
|
213
|
-
tracing::
|
|
282
|
+
tracing::HostTracingProfile stopTracing();
|
|
214
283
|
|
|
215
284
|
private:
|
|
216
285
|
HostTarget &target_;
|
|
@@ -226,12 +295,15 @@ class JSINSPECTOR_EXPORT HostTarget : public EnableExecutorFromThis<HostTarget>
|
|
|
226
295
|
public:
|
|
227
296
|
/**
|
|
228
297
|
* Constructs a new HostTarget.
|
|
298
|
+
*
|
|
229
299
|
* \param delegate The HostTargetDelegate that will
|
|
230
300
|
* receive events from this HostTarget. The caller is responsible for ensuring
|
|
231
301
|
* that the HostTargetDelegate outlives this object.
|
|
302
|
+
*
|
|
232
303
|
* \param executor An executor that may be used to call methods on this
|
|
233
304
|
* HostTarget while it exists. \c create additionally guarantees that the
|
|
234
305
|
* executor will not be called after the HostTarget is destroyed.
|
|
306
|
+
*
|
|
235
307
|
* \note Copies of the provided executor may be destroyed on arbitrary
|
|
236
308
|
* threads, including after the HostTarget is destroyed. Callers must ensure
|
|
237
309
|
* that such destructor calls are safe - e.g. if using a lambda as the
|
|
@@ -279,6 +351,7 @@ class JSINSPECTOR_EXPORT HostTarget : public EnableExecutorFromThis<HostTarget>
|
|
|
279
351
|
*/
|
|
280
352
|
void sendCommand(HostCommand command);
|
|
281
353
|
|
|
354
|
+
#pragma region Tracing
|
|
282
355
|
/**
|
|
283
356
|
* Creates a new HostTracingAgent.
|
|
284
357
|
* This Agent is not owned by the HostTarget. The Agent will be destroyed at
|
|
@@ -292,19 +365,16 @@ class JSINSPECTOR_EXPORT HostTarget : public EnableExecutorFromThis<HostTarget>
|
|
|
292
365
|
* Starts trace recording for this HostTarget.
|
|
293
366
|
*
|
|
294
367
|
* \param mode In which mode to start the trace recording.
|
|
368
|
+
* \param enabledCategories The set of categories to enable.
|
|
369
|
+
*
|
|
295
370
|
* \return false if already tracing, true otherwise.
|
|
296
371
|
*/
|
|
297
|
-
bool startTracing(tracing::Mode mode);
|
|
372
|
+
bool startTracing(tracing::Mode mode, std::set<tracing::Category> enabledCategories);
|
|
298
373
|
|
|
299
374
|
/**
|
|
300
375
|
* Stops previously started trace recording.
|
|
301
376
|
*/
|
|
302
|
-
tracing::
|
|
303
|
-
|
|
304
|
-
/**
|
|
305
|
-
* Returns the state of the background trace, running, stopped, or disabled
|
|
306
|
-
*/
|
|
307
|
-
tracing::TracingState tracingState() const;
|
|
377
|
+
tracing::HostTracingProfile stopTracing();
|
|
308
378
|
|
|
309
379
|
/**
|
|
310
380
|
* Returns whether there is an active session with the Fusebox client, i.e.
|
|
@@ -313,22 +383,30 @@ class JSINSPECTOR_EXPORT HostTarget : public EnableExecutorFromThis<HostTarget>
|
|
|
313
383
|
bool hasActiveSessionWithFuseboxClient() const;
|
|
314
384
|
|
|
315
385
|
/**
|
|
316
|
-
* Emits the
|
|
386
|
+
* Emits the HostTracingProfile for the first active session with the Fusebox
|
|
317
387
|
* client.
|
|
318
388
|
*
|
|
319
389
|
* @see \c hasActiveFrontendSession
|
|
320
390
|
*/
|
|
321
|
-
void
|
|
391
|
+
void emitTracingProfileForFirstFuseboxClient(tracing::HostTracingProfile tracingProfile) const;
|
|
322
392
|
|
|
323
393
|
/**
|
|
324
394
|
* Emits a system state changed event to all active sessions.
|
|
325
395
|
*/
|
|
326
396
|
void emitSystemStateChanged(bool isSingleHost) const;
|
|
327
397
|
|
|
398
|
+
/**
|
|
399
|
+
* An endpoint for the Host to report frame timings that will be recorded if and only if there is currently an active
|
|
400
|
+
* tracing session.
|
|
401
|
+
*/
|
|
402
|
+
void recordFrameTimings(tracing::FrameTimingSequence frameTimingSequence);
|
|
403
|
+
#pragma endregion
|
|
404
|
+
|
|
328
405
|
private:
|
|
329
406
|
/**
|
|
330
407
|
* Constructs a new HostTarget.
|
|
331
408
|
* The caller must call setExecutor immediately afterwards.
|
|
409
|
+
*
|
|
332
410
|
* \param delegate The HostTargetDelegate that will
|
|
333
411
|
* receive events from this HostTarget. The caller is responsible for ensuring
|
|
334
412
|
* that the HostTargetDelegate outlives this object.
|
|
@@ -347,6 +425,7 @@ class JSINSPECTOR_EXPORT HostTarget : public EnableExecutorFromThis<HostTarget>
|
|
|
347
425
|
std::unique_ptr<PerfMonitorUpdateHandler> perfMonitorUpdateHandler_;
|
|
348
426
|
std::unique_ptr<HostRuntimeBinding> perfMetricsBinding_;
|
|
349
427
|
|
|
428
|
+
#pragma region Tracing
|
|
350
429
|
/**
|
|
351
430
|
* Current pending trace recording, which encapsulates the configuration of
|
|
352
431
|
* the tracing session and the state.
|
|
@@ -354,6 +433,14 @@ class JSINSPECTOR_EXPORT HostTarget : public EnableExecutorFromThis<HostTarget>
|
|
|
354
433
|
* Should only be allocated when there is an active tracing session.
|
|
355
434
|
*/
|
|
356
435
|
std::unique_ptr<HostTargetTraceRecording> traceRecording_{nullptr};
|
|
436
|
+
/**
|
|
437
|
+
* Protects the state inside traceRecording_.
|
|
438
|
+
*
|
|
439
|
+
* Calls to tracing subsystem could happen from different threads, depending on the mode (Background or CDP) and
|
|
440
|
+
* the method: the Host could report frame timings from any arbitrary thread.
|
|
441
|
+
*/
|
|
442
|
+
std::mutex tracingMutex_;
|
|
443
|
+
#pragma endregion
|
|
357
444
|
|
|
358
445
|
inline HostTargetDelegate &getDelegate()
|
|
359
446
|
{
|
|
@@ -8,12 +8,26 @@
|
|
|
8
8
|
#include "HostTargetTraceRecording.h"
|
|
9
9
|
#include "HostTarget.h"
|
|
10
10
|
|
|
11
|
+
#include <oscompat/OSCompat.h>
|
|
12
|
+
|
|
11
13
|
namespace facebook::react::jsinspector_modern {
|
|
12
14
|
|
|
13
15
|
HostTargetTraceRecording::HostTargetTraceRecording(
|
|
16
|
+
HostTarget& hostTarget,
|
|
14
17
|
tracing::Mode tracingMode,
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
std::set<tracing::Category> enabledCategories,
|
|
19
|
+
std::optional<HighResDuration> windowSize)
|
|
20
|
+
: hostTarget_(hostTarget),
|
|
21
|
+
tracingMode_(tracingMode),
|
|
22
|
+
enabledCategories_(std::move(enabledCategories)),
|
|
23
|
+
windowSize_(windowSize) {
|
|
24
|
+
if (windowSize) {
|
|
25
|
+
frameTimings_ = tracing::TimeWindowedBuffer<tracing::FrameTimingSequence>(
|
|
26
|
+
[](auto& sequence) { return sequence.beginTimestamp; }, *windowSize);
|
|
27
|
+
} else {
|
|
28
|
+
frameTimings_ = tracing::TimeWindowedBuffer<tracing::FrameTimingSequence>();
|
|
29
|
+
};
|
|
30
|
+
}
|
|
17
31
|
|
|
18
32
|
void HostTargetTraceRecording::setTracedInstance(
|
|
19
33
|
InstanceTarget* instanceTarget) {
|
|
@@ -29,14 +43,13 @@ void HostTargetTraceRecording::start() {
|
|
|
29
43
|
hostTracingAgent_ == nullptr &&
|
|
30
44
|
"Tracing Agent for the HostTarget was already initialized.");
|
|
31
45
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
};
|
|
46
|
+
startTime_ = HighResTimeStamp::now();
|
|
47
|
+
state_ = tracing::TraceRecordingState(
|
|
48
|
+
tracingMode_, enabledCategories_, windowSize_);
|
|
36
49
|
hostTracingAgent_ = hostTarget_.createTracingAgent(*state_);
|
|
37
50
|
}
|
|
38
51
|
|
|
39
|
-
tracing::
|
|
52
|
+
tracing::HostTracingProfile HostTargetTraceRecording::stop() {
|
|
40
53
|
assert(
|
|
41
54
|
hostTracingAgent_ != nullptr &&
|
|
42
55
|
"TracingAgent for the HostTarget has not been initialized.");
|
|
@@ -48,7 +61,25 @@ tracing::TraceRecordingState HostTargetTraceRecording::stop() {
|
|
|
48
61
|
auto state = std::move(*state_);
|
|
49
62
|
state_.reset();
|
|
50
63
|
|
|
51
|
-
|
|
64
|
+
auto startTime = *startTime_;
|
|
65
|
+
startTime_.reset();
|
|
66
|
+
|
|
67
|
+
return tracing::HostTracingProfile{
|
|
68
|
+
.processId = oscompat::getCurrentProcessId(),
|
|
69
|
+
.startTime = startTime,
|
|
70
|
+
.frameTimings = frameTimings_.pruneExpiredAndExtract(),
|
|
71
|
+
.instanceTracingProfiles = std::move(state.instanceTracingProfiles),
|
|
72
|
+
.runtimeSamplingProfiles = std::move(state.runtimeSamplingProfiles),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
void HostTargetTraceRecording::recordFrameTimings(
|
|
77
|
+
tracing::FrameTimingSequence frameTimingSequence) {
|
|
78
|
+
assert(
|
|
79
|
+
state_.has_value() &&
|
|
80
|
+
"The state for this tracing session has not been initialized.");
|
|
81
|
+
|
|
82
|
+
frameTimings_.push(frameTimingSequence);
|
|
52
83
|
}
|
|
53
84
|
|
|
54
85
|
} // namespace facebook::react::jsinspector_modern
|
|
@@ -11,9 +11,15 @@
|
|
|
11
11
|
#include "HostTarget.h"
|
|
12
12
|
#include "InstanceTarget.h"
|
|
13
13
|
|
|
14
|
+
#include <jsinspector-modern/tracing/FrameTimingSequence.h>
|
|
15
|
+
#include <jsinspector-modern/tracing/HostTracingProfile.h>
|
|
16
|
+
#include <jsinspector-modern/tracing/TimeWindowedBuffer.h>
|
|
14
17
|
#include <jsinspector-modern/tracing/TraceRecordingState.h>
|
|
18
|
+
#include <jsinspector-modern/tracing/TracingCategory.h>
|
|
19
|
+
#include <react/timing/primitives.h>
|
|
15
20
|
|
|
16
21
|
#include <optional>
|
|
22
|
+
#include <set>
|
|
17
23
|
|
|
18
24
|
namespace facebook::react::jsinspector_modern {
|
|
19
25
|
|
|
@@ -28,7 +34,11 @@ namespace facebook::react::jsinspector_modern {
|
|
|
28
34
|
*/
|
|
29
35
|
class HostTargetTraceRecording {
|
|
30
36
|
public:
|
|
31
|
-
|
|
37
|
+
HostTargetTraceRecording(
|
|
38
|
+
HostTarget &hostTarget,
|
|
39
|
+
tracing::Mode tracingMode,
|
|
40
|
+
std::set<tracing::Category> enabledCategories,
|
|
41
|
+
std::optional<HighResDuration> windowSize = std::nullopt);
|
|
32
42
|
|
|
33
43
|
inline bool isBackgroundInitiated() const
|
|
34
44
|
{
|
|
@@ -53,22 +63,34 @@ class HostTargetTraceRecording {
|
|
|
53
63
|
void start();
|
|
54
64
|
|
|
55
65
|
/**
|
|
56
|
-
* Stops the recording and
|
|
66
|
+
* Stops the recording and returns the recorded HostTracingProfile.
|
|
57
67
|
*
|
|
58
68
|
* Will deallocate all Tracing Agents.
|
|
59
69
|
*/
|
|
60
|
-
tracing::
|
|
70
|
+
tracing::HostTracingProfile stop();
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Adds the frame timing sequence to the current state of this trace recording.
|
|
74
|
+
*
|
|
75
|
+
* The caller guarantees the protection from data races. This is protected by the tracing mutex in HostTarget.
|
|
76
|
+
*/
|
|
77
|
+
void recordFrameTimings(tracing::FrameTimingSequence frameTimingSequence);
|
|
61
78
|
|
|
62
79
|
private:
|
|
80
|
+
/**
|
|
81
|
+
* The Host for which this Trace Recording is going to happen.
|
|
82
|
+
*/
|
|
83
|
+
HostTarget &hostTarget_;
|
|
84
|
+
|
|
63
85
|
/**
|
|
64
86
|
* The mode in which this trace recording was initialized.
|
|
65
87
|
*/
|
|
66
88
|
tracing::Mode tracingMode_;
|
|
67
89
|
|
|
68
90
|
/**
|
|
69
|
-
* The
|
|
91
|
+
* The timestamp at which this Trace Recording started.
|
|
70
92
|
*/
|
|
71
|
-
|
|
93
|
+
std::optional<HighResTimeStamp> startTime_;
|
|
72
94
|
|
|
73
95
|
/**
|
|
74
96
|
* The state of the current Trace Recording.
|
|
@@ -81,6 +103,21 @@ class HostTargetTraceRecording {
|
|
|
81
103
|
* Only allocated if the recording is enabled.
|
|
82
104
|
*/
|
|
83
105
|
std::shared_ptr<HostTracingAgent> hostTracingAgent_;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* The list of categories that are enabled for this recording.
|
|
109
|
+
*/
|
|
110
|
+
std::set<tracing::Category> enabledCategories_;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* The size of the time window for this recording.
|
|
114
|
+
*/
|
|
115
|
+
std::optional<HighResDuration> windowSize_;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Frame timings captured on the Host side.
|
|
119
|
+
*/
|
|
120
|
+
tracing::TimeWindowedBuffer<tracing::FrameTimingSequence> frameTimings_;
|
|
84
121
|
};
|
|
85
122
|
|
|
86
123
|
} // namespace facebook::react::jsinspector_modern
|
|
@@ -5,18 +5,27 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
#include <jsinspector-modern/tracing/TracingState.h>
|
|
9
|
-
|
|
10
8
|
#include "HostTarget.h"
|
|
11
9
|
#include "HostTargetTraceRecording.h"
|
|
12
10
|
|
|
13
11
|
namespace facebook::react::jsinspector_modern {
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
namespace {
|
|
14
|
+
|
|
15
|
+
// The size of the timeline for the trace recording that happened in the
|
|
16
|
+
// background.
|
|
17
|
+
constexpr HighResDuration kBackgroundTraceWindowSize =
|
|
18
|
+
HighResDuration::fromMilliseconds(20000);
|
|
19
|
+
|
|
20
|
+
} // namespace
|
|
21
|
+
|
|
22
|
+
bool HostTargetController::startTracing(
|
|
23
|
+
tracing::Mode tracingMode,
|
|
24
|
+
std::set<tracing::Category> enabledCategories) {
|
|
25
|
+
return target_.startTracing(tracingMode, std::move(enabledCategories));
|
|
17
26
|
}
|
|
18
27
|
|
|
19
|
-
tracing::
|
|
28
|
+
tracing::HostTracingProfile HostTargetController::stopTracing() {
|
|
20
29
|
return target_.stopTracing();
|
|
21
30
|
}
|
|
22
31
|
|
|
@@ -27,45 +36,69 @@ std::shared_ptr<HostTracingAgent> HostTarget::createTracingAgent(
|
|
|
27
36
|
return agent;
|
|
28
37
|
}
|
|
29
38
|
|
|
30
|
-
bool HostTarget::startTracing(
|
|
39
|
+
bool HostTarget::startTracing(
|
|
40
|
+
tracing::Mode tracingMode,
|
|
41
|
+
std::set<tracing::Category> enabledCategories) {
|
|
42
|
+
std::lock_guard lock(tracingMutex_);
|
|
43
|
+
|
|
31
44
|
if (traceRecording_ != nullptr) {
|
|
32
45
|
if (traceRecording_->isBackgroundInitiated() &&
|
|
33
46
|
tracingMode == tracing::Mode::CDP) {
|
|
47
|
+
if (auto tracingDelegate = delegate_.getTracingDelegate()) {
|
|
48
|
+
tracingDelegate->onTracingStopped();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
traceRecording_->stop();
|
|
34
52
|
traceRecording_.reset();
|
|
35
53
|
} else {
|
|
36
54
|
return false;
|
|
37
55
|
}
|
|
38
56
|
}
|
|
39
57
|
|
|
40
|
-
|
|
41
|
-
std::
|
|
58
|
+
auto timeWindow = tracingMode == tracing::Mode::Background
|
|
59
|
+
? std::make_optional(kBackgroundTraceWindowSize)
|
|
60
|
+
: std::nullopt;
|
|
61
|
+
auto screenshotsCategoryEnabled =
|
|
62
|
+
enabledCategories.contains(tracing::Category::Screenshot);
|
|
63
|
+
|
|
64
|
+
traceRecording_ = std::make_unique<HostTargetTraceRecording>(
|
|
65
|
+
*this, tracingMode, std::move(enabledCategories), timeWindow);
|
|
42
66
|
traceRecording_->setTracedInstance(currentInstance_.get());
|
|
43
67
|
traceRecording_->start();
|
|
44
68
|
|
|
69
|
+
if (auto tracingDelegate = delegate_.getTracingDelegate()) {
|
|
70
|
+
tracingDelegate->onTracingStarted(tracingMode, screenshotsCategoryEnabled);
|
|
71
|
+
}
|
|
72
|
+
|
|
45
73
|
return true;
|
|
46
74
|
}
|
|
47
75
|
|
|
48
|
-
tracing::
|
|
76
|
+
tracing::HostTracingProfile HostTarget::stopTracing() {
|
|
77
|
+
std::lock_guard lock(tracingMutex_);
|
|
78
|
+
|
|
49
79
|
assert(traceRecording_ != nullptr && "No tracing in progress");
|
|
50
80
|
|
|
51
|
-
auto
|
|
81
|
+
if (auto tracingDelegate = delegate_.getTracingDelegate()) {
|
|
82
|
+
tracingDelegate->onTracingStopped();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
auto profile = traceRecording_->stop();
|
|
52
86
|
traceRecording_.reset();
|
|
53
87
|
|
|
54
|
-
return
|
|
88
|
+
return profile;
|
|
55
89
|
}
|
|
56
90
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
91
|
+
void HostTarget::recordFrameTimings(
|
|
92
|
+
tracing::FrameTimingSequence frameTimingSequence) {
|
|
93
|
+
std::lock_guard lock(tracingMutex_);
|
|
61
94
|
|
|
62
|
-
if (traceRecording_
|
|
63
|
-
|
|
95
|
+
if (traceRecording_) {
|
|
96
|
+
traceRecording_->recordFrameTimings(std::move(frameTimingSequence));
|
|
97
|
+
} else {
|
|
98
|
+
assert(
|
|
99
|
+
false &&
|
|
100
|
+
"The HostTarget is not being profiled. Did you call recordFrameTimings() from the native Host side when there is no tracing in progress?");
|
|
64
101
|
}
|
|
65
|
-
|
|
66
|
-
// This means we have a traceRecording_, but not running in the background.
|
|
67
|
-
// CDP initiated this trace so we should report as disabled.
|
|
68
|
-
return tracing::TracingState::EnabledInCDPMode;
|
|
69
102
|
}
|
|
70
103
|
|
|
71
104
|
} // namespace facebook::react::jsinspector_modern
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include "InspectorInterfaces.h"
|
|
11
|
+
|
|
12
|
+
#include "cdp/CdpJson.h"
|
|
13
|
+
#include "tracing/HostTracingProfile.h"
|
|
14
|
+
#include "tracing/HostTracingProfileSerializer.h"
|
|
15
|
+
|
|
16
|
+
#include <array>
|
|
17
|
+
#include <concepts>
|
|
18
|
+
#include <cstdint>
|
|
19
|
+
#include <ranges>
|
|
20
|
+
|
|
21
|
+
namespace facebook::react::jsinspector_modern {
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Emits a captured HostTracingProfile in a series of
|
|
25
|
+
* Tracing.dataCollected events, followed by a Tracing.tracingComplete event, to zero or more
|
|
26
|
+
* FrontendChannels. If \p isBackgroundTrace is true, a ReactNativeApplication.traceRequested
|
|
27
|
+
* notification is sent to each FrontendChannel before the trace events are emitted.
|
|
28
|
+
*/
|
|
29
|
+
template <typename ChannelsRange>
|
|
30
|
+
void emitNotificationsForTracingProfile(
|
|
31
|
+
tracing::HostTracingProfile &&hostTracingProfile,
|
|
32
|
+
const ChannelsRange &channels,
|
|
33
|
+
bool isBackgroundTrace)
|
|
34
|
+
requires std::ranges::range<ChannelsRange> &&
|
|
35
|
+
std::convertible_to<std::ranges::range_value_t<ChannelsRange>, FrontendChannel>
|
|
36
|
+
{
|
|
37
|
+
/**
|
|
38
|
+
* Maximum serialized byte size of a Trace Event chunk before it is flushed
|
|
39
|
+
* with a Tracing.dataCollected event.
|
|
40
|
+
*/
|
|
41
|
+
static constexpr size_t TRACE_EVENT_CHUNK_MAX_BYTES = 10 * 1024 * 1024; // 10 MiB
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The maximum number of ProfileChunk trace events
|
|
45
|
+
* that will be sent in a single CDP Tracing.dataCollected message.
|
|
46
|
+
*/
|
|
47
|
+
static constexpr uint16_t PROFILE_TRACE_EVENT_CHUNK_SIZE = 10;
|
|
48
|
+
|
|
49
|
+
if (std::ranges::empty(channels)) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (isBackgroundTrace) {
|
|
54
|
+
for (auto &frontendChannel : channels) {
|
|
55
|
+
frontendChannel(cdp::jsonNotification("ReactNativeApplication.traceRequested"));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Serialize each chunk once and send it to all eligible sessions.
|
|
60
|
+
tracing::HostTracingProfileSerializer::emitAsDataCollectedChunks(
|
|
61
|
+
std::move(hostTracingProfile),
|
|
62
|
+
[&](folly::dynamic &&serializedChunk) {
|
|
63
|
+
for (auto &frontendChannel : channels) {
|
|
64
|
+
frontendChannel(
|
|
65
|
+
cdp::jsonNotification("Tracing.dataCollected", folly::dynamic::object("value", serializedChunk)));
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
TRACE_EVENT_CHUNK_MAX_BYTES,
|
|
69
|
+
PROFILE_TRACE_EVENT_CHUNK_SIZE);
|
|
70
|
+
|
|
71
|
+
for (auto &frontendChannel : channels) {
|
|
72
|
+
frontendChannel(
|
|
73
|
+
cdp::jsonNotification("Tracing.tracingComplete", folly::dynamic::object("dataLossOccurred", false)));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Convenience overload of emitNotificationsForTracingProfile() for a single FrontendChannel.
|
|
79
|
+
*/
|
|
80
|
+
inline void emitNotificationsForTracingProfile(
|
|
81
|
+
tracing::HostTracingProfile &&hostTracingProfile,
|
|
82
|
+
const FrontendChannel &channel,
|
|
83
|
+
bool isBackgroundTrace)
|
|
84
|
+
{
|
|
85
|
+
std::array<FrontendChannel, 1> channels{channel};
|
|
86
|
+
emitNotificationsForTracingProfile(std::move(hostTracingProfile), channels, isBackgroundTrace);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
} // namespace facebook::react::jsinspector_modern
|