Android开发 camera被占用的问题

背景:

项目在Android 7.0的系统新加了一个camera2用于扫描。问题出在如果调用camera.open(2)打开camera2后没有调用release,系统相机会卡死,扫描APK也会无法使用,客户希望从framework层规避此类问题。也就是,即使apk不正规调用camera(没有释放),也不应该引起系统camera挂掉

分析:

原因就是camera2被占用后开启camera0或者camera1时仍然使用的camera2的参数配置,导致分辨率什么的都不对,系统异常等待。

解决方案:

失败案例1:在hardware Camera类中加个静态变量来区分camera2是否busy,在camera open时判断如果是cameraid==2,就将标识位计为true,release时不做判断,直接置为false。在getCameraInfo判断,如果是true则抛出异常。但是现在标识位第一次使用后不知道在什么地方被置为false。后来经过调查,多进程会导致static变量无法共享,当扫描apk调用camera时,静态变量会先初始化为false,调用camera.open(2)时,标识位变成true,假设此次camera2没有成功释放,此时打开系统相机,由于系统相机是另一个应用,会开启另一个进程,那么标识位会重置为false,但实际上camera2并没有释放,应该是true。该方案被pass。
失败原因:多进程引起静态变量的重新初始化,java中static变量只会初始化一次是在同一进程,如果换了进程,也就不再是同一个static变量了。(Android艺术探索IPC通信一节有详细讲为什么会出问题)

其他方案:使用数据库(Settings.Global.putInt()或者写文件或者使用SystemProperties.set(“myflag”,”true”);的方式,理论上是可行的,不过都最终卡在了权限问题上了,如果不设置adb shell setenforce 0,会导致无法创建文件,写数据库。而ystemProperties.set(“myflag”,”true”)会提示需要申请一个权限。如果是在App层,很容易做到,在清单文件配置即可,如果是android 6.0以上系统,需要添加主动申请权限的代码;但是现在修改的代码在framework base下面,完全不知道如何申请权限,如有大虾知道,还请不吝赐教。

最终方案:在frameworks/av/services/camera/libcameraservice/CameraService.cpp 和CameraService.h中做保护,定义一个方法,遍历camera,如果有任一camera在使用,就返回true(有camera在使用了,无法获取打开新的camera),只允许打开一个camera。

String8 id;
for(int i=0; i< mNumberOfCameras; i++)
{
    id = String8::format("%d", i);
    if (checkIfDeviceIsUsable(id) != NO_ERROR) {
           return true;
   }
}
return false;

checkIfDeviceIsUsable应该是android原生的代码

status_t CameraService::checkIfDeviceIsUsable(const String8& cameraId) const {
    auto cameraState = getCameraState(cameraId);
    int callingPid = getCallingPid();
    if (cameraState == nullptr) {
        ALOGE("CameraService::connect X (PID %d) rejected (invalid camera ID %s)", callingPid,
                cameraId.string());
        return -ENODEV;
    }

    int32_t currentStatus = cameraState->getStatus();
    if (currentStatus == ICameraServiceListener::STATUS_NOT_PRESENT) {
        ALOGE("CameraService::connect X (PID %d) rejected (camera %s is not connected)",
                callingPid, cameraId.string());
        return -ENODEV;
    } else if (currentStatus == ICameraServiceListener::STATUS_ENUMERATING) {
        ALOGE("CameraService::connect X (PID %d) rejected, (camera %s is initializing)",
                callingPid, cameraId.string());
        return -EBUSY;
    } else if (currentStatus == ICameraServiceListener::STATUS_NOT_AVAILABLE) {//此处为后来加上
        ALOGE("CameraService::connect X (PID %d) rejected, (camera %s is not available)",
                callingPid, cameraId.string());
        return -EBUSY;
    }

    return NO_ERROR;
}

不管camera对象有几个,管理camera的service只有一个,这样就不用考虑什么进程线程的问题了,其实上面的几个方案思路一致,都是记录一个标识位来表示camera2的使用状态,后来无法使用,有的是遇到跨进程共享问题,有的是遇到权限问题。不过说道跨进程共享问题,数据库和文件肯定是能解决问题的,但是无奈卡在权限问题上了。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值