From 6b3a39db9c55384b2d6046fc75f4002852f84029 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Wed, 22 Jul 2026 17:45:28 +0200 Subject: [PATCH 1/2] perf(android-replay): Use RGB_565 when alpha is unnecessary Reduce replay screenshot memory while retaining ARGB_8888 for SurfaceView compositing. Refs GH-5340 Co-Authored-By: Codex --- .../sentry/android/replay/screenshot/CanvasStrategy.kt | 2 +- .../android/replay/screenshot/PixelCopyStrategy.kt | 10 +++++++++- .../android/replay/screenshot/PixelCopyStrategyTest.kt | 9 +++++++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/sentry-android-replay/src/main/java/io/sentry/android/replay/screenshot/CanvasStrategy.kt b/sentry-android-replay/src/main/java/io/sentry/android/replay/screenshot/CanvasStrategy.kt index 406b23a9e4e..c3deefbf71b 100644 --- a/sentry-android-replay/src/main/java/io/sentry/android/replay/screenshot/CanvasStrategy.kt +++ b/sentry-android-replay/src/main/java/io/sentry/android/replay/screenshot/CanvasStrategy.kt @@ -97,7 +97,7 @@ internal class CanvasStrategy( Bitmap.createBitmap( config.recordingWidth, config.recordingHeight, - Bitmap.Config.ARGB_8888, + Bitmap.Config.RGB_565, ) } } diff --git a/sentry-android-replay/src/main/java/io/sentry/android/replay/screenshot/PixelCopyStrategy.kt b/sentry-android-replay/src/main/java/io/sentry/android/replay/screenshot/PixelCopyStrategy.kt index 00a64dbfadc..bea18384d0d 100644 --- a/sentry-android-replay/src/main/java/io/sentry/android/replay/screenshot/PixelCopyStrategy.kt +++ b/sentry-android-replay/src/main/java/io/sentry/android/replay/screenshot/PixelCopyStrategy.kt @@ -51,7 +51,15 @@ internal class PixelCopyStrategy( private val executor = executorProvider.getExecutor() private val mainLooperHandler = executorProvider.getMainLooperHandler() private val screenshot = - Bitmap.createBitmap(config.recordingWidth, config.recordingHeight, Bitmap.Config.ARGB_8888) + Bitmap.createBitmap( + config.recordingWidth, + config.recordingHeight, + if (options.sessionReplay.isCaptureSurfaceViews) { + Bitmap.Config.ARGB_8888 + } else { + Bitmap.Config.RGB_565 + }, + ) private val prescaledMatrix by lazy(NONE) { Matrix().apply { preScale(config.scaleFactorX, config.scaleFactorY) } } private val lastCaptureSuccessful = AtomicBoolean(false) diff --git a/sentry-android-replay/src/test/java/io/sentry/android/replay/screenshot/PixelCopyStrategyTest.kt b/sentry-android-replay/src/test/java/io/sentry/android/replay/screenshot/PixelCopyStrategyTest.kt index 834998da707..78168ee8644 100644 --- a/sentry-android-replay/src/test/java/io/sentry/android/replay/screenshot/PixelCopyStrategyTest.kt +++ b/sentry-android-replay/src/test/java/io/sentry/android/replay/screenshot/PixelCopyStrategyTest.kt @@ -38,6 +38,7 @@ import kotlin.test.assertFalse import kotlin.test.assertTrue import org.junit.runner.RunWith import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.doAnswer import org.mockito.kotlin.mock import org.mockito.kotlin.never @@ -310,7 +311,9 @@ class PixelCopyStrategyTest { assertFalse(fixture.contentChangedMarked.get()) assertTrue(strategy.lastCaptureSuccessful()) - verify(fixture.callback).onScreenshotRecorded(any()) + val screenshot = argumentCaptor() + verify(fixture.callback).onScreenshotRecorded(screenshot.capture()) + assertEquals(Bitmap.Config.RGB_565, screenshot.firstValue.config) } @Test @@ -342,7 +345,9 @@ class PixelCopyStrategyTest { shadowOf(Looper.getMainLooper()).idle() assertTrue(strategy.lastCaptureSuccessful()) - verify(fixture.callback).onScreenshotRecorded(any()) + val screenshot = argumentCaptor() + verify(fixture.callback).onScreenshotRecorded(screenshot.capture()) + assertEquals(Bitmap.Config.ARGB_8888, screenshot.firstValue.config) } @Test From 05221777721dc3b35c86bb592c05245489edd4cc Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Wed, 22 Jul 2026 17:48:58 +0200 Subject: [PATCH 2/2] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48ce2126e61..e2d5b44581b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Fixes - Prevent concurrent PixelCopy access during Session Replay masking and bitmap cleanup ([#5808](https://github.com/getsentry/sentry-java/pull/5808)) +- Reduce Session Replay screenshot memory usage ([#5821](https://github.com/getsentry/sentry-java/pull/5821)) - Backfill release, environment, distribution, tags, and app version/build—and use the matching replay-on-error sample rate—for `ApplicationExitInfo` ANR and native crash events captured before SDK initialization, without reusing options cached by a later app update ([#5762](https://github.com/getsentry/sentry-java/pull/5762)) - `SentryTagModifierNode.isImportantForBounds` now matches the default behavior and returns `true` ([#5789](https://github.com/getsentry/sentry-java/pull/5789)) - Prevent a `StackOverflowError` when a `beforeSend`, `beforeBreadcrumb`, `beforeSendLog`, or `beforeEnvelope` callback triggers another capture (directly or through a logging integration such as Timber) ([#5737](https://github.com/getsentry/sentry-java/pull/5737))