Camera2 OpenCamera流程 (Framework到CameraService)

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、handleEvictionsLocked()
接下来我们看看这个函数是如何处理摄像头冲突的。

status_t CameraService::handleEvictionsLocked(const String8& , int clientPid,
        apiLevel effectiveApiLevel, const sp<IBinder>& remoteCallback, const String8& packageName,
        /*out*/ 
        sp<BasicClient>* client,
        std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>>* partial) {
    ATRACE_CALL();
    status_t ret = NO_ERROR;
    //std::shared_ptr<resource_policy::ClientDescriptor<String8,sp<CameraService::BasicClient>>>  shared_ptr  是一种智能指针
    std::vector<DescriptorPtr> evictedClients;
    DescriptorPtr clientDescriptor;
    {
        if (effectiveApiLevel == API_1) { //API1的逻辑 这里不分析
        }
        //通过遍历CameraManager中的mClients列表遍历来获取所有打开相机的进程的pid
        std::vector<int> ownerPids(mActiveClientManager.getAllOwners());
        ownerPids.push_back(clientPid); // 将当前需要打开相机的进程的pid push到这个数组中
        std::vector<int> priorityScores(ownerPids.size()); //优先级列表
        std::vector<int> states(ownerPids.size());   //状态列表
        // 调用到了IProcessInfoService里面,这个里面会进行IPC机制调用到系统服务,来给这些进程进行优先级和状态的赋值 。
       // 一般不 会这里面的逻辑去修改来改变进程的优先级,一般是处理返回回来的优先级和状态来进行修改
        status_t err = ProcessInfoService::getProcessStatesScoresFromPids(
                ownerPids.size(), &ownerPids[0], /*out*/&states[0],
                /*out*/&priorityScores[0]);
        if (err != OK) {
            ALOGE("%s: Priority score query failed: %d", __FUNCTION__, err);
            return err;
        }
        // 将本地已经打开了摄像头的进程(不包含即将打开摄像头的进程)的优先级和状态赋值给一个新的集合pidToPriorityMap
        for (size_t i = 0; i < ownerPids.size() - 1; i++) {  //这里的 ownerPids.size() - 1  排除了即将打开摄像头的进程
            pidToPriorityMap.emplace(ownerPids[i],resource_policy::ClientPriority(priorityScores[i], states[i]));
        }
        mActiveClientManager.updatePriorities(pidToPriorityMap); //将pidToPriorityMap
        // 从本地mCameraStates集合中获取要打开相机的状态信息
        auto state = getCameraState(cameraId);
        if (state == nullptr) {
            ALOGE("CameraService::connect X (PID %d) rejected (no camera device with ID %s)",clientPid, cameraId.string());
            // Should never get here because validateConnectLocked should have errored out
            return BAD_VALUE;
        }
        // 会使用std::make_share 调用到ClientDescriptor的构造函数,因为是即将打开摄像头的进程所以这里的BasicClient是空的。
        clientDescriptor = CameraClientManager::makeClientDescriptor(cameraId,
                sp<BasicClient>{nullptr}, static_cast<int32_t>(state->getCost()),
                state->getConflicting(),
                priorityScores[priorityScores.size() - 1],
                clientPid,
                states[states.size() - 1]);
        // 通过和当前的进程的clientDescriptor 对象对比,判断本地的mClients列表中哪些进程是冲突的
        auto evicted = mActiveClientManager.wouldEvict(clientDescriptor);//返回的std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
        // 如果冲突列表中有即将开启的进程,那么就说明有其他优先级更高的进程正在使用摄像头,所以当前进程就会打开失败。
        if (std::find(evicted.begin(), evicted.end(), clientDescriptor) != evicted.end()) {
            ALOGE("CameraService::connect X (PID %d) rejected (existing client(s) with higher" " priority).", clientPid);
            sp<BasicClient> clientSp = clientDescriptor->getValue();
            String8 curTime = getFormattedCurrentTime();
            auto incompatibleClients = mActiveClientManager.getIncompatibleClients(clientDescriptor);
            ...........................  //省略代码  主要是构建错误信息msg
            for (auto& i : incompatibleClients) {
                 ....................  //省略代码  主要是构建错误信息msg和打印错误
            }
            // Log the client's attempt
            Mutex::Autolock l(mLogLock);
            mEventLog.add(msg);
            return -EBUSY;
        }
        //即将开启的进程优先级高可以开启摄像头  那么就把冲突列表中开了摄像头的进程一一关闭其打开的摄像头
        for (auto& i : evicted) {
            sp<BasicClient> clientSp = i->getValue();
            if (clientSp.get() == nullptr) {
                ALOGE("%s: Invalid state: Null client in active client list.", __FUNCTION__);
                // TODO: Remove this
                LOG_ALWAYS_FATAL("%s: Invalid state for CameraService, null client in active list", __FUNCTION__);
                mActiveClientManager.remove(i);
                continue;
            }

            ALOGE("CameraService::connect evicting conflicting client for camera ID %s",
                    i->getKey().string());
            evictedClients.push_back(i);
            // Notify the client of disconnection
            clientSp->notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
                    CaptureResultExtras());
        }
    }
    mServiceLock.unlock();
    // Clear caller identity temporarily so client disconnect PID checks work correctly
    int64_t token = IPCThreadState::self()->clearCallingIdentity();
    // Destroy evicted clients
    for (auto& i : evictedClients) {
        // Disconnect is blocking, and should only have returned when HAL has cleaned up
        i->getValue()->disconnect(); // Clients will remove themselves from the active client list
    }

    IPCThreadState::self()->restoreCallingIdentity(token);

    for (const auto& i : evictedClients) {
        ALOGV("%s: Waiting for disconnect to complete for client for device %s (PID %" PRId32 ")",  __FUNCTION__, i->getKey().string(), i->getOwnerId());
        ret = mActiveClientManager.waitUntilRemoved(i, DEFAULT_DISCONNECT_TIMEOUT_NS);
        if (ret == TIMED_OUT) {
            ALOGE("%s: Timed out waiting for client for device %s to disconnect, " "current clients:\n%s", __FUNCTION__, i->getKey().string(), mActiveClientManager.toString().string());
            return -EBUSY;
        }
        if (ret != NO_ERROR) {
            ALOGE("%s: Received error waiting for client for device %s to disconnect: %s (%d), ""current clients:\n%s", __FUNCTION__, i->getKey().string(), strerror(-ret),ret, mActiveClientManager.toString().string());
            return ret;
        }
    }
    evictedClients.clear();
    // Once clients have been disconnected, relock
    mServiceLock.lock();
    // Check again if the device was unplugged or something while we weren't holding mServiceLock
    if ((ret = checkIfDeviceIsUsable(cameraId)) != NO_ERROR) {
        return ret;
    }
    *partial = clientDescriptor;
    return NO_ERROR;
}

