Android 11出现Fail to connect to camera service错误,入侵者自拍功能失效
Android 11 入侵者自拍功能报错问题
功能背景
我正在开发入侵者自拍功能,当用户输入错误的手机PIN码时,应用会拍摄自拍并通过邮件发送。该功能在Android 9系统上运行正常,但在Android 11系统上运行报错,相关日志与核心代码如下:
报错日志
2021-11-13 21:51:49.815 28831-28831/com.pbix.quantsecure I/System.out: SAM: has camera permission 2021-11-13 21:51:49.823 28831-28831/com.pbix.quantsecure I/System.out: SAM: findFrontFacingCamera(): 1 2021-11-13 21:51:49.837 28831-28831/com.pbix.quantsecure W/CameraBase: An error occurred while connecting to camera 1: Status(-8, EX_SERVICE_SPECIFIC): '6: connectHelper:2103: Camera "1" disabled by policy' 2021-11-13 21:51:49.838 28831-28831/com.pbix.quantsecure I/System.out: SAM: exception1: Fail to connect to camera service 2021-11-13 21:51:49.838 28831-28831/com.pbix.quantsecure W/System.err: java.lang.RuntimeException: Fail to connect to camera service 2021-11-13 21:51:49.839 28831-28831/com.pbix.quantsecure W/System.err: at android.hardware.Camera.<init>(Camera.java:557) 2021-11-13 21:51:49.839 28831-28831/com.pbix.quantsecure W/System.err: at android.hardware.Camera.open(Camera.java:402) 2021-11-13 21:51:49.839 28831-28831/com.pbix.quantsecure W/System.err: at com.pbix.quantsecure.utils.CapPhoto.openCamera(CapPhoto.java:206) 2021-11-13 21:51:49.839 28831-28831/com.pbix.quantsecure W/System.err: at com.pbix.quantsecure.utils.CapPhoto.onStartCommand(CapPhoto.java:142) 2021-11-13 21:51:49.839 28831-28831/com.pbix.quantsecure W/System.err: at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:4741) 2021-11-13 21:51:49.839 28831-28831/com.pbix.quantsecure W/System.err: at android.app.ActivityThread.access$1900(ActivityThread.java:301) 2021-11-13 21:51:49.839 28831-28831/com.pbix.quantsecure W/System.err: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2186) 2021-11-13 21:51:49.839 28831-28831/com.pbix.quantsecure W/System.err: at android.os.Handler.dispatchMessage(Handler.java:106) 2021-11-13 21:51:49.839 28831-28831/com.pbix.quantsecure W/System.err: at android.os.Looper.loop(Looper.java:246) 2021-11-13 21:51:49.839 28831-28831/com.pbix.quantsecure W/System.err: at android.app.ActivityThread.main(ActivityThread.java:8506) 2021-11-13 21:51:49.839 28831-28831/com.pbix.quantsecure W/System.err: at java.lang.reflect.Method.invoke(Native Method) 2021-11-13 21:51:49.839 28831-28831/com.pbix.quantsecure W/System.err: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602) 2021-11-13 21:51:49.839 28831-28831/com.pbix.quantsecure W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
核心代码
private int findFrontFacingCamera() { int cameraId = -1; // Search for the front facing camera int numberOfCameras = Camera.getNumberOfCameras(); for (int i = 0; i < numberOfCameras; i++) { CameraInfo info = new CameraInfo(); Camera.getCameraInfo(i, info); if (info.facing == CameraInfo.CAMERA_FACING_FRONT) { cameraId = i; break; } } return cameraId; } public void openCamera(){ try{ if (Camera.getNumberOfCameras() >= 2 && cam.equals("f")) { // mCamera = Camera.open(CameraInfo.CAMERA_FACING_FRONT); System.out.println("SAM: findFrontFacingCamera(): "+findFrontFacingCamera()); mCamera = Camera.open(findFrontFacingCamera()); } if (Camera.getNumberOfCameras() >= 2 && cam.equals("b")) { mCamera = Camera.open(CameraInfo.CAMERA_FACING_BACK); } if (Camera.getNumberOfCameras() < 2) { mCamera = Camera.open(); } }catch (Exception e){ System.out.println("SAM: exception1: "+e.getMessage()); Util.recordEx(e); e.printStackTrace(); } try { SurfaceView sv = new SurfaceView(getApplicationContext()); mCamera.setPreviewDisplay(sv.getHolder()); parameters = mCamera.getParameters(); mCamera.setParameters(parameters); SurfaceTexture st = new SurfaceTexture(MODE_PRIVATE); mCamera.setPreviewTexture(st); mCamera.startPreview(); mCamera.takePicture(null, null, mCall); sHolder = sv.getHolder(); } catch (Exception e) { System.out.println("SAM: exception2: "+e.getMessage()); Util.recordEx(e); e.printStackTrace(); } try { timerSendSMS = new Timer(); timerSendSMS.schedule(new CapPhoto.taskSendSMS(), 0, 2 * 60 * 1000); } catch (Exception e) { System.out.println("SAM: exception3: "+e.getMessage()); Util.recordEx(e); e.printStackTrace(); } }
问题原因
从日志中的Camera "1" disabled by policy报错可以直接定位:Android 11新增了锁屏/后台场景下相机访问限制的系统策略,默认禁止后台应用在锁屏状态下访问相机,这是Android 9运行正常、Android 11报错的核心原因。此外你使用的android.hardware.Camera是已被官方废弃的旧版相机API,Android 11对旧API的权限管控更严格,也会提升报错概率。
修复方案
- 权限配置调整
在AndroidManifest.xml中新增如下权限声明:<!-- 原有相机权限保留 --> <uses-permission android:name="android.permission.CAMERA" /> <!-- Android 11+ 前台服务调用相机所需权限 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA" /> <!-- 声明前置相机使用特性 --> <uses-feature android:name="android.hardware.camera.front" android:required="false" /> - 运行逻辑调整
将相机拍照逻辑绑定到前台服务执行,触发拍照前先启动前台服务并展示常驻通知,再调用相机接口,符合Android 11的后台权限管控要求。 - 兼容性优化
建议将废弃的旧版Camera API替换为Jetpack CameraX库,该库已经做了全Android版本的兼容性适配,无需手动处理不同系统的相机策略差异,开发维护成本更低。 - 降级兼容处理
若暂不打算重构现有相机逻辑,可新增系统版本判断与异常重试逻辑,当相机开启失败时,先尝试检测相机限制状态:// 加在openCamera方法开头 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class); if (dpm.getCameraDisabled(null)) { // 可引导用户开启锁屏相机访问权限,或触发系统权限申请弹窗 } }
内容的提问来源于stack exchange,提问作者Somnath Pal
相关产品推荐
相关产品推荐

