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
package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/FrameTimingsObserver.kt
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
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
|
+
package com.facebook.react.devsupport.inspector
|
|
9
|
+
|
|
10
|
+
import android.graphics.Bitmap
|
|
11
|
+
import android.os.Build
|
|
12
|
+
import android.os.Handler
|
|
13
|
+
import android.os.Looper
|
|
14
|
+
import android.os.Process
|
|
15
|
+
import android.view.FrameMetrics
|
|
16
|
+
import android.view.PixelCopy
|
|
17
|
+
import android.view.Window
|
|
18
|
+
import com.facebook.proguard.annotations.DoNotStripAny
|
|
19
|
+
import java.io.ByteArrayOutputStream
|
|
20
|
+
import java.util.concurrent.Executors
|
|
21
|
+
import java.util.concurrent.atomic.AtomicBoolean
|
|
22
|
+
import java.util.concurrent.atomic.AtomicReference
|
|
23
|
+
import kotlinx.coroutines.CoroutineDispatcher
|
|
24
|
+
import kotlinx.coroutines.CoroutineScope
|
|
25
|
+
import kotlinx.coroutines.Dispatchers
|
|
26
|
+
import kotlinx.coroutines.asCoroutineDispatcher
|
|
27
|
+
import kotlinx.coroutines.launch
|
|
28
|
+
|
|
29
|
+
@DoNotStripAny
|
|
30
|
+
internal class FrameTimingsObserver(
|
|
31
|
+
private val screenshotsEnabled: Boolean,
|
|
32
|
+
private val onFrameTimingSequence: (sequence: FrameTimingSequence) -> Unit,
|
|
33
|
+
) {
|
|
34
|
+
private val isSupported = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
|
|
35
|
+
private val mainHandler = Handler(Looper.getMainLooper())
|
|
36
|
+
|
|
37
|
+
// Serial dispatcher for encoding work (single background thread). We limit to 1 thread to
|
|
38
|
+
// minimize the performance impact of screenshot recording.
|
|
39
|
+
private val encodingDispatcher: CoroutineDispatcher =
|
|
40
|
+
Executors.newSingleThreadExecutor().asCoroutineDispatcher()
|
|
41
|
+
|
|
42
|
+
// Stores the most recently captured frame to opportunistically encode after the current frame.
|
|
43
|
+
// Replaced frames are emitted as timings without screenshots.
|
|
44
|
+
private val lastFrameBuffer = AtomicReference<FrameData?>(null)
|
|
45
|
+
|
|
46
|
+
private var frameCounter: Int = 0
|
|
47
|
+
private val encodingInProgress = AtomicBoolean(false)
|
|
48
|
+
@Volatile private var isTracing: Boolean = false
|
|
49
|
+
@Volatile private var currentWindow: Window? = null
|
|
50
|
+
|
|
51
|
+
private data class FrameData(
|
|
52
|
+
val bitmap: Bitmap,
|
|
53
|
+
val frameId: Int,
|
|
54
|
+
val threadId: Int,
|
|
55
|
+
val beginTimestamp: Long,
|
|
56
|
+
val endTimestamp: Long,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
fun start() {
|
|
60
|
+
if (!isSupported) {
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
frameCounter = 0
|
|
65
|
+
encodingInProgress.set(false)
|
|
66
|
+
lastFrameBuffer.set(null)
|
|
67
|
+
isTracing = true
|
|
68
|
+
|
|
69
|
+
// Emit initial frame event
|
|
70
|
+
val timestamp = System.nanoTime()
|
|
71
|
+
emitFrameTiming(timestamp, timestamp)
|
|
72
|
+
|
|
73
|
+
currentWindow?.addOnFrameMetricsAvailableListener(frameMetricsListener, mainHandler)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
fun stop() {
|
|
77
|
+
if (!isSupported) {
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
isTracing = false
|
|
82
|
+
|
|
83
|
+
currentWindow?.removeOnFrameMetricsAvailableListener(frameMetricsListener)
|
|
84
|
+
mainHandler.removeCallbacksAndMessages(null)
|
|
85
|
+
lastFrameBuffer.getAndSet(null)?.bitmap?.recycle()
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
fun setCurrentWindow(window: Window?) {
|
|
89
|
+
if (!isSupported || currentWindow === window) {
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
currentWindow?.removeOnFrameMetricsAvailableListener(frameMetricsListener)
|
|
94
|
+
currentWindow = window
|
|
95
|
+
if (isTracing) {
|
|
96
|
+
currentWindow?.addOnFrameMetricsAvailableListener(frameMetricsListener, mainHandler)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private val frameMetricsListener =
|
|
101
|
+
Window.OnFrameMetricsAvailableListener { _, frameMetrics, _ ->
|
|
102
|
+
// Guard against calls after stop()
|
|
103
|
+
if (!isTracing) {
|
|
104
|
+
return@OnFrameMetricsAvailableListener
|
|
105
|
+
}
|
|
106
|
+
val beginTimestamp = frameMetrics.getMetric(FrameMetrics.VSYNC_TIMESTAMP)
|
|
107
|
+
val endTimestamp = beginTimestamp + frameMetrics.getMetric(FrameMetrics.TOTAL_DURATION)
|
|
108
|
+
emitFrameTiming(beginTimestamp, endTimestamp)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private fun emitFrameTiming(beginTimestamp: Long, endTimestamp: Long) {
|
|
112
|
+
val frameId = frameCounter++
|
|
113
|
+
val threadId = Process.myTid()
|
|
114
|
+
|
|
115
|
+
if (!screenshotsEnabled) {
|
|
116
|
+
// Screenshots disabled - emit without screenshot
|
|
117
|
+
emitFrameEvent(frameId, threadId, beginTimestamp, endTimestamp, null)
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
captureScreenshot(frameId, threadId, beginTimestamp, endTimestamp) { frameData ->
|
|
122
|
+
if (frameData != null) {
|
|
123
|
+
if (encodingInProgress.compareAndSet(false, true)) {
|
|
124
|
+
// Not encoding - encode this frame immediately
|
|
125
|
+
encodeFrame(frameData)
|
|
126
|
+
} else {
|
|
127
|
+
// Encoding thread busy - store current screenshot in buffer for tail-capture
|
|
128
|
+
val oldFrameData = lastFrameBuffer.getAndSet(frameData)
|
|
129
|
+
if (oldFrameData != null) {
|
|
130
|
+
// Skipped frame - emit event without screenshot
|
|
131
|
+
emitFrameEvent(
|
|
132
|
+
oldFrameData.frameId,
|
|
133
|
+
oldFrameData.threadId,
|
|
134
|
+
oldFrameData.beginTimestamp,
|
|
135
|
+
oldFrameData.endTimestamp,
|
|
136
|
+
null,
|
|
137
|
+
)
|
|
138
|
+
oldFrameData.bitmap.recycle()
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
} else {
|
|
142
|
+
// Failed to capture (e.g. timeout) - emit without screenshot
|
|
143
|
+
emitFrameEvent(frameId, threadId, beginTimestamp, endTimestamp, null)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
private fun emitFrameEvent(
|
|
149
|
+
frameId: Int,
|
|
150
|
+
threadId: Int,
|
|
151
|
+
beginTimestamp: Long,
|
|
152
|
+
endTimestamp: Long,
|
|
153
|
+
screenshot: ByteArray?,
|
|
154
|
+
) {
|
|
155
|
+
CoroutineScope(Dispatchers.Default).launch {
|
|
156
|
+
onFrameTimingSequence(
|
|
157
|
+
FrameTimingSequence(frameId, threadId, beginTimestamp, endTimestamp, screenshot)
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
private fun encodeFrame(frameData: FrameData) {
|
|
163
|
+
CoroutineScope(encodingDispatcher).launch {
|
|
164
|
+
try {
|
|
165
|
+
val screenshot = encodeScreenshot(frameData.bitmap)
|
|
166
|
+
emitFrameEvent(
|
|
167
|
+
frameData.frameId,
|
|
168
|
+
frameData.threadId,
|
|
169
|
+
frameData.beginTimestamp,
|
|
170
|
+
frameData.endTimestamp,
|
|
171
|
+
screenshot,
|
|
172
|
+
)
|
|
173
|
+
} finally {
|
|
174
|
+
frameData.bitmap.recycle()
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Clear encoding flag early, allowing new frames to start fresh encoding sessions
|
|
178
|
+
encodingInProgress.set(false)
|
|
179
|
+
|
|
180
|
+
// Opportunistically encode tail frame (if present) without blocking new frames
|
|
181
|
+
val tailFrame = lastFrameBuffer.getAndSet(null)
|
|
182
|
+
if (tailFrame != null) {
|
|
183
|
+
try {
|
|
184
|
+
val screenshot = encodeScreenshot(tailFrame.bitmap)
|
|
185
|
+
emitFrameEvent(
|
|
186
|
+
tailFrame.frameId,
|
|
187
|
+
tailFrame.threadId,
|
|
188
|
+
tailFrame.beginTimestamp,
|
|
189
|
+
tailFrame.endTimestamp,
|
|
190
|
+
screenshot,
|
|
191
|
+
)
|
|
192
|
+
} finally {
|
|
193
|
+
tailFrame.bitmap.recycle()
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Must be called from the main thread so that PixelCopy captures the current frame.
|
|
200
|
+
private fun captureScreenshot(
|
|
201
|
+
frameId: Int,
|
|
202
|
+
threadId: Int,
|
|
203
|
+
beginTimestamp: Long,
|
|
204
|
+
endTimestamp: Long,
|
|
205
|
+
callback: (FrameData?) -> Unit,
|
|
206
|
+
) {
|
|
207
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
|
208
|
+
// PixelCopy not available
|
|
209
|
+
callback(null)
|
|
210
|
+
return
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
val window = currentWindow
|
|
214
|
+
if (window == null) {
|
|
215
|
+
// No window
|
|
216
|
+
callback(null)
|
|
217
|
+
return
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
val decorView = window.decorView
|
|
221
|
+
val width = decorView.width
|
|
222
|
+
val height = decorView.height
|
|
223
|
+
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
|
|
224
|
+
|
|
225
|
+
PixelCopy.request(
|
|
226
|
+
window,
|
|
227
|
+
bitmap,
|
|
228
|
+
{ copyResult ->
|
|
229
|
+
if (copyResult == PixelCopy.SUCCESS) {
|
|
230
|
+
callback(FrameData(bitmap, frameId, threadId, beginTimestamp, endTimestamp))
|
|
231
|
+
} else {
|
|
232
|
+
bitmap.recycle()
|
|
233
|
+
callback(null)
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
mainHandler,
|
|
237
|
+
)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
private fun encodeScreenshot(bitmap: Bitmap): ByteArray? {
|
|
241
|
+
var scaledBitmap: Bitmap? = null
|
|
242
|
+
return try {
|
|
243
|
+
val window = currentWindow ?: return null
|
|
244
|
+
val width = bitmap.width
|
|
245
|
+
val height = bitmap.height
|
|
246
|
+
val density = window.context.resources.displayMetrics.density
|
|
247
|
+
val scaledWidth = (width / density * SCREENSHOT_SCALE_FACTOR).toInt()
|
|
248
|
+
val scaledHeight = (height / density * SCREENSHOT_SCALE_FACTOR).toInt()
|
|
249
|
+
scaledBitmap = Bitmap.createScaledBitmap(bitmap, scaledWidth, scaledHeight, true)
|
|
250
|
+
|
|
251
|
+
val compressFormat =
|
|
252
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) Bitmap.CompressFormat.WEBP_LOSSY
|
|
253
|
+
else Bitmap.CompressFormat.JPEG
|
|
254
|
+
|
|
255
|
+
ByteArrayOutputStream(SCREENSHOT_OUTPUT_SIZE_HINT).use { outputStream ->
|
|
256
|
+
scaledBitmap.compress(compressFormat, SCREENSHOT_QUALITY, outputStream)
|
|
257
|
+
outputStream.toByteArray()
|
|
258
|
+
}
|
|
259
|
+
} catch (e: Exception) {
|
|
260
|
+
null
|
|
261
|
+
} finally {
|
|
262
|
+
scaledBitmap?.recycle()
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
companion object {
|
|
267
|
+
private const val SCREENSHOT_SCALE_FACTOR = 1.0f
|
|
268
|
+
private const val SCREENSHOT_QUALITY = 80
|
|
269
|
+
|
|
270
|
+
// Capacity hint for the ByteArrayOutputStream used during bitmap
|
|
271
|
+
// compression. Sized slightly above typical compressed output to minimise
|
|
272
|
+
// internal buffer resizing.
|
|
273
|
+
private const val SCREENSHOT_OUTPUT_SIZE_HINT = 65536 // 64 KB
|
|
274
|
+
}
|
|
275
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
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
|
+
package com.facebook.react.devsupport.inspector
|
|
9
|
+
|
|
10
|
+
import com.facebook.proguard.annotations.DoNotStripAny
|
|
11
|
+
|
|
12
|
+
@DoNotStripAny
|
|
13
|
+
internal enum class TracingState {
|
|
14
|
+
DISABLED, // There is no active trace
|
|
15
|
+
ENABLED_IN_BACKGROUND_MODE, // Trace is currently running in background mode
|
|
16
|
+
ENABLED_IN_CDP_MODE, // Trace is currently running in CDP mode
|
|
17
|
+
}
|
package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/TracingStateListener.kt
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
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
|
+
package com.facebook.react.devsupport.inspector
|
|
9
|
+
|
|
10
|
+
import com.facebook.proguard.annotations.DoNotStripAny
|
|
11
|
+
|
|
12
|
+
@DoNotStripAny
|
|
13
|
+
internal fun interface TracingStateListener {
|
|
14
|
+
public fun onStateChanged(state: TracingState, screenshotsEnabled: Boolean)
|
|
15
|
+
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
package com.facebook.react.devsupport.perfmonitor
|
|
9
9
|
|
|
10
|
-
import com.facebook.react.devsupport.
|
|
10
|
+
import com.facebook.react.devsupport.inspector.TracingState
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* [Experimental] Interface implemented by [com.facebook.react.runtime.ReactHostInspectorTarget]
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
package com.facebook.react.devsupport.perfmonitor
|
|
9
9
|
|
|
10
10
|
import com.facebook.react.bridge.UiThreadUtil
|
|
11
|
-
import com.facebook.react.devsupport.
|
|
11
|
+
import com.facebook.react.devsupport.inspector.TracingState
|
|
12
12
|
|
|
13
13
|
internal class PerfMonitorOverlayManager(
|
|
14
14
|
private val devHelper: PerfMonitorDevHelper,
|
|
@@ -21,7 +21,7 @@ internal class PerfMonitorOverlayManager(
|
|
|
21
21
|
get() = enabled
|
|
22
22
|
|
|
23
23
|
private var view: PerfMonitorOverlayView? = null
|
|
24
|
-
private var tracingState: TracingState = TracingState.
|
|
24
|
+
private var tracingState: TracingState = TracingState.ENABLED_IN_CDP_MODE
|
|
25
25
|
private var perfIssueCount: Int = 0
|
|
26
26
|
|
|
27
27
|
/** Enable the Perf Monitor overlay. */
|
|
@@ -92,7 +92,7 @@ internal class PerfMonitorOverlayManager(
|
|
|
92
92
|
|
|
93
93
|
private fun handleRecordingButtonPress() {
|
|
94
94
|
when (tracingState) {
|
|
95
|
-
TracingState.
|
|
95
|
+
TracingState.ENABLED_IN_BACKGROUND_MODE -> {
|
|
96
96
|
devHelper.inspectorTarget?.let { target ->
|
|
97
97
|
if (!target.pauseAndAnalyzeBackgroundTrace()) {
|
|
98
98
|
onRequestOpenDevTools()
|
|
@@ -102,7 +102,7 @@ internal class PerfMonitorOverlayManager(
|
|
|
102
102
|
TracingState.DISABLED -> {
|
|
103
103
|
devHelper.inspectorTarget?.resumeBackgroundTrace()
|
|
104
104
|
}
|
|
105
|
-
TracingState.
|
|
105
|
+
TracingState.ENABLED_IN_CDP_MODE -> Unit
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
}
|
|
@@ -21,7 +21,7 @@ import android.widget.TextView
|
|
|
21
21
|
import androidx.core.view.ViewCompat
|
|
22
22
|
import androidx.core.view.WindowInsetsCompat
|
|
23
23
|
import com.facebook.react.R
|
|
24
|
-
import com.facebook.react.devsupport.
|
|
24
|
+
import com.facebook.react.devsupport.inspector.TracingState
|
|
25
25
|
import com.facebook.react.uimanager.DisplayMetricsHolder
|
|
26
26
|
import com.facebook.react.uimanager.PixelUtil
|
|
27
27
|
|
|
@@ -50,12 +50,12 @@ internal class PerfMonitorOverlayView(
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
fun updateRecordingState(state: TracingState) {
|
|
53
|
-
if (state == TracingState.
|
|
53
|
+
if (state == TracingState.ENABLED_IN_CDP_MODE) {
|
|
54
54
|
dialog.hide()
|
|
55
55
|
return
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
if (state == TracingState.
|
|
58
|
+
if (state == TracingState.ENABLED_IN_BACKGROUND_MODE) {
|
|
59
59
|
(statusIndicator.background as GradientDrawable).setColor(Color.RED)
|
|
60
60
|
statusLabel.text = "Profiling Active"
|
|
61
61
|
tooltipLabel.text =
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
package com.facebook.react.devsupport.perfmonitor
|
|
9
9
|
|
|
10
|
-
import com.facebook.react.devsupport.
|
|
10
|
+
import com.facebook.react.devsupport.inspector.TracingState
|
|
11
11
|
|
|
12
12
|
/** [Experimental] An interface for subscribing to updates for the V2 Perf Monitor. */
|
|
13
13
|
internal interface PerfMonitorUpdateListener {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*
|
|
7
|
-
* @generated SignedSource<<
|
|
7
|
+
* @generated SignedSource<<a92c35b9527c3954516ee68db651afa7>>
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -372,12 +372,24 @@ public object ReactNativeFeatureFlags {
|
|
|
372
372
|
@JvmStatic
|
|
373
373
|
public fun fuseboxEnabledRelease(): Boolean = accessor.fuseboxEnabledRelease()
|
|
374
374
|
|
|
375
|
+
/**
|
|
376
|
+
* Enable frame timings and screenshots support in the React Native DevTools CDP backend. This flag is global and should not be changed across React Host lifetimes.
|
|
377
|
+
*/
|
|
378
|
+
@JvmStatic
|
|
379
|
+
public fun fuseboxFrameRecordingEnabled(): Boolean = accessor.fuseboxFrameRecordingEnabled()
|
|
380
|
+
|
|
375
381
|
/**
|
|
376
382
|
* Enable network inspection support in the React Native DevTools CDP backend. Requires `enableBridgelessArchitecture`. This flag is global and should not be changed across React Host lifetimes.
|
|
377
383
|
*/
|
|
378
384
|
@JvmStatic
|
|
379
385
|
public fun fuseboxNetworkInspectionEnabled(): Boolean = accessor.fuseboxNetworkInspectionEnabled()
|
|
380
386
|
|
|
387
|
+
/**
|
|
388
|
+
* Enable Page.captureScreenshot CDP method support in the React Native DevTools CDP backend. This flag is global and should not be changed across React Host lifetimes.
|
|
389
|
+
*/
|
|
390
|
+
@JvmStatic
|
|
391
|
+
public fun fuseboxScreenshotCaptureEnabled(): Boolean = accessor.fuseboxScreenshotCaptureEnabled()
|
|
392
|
+
|
|
381
393
|
/**
|
|
382
394
|
* Hides offscreen VirtualViews on iOS by setting hidden = YES to avoid extra cost of views
|
|
383
395
|
*/
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*
|
|
7
|
-
* @generated SignedSource<<
|
|
7
|
+
* @generated SignedSource<<a9ec10139cccac681fb73d8155377b02>>
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -77,7 +77,9 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
|
|
|
77
77
|
private var fixMappingOfEventPrioritiesBetweenFabricAndReactCache: Boolean? = null
|
|
78
78
|
private var fuseboxAssertSingleHostStateCache: Boolean? = null
|
|
79
79
|
private var fuseboxEnabledReleaseCache: Boolean? = null
|
|
80
|
+
private var fuseboxFrameRecordingEnabledCache: Boolean? = null
|
|
80
81
|
private var fuseboxNetworkInspectionEnabledCache: Boolean? = null
|
|
82
|
+
private var fuseboxScreenshotCaptureEnabledCache: Boolean? = null
|
|
81
83
|
private var hideOffscreenVirtualViewsOnIOSCache: Boolean? = null
|
|
82
84
|
private var overrideBySynchronousMountPropsAtMountingAndroidCache: Boolean? = null
|
|
83
85
|
private var perfIssuesEnabledCache: Boolean? = null
|
|
@@ -619,6 +621,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
|
|
|
619
621
|
return cached
|
|
620
622
|
}
|
|
621
623
|
|
|
624
|
+
override fun fuseboxFrameRecordingEnabled(): Boolean {
|
|
625
|
+
var cached = fuseboxFrameRecordingEnabledCache
|
|
626
|
+
if (cached == null) {
|
|
627
|
+
cached = ReactNativeFeatureFlagsCxxInterop.fuseboxFrameRecordingEnabled()
|
|
628
|
+
fuseboxFrameRecordingEnabledCache = cached
|
|
629
|
+
}
|
|
630
|
+
return cached
|
|
631
|
+
}
|
|
632
|
+
|
|
622
633
|
override fun fuseboxNetworkInspectionEnabled(): Boolean {
|
|
623
634
|
var cached = fuseboxNetworkInspectionEnabledCache
|
|
624
635
|
if (cached == null) {
|
|
@@ -628,6 +639,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
|
|
|
628
639
|
return cached
|
|
629
640
|
}
|
|
630
641
|
|
|
642
|
+
override fun fuseboxScreenshotCaptureEnabled(): Boolean {
|
|
643
|
+
var cached = fuseboxScreenshotCaptureEnabledCache
|
|
644
|
+
if (cached == null) {
|
|
645
|
+
cached = ReactNativeFeatureFlagsCxxInterop.fuseboxScreenshotCaptureEnabled()
|
|
646
|
+
fuseboxScreenshotCaptureEnabledCache = cached
|
|
647
|
+
}
|
|
648
|
+
return cached
|
|
649
|
+
}
|
|
650
|
+
|
|
631
651
|
override fun hideOffscreenVirtualViewsOnIOS(): Boolean {
|
|
632
652
|
var cached = hideOffscreenVirtualViewsOnIOSCache
|
|
633
653
|
if (cached == null) {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*
|
|
7
|
-
* @generated SignedSource<<
|
|
7
|
+
* @generated SignedSource<<ceb1cf55a1d6b6d71ad27ec7f8594b50>>
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -142,8 +142,12 @@ public object ReactNativeFeatureFlagsCxxInterop {
|
|
|
142
142
|
|
|
143
143
|
@DoNotStrip @JvmStatic public external fun fuseboxEnabledRelease(): Boolean
|
|
144
144
|
|
|
145
|
+
@DoNotStrip @JvmStatic public external fun fuseboxFrameRecordingEnabled(): Boolean
|
|
146
|
+
|
|
145
147
|
@DoNotStrip @JvmStatic public external fun fuseboxNetworkInspectionEnabled(): Boolean
|
|
146
148
|
|
|
149
|
+
@DoNotStrip @JvmStatic public external fun fuseboxScreenshotCaptureEnabled(): Boolean
|
|
150
|
+
|
|
147
151
|
@DoNotStrip @JvmStatic public external fun hideOffscreenVirtualViewsOnIOS(): Boolean
|
|
148
152
|
|
|
149
153
|
@DoNotStrip @JvmStatic public external fun overrideBySynchronousMountPropsAtMountingAndroid(): Boolean
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*
|
|
7
|
-
* @generated SignedSource<<
|
|
7
|
+
* @generated SignedSource<<fd1d27cb393bb274b44db0bcec73c7f8>>
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -137,8 +137,12 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
|
|
|
137
137
|
|
|
138
138
|
override fun fuseboxEnabledRelease(): Boolean = false
|
|
139
139
|
|
|
140
|
+
override fun fuseboxFrameRecordingEnabled(): Boolean = false
|
|
141
|
+
|
|
140
142
|
override fun fuseboxNetworkInspectionEnabled(): Boolean = true
|
|
141
143
|
|
|
144
|
+
override fun fuseboxScreenshotCaptureEnabled(): Boolean = false
|
|
145
|
+
|
|
142
146
|
override fun hideOffscreenVirtualViewsOnIOS(): Boolean = false
|
|
143
147
|
|
|
144
148
|
override fun overrideBySynchronousMountPropsAtMountingAndroid(): Boolean = false
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*
|
|
7
|
-
* @generated SignedSource<<
|
|
7
|
+
* @generated SignedSource<<38e86d50298e5c4199d456f709ac13fc>>
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -81,7 +81,9 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
|
|
|
81
81
|
private var fixMappingOfEventPrioritiesBetweenFabricAndReactCache: Boolean? = null
|
|
82
82
|
private var fuseboxAssertSingleHostStateCache: Boolean? = null
|
|
83
83
|
private var fuseboxEnabledReleaseCache: Boolean? = null
|
|
84
|
+
private var fuseboxFrameRecordingEnabledCache: Boolean? = null
|
|
84
85
|
private var fuseboxNetworkInspectionEnabledCache: Boolean? = null
|
|
86
|
+
private var fuseboxScreenshotCaptureEnabledCache: Boolean? = null
|
|
85
87
|
private var hideOffscreenVirtualViewsOnIOSCache: Boolean? = null
|
|
86
88
|
private var overrideBySynchronousMountPropsAtMountingAndroidCache: Boolean? = null
|
|
87
89
|
private var perfIssuesEnabledCache: Boolean? = null
|
|
@@ -680,6 +682,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
|
|
|
680
682
|
return cached
|
|
681
683
|
}
|
|
682
684
|
|
|
685
|
+
override fun fuseboxFrameRecordingEnabled(): Boolean {
|
|
686
|
+
var cached = fuseboxFrameRecordingEnabledCache
|
|
687
|
+
if (cached == null) {
|
|
688
|
+
cached = currentProvider.fuseboxFrameRecordingEnabled()
|
|
689
|
+
accessedFeatureFlags.add("fuseboxFrameRecordingEnabled")
|
|
690
|
+
fuseboxFrameRecordingEnabledCache = cached
|
|
691
|
+
}
|
|
692
|
+
return cached
|
|
693
|
+
}
|
|
694
|
+
|
|
683
695
|
override fun fuseboxNetworkInspectionEnabled(): Boolean {
|
|
684
696
|
var cached = fuseboxNetworkInspectionEnabledCache
|
|
685
697
|
if (cached == null) {
|
|
@@ -690,6 +702,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
|
|
|
690
702
|
return cached
|
|
691
703
|
}
|
|
692
704
|
|
|
705
|
+
override fun fuseboxScreenshotCaptureEnabled(): Boolean {
|
|
706
|
+
var cached = fuseboxScreenshotCaptureEnabledCache
|
|
707
|
+
if (cached == null) {
|
|
708
|
+
cached = currentProvider.fuseboxScreenshotCaptureEnabled()
|
|
709
|
+
accessedFeatureFlags.add("fuseboxScreenshotCaptureEnabled")
|
|
710
|
+
fuseboxScreenshotCaptureEnabledCache = cached
|
|
711
|
+
}
|
|
712
|
+
return cached
|
|
713
|
+
}
|
|
714
|
+
|
|
693
715
|
override fun hideOffscreenVirtualViewsOnIOS(): Boolean {
|
|
694
716
|
var cached = hideOffscreenVirtualViewsOnIOSCache
|
|
695
717
|
if (cached == null) {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*
|
|
7
|
-
* @generated SignedSource<<
|
|
7
|
+
* @generated SignedSource<<eb09ee29f25cd03df2e7c3d2b3def992>>
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -137,8 +137,12 @@ public interface ReactNativeFeatureFlagsProvider {
|
|
|
137
137
|
|
|
138
138
|
@DoNotStrip public fun fuseboxEnabledRelease(): Boolean
|
|
139
139
|
|
|
140
|
+
@DoNotStrip public fun fuseboxFrameRecordingEnabled(): Boolean
|
|
141
|
+
|
|
140
142
|
@DoNotStrip public fun fuseboxNetworkInspectionEnabled(): Boolean
|
|
141
143
|
|
|
144
|
+
@DoNotStrip public fun fuseboxScreenshotCaptureEnabled(): Boolean
|
|
145
|
+
|
|
142
146
|
@DoNotStrip public fun hideOffscreenVirtualViewsOnIOS(): Boolean
|
|
143
147
|
|
|
144
148
|
@DoNotStrip public fun overrideBySynchronousMountPropsAtMountingAndroid(): Boolean
|
|
@@ -23,6 +23,45 @@ public object PerformanceTracer {
|
|
|
23
23
|
SoLoader.loadLibrary("react_performancetracerjni")
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
public fun <T> trace(name: String, block: () -> T): T {
|
|
27
|
+
return trace(name, null /* track */, null /* trackGroup */, null /* color */, block)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public fun <T> trace(name: String, track: String, block: () -> T): T {
|
|
31
|
+
return trace(name, track, null /* trackGroup */, null /* color */, block)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public fun <T> trace(name: String, track: String, trackGroup: String, block: () -> T): T {
|
|
35
|
+
return trace(name, track, trackGroup, null /* color */, block)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public fun <T> trace(
|
|
39
|
+
name: String,
|
|
40
|
+
track: String?,
|
|
41
|
+
trackGroup: String?,
|
|
42
|
+
color: String?,
|
|
43
|
+
block: () -> T,
|
|
44
|
+
): T {
|
|
45
|
+
if (!isTracing()) {
|
|
46
|
+
return block()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
val startTimeNanos = java.lang.System.nanoTime()
|
|
50
|
+
try {
|
|
51
|
+
return block()
|
|
52
|
+
} finally {
|
|
53
|
+
val endTimeNanos = java.lang.System.nanoTime()
|
|
54
|
+
reportTimeStamp(
|
|
55
|
+
name,
|
|
56
|
+
startTimeNanos,
|
|
57
|
+
endTimeNanos,
|
|
58
|
+
track,
|
|
59
|
+
trackGroup,
|
|
60
|
+
color,
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
26
65
|
/** Callback interface for tracing state changes. */
|
|
27
66
|
@DoNotStrip
|
|
28
67
|
public interface TracingStateCallback {
|
|
@@ -63,7 +63,7 @@ public class BlobModule(reactContext: ReactApplicationContext) :
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
internal val networkingUriHandler =
|
|
67
67
|
object : NetworkingModule.UriHandler {
|
|
68
68
|
override fun supports(uri: Uri, responseType: String): Boolean {
|
|
69
69
|
val scheme = uri.scheme
|