首先给ownerPids向量进行赋值,这里会调用mActiveClientManager.getAllOwners()函数,这里的mActiveClientManager是CameraService::CameraClientManager它继承了ClientManager对象。所以这里的getAllOwners()会调用到ClientManager中:

// 通过遍历ClientManager中的全局变量mClients(std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> mClients;)列表。
// 将列表元素ClientDescriptor中的mOwnerId(也就是pid)创建成一个集合返回
std::vector<int32_t> ClientManager<KEY, VALUE, LISTENER>::getAllOwners() const {
    Mutex::Autolock lock(mLock);
    std::set<int32_t> owners;
    for (const auto& i : mClients) {
        owners.emplace(i->getOwnerId());
    }
    return std::vector<int32_t>(owners.begin(), owners.end());
}

在获取到CameraService本地保存的已开启摄像头的进程和将要开启摄像头的进程的pid列表后,调用到IProcessInfoService对应的系统服务来给这些进程进行优先级和状态进行赋值,并存放到priorityScores和states向量中。然后将进程向量ownerPids、优先级向量priorityScores和状态向量states等信息中除了即将打开摄像头的进程的其他进程的状态和优先级赋值到pidToPriorityMap集合中,并将这个集合给到mActiveClientManager(CameraManager)对象,用来更新其内部的mClients列表中元素的优先级的值。
然后进一步通过本地的mCameraStates列表获取即将开启摄像头的状态信息。并通过上面的信息,来创建即将开启摄像头进程对ClientDescriptor对象 clientDescriptor = CameraClientManager::makeClientDescriptor()。

