Skip to content

Commit d0b25df

Browse files
romtsnclaude
andcommitted
fix(replay): Reconfig on single-dim resizes and recycle SurfaceView bitmap on throw
Two review-bot findings: 1. determineWindowSize used && to compare new vs last-known dimensions, so single-dimension resizes (split-screen drag, partial multi-window adjustments, foldable transitions where only one dim shifts) were silently dropped — onWindowSizeChanged only fired when both width AND height differed. The new layout listener already detects single-dim changes with ||, but then delegated to a function that AND'd them away. Switch the existing checks to || so any size delta reconfigs the recorder, matching the listener's intent. 2. In captureSurfaceViews, if PixelCopy.request or getLocationOnScreen threw after svBitmap was allocated, the catch path logged the error but never recycled the bitmap, leaking it until GC. Track the bitmap in a nullable local that the catch block recycles, and clear it after PixelCopy.request returns successfully so ownership transfers to the async callback without double-recycling. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 001f3ad commit d0b25df

2 files changed

Lines changed: 13 additions & 7 deletions

File tree

sentry-android-replay/src/main/java/io/sentry/android/replay/WindowRecorder.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ internal class WindowRecorder(
181181

182182
fun determineWindowSize(root: View) {
183183
if (root.hasSize()) {
184-
if (root.width != lastKnownWindowSize.x && root.height != lastKnownWindowSize.y) {
184+
if (root.width != lastKnownWindowSize.x || root.height != lastKnownWindowSize.y) {
185185
lastKnownWindowSize.set(root.width, root.height)
186186
windowCallback.onWindowSizeChanged(root.width, root.height)
187187
}
@@ -197,7 +197,7 @@ internal class WindowRecorder(
197197
}
198198
if (root.hasSize()) {
199199
root.removeOnPreDrawListenerSafe(this)
200-
if (root.width != lastKnownWindowSize.x && root.height != lastKnownWindowSize.y) {
200+
if (root.width != lastKnownWindowSize.x || root.height != lastKnownWindowSize.y) {
201201
lastKnownWindowSize.set(root.width, root.height)
202202
windowCallback.onWindowSizeChanged(root.width, root.height)
203203
}

sentry-android-replay/src/main/java/io/sentry/android/replay/screenshot/PixelCopyStrategy.kt

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -181,37 +181,43 @@ internal class PixelCopyStrategy(
181181
continue
182182
}
183183

184+
var svBitmap: Bitmap? = null
184185
try {
185-
val svBitmap =
186+
svBitmap =
186187
Bitmap.createBitmap(surfaceView.width, surfaceView.height, Bitmap.Config.ARGB_8888)
188+
val bitmapToCapture = svBitmap
187189

188190
surfaceView.getLocationOnScreen(svLocation)
189191
val capturedX = svLocation[0]
190192
val capturedY = svLocation[1]
191193

192194
PixelCopy.request(
193195
surfaceView,
194-
svBitmap,
196+
bitmapToCapture,
195197
{ copyResult: Int ->
196198
if (isClosed.get()) {
197-
svBitmap.recycle()
199+
bitmapToCapture.recycle()
198200
// still drive the completion latch so any prior captures get recycled by the
199201
// composite step's early-return path.
200202
onCaptureComplete()
201203
return@request
202204
}
203205
if (copyResult == PixelCopy.SUCCESS) {
204-
captures[index] = SurfaceViewCapture(svBitmap, capturedX, capturedY)
206+
captures[index] = SurfaceViewCapture(bitmapToCapture, capturedX, capturedY)
205207
} else {
206-
svBitmap.recycle()
208+
bitmapToCapture.recycle()
207209
options.logger.log(INFO, "Failed to capture SurfaceView: %d", copyResult)
208210
}
209211
onCaptureComplete()
210212
},
211213
mainLooperHandler.handler,
212214
)
215+
// Ownership transferred to the PixelCopy callback — clear local so catch doesn't
216+
// double-recycle if the recycle paths above already ran.
217+
svBitmap = null
213218
} catch (e: Throwable) {
214219
options.logger.log(WARNING, "Failed to capture SurfaceView", e)
220+
svBitmap?.recycle()
215221
onCaptureComplete()
216222
}
217223
}

0 commit comments

Comments
 (0)