react-native 0.83.3 → 0.83.5

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.
Files changed (107) hide show
  1. package/Libraries/Core/ReactNativeVersion.js +1 -1
  2. package/Libraries/Utilities/Appearance.js +6 -1
  3. package/React/Base/RCTVersion.m +1 -1
  4. package/React/DevSupport/RCTFrameTimingsObserver.h +24 -0
  5. package/React/DevSupport/RCTFrameTimingsObserver.mm +298 -0
  6. package/React/FBReactNativeSpec/FBReactNativeSpecJSI.h +16 -0
  7. package/ReactAndroid/api/ReactAndroid.api +0 -9
  8. package/ReactAndroid/gradle.properties +1 -1
  9. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/BridgelessDevSupportManager.kt +2 -2
  10. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerBase.kt +7 -7
  11. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/InspectorFlags.kt +4 -0
  12. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/FrameTimingSequence.kt +16 -0
  13. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/FrameTimingsObserver.kt +275 -0
  14. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/TracingState.kt +17 -0
  15. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/TracingStateListener.kt +15 -0
  16. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/{interfaces → inspector}/TracingStateProvider.kt +1 -1
  17. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/perfmonitor/PerfMonitorInspectorTargetBinding.kt +1 -1
  18. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/perfmonitor/PerfMonitorOverlayManager.kt +4 -4
  19. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/perfmonitor/PerfMonitorOverlayView.kt +3 -3
  20. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/perfmonitor/PerfMonitorUpdateListener.kt +1 -1
  21. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt +13 -1
  22. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt +21 -1
  23. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt +5 -1
  24. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +5 -1
  25. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt +23 -1
  26. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt +5 -1
  27. package/ReactAndroid/src/main/java/com/facebook/react/internal/tracing/PerformanceTracer.kt +39 -0
  28. package/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.kt +1 -1
  29. package/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkEventUtil.kt +20 -19
  30. package/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.kt +6 -12
  31. package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +1 -1
  32. package/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.kt +86 -4
  33. package/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImplDevHelper.kt +3 -3
  34. package/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostInspectorTarget.kt +10 -6
  35. package/ReactAndroid/src/main/jni/react/devsupport/JInspectorFlags.cpp +22 -0
  36. package/ReactAndroid/src/main/jni/react/devsupport/JInspectorFlags.h +2 -0
  37. package/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp +29 -1
  38. package/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h +7 -1
  39. package/ReactAndroid/src/main/jni/react/runtime/jni/JReactHostInspectorTarget.cpp +196 -17
  40. package/ReactAndroid/src/main/jni/react/runtime/jni/JReactHostInspectorTarget.h +168 -18
  41. package/ReactAndroid/src/main/jni/third-party/folly/CMakeLists.txt +1 -0
  42. package/ReactCommon/cxxreact/ReactNativeVersion.h +2 -2
  43. package/ReactCommon/jsinspector-modern/HostAgent.cpp +45 -10
  44. package/ReactCommon/jsinspector-modern/HostAgent.h +2 -2
  45. package/ReactCommon/jsinspector-modern/HostTarget.cpp +14 -7
  46. package/ReactCommon/jsinspector-modern/HostTarget.h +101 -14
  47. package/ReactCommon/jsinspector-modern/HostTargetTraceRecording.cpp +39 -8
  48. package/ReactCommon/jsinspector-modern/HostTargetTraceRecording.h +42 -5
  49. package/ReactCommon/jsinspector-modern/HostTargetTracing.cpp +54 -21
  50. package/ReactCommon/jsinspector-modern/HostTargetTracing.h +89 -0
  51. package/ReactCommon/jsinspector-modern/InspectorFlags.cpp +12 -0
  52. package/ReactCommon/jsinspector-modern/InspectorFlags.h +12 -0
  53. package/ReactCommon/jsinspector-modern/InspectorInterfaces.cpp +3 -7
  54. package/ReactCommon/jsinspector-modern/InstanceAgent.cpp +2 -11
  55. package/ReactCommon/jsinspector-modern/NetworkIOAgent.cpp +1 -1
  56. package/ReactCommon/jsinspector-modern/TracingAgent.cpp +29 -13
  57. package/ReactCommon/jsinspector-modern/TracingAgent.h +5 -4
  58. package/ReactCommon/jsinspector-modern/tests/HostTargetTest.cpp +65 -0
  59. package/ReactCommon/jsinspector-modern/tests/InspectorMocks.h +23 -2
  60. package/ReactCommon/jsinspector-modern/tests/JsiIntegrationTest.cpp +1 -0
  61. package/ReactCommon/jsinspector-modern/tests/NetworkReporterTest.cpp +1 -0
  62. package/ReactCommon/jsinspector-modern/tests/TracingTest.cpp +335 -0
  63. package/ReactCommon/jsinspector-modern/tests/TracingTest.h +95 -0
  64. package/ReactCommon/jsinspector-modern/tests/utils/InspectorFlagOverridesGuard.cpp +10 -0
  65. package/ReactCommon/jsinspector-modern/tests/utils/InspectorFlagOverridesGuard.h +3 -1
  66. package/ReactCommon/jsinspector-modern/tracing/CMakeLists.txt +1 -0
  67. package/ReactCommon/jsinspector-modern/tracing/FrameTimingSequence.h +61 -0
  68. package/ReactCommon/jsinspector-modern/tracing/HostTracingProfile.h +43 -0
  69. package/ReactCommon/jsinspector-modern/tracing/HostTracingProfileSerializer.cpp +165 -0
  70. package/ReactCommon/jsinspector-modern/tracing/HostTracingProfileSerializer.h +50 -0
  71. package/ReactCommon/jsinspector-modern/tracing/PerformanceTracer.cpp +16 -14
  72. package/ReactCommon/jsinspector-modern/tracing/PerformanceTracerSection.h +113 -0
  73. package/ReactCommon/jsinspector-modern/tracing/React-jsinspectortracing.podspec +1 -0
  74. package/ReactCommon/jsinspector-modern/tracing/TimeWindowedBuffer.h +158 -0
  75. package/ReactCommon/jsinspector-modern/tracing/TraceEvent.h +2 -1
  76. package/ReactCommon/jsinspector-modern/tracing/TraceEventGenerator.cpp +100 -0
  77. package/ReactCommon/jsinspector-modern/tracing/TraceEventGenerator.h +60 -0
  78. package/ReactCommon/jsinspector-modern/tracing/TraceEventSerializer.cpp +44 -1
  79. package/ReactCommon/jsinspector-modern/tracing/TraceEventSerializer.h +7 -0
  80. package/ReactCommon/jsinspector-modern/tracing/TraceRecordingState.h +18 -7
  81. package/ReactCommon/jsinspector-modern/tracing/TracingCategory.h +136 -0
  82. package/ReactCommon/jsinspector-modern/tracing/tests/TimeWindowedBufferTest.cpp +352 -0
  83. package/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp +9 -1
  84. package/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h +11 -1
  85. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp +65 -29
  86. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h +6 -2
  87. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +9 -1
  88. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h +19 -1
  89. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h +3 -1
  90. package/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.mm +3 -1
  91. package/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp +11 -1
  92. package/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h +5 -1
  93. package/ReactCommon/react/performance/timeline/PerformanceObserver.cpp +18 -6
  94. package/ReactCommon/react/performance/timeline/PerformanceObserver.h +2 -0
  95. package/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm +115 -0
  96. package/ReactCommon/{jsinspector-modern → react/utils}/Base64.h +2 -2
  97. package/gradle/libs.versions.toml +1 -1
  98. package/package.json +8 -8
  99. package/scripts/cocoapods/utils.rb +1 -0
  100. package/src/private/featureflags/ReactNativeFeatureFlags.js +11 -1
  101. package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +3 -1
  102. package/third-party-podspecs/RCT-Folly.podspec +1 -1
  103. package/third-party-podspecs/fmt.podspec +2 -2
  104. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/interfaces/TracingState.kt +0 -19
  105. package/ReactCommon/jsinspector-modern/tracing/TraceRecordingStateSerializer.cpp +0 -68
  106. package/ReactCommon/jsinspector-modern/tracing/TraceRecordingStateSerializer.h +0 -42
  107. package/ReactCommon/jsinspector-modern/tracing/TracingState.h +0 -24