2.2.1.1 mActiveClientManager.wouldEvict(clientDescriptor)
创建完成之后会调用mActiveClientManager.wouldEvict(clientDescriptor)将该对象给到mActiveClientManager对象调用进行计算,得到一个摄像头使用冲突列表。计算代码如下:

// KEY--string8(cameraId)  VALUE--BasicClient(CameraDeviceClient)
template<class KEY, class VALUE, class LISTENER> 
std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
ClientManager<KEY, VALUE, LISTENER>::wouldEvictLocked(const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client,
        bool returnIncompatibleClients) const {
    //初始化冲突列表
    std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> evictList;
    // Disallow null clients, return input
    if (client == nullptr) {
        evictList.push_back(client);
        return evictList;
    }
    //这里的client是在上面函数传递过来的 是即将开启摄像头进程匹配的ClientDescriptor对象
    const KEY& key = client->getKey();  //将要开启摄像头的cameraId
    int32_t cost = client->getCost(); //对应的摄像头支持的最大数,通过CameraState获取到的
    ClientPriority priority = client->getPriority();//通过CameraState获取到的
    int32_t owner = client->getOwnerId();//上层app的pid
    int64_t totalCost = getCurrentCostLocked() + cost;
    // Determine the MRU of the owners tied for having the highest priority
    int32_t highestPriorityOwner = owner;
    ClientPriority highestPriority = priority;
    for (const auto& i : mClients) {  //遍历所有的Client 将冲突的Client放到冲突列表中
        ClientPriority curPriority = i->getPriority();
        if (curPriority <= highestPriority) {
            highestPriority = curPriority;
            highestPriorityOwner = i->getOwnerId();
        }
    }
    if (highestPriority == priority) {
        // Switch back owner if the incoming client has the highest priority, as it is MRU
        highestPriorityOwner = owner;
    }
    // Build eviction list of clients to remove
    for (const auto& i : mClients) {
        const KEY& curKey = i->getKey();
        int32_t curCost = i->getCost();
        ClientPriority curPriority = i->getPriority();
        int32_t curOwner = i->getOwnerId();
        bool conflicting = (curKey == key || i->isConflicting(key) ||client->isConflicting(curKey));
        if (!returnIncompatibleClients) {
            // Find evicted clients
            if (conflicting && curPriority < priority) {
                // Pre-existing conflicting client with higher priority exists
                evictList.clear();
                evictList.push_back(client);
                return evictList;
            } else if (conflicting || ((totalCost > mMaxCost && curCost > 0) &&(curPriority >= priority) && !(highestPriorityOwner == owner && owner == curOwner))) { 
                evictList.push_back(i);
                totalCost -= curCost;
            }
        } else {
            // Find clients preventing the incoming client from being added
            if (curPriority < priority && (conflicting || (totalCost > mMaxCost && curCost > 0))) {
                // Pre-existing conflicting client with higher priority exists
                evictList.push_back(i);
            }
        }
    }
    // Immediately return the incompatible clients if we are calculating these instead
    if (returnIncompatibleClients) {
        return evictList;
    }
    // If the total cost is too high, return the input unless the input has the highest priority
    if (totalCost > mMaxCost && highestPriorityOwner != owner) {
        evictList.clear();
        evictList.push_back(client);
        return evictList;
    }
    return evictList;
}

