From 4aa7aa4af255f7bfb00088ce5568a77eb4bedc99 Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Mon, 19 Oct 2026 10:03:19 +0000 Subject: [PATCH 1/2] fix(replay): Use software canvas for the video encoder on the Android Emulator Co-Authored-By: Roman Zavarnitsyn --- .../replay/video/SimpleVideoEncoder.kt | 47 ++++++++++------- .../video/SimpleVideoEncoderCanvasTest.kt | 51 +++++++++++++++++++ 2 files changed, 80 insertions(+), 18 deletions(-) create mode 100644 sentry-android-replay/src/test/java/io/sentry/android/replay/video/SimpleVideoEncoderCanvasTest.kt diff --git a/sentry-android-replay/src/main/java/io/sentry/android/replay/video/SimpleVideoEncoder.kt b/sentry-android-replay/src/main/java/io/sentry/android/replay/video/SimpleVideoEncoder.kt index dd9af1c24d6..b1e3cd20513 100644 --- a/sentry-android-replay/src/main/java/io/sentry/android/replay/video/SimpleVideoEncoder.kt +++ b/sentry-android-replay/src/main/java/io/sentry/android/replay/video/SimpleVideoEncoder.kt @@ -177,25 +177,8 @@ internal class SimpleVideoEncoder( } fun encode(image: Bitmap) { - /** - * it seems that Xiaomi devices have problems with hardware canvas, so we have to use lockCanvas - * instead https://stackoverflow.com/a/73520742 - * --- - * Same for Motorola devices. - * --- - * As for the Spreadtrum/Unisoc chipset, it can be spread across various devices, so we have to - * check the SOC_MANUFACTURER property, as the manufacturer name might have changed. - * https://github.com/getsentry/sentry-android-gradle-plugin/issues/861#issuecomment-2867021256 - */ val canvas = - if ( - Build.MANUFACTURER.contains("xiaomi", ignoreCase = true) || - Build.MANUFACTURER.contains("motorola", ignoreCase = true) || - SystemProperties.get(SystemProperties.Property.SOC_MANUFACTURER) - .equals("spreadtrum", ignoreCase = true) || - SystemProperties.get(SystemProperties.Property.SOC_MANUFACTURER) - .equals("unisoc", ignoreCase = true) - ) { + if (shouldUseSoftwareCanvas()) { surface?.lockCanvas(null) } else { surface?.lockHardwareCanvas() @@ -338,6 +321,34 @@ internal class SimpleVideoEncoder( } } +/** + * Whether frames should be drawn onto the encoder's input surface with a software canvas + * ([Surface.lockCanvas]) instead of a hardware one ([Surface.lockHardwareCanvas]). + * + * It seems that Xiaomi devices have problems with hardware canvas, so we have to use lockCanvas + * instead https://stackoverflow.com/a/73520742 + * --- + * Same for Motorola devices. + * --- + * As for the Spreadtrum/Unisoc chipset, it can be spread across various devices, so we have to + * check the SOC_MANUFACTURER property, as the manufacturer name might have changed. + * https://github.com/getsentry/sentry-android-gradle-plugin/issues/861#issuecomment-2867021256 + * --- + * On the Android Emulator (goldfish/ranchu), a hardware canvas makes hwui own an EGL window surface + * on the input surface. The emulator's EGL driver keeps a dequeued buffer on it and cancels that + * buffer when the surface is destroyed, which can crash natively in eglDestroySurface once the + * encoder has been torn down. https://github.com/getsentry/sentry-java/issues/6279 + */ +internal fun shouldUseSoftwareCanvas(): Boolean = + Build.MANUFACTURER.contains("xiaomi", ignoreCase = true) || + Build.MANUFACTURER.contains("motorola", ignoreCase = true) || + SystemProperties.get(SystemProperties.Property.SOC_MANUFACTURER) + .equals("spreadtrum", ignoreCase = true) || + SystemProperties.get(SystemProperties.Property.SOC_MANUFACTURER) + .equals("unisoc", ignoreCase = true) || + Build.HARDWARE.contains("goldfish", ignoreCase = true) || + Build.HARDWARE.contains("ranchu", ignoreCase = true) + @SuppressLint("UseRequiresApi") @TargetApi(24) internal data class MuxerConfig( diff --git a/sentry-android-replay/src/test/java/io/sentry/android/replay/video/SimpleVideoEncoderCanvasTest.kt b/sentry-android-replay/src/test/java/io/sentry/android/replay/video/SimpleVideoEncoderCanvasTest.kt new file mode 100644 index 00000000000..01598df8ef8 --- /dev/null +++ b/sentry-android-replay/src/test/java/io/sentry/android/replay/video/SimpleVideoEncoderCanvasTest.kt @@ -0,0 +1,51 @@ +package io.sentry.android.replay.video + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.google.common.truth.Truth.assertThat +import kotlin.test.Test +import org.junit.runner.RunWith +import org.robolectric.annotation.Config +import org.robolectric.shadows.ShadowBuild + +@RunWith(AndroidJUnit4::class) +@Config(sdk = [30]) +class SimpleVideoEncoderCanvasTest { + + @Test + fun `uses hardware canvas on regular devices`() { + ShadowBuild.setManufacturer("Google") + ShadowBuild.setHardware("tensor") + + assertThat(shouldUseSoftwareCanvas()).isFalse() + } + + @Test + fun `uses software canvas on Xiaomi devices`() { + ShadowBuild.setManufacturer("Xiaomi") + + assertThat(shouldUseSoftwareCanvas()).isTrue() + } + + @Test + fun `uses software canvas on Motorola devices`() { + ShadowBuild.setManufacturer("motorola") + + assertThat(shouldUseSoftwareCanvas()).isTrue() + } + + @Test + fun `uses software canvas on ranchu emulators`() { + ShadowBuild.setManufacturer("Google") + ShadowBuild.setHardware("ranchu") + + assertThat(shouldUseSoftwareCanvas()).isTrue() + } + + @Test + fun `uses software canvas on goldfish emulators`() { + ShadowBuild.setManufacturer("unknown") + ShadowBuild.setHardware("goldfish") + + assertThat(shouldUseSoftwareCanvas()).isTrue() + } +} From a85cc01370ab8735803a81ee87cf54ccbe7675be Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Mon, 19 Oct 2026 10:11:56 +0000 Subject: [PATCH 2/2] changelog Co-Authored-By: Roman Zavarnitsyn Co-Authored-By: Roman Zavarnitsyn --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index acca00fc3c3..8fbe9dd5074 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - Android 7.1.0 (API 25) and older don't trust the Let's Encrypt root certificate (ISRG Root X1), so without this fix, the SDK on those devices can no longer send events to Sentry after the switch. - The SDK now bundles ISRG Root X1 and trusts it in addition to the device's root certificates on API 25 and lower. This only applies to the SDK's own uploads to Sentry SaaS (DSNs on `sentry.io`), not to self-hosted Sentry, not to any other connection your app makes, and not if you set your own `SentryOptions.setSslSocketFactory`. - Apps need to update to an SDK version with this fix to keep sending events from these devices. +- Session Replay: Use a software canvas for video encoding on the Android Emulator to avoid a native crash in `eglDestroySurface` ([#6282](https://github.com/getsentry/sentry-java/pull/6282)) ### Internal