Camera2 OpenCamera流程

26e7011cffd9eb6256dfa631571afca4.gif

和你一起终身学习,这里是程序员Android

经典好文推荐,通过阅读本文,您将收获以下知识点:

1.1、APP层传递摄像头id来打开摄像头

这里的callback是回调给APP的摄像头打开的结果
handler这里主要是设置上面的回调所在的线程。该参数可以为空,为空framework会内部创建一个当前线程的Handler。

openCamera(@NonNull String cameraId, @NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler)
1.2、调用到CameraManager内部的openCameraForUid
openCameraForUid(cameraId, callback, CameraDeviceImpl.checkAndWrapHandler(handler), USE_CALLING_UID);
1.3、进一步调用内部函数openCameraDeviceUserAsync (只贴了相关的部分代码)
//uid在这里是USE_CALLING_UID的值为-1
private CameraDevice openCameraDeviceUserAsync(String cameraId,CameraDevice.StateCallback callback, Executor executor, final int uid)
         throws CameraAccessException {
        CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
        CameraDevice device = null;
        synchronized (mLock) { //同步       
            //这里是ICameraDeviceCallbacks的服务端的实现对象,传递给CameraService进程用来传递信息给framework
            ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks(); 
            if (supportsCamera2ApiLocked(cameraId)) {
                // Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
                // 通过ServiceManager对象获取CameraService进程的Binder
                ICameraService cameraService = CameraManagerGlobal.get().getCameraService();        
               //获取到CameraService的代理过后就调用connectDevice()函数来打开摄像头
                cameraUser = cameraService.connectDevice(callbacks, cameraId,mContext.getOpPackageName(), uid);
            } else {  // Use legacy camera implementation for HAL1 devices
                int id;
                id = Integer.parseInt(cameraId);   
                Log.i(TAG, "Using legacy camera HAL.");
                cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);  
            }
            // 将CameraService进程返回的ICameraDeviceUser的具体实现对象传递给CameraDeviceImpl对象。
            // 这样可以在CameraDeviceImpl对象中调用CameraService进程的CameraDeviceClient对象
            deviceImpl.setRemoteDevice(cameraUser);
            device = deviceImpl;
        }
        return device;
    }

framework层的API中最后通过AIDL机制通过代码cameraService.connectDevice() 让软件执行到了CameraService进程中的CameraService.cpp中

2.1、cameraService.connectDevice()

framework层的API中最后通过调用到了下面:

//这里的cameraCb是一个AIDL文件  它的实现(服务端)是在上面Framework中的CameraDeviceImpl中
Status CameraService::connectDevice(const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb, const String16& cameraId,
    const String16& clientPackageName,int clientUid,
     /*out 函数的输出对象*/
    sp<hardware::camera2::ICameraDeviceUser>* device) {
    ATRACE_CALL();
    Status ret = Status::ok();
    String8 id = String8(cameraId);
    sp<CameraDeviceClient> client = nullptr;
    //此处调用的 connectHelper 方法才真正实现了连接逻辑(HAL1 时最终也调用到这个方法)
    ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
            /*api1CameraId*/-1,
            CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName,
            clientUid, USE_CALLING_PID, API_2,
            /*legacyMode*/ false, 
            /*shimUpdateOnly*/ false,
            /*out*/client); 
    if(!ret.isOk()) {   //connect失败的情况
        logRejected(id, getCallingPid(), String8(clientPackageName),
                ret.toString8());
        return ret;
    }
    *device = client;
    return ret;
}

上面的函数主要是做了一些声明和初始化的操作。

2.2、CameraService::connectHelper()

继续往下分析就来到了connectHelper()