该函数主要是将当前应用的ClientDescriptor对象通过和本地已经打开了摄像头的应用对应的ClientDescriptor对象列表(该列表在上面connectHelper()中打开摄像头成功过后就会调用finishConnectLocked(client, partial)保存到本地的mClients中) 进行对比来得到一个冲突列表(意思是这个列表里面可能有当前应用)。
得到这个当前列表之后继续回到上面2.2.1 handleEvictionsLocked()的代码流程中,然后继续往下执行。在得到了冲突列表之后,如果当前进程在冲突列表中,就会返回失败,整个openCamera流程就到这结束了。如果当前进程不在冲突列表中,就遍历冲突列表把其中的进程操作的摄像头流程进行终止。
解决万冲突之后,就会去创建ICameraDeviceUser的实例。

2.2.2 CameraService::makeClient()**

解决冲突过后就是去新建一个CameraDeviceClient(CameraDeviceClient是ICameraDeviceClient的实现)对象。

/ 主要是根据 API 版本以及 HAL 版本来选择生成具体的 Client 实例,
// Client 就沿着前面分析下来的路径返回到 CameraDeviceImpl 实例中,被保存到 mRemoteDevice。
Status CameraService::makeClient(const sp<CameraService>& cameraService,
        const sp<IInterface>& cameraCb, const String16& packageName, const String8& cameraId,
        int api1CameraId, int facing, int clientPid, uid_t clientUid, int servicePid,
        bool legacyMode, int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
        /*out*/sp<BasicClient>* client) {

    if (halVersion < 0 || halVersion == deviceVersion) {
        // Default path: HAL version is unspecified by caller, create CameraClient
        // based on device version reported by the HAL.
        switch(deviceVersion) {
          case CAMERA_DEVICE_API_VERSION_1_0:
            if (effectiveApiLevel == API_1) {  // Camera1 API route
                sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
                *client = new CameraClient(cameraService, tmp, packageName,
                        api1CameraId, facing, clientPid, clientUid,
                        getpid(), legacyMode);
            } else { // Camera2 API route
                ALOGW("Camera using old HAL version: %d", deviceVersion);
                return STATUS_ERROR_FMT(ERROR_DEPRECATED_HAL,
                        "Camera device \"%s\" HAL version %d does not support camera2 API",
                        cameraId.string(), deviceVersion);
            }
            break;
          case CAMERA_DEVICE_API_VERSION_3_0:
          case CAMERA_DEVICE_API_VERSION_3_1:
          case CAMERA_DEVICE_API_VERSION_3_2:
          case CAMERA_DEVICE_API_VERSION_3_3:
          case CAMERA_DEVICE_API_VERSION_3_4:
            if (effectiveApiLevel == API_1) { // Camera1 API route
                sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
                *client = new Camera2Client(cameraService, tmp, packageName,
                        cameraId, api1CameraId,
                        facing, clientPid, clientUid,
                        servicePid, legacyMode);
            } else { // Camera2 API route
                sp<hardware::camera2::ICameraDeviceCallbacks> tmp =
                        static_cast<hardware::camera2::ICameraDeviceCallbacks*>(cameraCb.get());
                *client = new CameraDeviceClient(cameraService, tmp, packageName, cameraId,
                        facing, clientPid, clientUid, servicePid);
            }
            break;
          default:
            // Should not be reachable
            ALOGE("Unknown camera device HAL version: %d", deviceVersion);
            return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
                    "Camera device \"%s\" has unknown HAL version %d",
                    cameraId.string(), deviceVersion);
        }
    } else {
        // A particular HAL version is requested by caller. Create CameraClient
        // based on the requested HAL version.
        if (deviceVersion > CAMERA_DEVICE_API_VERSION_1_0 &&
            halVersion == CAMERA_DEVICE_API_VERSION_1_0) {
            // Only support higher HAL version device opened as HAL1.0 device.
            sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
            *client = new CameraClient(cameraService, tmp, packageName,
                    api1CameraId, facing, clientPid, clientUid,
                    servicePid, legacyMode);
        } else {
            // Other combinations (e.g. HAL3.x open as HAL2.x) are not supported yet.
            ALOGE("Invalid camera HAL version %x: HAL %x device can only be"
                    " opened as HAL %x device", halVersion, deviceVersion,
                    CAMERA_DEVICE_API_VERSION_1_0);
            return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
                    "Camera device \"%s\" (HAL version %d) cannot be opened as HAL version %d",
                    cameraId.string(), deviceVersion, halVersion);
        }
    }
    return Status::ok();
}

