Repository navigation
Session Replay: native SIGSEGV in eglDestroySurface (libEGL_emulation) when SimpleVideoEncoder releases its input surface on the Android emulator #6279
Description
Integration
sentry-android (Session Replay, sentry-android-replay)
Build System
Gradle
AGP Version
9.3.1
Proguard
Disabled (debug build)
Other Error Monitoring Solution
Firebase Crashlytics
Version
8.47.0 (sentry-android-gradle-plugin 6.14.0, sentry-native 0.15.2). The relevant code is unchanged in 8.61.0.
Steps to Reproduce
This is an intermittent race, not a deterministic repro.
- Enable Session Replay in session mode (
io.sentry.session-replay.session-sample-rate = 1.0), defaultPIXEL_COPYscreenshot strategy, NDK integration enabled. - Run the app on an Android Emulator arm64 image:
system-images;android-37.1;google_apis_playstore_ps16k;arm64-v8a(16 KB page size, Android 17, buildCP31.260623.012), emulator 37.2.12.0, macOS / Apple Silicon host. - Use the app normally while replay records segments (roughly one every 5 s).
We saw one crash after about 2 minutes (25 replay segments). An earlier 25-minute session (312 segments) did not crash.
Expected Result
Releasing a replay segment's video encoder does not crash the process.
Actual Result
Native crash on hwui's RenderThread while it destroys an EGL window surface. All frames are system/vendor code (no app frames):
SIGSEGV: Segfault (signalhandler, unhandled)
<unknown> /system/lib64/libutils.so
android::RefBase::incStrongRequireStrong /system/lib64/libutils.so
android::GraphicBuffer::from /system/lib64/libui.so
android::Surface::hook_cancelBuffer /system/lib64/libgui.so
egl_window_surface_t::~egl_window_surface_t /vendor/lib64/egl/libEGL_emulation.so
egl_window_surface_t::~egl_window_surface_t /vendor/lib64/egl/libEGL_emulation.so
eglDestroySurface /vendor/lib64/egl/libEGL_emulation.so
<unknown> /system/lib64/libEGL.so
<unknown> x7 /system/lib64/libhwui.so
android::Thread::_threadLoop /system/lib64/libutils.so
<unknown> /system/lib64/libutils.so
<unknown> x2 /apex/com.android.runtime/lib64/bionic/libc.so
The crash time lines up with the end of the last recorded replay segment: the replay for that session ends in the same second the native crash was captured.
Why we think SimpleVideoEncoder is the source. The libhwui frames are not symbolicated, so this comes from the shape of the stack plus the timing, not a frame-by-frame match:
SimpleVideoEncoder.encode()draws each frame withsurface.lockHardwareCanvas()on non-Xiaomi/Motorola/Unisoc devices (SimpleVideoEncoder.kt#L201 @ 8.61.0). That gives theMediaCodecinputSurfacea hwui context, which owns an EGL window surface on the RenderThread.SimpleVideoEncoder.release()callsmediaCodec.release()beforesurface?.release()(L313-L330 @ 8.61.0). So the hwui context's EGL surface is destroyed after the codec, which is the BufferQueue consumer, has already been released.- The emulator's EGL driver keeps a dequeued buffer on its window surface and cancels it in
~egl_window_surface_t. By then the buffer behind it has already been freed, soGraphicBuffer::from→incStrongRequireStrongdereferences a dead object.
The emulator's libEGL_emulation is arguably at fault for touching a freed buffer. But the replay SDK is the code that creates and tears down this surface every few seconds, and only on the emulator does that become a process crash.
Possible fixes
Either of these, or both, would remove the window:
- In
SimpleVideoEncoder.release(), release the inputSurface(which destroys its hwui context and EGL surface) beforemediaCodec.release(), afterdrainCodec(true)/mediaCodec.stop(). - Use
surface.lockCanvas(null)instead oflockHardwareCanvas()on emulators, as is already done for Xiaomi, Motorola, and Unisoc. For example, checkBuild.HARDWAREforranchuorgoldfish, orBuild.FINGERPRINTstarting withgeneric/google/sdk_gphone.
We can test a patched build on the same emulator image if that helps.
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsNo status
Activity
linear-code commentedon Oct 19, 2026
JAVA-780
romtsn commentedon Oct 19, 2026
hi, thanks for the detailed analysis and the suggested fix -- I've chosen the 2nd option as this only concerns emulators and it's a less involved fix than the 1st one (it would require testing on more devices which we don't currently own). Once #6282 lands you can try it in the next version of the SDK 👍