template<class CALLBACK, class CLIENT> //模板类  <ICameraDeviceCallbacks,CameraDeviceClient>
Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId, int api1CameraId, int halVersion, const String16& clientPackageName,
    int clientUid, int clientPid, apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly, /*out*/sp<CLIENT>& device) {
    binder::Status ret = binder::Status::ok();
    String8 clientName8(clientPackageName);
    int originalClientPid = 0;
    sp<CLIENT> client = nullptr;
    {
       // 同步锁防止不同进程同一时刻都在打开摄像头
        std::unique_ptr<AutoConditionLock> lock =AutoConditionLock::waitAndAcquire(mServiceLockWrapper, DEFAULT_CONNECT_TIMEOUT_NS);
        if (lock == nullptr) {
            ALOGE("CameraService::connect (PID %d) rejected (too many other clients connecting).",clientPid);
            return STATUS_ERROR_FMT(ERROR_MAX_CAMERAS_IN_USE,
                    "Cannot open camera %s for \"%s\" (PID %d): Too many other clients connecting",
                    cameraId.string(), clientName8.string(), clientPid);
        }

        // 对客户端的摄像头权限进行检查
        if(!(ret = validateConnectLocked(cameraId, clientName8,/*inout*/clientUid, /*inout*/clientPid, /*out*/originalClientPid)).isOk()) {
            return ret;
        }
        status_t err;
        sp<BasicClient> clientTmp = nullptr;
        std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>> partial;
        //1、handleEvictionsLocked就是在这里处理多进程打开摄像头冲突的 
        if ((err = handleEvictionsLocked(cameraId, originalClientPid, effectiveApiLevel,IInterface::asBinder(cameraCb), clientName8,
                 /*out*/&clientTmp, //使用camera2的api的时候这个对象为空
                 /*out*/&partial)
                 ) != NO_ERROR) {
               // 条件里面主要是return error  流程到此就结束了
        }
        if (clientTmp.get() != nullptr) {
            device = static_cast<CLIENT*>(clientTmp.get());
            return ret;
        }
        sp<BasicClient> tmp = nullptr;
         //2、调用 makeClient 生成 CameraDeviceClient 实例。
        if(!(ret = makeClient(this, cameraCb, clientPackageName,cameraId, api1CameraId, facing, clientPid, clientUid, getpid(), legacyMode,
                halVersion, deviceVersion, effectiveApiLevel, /*out*/&tmp)).isOk()) {
            return ret;  //返回失败
        }
        client = static_cast<CLIENT*>(tmp.get()); //将makeClient()函数生成的tmp对象强转成CLIENT*也就是CameraDeviceClient*
        //3、这里会调用到CameraDeviceClient::initialize() --->  CameraDeviceClient::initializeImpl() ---> Camera2ClientBase::initialize()  ---> 
        // Camera2ClientBase::initializeImpl() ---> Camera3Device::initialize()
        err = client->initialize(mCameraProviderManager, mMonitorTags);
        if (err != OK) {
            ALOGE("%s: Could not initialize client from HAL.", __FUNCTION__);
            // 到这会返回错误信息打开失败 流程终止 return error 
        }
        if (shimUpdateOnly) { //该值是上一个函数传递过来的该值为false
            // If only updating legacy shim parameters, immediately disconnect client
            mServiceLock.unlock();
            client->disconnect();
            mServiceLock.lock();
        } else {
            //4、add client to active clients list 将打开摄像头成功后的client转换成ClientDescriptor添加到ClientManager对象中的mClients列表中
            finishConnectLocked(client, partial);
        }
    } // lock is destroyed, allow further connect calls
    device = client;
    return ret;
}

上面函数进来首先做一些同步机制和权限验证,然后调用到handleEvictionsLocked()函数。这个函数主要是来处理Camera多进程使用摄像头冲突的。在执行完handleEvictionsLocked()函数后,和当前客户端打开摄像头的操作冲突的进程会去关闭或者断开摄像头的操作。然后去调用makeClient()函数去创建一个CameraDeviceClient对象。然后会调用client->initialize()函数对创建的CameraDeviceClient这个对象去进行一些初始化(主要是和CameraProvider进程的操作)和验证。如果验证OK就会将该对象返回给上层函数最后通过IPC返回给上层APP(这里使用了匿名Binder的机制 -- framework层的ICameraDeviceUser是客户端,CameraService进程中的ClientDeviceClient继承了BnCameraDeviceUser所以是服务端)。

2.2.1、handleEviction

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员Android

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值