这个里面的逻辑比较简单就是根据当前使用的API的版本来创建一个ICameraDeviceUser的实例对象,这里创建的是CameraDeviceClient这个对象。
2.2.2.1 CameraDeviceClient()的构造函数
这里结合类图我们可以知道下面的这一层继承关系
CameraDeviceClient --|> Camera2ClientBase:继承
Camera2ClientBase --|> CameraDeviceClientBase:继承
CameraDeviceClientBase --|> CameraService::BasicClient

CameraDeviceClient::CameraDeviceClient(const sp<CameraService>& cameraService,
        const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
        const String16& clientPackageName,
        const String8& cameraId,
        int cameraFacing,
        int clientPid,
        uid_t clientUid,
        int servicePid) :
    Camera2ClientBase(cameraService, remoteCallback, clientPackageName,
                cameraId, /*API1 camera ID*/ -1,
                cameraFacing, clientPid, clientUid, servicePid),
    mInputStream(),
    mStreamingRequestId(REQUEST_ID_NONE),
    mRequestIdCounter(0) {

    ATRACE_CALL();
    ALOGI("CameraDeviceClient %s: Opened", cameraId.string());
}

------------------------------------------------------------------------------------------------
上面的构造函数中主动调用了其父类Camera2ClientBase的构造函数
template <typename TClientBase> //CameraDeviceClientBase
Camera2ClientBase<TClientBase>::Camera2ClientBase(
        const sp<CameraService>& cameraService,
        const sp<TCamCallbacks>& remoteCallback,
        const String16& clientPackageName,
        const String8& cameraId,
        int api1CameraId,
        int cameraFacing,
        int clientPid,
        uid_t clientUid,
        int servicePid):
        TClientBase(cameraService, remoteCallback, clientPackageName,
                cameraId, api1CameraId, cameraFacing, clientPid, clientUid, servicePid),
        mSharedCameraCallbacks(remoteCallback),
        mDeviceVersion(cameraService->getDeviceVersion(TClientBase::mCameraIdStr)),
        mDeviceActive(false), mApi1CameraId(api1CameraId)
{
    ALOGI("Camera %s: Opened. Client: %s (PID %d, UID %d)", cameraId.string(),
            String8(clientPackageName).string(), clientPid, clientUid);

    mInitialClientPid = clientPid;
    // 就是在这里创建了一个Camera3Device对象 这个对象对后面的Session和Capture的流程起到关键作用
    mDevice = new Camera3Device(cameraId); 
    LOG_ALWAYS_FATAL_IF(mDevice == 0, "Device should never be NULL here.");
}

-------------------------------------------------------------------------------------------------------------
上面的代码有执行了其父类CameraDeviceClientBase的构造函数

CameraDeviceClientBase::CameraDeviceClientBase(
        const sp<CameraService>& cameraService,
        const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
        const String16& clientPackageName,
        const String8& cameraId,
        int api1CameraId,
        int cameraFacing,
        int clientPid,
        uid_t clientUid,
        int servicePid) :
    BasicClient(cameraService,
            IInterface::asBinder(remoteCallback),
            clientPackageName,
            cameraId,
            cameraFacing,
            clientPid,
            clientUid,
            servicePid),
    mRemoteCallback(remoteCallback) {
    // We don't need it for API2 clients, but Camera2ClientBase requires it.
    (void) api1CameraId;
}

