Skip to content

Commit 863f5c0

Browse files
rubennortemeta-codesync[bot]
authored andcommitted
Capture initial screenshot when starting frame timing trace (#55720)
Summary: Pull Request resolved: #55720 Changelog: [internal] When tracing starts, the frame metrics listener only fires when new frames are rendered. This means if no UI changes occur during a trace, no screenshots are captured. This also causes the initial state of the UI to be missing from the trace. This change captures an initial screenshot immediately when `start()` is called, ensuring there's always at least one frame recorded at the beginning of a trace regardless of whether UI changes occur. The implementation also refactors the frame emission logic into a shared `emitFrameTiming()` method to eliminate code duplication between the frame metrics listener and the initial capture. Reviewed By: huntie Differential Revision: D94223073 fbshipit-source-id: b84edae7caa15e24b437ef151e9a6c42916817d3
1 parent f31bb88 commit 863f5c0

1 file changed

Lines changed: 25 additions & 17 deletions

File tree

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/FrameTimingsObserver.kt

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,23 +38,7 @@ internal class FrameTimingsObserver(
3838
Window.OnFrameMetricsAvailableListener { _, frameMetrics, _dropCount ->
3939
val beginTimestamp = frameMetrics.getMetric(FrameMetrics.VSYNC_TIMESTAMP)
4040
val endTimestamp = beginTimestamp + frameMetrics.getMetric(FrameMetrics.TOTAL_DURATION)
41-
42-
val frameId = frameCounter++
43-
val threadId = Process.myTid()
44-
45-
CoroutineScope(Dispatchers.Default).launch {
46-
val screenshot = if (screenshotsEnabled) captureScreenshot() else null
47-
48-
onFrameTimingSequence(
49-
FrameTimingSequence(
50-
frameId,
51-
threadId,
52-
beginTimestamp,
53-
endTimestamp,
54-
screenshot,
55-
)
56-
)
57-
}
41+
emitFrameTiming(beginTimestamp, endTimestamp)
5842
}
5943

6044
private suspend fun captureScreenshot(): String? = suspendCoroutine { continuation ->
@@ -123,9 +107,33 @@ internal class FrameTimingsObserver(
123107
return
124108
}
125109

110+
// Capture initial screenshot to ensure there's always at least one frame
111+
// recorded at the start of tracing, even if no UI changes occur
112+
val timestamp = System.nanoTime()
113+
emitFrameTiming(timestamp, timestamp)
114+
126115
window.addOnFrameMetricsAvailableListener(frameMetricsListener, handler)
127116
}
128117

118+
private fun emitFrameTiming(beginTimestamp: Long, endTimestamp: Long) {
119+
val frameId = frameCounter++
120+
val threadId = Process.myTid()
121+
122+
CoroutineScope(Dispatchers.Default).launch {
123+
val screenshot = if (screenshotsEnabled) captureScreenshot() else null
124+
125+
onFrameTimingSequence(
126+
FrameTimingSequence(
127+
frameId,
128+
threadId,
129+
beginTimestamp,
130+
endTimestamp,
131+
screenshot,
132+
)
133+
)
134+
}
135+
}
136+
129137
fun stop() {
130138
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
131139
return

0 commit comments

Comments
 (0)