Android 8.1.0下CameraCaptureSessionImpl.finalize()超时崩溃求助
Android 8.1.0下Camera2+Agora视频聊天崩溃排查与解决方案
崩溃日志
Fatal Exception: java.util.concurrent.TimeoutException: android.hardware.camera2.impl.CameraCaptureSessionImpl.finalize() timed out after 10 seconds at android.hardware.camera2.impl.CameraCaptureSessionImpl.close(CameraCaptureSessionImpl.java:373) at android.hardware.camera2.impl.CameraCaptureSessionImpl.finalize(CameraCaptureSessionImpl.java:663) at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:250) at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:237) at java.lang.Daemons$Daemon.run(Daemons.java:103) at java.lang.Thread.run(Thread.java:780)
排查思路
- 核查
CameraCaptureSession生命周期管理:确认是否依赖GC的finalize()方法释放资源,而未主动调用close()。Android 8.1.0的Camera2实现中,finalize()触发的资源释放可能存在锁竞争或线程阻塞问题。 - 检查Agora与Camera2的资源释放顺序:确认离开视频频道时,是否先停止Agora的视频采集、释放Agora引擎,再清理Camera2资源,避免两者资源占用冲突。
- 排查后台线程阻塞:
CameraCaptureSession.close()依赖后台线程执行,若线程被锁、IO操作或其他任务阻塞,会导致finalize()超时。检查自定义Camera回调线程或Agora线程是否存在资源竞争。 - 模拟高频场景复现:使用Android 8.1.0设备(如Pixel 2、小米6),模拟频繁进入/退出视频聊天、切换前后摄像头等操作,尝试触发崩溃。
解决方案
- 主动释放
CameraCaptureSession:在页面销毁或停止视频采集时,显式调用close()并置空引用,跳过GC的finalize()流程:
// 在Activity/Fragment的onDestroy或停止采集方法中 if (mCaptureSession != null) { mCaptureSession.close(); mCaptureSession = null; }
- 调整Agora与Camera2的资源释放顺序:先停止Agora视频流、离开频道、销毁引擎,再释放Camera2资源:
// 停止Agora本地视频流 mRtcEngine.muteLocalVideoStream(true); // 离开Agora频道 mRtcEngine.leaveChannel(); // 销毁Agora引擎实例 mRtcEngine.destroy(); // 释放Camera2资源 if (mCaptureSession != null) { mCaptureSession.close(); mCaptureSession = null; } if (mCameraDevice != null) { mCameraDevice.close(); mCameraDevice = null; }
- 确保Camera2操作在独立线程执行:使用
HandlerThread处理Camera2的创建、关闭等操作,避免主线程阻塞导致close()超时:
// 初始化Camera2线程 HandlerThread cameraThread = new HandlerThread("CameraThread"); cameraThread.start(); Handler cameraHandler = new Handler(cameraThread.getLooper()); // 在cameraHandler中执行CameraCaptureSession的创建与关闭 cameraHandler.post(() -> { // 创建或关闭CaptureSession的逻辑 });
- Android 8.1.0专属兼容:针对该版本增加延迟释放逻辑,避免资源竞争:
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O_MR1) { new Handler().postDelayed(() -> { if (mCaptureSession != null) { mCaptureSession.close(); mCaptureSession = null; } }, 500); }
内容的提问来源于stack exchange,提问作者Taewoo Kim
相关产品推荐
相关产品推荐