-------------------------------------------------------------------------------------------------
然后继续调用父类BaseClient的构造函数
CameraService::BasicClient::BasicClient(const sp<CameraService>& cameraService,
        const sp<IBinder>& remoteCallback,
        const String16& clientPackageName,
        const String8& cameraIdStr, int cameraFacing,
        int clientPid, uid_t clientUid,
        int servicePid):
        mCameraIdStr(cameraIdStr), mCameraFacing(cameraFacing),
        mClientPackageName(clientPackageName), mClientPid(clientPid), mClientUid(clientUid),
        mServicePid(servicePid),
        mDisconnected(false),
        mRemoteBinder(remoteCallback)
{
    if (sCameraService == nullptr) {
        sCameraService = cameraService;
    }
    mOpsActive = false;
    mDestructionStarted = false;
    if (mClientPackageName.size() <= 0) { // 如果没有包名 通过Binder获取应用层的包名信息
        sp<IServiceManager> sm = defaultServiceManager();
        sp<IBinder> binder = sm->getService(String16(kPermissionServiceName));
        if (binder == 0) {
            ALOGE("Cannot get permission service");
            // Leave mClientPackageName unchanged (empty) and the further interaction
            // with camera will fail in BasicClient::startCameraOps
            return;
        }
        sp<IPermissionController> permCtrl = interface_cast<IPermissionController>(binder);
        Vector<String16> packages;
        permCtrl->getPackagesForUid(mClientUid, packages);
        if (packages.isEmpty()) {
            ALOGE("No packages for calling UID");
            // Leave mClientPackageName unchanged (empty) and the further interaction
            // with camera will fail in BasicClient::startCameraOps
            return;
        }
        mClientPackageName = packages[0];
    }
}

执行完上面的构造函数之后就可以获取生成CameraDeviceClient对象。以上构造函数没有什么特别的逻辑主要是将构造函数中的参数进行保存和一些变量的初始化。最重要的一个操作就是在Camera2ClientBase的构造函数中new了一个Camera3Device对象。cmaeraid --- CameraDeviceClient --- Camera3Device 这是1对1的关系。

对象创建完成之后让我们继续回调2.2 connectHelper() 函数中继续分析下面的代码会执行到 client->initialize(mCameraProviderManager, mMonitorTags)对上面创建的CameraDeviceClient进行初始化。

2.2.3 CameraDeviceClient::initialize(sp<CameraProviderManager> manager,const String8& monitorTags)**

开始CameraDeviceClient的初始化流程

status_t CameraDeviceClient::initialize(sp<CameraProviderManager> manager,
        const String8& monitorTags) {
    return initializeImpl(manager, monitorTags);
}

template<typename TProviderPtr>
status_t CameraDeviceClient::initializeImpl(TProviderPtr providerPtr, const String8& monitorTags) {
    ATRACE_CALL();
    status_t res;

    res = Camera2ClientBase::initialize(providerPtr, monitorTags);
    if (res != OK) {
        return res;
    }

    String8 threadName;
    mFrameProcessor = new FrameProcessorBase(mDevice);
    threadName = String8::format("CDU-%s-FrameProc", mCameraIdStr.string());
    mFrameProcessor->run(threadName.string());

    mFrameProcessor->registerListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
                                      FRAME_PROCESSOR_LISTENER_MAX_ID,
                                      /*listener*/this,
                                      /*sendPartials*/true);

    auto deviceInfo = mDevice->info();
    camera_metadata_entry_t physicalKeysEntry = deviceInfo.find(
            ANDROID_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS);
    if (physicalKeysEntry.count > 0) {
        mSupportedPhysicalRequestKeys.insert(mSupportedPhysicalRequestKeys.begin(),
                physicalKeysEntry.data.i32,
                physicalKeysEntry.data.i32 + physicalKeysEntry.count);
    }

    return OK;
}

该函数第一个就是调用 Camera2ClientBase::initialize(providerPtr, monitorTags);

<>2.2.3.1 Camera2ClientBase<TClientBase>::initialize(sp<CameraProviderManager> manager,const String8& monitorTags)

template <typename TClientBase>
status_t Camera2ClientBase<TClientBase>::initialize(sp<CameraProviderManager> manager,
        const String8& monitorTags) {
    return initializeImpl(manager, monitorTags);
}