@@ -111,8 +111,9 @@ class HostTargetSession {
111
111
  return hostAgent_.hasFuseboxClientConnected();
112
112
  }
113
113
 
114
- void emitTraceRecording(tracing::TraceRecordingState traceRecording) const {
115
- hostAgent_.emitExternalTraceRecording(std::move(traceRecording));
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::emitTraceRecordingForFirstFuseboxClient(
386
- tracing::TraceRecordingState traceRecording) const {
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
- * TraceRecordingState object is not copiable for performance reasons,
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.emitTraceRecording(std::move(traceRecording));
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 trace recording state if there is one that needs to be
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::TraceRecordingState> unstable_getTraceRecordingThatWillBeEmittedOnInitialization()
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::TraceRecordingState stopTracing();
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::TraceRecordingState stopTracing();
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 trace recording for the first active session with the Fusebox
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 emitTraceRecordingForFirstFuseboxClient(tracing::TraceRecordingState traceRecording) const;
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
- HostTarget& hostTarget)
16
- : tracingMode_(tracingMode), hostTarget_(hostTarget) {}
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
- state_ = tracing::TraceRecordingState{
33
- .mode = tracingMode_,
34
- .startTime = HighResTimeStamp::now(),
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::TraceRecordingState HostTargetTraceRecording::stop() {
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
- return state;
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
- explicit HostTargetTraceRecording(tracing::Mode tracingMode, HostTarget &hostTarget);
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 drops the recording state.
66
+ * Stops the recording and returns the recorded HostTracingProfile.
57
67
  *
58
68
  * Will deallocate all Tracing Agents.
59
69
  */
60
- tracing::TraceRecordingState stop();
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 Host for which this Trace Recording is going to happen.
91
+ * The timestamp at which this Trace Recording started.
70
92
  */
71
- HostTarget &hostTarget_;
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
- bool HostTargetController::startTracing(tracing::Mode tracingMode) {
16
- return target_.startTracing(tracingMode);
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::TraceRecordingState HostTargetController::stopTracing() {
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(tracing::Mode tracingMode) {
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
- traceRecording_ =
41
- std::make_unique<HostTargetTraceRecording>(tracingMode, *this);
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::TraceRecordingState HostTarget::stopTracing() {
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 state = traceRecording_->stop();
81
+ if (auto tracingDelegate = delegate_.getTracingDelegate()) {
82
+ tracingDelegate->onTracingStopped();
83
+ }
84
+
85
+ auto profile = traceRecording_->stop();
52
86
  traceRecording_.reset();
53
87
 
54
- return state;
88
+ return profile;
55
89
  }
56
90
 
57
- tracing::TracingState HostTarget::tracingState() const {
58
- if (traceRecording_ == nullptr) {
59
- return tracing::TracingState::Disabled;
60
- }
91
+ void HostTarget::recordFrameTimings(
92
+ tracing::FrameTimingSequence frameTimingSequence) {
93
+ std::lock_guard lock(tracingMutex_);
61
94
 
62
- if (traceRecording_->isBackgroundInitiated()) {
63
- return tracing::TracingState::EnabledInBackgroundMode;
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