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.
- package/Libraries/Core/ReactNativeVersion.js +1 -1
- package/Libraries/Utilities/Appearance.js +6 -1
- package/React/Base/RCTVersion.m +1 -1
- 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/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/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 +8 -8
- 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
|
@@ -0,0 +1,335 @@
|
|
|
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
|
+
#include "TracingTest.h"
|
|
9
|
+
#include "engines/JsiIntegrationTestHermesEngineAdapter.h"
|
|
10
|
+
|
|
11
|
+
#include <folly/executors/QueuedImmediateExecutor.h>
|
|
12
|
+
#include <jsinspector-modern/InspectorFlags.h>
|
|
13
|
+
#include <react/featureflags/ReactNativeFeatureFlags.h>
|
|
14
|
+
#include <react/networking/NetworkReporter.h>
|
|
15
|
+
|
|
16
|
+
using namespace ::testing;
|
|
17
|
+
|
|
18
|
+
namespace facebook::react::jsinspector_modern {
|
|
19
|
+
|
|
20
|
+
class TracingTest : public TracingTestBase<
|
|
21
|
+
JsiIntegrationTestHermesEngineAdapter,
|
|
22
|
+
folly::QueuedImmediateExecutor> {
|
|
23
|
+
protected:
|
|
24
|
+
TracingTest() : TracingTestBase() {}
|
|
25
|
+
|
|
26
|
+
void SetUp() override {
|
|
27
|
+
JsiIntegrationPortableTestBase::SetUp();
|
|
28
|
+
connect();
|
|
29
|
+
EXPECT_CALL(
|
|
30
|
+
fromPage(),
|
|
31
|
+
onMessage(
|
|
32
|
+
JsonParsed(AllOf(AtJsonPtr("/method", "Debugger.scriptParsed")))))
|
|
33
|
+
.Times(AnyNumber());
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
TEST_F(TracingTest, EnablesSamplingProfilerOnlyCategoryIsSpecified) {
|
|
38
|
+
InSequence s;
|
|
39
|
+
|
|
40
|
+
startTracing({});
|
|
41
|
+
auto allTraceEvents = endTracingAndCollectEvents();
|
|
42
|
+
|
|
43
|
+
EXPECT_THAT(
|
|
44
|
+
allTraceEvents,
|
|
45
|
+
Not(Contains(AllOf(
|
|
46
|
+
AtJsonPtr("/name", "Profile"),
|
|
47
|
+
AtJsonPtr("/cat", "disabled-by-default-v8.cpu_profiler")))));
|
|
48
|
+
|
|
49
|
+
startTracing({tracing::Category::JavaScriptSampling});
|
|
50
|
+
allTraceEvents = endTracingAndCollectEvents();
|
|
51
|
+
|
|
52
|
+
EXPECT_THAT(
|
|
53
|
+
allTraceEvents,
|
|
54
|
+
Contains(AllOf(
|
|
55
|
+
AtJsonPtr("/name", "Profile"),
|
|
56
|
+
AtJsonPtr("/cat", "disabled-by-default-v8.cpu_profiler"))));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
TEST_F(TracingTest, RecordsFrameTimings) {
|
|
60
|
+
InSequence s;
|
|
61
|
+
|
|
62
|
+
page_->startTracing(tracing::Mode::Background, {tracing::Category::Timeline});
|
|
63
|
+
|
|
64
|
+
auto now = HighResTimeStamp::now();
|
|
65
|
+
auto frameTimingSequence = tracing::FrameTimingSequence(
|
|
66
|
+
1, // id
|
|
67
|
+
11, // threadId
|
|
68
|
+
now,
|
|
69
|
+
now + HighResDuration::fromNanoseconds(50));
|
|
70
|
+
|
|
71
|
+
page_->recordFrameTimings(frameTimingSequence);
|
|
72
|
+
|
|
73
|
+
auto tracingProfile = page_->stopTracing();
|
|
74
|
+
EXPECT_EQ(tracingProfile.frameTimings.size(), 1u);
|
|
75
|
+
EXPECT_EQ(tracingProfile.frameTimings[0].id, frameTimingSequence.id);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
TEST_F(TracingTest, EmitsRecordedFrameTimingSequences) {
|
|
79
|
+
InSequence s;
|
|
80
|
+
|
|
81
|
+
startTracing();
|
|
82
|
+
auto now = HighResTimeStamp::now();
|
|
83
|
+
page_->recordFrameTimings(
|
|
84
|
+
tracing::FrameTimingSequence(
|
|
85
|
+
1, // id
|
|
86
|
+
11, // threadId
|
|
87
|
+
now,
|
|
88
|
+
now + HighResDuration::fromNanoseconds(50)));
|
|
89
|
+
|
|
90
|
+
auto allTraceEvents = endTracingAndCollectEvents();
|
|
91
|
+
EXPECT_THAT(allTraceEvents, Contains(AtJsonPtr("/name", "BeginFrame")));
|
|
92
|
+
EXPECT_THAT(allTraceEvents, Contains(AtJsonPtr("/name", "DrawFrame")));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
TEST_F(TracingTest, EmitsScreenshotEventWhenScreenshotValuePassed) {
|
|
96
|
+
InSequence s;
|
|
97
|
+
|
|
98
|
+
startTracing({tracing::Category::Screenshot});
|
|
99
|
+
auto now = HighResTimeStamp::now();
|
|
100
|
+
page_->recordFrameTimings(
|
|
101
|
+
tracing::FrameTimingSequence(
|
|
102
|
+
1, // id
|
|
103
|
+
11, // threadId
|
|
104
|
+
now,
|
|
105
|
+
now + HighResDuration::fromNanoseconds(50),
|
|
106
|
+
std::vector<uint8_t>{}));
|
|
107
|
+
|
|
108
|
+
auto allTraceEvents = endTracingAndCollectEvents();
|
|
109
|
+
EXPECT_THAT(allTraceEvents, Contains(AtJsonPtr("/name", "Screenshot")));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
TEST_F(
|
|
113
|
+
TracingTest,
|
|
114
|
+
SecondSessionTracingStartIsRejectedWhileFirstSessionIsTracing) {
|
|
115
|
+
auto secondary = connectSecondary();
|
|
116
|
+
InSequence s;
|
|
117
|
+
|
|
118
|
+
// Session 1 starts tracing successfully
|
|
119
|
+
startTracing();
|
|
120
|
+
|
|
121
|
+
// Session 2 tries to start tracing - should get error
|
|
122
|
+
EXPECT_CALL(
|
|
123
|
+
secondary.fromPage(),
|
|
124
|
+
onMessage(JsonParsed(AllOf(
|
|
125
|
+
AtJsonPtr("/id", 2),
|
|
126
|
+
AtJsonPtr("/error/message", "Tracing has already been started")))));
|
|
127
|
+
secondary.toPage().sendMessage(R"({"id": 2, "method": "Tracing.start"})");
|
|
128
|
+
|
|
129
|
+
// Session 1 ends tracing normally
|
|
130
|
+
endTracingAndCollectEvents();
|
|
131
|
+
|
|
132
|
+
// Now Session 2 can start tracing
|
|
133
|
+
EXPECT_CALL(
|
|
134
|
+
secondary.fromPage(), onMessage(JsonEq(R"({"id": 3, "result": {}})")));
|
|
135
|
+
secondary.toPage().sendMessage(R"({"id": 3, "method": "Tracing.start"})");
|
|
136
|
+
|
|
137
|
+
// Clean up - end secondary's tracing
|
|
138
|
+
EXPECT_CALL(
|
|
139
|
+
secondary.fromPage(), onMessage(JsonEq(R"({"id": 4, "result": {}})")));
|
|
140
|
+
EXPECT_CALL(
|
|
141
|
+
secondary.fromPage(),
|
|
142
|
+
onMessage(JsonParsed(AtJsonPtr("/method", "Tracing.dataCollected"))))
|
|
143
|
+
.Times(AtLeast(1));
|
|
144
|
+
EXPECT_CALL(
|
|
145
|
+
secondary.fromPage(),
|
|
146
|
+
onMessage(JsonParsed(AtJsonPtr("/method", "Tracing.tracingComplete"))));
|
|
147
|
+
secondary.toPage().sendMessage(R"({"id": 4, "method": "Tracing.end"})");
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
TEST_F(TracingTest, CDPTracingPreemptsBackgroundTracing) {
|
|
151
|
+
InSequence s;
|
|
152
|
+
|
|
153
|
+
// Start background tracing directly
|
|
154
|
+
page_->startTracing(tracing::Mode::Background, {});
|
|
155
|
+
|
|
156
|
+
// CDP Tracing.start should preempt background (succeed, not fail)
|
|
157
|
+
startTracing();
|
|
158
|
+
|
|
159
|
+
// End tracing normally
|
|
160
|
+
endTracingAndCollectEvents();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
TEST_F(TracingTest, BackgroundTracingIsRejectedWhileCDPTracingIsRunning) {
|
|
164
|
+
InSequence s;
|
|
165
|
+
|
|
166
|
+
// Start CDP tracing
|
|
167
|
+
startTracing();
|
|
168
|
+
|
|
169
|
+
// Background tracing should be rejected
|
|
170
|
+
bool started = page_->startTracing(tracing::Mode::Background, {});
|
|
171
|
+
EXPECT_FALSE(started);
|
|
172
|
+
|
|
173
|
+
// End CDP tracing
|
|
174
|
+
endTracingAndCollectEvents();
|
|
175
|
+
|
|
176
|
+
// Now background tracing should succeed
|
|
177
|
+
started = page_->startTracing(tracing::Mode::Background, {});
|
|
178
|
+
EXPECT_TRUE(started);
|
|
179
|
+
|
|
180
|
+
// Clean up
|
|
181
|
+
page_->stopTracing();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
TEST_F(TracingTest, EmitsToAllSessionsWithReactNativeApplicationDomainEnabled) {
|
|
185
|
+
auto secondaryFusebox = this->connectSecondary();
|
|
186
|
+
auto secondaryNonFusebox = this->connectSecondary();
|
|
187
|
+
|
|
188
|
+
// Enable ReactNativeApplication domain on primary and secondaryFusebox
|
|
189
|
+
// sessions (but NOT on secondaryNonFusebox)
|
|
190
|
+
{
|
|
191
|
+
InSequence s;
|
|
192
|
+
EXPECT_CALL(
|
|
193
|
+
this->fromPage(),
|
|
194
|
+
onMessage(JsonParsed(
|
|
195
|
+
AtJsonPtr("/method", "ReactNativeApplication.metadataUpdated"))));
|
|
196
|
+
EXPECT_CALL(
|
|
197
|
+
this->fromPage(), onMessage(JsonEq(R"({"id": 1, "result": {}})")));
|
|
198
|
+
}
|
|
199
|
+
this->toPage_->sendMessage(
|
|
200
|
+
R"({"id": 1, "method": "ReactNativeApplication.enable"})");
|
|
201
|
+
|
|
202
|
+
{
|
|
203
|
+
InSequence s;
|
|
204
|
+
EXPECT_CALL(
|
|
205
|
+
secondaryFusebox.fromPage(),
|
|
206
|
+
onMessage(JsonParsed(
|
|
207
|
+
AtJsonPtr("/method", "ReactNativeApplication.metadataUpdated"))));
|
|
208
|
+
EXPECT_CALL(
|
|
209
|
+
secondaryFusebox.fromPage(),
|
|
210
|
+
onMessage(JsonEq(R"({"id": 1, "result": {}})")));
|
|
211
|
+
}
|
|
212
|
+
secondaryFusebox.toPage().sendMessage(
|
|
213
|
+
R"({"id": 1, "method": "ReactNativeApplication.enable"})");
|
|
214
|
+
|
|
215
|
+
// Start background tracing
|
|
216
|
+
this->page_->startTracing(
|
|
217
|
+
tracing::Mode::Background, {tracing::Category::Timeline});
|
|
218
|
+
|
|
219
|
+
// Record some frame timings
|
|
220
|
+
auto now = HighResTimeStamp::now();
|
|
221
|
+
this->page_->recordFrameTimings(
|
|
222
|
+
tracing::FrameTimingSequence(
|
|
223
|
+
1, // id
|
|
224
|
+
11, // threadId
|
|
225
|
+
now,
|
|
226
|
+
now + HighResDuration::fromNanoseconds(50)));
|
|
227
|
+
|
|
228
|
+
// Primary and secondaryFusebox sessions should receive the trace.
|
|
229
|
+
// Events within each session are ordered, but order between sessions is
|
|
230
|
+
// arbitrary.
|
|
231
|
+
Sequence primarySeq;
|
|
232
|
+
Sequence secondarySeq;
|
|
233
|
+
|
|
234
|
+
EXPECT_CALL(
|
|
235
|
+
this->fromPage(),
|
|
236
|
+
onMessage(JsonParsed(
|
|
237
|
+
AtJsonPtr("/method", "ReactNativeApplication.traceRequested"))))
|
|
238
|
+
.InSequence(primarySeq);
|
|
239
|
+
EXPECT_CALL(
|
|
240
|
+
this->fromPage(),
|
|
241
|
+
onMessage(JsonParsed(AtJsonPtr("/method", "Tracing.dataCollected"))))
|
|
242
|
+
.Times(AtLeast(1))
|
|
243
|
+
.InSequence(primarySeq);
|
|
244
|
+
EXPECT_CALL(
|
|
245
|
+
this->fromPage(),
|
|
246
|
+
onMessage(JsonParsed(AtJsonPtr("/method", "Tracing.tracingComplete"))))
|
|
247
|
+
.InSequence(primarySeq);
|
|
248
|
+
|
|
249
|
+
EXPECT_CALL(
|
|
250
|
+
secondaryFusebox.fromPage(),
|
|
251
|
+
onMessage(JsonParsed(
|
|
252
|
+
AtJsonPtr("/method", "ReactNativeApplication.traceRequested"))))
|
|
253
|
+
.InSequence(secondarySeq);
|
|
254
|
+
EXPECT_CALL(
|
|
255
|
+
secondaryFusebox.fromPage(),
|
|
256
|
+
onMessage(JsonParsed(AtJsonPtr("/method", "Tracing.dataCollected"))))
|
|
257
|
+
.Times(AtLeast(1))
|
|
258
|
+
.InSequence(secondarySeq);
|
|
259
|
+
EXPECT_CALL(
|
|
260
|
+
secondaryFusebox.fromPage(),
|
|
261
|
+
onMessage(JsonParsed(AtJsonPtr("/method", "Tracing.tracingComplete"))))
|
|
262
|
+
.InSequence(secondarySeq);
|
|
263
|
+
|
|
264
|
+
// secondaryNonFusebox should NOT receive anything (it did not enable the
|
|
265
|
+
// domain)
|
|
266
|
+
EXPECT_CALL(secondaryNonFusebox.fromPage(), onMessage(_)).Times(0);
|
|
267
|
+
|
|
268
|
+
// Stop tracing and emit to all eligible sessions
|
|
269
|
+
EXPECT_TRUE(this->page_->stopAndMaybeEmitBackgroundTrace());
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
TEST_F(TracingTest, StashedTraceIsEmittedOnlyToFirstEligibleSession) {
|
|
273
|
+
// Start background tracing with no sessions having ReactNativeApplication
|
|
274
|
+
// enabled
|
|
275
|
+
this->page_->startTracing(
|
|
276
|
+
tracing::Mode::Background, {tracing::Category::Timeline});
|
|
277
|
+
|
|
278
|
+
// Record some frame timings
|
|
279
|
+
auto now = HighResTimeStamp::now();
|
|
280
|
+
this->page_->recordFrameTimings(
|
|
281
|
+
tracing::FrameTimingSequence(
|
|
282
|
+
1, // id
|
|
283
|
+
11, // threadId
|
|
284
|
+
now,
|
|
285
|
+
now + HighResDuration::fromNanoseconds(50)));
|
|
286
|
+
|
|
287
|
+
// Stop tracing - no eligible sessions exist, so the trace is stashed
|
|
288
|
+
EXPECT_FALSE(this->page_->stopAndMaybeEmitBackgroundTrace());
|
|
289
|
+
|
|
290
|
+
// Now the primary session enables ReactNativeApplication - it should receive
|
|
291
|
+
// the stashed trace. Events within a session are ordered.
|
|
292
|
+
Sequence primarySeq;
|
|
293
|
+
EXPECT_CALL(
|
|
294
|
+
this->fromPage(),
|
|
295
|
+
onMessage(JsonParsed(
|
|
296
|
+
AtJsonPtr("/method", "ReactNativeApplication.metadataUpdated"))))
|
|
297
|
+
.InSequence(primarySeq);
|
|
298
|
+
EXPECT_CALL(
|
|
299
|
+
this->fromPage(),
|
|
300
|
+
onMessage(JsonParsed(
|
|
301
|
+
AtJsonPtr("/method", "ReactNativeApplication.traceRequested"))))
|
|
302
|
+
.InSequence(primarySeq);
|
|
303
|
+
EXPECT_CALL(
|
|
304
|
+
this->fromPage(),
|
|
305
|
+
onMessage(JsonParsed(AtJsonPtr("/method", "Tracing.dataCollected"))))
|
|
306
|
+
.Times(AtLeast(1))
|
|
307
|
+
.InSequence(primarySeq);
|
|
308
|
+
EXPECT_CALL(
|
|
309
|
+
this->fromPage(),
|
|
310
|
+
onMessage(JsonParsed(AtJsonPtr("/method", "Tracing.tracingComplete"))))
|
|
311
|
+
.InSequence(primarySeq);
|
|
312
|
+
EXPECT_CALL(this->fromPage(), onMessage(JsonEq(R"({"id": 1, "result": {}})")))
|
|
313
|
+
.InSequence(primarySeq);
|
|
314
|
+
this->toPage_->sendMessage(
|
|
315
|
+
R"({"id": 1, "method": "ReactNativeApplication.enable"})");
|
|
316
|
+
|
|
317
|
+
// Connect a secondary session and enable ReactNativeApplication - it should
|
|
318
|
+
// NOT receive the already-emitted stashed trace
|
|
319
|
+
auto secondary = this->connectSecondary();
|
|
320
|
+
Sequence secondarySeq;
|
|
321
|
+
EXPECT_CALL(
|
|
322
|
+
secondary.fromPage(),
|
|
323
|
+
onMessage(JsonParsed(
|
|
324
|
+
AtJsonPtr("/method", "ReactNativeApplication.metadataUpdated"))))
|
|
325
|
+
.InSequence(secondarySeq);
|
|
326
|
+
// No traceRequested, dataCollected, or tracingComplete expected for
|
|
327
|
+
// secondary
|
|
328
|
+
EXPECT_CALL(
|
|
329
|
+
secondary.fromPage(), onMessage(JsonEq(R"({"id": 1, "result": {}})")))
|
|
330
|
+
.InSequence(secondarySeq);
|
|
331
|
+
secondary.toPage().sendMessage(
|
|
332
|
+
R"({"id": 1, "method": "ReactNativeApplication.enable"})");
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
} // namespace facebook::react::jsinspector_modern
|
|
@@ -0,0 +1,95 @@
|
|
|
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 "FollyDynamicMatchers.h"
|
|
11
|
+
#include "JsiIntegrationTest.h"
|
|
12
|
+
|
|
13
|
+
#include <fmt/format.h>
|
|
14
|
+
#include <folly/dynamic.h>
|
|
15
|
+
#include <folly/json.h>
|
|
16
|
+
#include <gmock/gmock.h>
|
|
17
|
+
|
|
18
|
+
#include <set>
|
|
19
|
+
#include <vector>
|
|
20
|
+
|
|
21
|
+
namespace facebook::react::jsinspector_modern {
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Base test class providing tracing-related test utilities for tests.
|
|
25
|
+
*/
|
|
26
|
+
template <typename EngineAdapter, typename Executor>
|
|
27
|
+
class TracingTestBase : public JsiIntegrationPortableTestBase<EngineAdapter, Executor> {
|
|
28
|
+
protected:
|
|
29
|
+
using JsiIntegrationPortableTestBase<EngineAdapter, Executor>::JsiIntegrationPortableTestBase;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Helper method to start tracing via Tracing.start CDP command.
|
|
33
|
+
*/
|
|
34
|
+
void startTracing(
|
|
35
|
+
const std::set<tracing::Category> &enabledCategories = {
|
|
36
|
+
tracing::Category::HiddenTimeline,
|
|
37
|
+
tracing::Category::JavaScriptSampling,
|
|
38
|
+
tracing::Category::RuntimeExecution,
|
|
39
|
+
tracing::Category::Timeline,
|
|
40
|
+
tracing::Category::UserTiming,
|
|
41
|
+
})
|
|
42
|
+
{
|
|
43
|
+
this->expectMessageFromPage(JsonEq(R"({
|
|
44
|
+
"id": 1,
|
|
45
|
+
"result": {}
|
|
46
|
+
})"));
|
|
47
|
+
|
|
48
|
+
this->toPage_->sendMessage(
|
|
49
|
+
fmt::format(
|
|
50
|
+
R"({{
|
|
51
|
+
"id": 1,
|
|
52
|
+
"method": "Tracing.start",
|
|
53
|
+
"params": {{ "categories": "{0}" }}
|
|
54
|
+
}})",
|
|
55
|
+
tracing::serializeTracingCategories(enabledCategories)));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Helper method to end tracing and collect all trace events from potentially
|
|
60
|
+
* multiple chunked Tracing.dataCollected messages.
|
|
61
|
+
* \returns A vector containing all collected trace events
|
|
62
|
+
*/
|
|
63
|
+
std::vector<folly::dynamic> endTracingAndCollectEvents()
|
|
64
|
+
{
|
|
65
|
+
testing::InSequence s;
|
|
66
|
+
|
|
67
|
+
this->expectMessageFromPage(JsonEq(R"({
|
|
68
|
+
"id": 1,
|
|
69
|
+
"result": {}
|
|
70
|
+
})"));
|
|
71
|
+
|
|
72
|
+
std::vector<folly::dynamic> allTraceEvents;
|
|
73
|
+
|
|
74
|
+
EXPECT_CALL(this->fromPage(), onMessage(JsonParsed(AtJsonPtr("/method", "Tracing.dataCollected"))))
|
|
75
|
+
.Times(testing::AtLeast(1))
|
|
76
|
+
.WillRepeatedly(testing::Invoke([&allTraceEvents](const std::string &message) {
|
|
77
|
+
auto parsedMessage = folly::parseJson(message);
|
|
78
|
+
auto &events = parsedMessage.at("params").at("value");
|
|
79
|
+
allTraceEvents.insert(
|
|
80
|
+
allTraceEvents.end(), std::make_move_iterator(events.begin()), std::make_move_iterator(events.end()));
|
|
81
|
+
}));
|
|
82
|
+
|
|
83
|
+
this->expectMessageFromPage(JsonParsed(
|
|
84
|
+
testing::AllOf(AtJsonPtr("/method", "Tracing.tracingComplete"), AtJsonPtr("/params/dataLossOccurred", false))));
|
|
85
|
+
|
|
86
|
+
this->toPage_->sendMessage(R"({
|
|
87
|
+
"id": 1,
|
|
88
|
+
"method": "Tracing.end"
|
|
89
|
+
})");
|
|
90
|
+
|
|
91
|
+
return allTraceEvents;
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
} // namespace facebook::react::jsinspector_modern
|
|
@@ -26,11 +26,21 @@ class ReactNativeFeatureFlagsOverrides
|
|
|
26
26
|
const InspectorFlagOverrides& overrides)
|
|
27
27
|
: overrides_(overrides) {}
|
|
28
28
|
|
|
29
|
+
bool fuseboxScreenshotCaptureEnabled() override {
|
|
30
|
+
return overrides_.screenshotCaptureEnabled.value_or(
|
|
31
|
+
ReactNativeFeatureFlagsDefaults::fuseboxScreenshotCaptureEnabled());
|
|
32
|
+
}
|
|
33
|
+
|
|
29
34
|
bool fuseboxEnabledRelease() override {
|
|
30
35
|
return overrides_.fuseboxEnabledRelease.value_or(
|
|
31
36
|
ReactNativeFeatureFlagsDefaults::fuseboxEnabledRelease());
|
|
32
37
|
}
|
|
33
38
|
|
|
39
|
+
bool fuseboxFrameRecordingEnabled() override {
|
|
40
|
+
return overrides_.frameRecordingEnabled.value_or(
|
|
41
|
+
ReactNativeFeatureFlagsDefaults::fuseboxFrameRecordingEnabled());
|
|
42
|
+
}
|
|
43
|
+
|
|
34
44
|
bool fuseboxNetworkInspectionEnabled() override {
|
|
35
45
|
return overrides_.networkInspectionEnabled.value_or(
|
|
36
46
|
ReactNativeFeatureFlagsDefaults::fuseboxNetworkInspectionEnabled());
|
|
@@ -19,9 +19,11 @@ namespace facebook::react::jsinspector_modern {
|
|
|
19
19
|
struct InspectorFlagOverrides {
|
|
20
20
|
// NOTE: Keep these entries in sync with ReactNativeFeatureFlagsOverrides in
|
|
21
21
|
// the implementation file.
|
|
22
|
+
std::optional<bool> screenshotCaptureEnabled;
|
|
23
|
+
std::optional<bool> enableNetworkEventReporting;
|
|
24
|
+
std::optional<bool> frameRecordingEnabled;
|
|
22
25
|
std::optional<bool> fuseboxEnabledRelease;
|
|
23
26
|
std::optional<bool> networkInspectionEnabled;
|
|
24
|
-
std::optional<bool> enableNetworkEventReporting;
|
|
25
27
|
};
|
|
26
28
|
|
|
27
29
|
/**
|
|
@@ -0,0 +1,61 @@
|
|
|
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 "TraceEvent.h"
|
|
11
|
+
|
|
12
|
+
#include <react/timing/primitives.h>
|
|
13
|
+
|
|
14
|
+
#include <cstdint>
|
|
15
|
+
#include <optional>
|
|
16
|
+
#include <vector>
|
|
17
|
+
|
|
18
|
+
namespace facebook::react::jsinspector_modern::tracing {
|
|
19
|
+
|
|
20
|
+
using FrameSequenceId = uint64_t;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* A struct representing a sequence of frame timings that happened on the Host side.
|
|
24
|
+
*/
|
|
25
|
+
struct FrameTimingSequence {
|
|
26
|
+
FrameTimingSequence() = delete;
|
|
27
|
+
|
|
28
|
+
FrameTimingSequence(
|
|
29
|
+
FrameSequenceId id,
|
|
30
|
+
ThreadId threadId,
|
|
31
|
+
HighResTimeStamp beginTimestamp,
|
|
32
|
+
HighResTimeStamp endTimestamp,
|
|
33
|
+
std::optional<std::vector<uint8_t>> screenshot = std::nullopt)
|
|
34
|
+
: id(id),
|
|
35
|
+
threadId(threadId),
|
|
36
|
+
beginTimestamp(beginTimestamp),
|
|
37
|
+
endTimestamp(endTimestamp),
|
|
38
|
+
screenshot(std::move(screenshot))
|
|
39
|
+
{
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Unique ID of the sequence, used by Chrome DevTools Frontend to identify the events that form one sequence.
|
|
44
|
+
*/
|
|
45
|
+
FrameSequenceId id;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The ID of the native thread that is associated with the frame.
|
|
49
|
+
*/
|
|
50
|
+
ThreadId threadId;
|
|
51
|
+
|
|
52
|
+
HighResTimeStamp beginTimestamp;
|
|
53
|
+
HighResTimeStamp endTimestamp;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Optional screenshot data captured during the frame.
|
|
57
|
+
*/
|
|
58
|
+
std::optional<std::vector<uint8_t>> screenshot;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
} // namespace facebook::react::jsinspector_modern::tracing
|
|
@@ -0,0 +1,43 @@
|
|
|
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 "FrameTimingSequence.h"
|
|
11
|
+
#include "InstanceTracingProfile.h"
|
|
12
|
+
#include "RuntimeSamplingProfile.h"
|
|
13
|
+
|
|
14
|
+
#include <react/timing/primitives.h>
|
|
15
|
+
|
|
16
|
+
#include <vector>
|
|
17
|
+
|
|
18
|
+
namespace facebook::react::jsinspector_modern::tracing {
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The final tracing profile for the given HostTarget.
|
|
22
|
+
* Contains all necessary information that is required to be be emitted as a series of Tracing.dataCollected CDP
|
|
23
|
+
* messages.
|
|
24
|
+
*/
|
|
25
|
+
struct HostTracingProfile {
|
|
26
|
+
// The ID of the OS-level process that this Trace Recording is associated
|
|
27
|
+
// with.
|
|
28
|
+
ProcessId processId;
|
|
29
|
+
|
|
30
|
+
// The timestamp at which this Trace Recording started.
|
|
31
|
+
HighResTimeStamp startTime;
|
|
32
|
+
|
|
33
|
+
// Frame timings captured on the Host side.
|
|
34
|
+
std::vector<FrameTimingSequence> frameTimings;
|
|
35
|
+
|
|
36
|
+
// All captured Instance Tracing Profiles during this Trace Recording.
|
|
37
|
+
std::vector<InstanceTracingProfile> instanceTracingProfiles;
|
|
38
|
+
|
|
39
|
+
// All captured Runtime Sampling Profiles during this Trace Recording.
|
|
40
|
+
std::vector<RuntimeSamplingProfile> runtimeSamplingProfiles;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
} // namespace facebook::react::jsinspector_modern::tracing
|