// TClientBase--CameraDeviceClientBase  TProviderPtr--CameraProviderManager
template <typename TClientBase>
template <typename TProviderPtr>
status_t Camera2ClientBase<TClientBase>::initializeImpl(TProviderPtr providerPtr, const String8& monitorTags) {
    ATRACE_CALL();
    ALOGV("%s: Initializing client for camera %s", __FUNCTION__,TClientBase::mCameraIdStr.string());
    status_t res;
    // Verify ops permissions  调用到CameraService::BasicClient::startCameraOps()里面主要是检查APP有没有相机操作权限
    res = TClientBase::startCameraOps();
    if (res != OK) {
        return res;
    }
    if (mDevice == NULL) {
        ALOGE("%s: Camera %s: No device connected", __FUNCTION__, TClientBase::mCameraIdStr.string());
        return NO_INIT;
    }
    res = mDevice->initialize(providerPtr, monitorTags);
    if (res != OK) {
        ALOGE("%s: Camera %s: unable to initialize device: %s (%d)", __FUNCTION__, TClientBase::mCameraIdStr.string(), strerror(-res), res);
        return res;
    }
    wp<CameraDeviceBase::NotificationListener> weakThis(this);
    res = mDevice->setNotifyCallback(weakThis);
    return OK;
}

上面首先就是对当前应用打开摄像头这一操作进行权限鉴权,然后调用了mDevice->initialize(providerPtr, monitorTags);继续进行初始化的操作,这样程序就来到了我们上面说的比较重要的一个对象Camera3Device对象中了。

2.2.4.2 Camera3Device::initialize

status_t Camera3Device::initialize(sp<CameraProviderManager> manager, const String8& monitorTags) {
    ATRACE_CALL();
    Mutex::Autolock il(mInterfaceLock);
    Mutex::Autolock l(mLock);
    ALOGV("%s: Initializing HIDL device for camera %s", __FUNCTION__, mId.string());
    if (mStatus != STATUS_UNINITIALIZED) {
        CLOGE("Already initialized!");
        return INVALID_OPERATION;
    }
    if (manager == nullptr) return INVALID_OPERATION;
    //这里对应了CameraProvider进程中的 ICameraDeviceSession.hal  (匿名Binder) 其服务端是在CameraProvider中的CameraDeviceSession.cpp
    sp<ICameraDeviceSession> session; 
    ATRACE_BEGIN("CameraHal::openSession");
    // 这里调用到CameraProviderManager的openSession主要是给session赋值(在这里面会去打开摄像头)
   //  this 在这是ICameraDeviceCallback.hal 回调接口的数据接收端 因为Camera3Device继承了ICameraDeviceCallback
    status_t res = manager->openSession(mId.string(), this, /*out*/ &session);
    ATRACE_END();
    if (res != OK) {
        SET_ERR_L("Could not open camera session: %s (%d)", strerror(-res), res);
        return res;
    }
    // 调用 CameraDeviceClient中的getCameraCharacteristics() 给mDeviceInfo赋值
    res = manager->getCameraCharacteristics(mId.string(), &mDeviceInfo);
    if (res != OK) {
        SET_ERR_L("Could not retrive camera characteristics: %s (%d)", strerror(-res), res);
        session->close();
        return res;
    }
    std::shared_ptr<RequestMetadataQueue> queue;
    auto requestQueueRet = session->getCaptureRequestMetadataQueue(
        [&queue](const auto& descriptor) {
            queue = std::make_shared<RequestMetadataQueue>(descriptor);
            if (!queue->isValid() || queue->availableToWrite() <= 0) {
                ALOGE("HAL returns empty request metadata fmq, not use it");
                queue = nullptr;
                // don't use the queue onwards.
            }
        });
    if (!requestQueueRet.isOk()) {
        ALOGE("Transaction error when getting request metadata fmq: %s, not use it",
                requestQueueRet.description().c_str());
        return DEAD_OBJECT;
    }

    std::unique_ptr<ResultMetadataQueue>& resQueue = mResultMetadataQueue;
    auto resultQueueRet = session->getCaptureResultMetadataQueue(
        [&resQueue](const auto& descriptor) {
            resQueue = std::make_unique<ResultMetadataQueue>(descriptor);
            if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
                ALOGE("HAL returns empty result metadata fmq, not use it");
                resQueue = nullptr;
                // Don't use the resQueue onwards.
            }
        });
    if (!resultQueueRet.isOk()) {
        ALOGE("Transaction error when getting result metadata queue from camera session: %s",
                resultQueueRet.description().c_str());
        return DEAD_OBJECT;
    }
    IF_ALOGV() {
        session->interfaceChain([](
            ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) {
                ALOGV("Session interface chain:");
                for (auto iface : interfaceChain) {
                    ALOGV("  %s", iface.c_str());
                }
            });
    }

    mInterface = new HalInterface(session, queue);
    std::string providerType;
    mVendorTagId = manager->getProviderTagIdLocked(mId.string());
    mTagMonitor.initialize(mVendorTagId);
    if (!monitorTags.isEmpty()) {
        mTagMonitor.parseTagsToMonitor(String8(monitorTags));
    }
    return initializeCommonLocked();
}



