复用SurfaceView播放视频触发SIGSEGV(信号11)崩溃问题求助
崩溃根本原因分析
- 该崩溃是Android 9(API 28)及以下版本的原生系统bug,触发路径为SurfaceView的异步位置更新逻辑:系统会将SurfaceView的位置变更任务放到hwui后台工作线程(hwuiTask)异步执行,当你复用SurfaceView、或者将SurfaceView从视图树移除后重新添加时,旧的
SurfaceControl实例已经被系统回收释放,但异步任务队列中未执行完的位置更新任务仍然持有该SurfaceControl的无效引用,执行时访问空指针偏移0x10的成员,触发SIGSEGV崩溃。 - 复用SurfaceView的场景下,如果未等待上一次Surface销毁回调完成就直接绑定新的播放数据源,会大幅提升该问题的触发概率。
可行解决方案
方案1:调整SurfaceView复用逻辑(兼容性最好,无性能损耗)
复用SurfaceView前执行以下操作,确保异步任务被清空:
- 先调用
yourSurfaceView.setVisibility(View.GONE),再调用requestLayout()触发视图重绘 - 等待
SurfaceHolder.Callback.surfaceDestroyed回调明确触发后,再将SurfaceView设置为View.VISIBLE,绑定新的播放数据源 - 禁止在surfaceDestroyed回调执行完成前,给SurfaceView绑定新的渲染上下文
方案2:关闭SurfaceView异步位置更新(仅适用于API 26~28)
通过反射关闭后台异步位置更新逻辑,让位置更新同步在主线程执行,避免异步任务持有无效引用,代码示例如下:
try { Method setEnableBgUpdates = SurfaceView.class.getDeclaredMethod("setEnableBackgroundPositionUpdates", boolean.class); setEnableBgUpdates.setAccessible(true); setEnableBgUpdates.invoke(yourSurfaceView, false); } catch (Exception e) { // 非Android 8.0~9版本无该方法,直接忽略即可 }
方案3:替换为TextureView实现
TextureView没有SurfaceControl异步更新的底层逻辑,复用逻辑更简单,完全不会触发该崩溃。唯一缺陷是比SurfaceView多一次图层合成步骤,性能略低,普通视频播放场景完全可以满足需求。
方案4:放弃SurfaceView复用
如果业务场景允许,每次播放新视频时直接创建新的SurfaceView实例,销毁旧实例,从根源避免旧实例的异步任务访问无效内存的问题。
内容的提问来源于stack exchange,提问作者Shekhar Kumar
相关产品推荐
相关产品推荐

