Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
@@ -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()
}
}
Loading