status_t Camera3Device::initializeCommonLocked() {
    /** Start up status tracker thread */
    mStatusTracker = new StatusTracker(this);
    status_t res = mStatusTracker->run(String8::format("C3Dev-%s-Status", mId.string()).string());
    if (res != OK) {
        SET_ERR_L("Unable to start status tracking thread: %s (%d)",strerror(-res), res);
        mInterface->close();
        mStatusTracker.clear();
        return res;
    }

    /** Register in-flight map to the status tracker */
    mInFlightStatusId = mStatusTracker->addComponent();

    /** Create buffer manager */
    mBufferManager = new Camera3BufferManager();

    Vector<int32_t> sessionParamKeys;
    camera_metadata_entry_t sessionKeysEntry = mDeviceInfo.find(
            ANDROID_REQUEST_AVAILABLE_SESSION_KEYS);
    if (sessionKeysEntry.count > 0) {
        sessionParamKeys.insertArrayAt(sessionKeysEntry.data.i32, 0, sessionKeysEntry.count);
    }
    /** Start up request queue thread */
    mRequestThread = new RequestThread(this, mStatusTracker, mInterface, sessionParamKeys);
    res = mRequestThread->run(String8::format("C3Dev-%s-ReqQueue", mId.string()).string());
    if (res != OK) {
        SET_ERR_L("Unable to start request queue thread: %s (%d)",
                strerror(-res), res);
        mInterface->close();
        mRequestThread.clear();
        return res;
    }
    mPreparerThread = new PreparerThread();

    internalUpdateStatusLocked(STATUS_UNCONFIGURED);
    mNextStreamId = 0;
    mDummyStreamId = NO_STREAM;
    mNeedConfig = true;
    mPauseStateNotify = false;

    // Measure the clock domain offset between camera and video/hw_composer
    camera_metadata_entry timestampSource =
            mDeviceInfo.find(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE);
    if (timestampSource.count > 0 && timestampSource.data.u8[0] ==
            ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME) {
        mTimestampOffset = getMonoToBoottimeOffset();
    }

    // Will the HAL be sending in early partial result metadata?
    camera_metadata_entry partialResultsCount =mDeviceInfo.find(ANDROID_REQUEST_PARTIAL_RESULT_COUNT);
    if (partialResultsCount.count > 0) {
        mNumPartialResults = partialResultsCount.data.i32[0];
        mUsePartialResult = (mNumPartialResults > 1);
    }

    camera_metadata_entry configs = mDeviceInfo.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
    for (uint32_t i = 0; i < configs.count; i += 4) {
        if (configs.data.i32[i] == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED &&
                configs.data.i32[i + 3] ==
                ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT) {
            mSupportedOpaqueInputSizes.add(Size(configs.data.i32[i + 1],configs.data.i32[i + 2]));
        }
    }
    if (DistortionMapper::isDistortionSupported(mDeviceInfo)) {
        res = mDistortionMapper.setupStaticInfo(mDeviceInfo);
        if (res != OK) {
            SET_ERR_L("Unable to read necessary calibration fields for distortion correction");
            return res;
        }
    }
    return OK;
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容