Camera2 OpenCamera流程 (Framework到CameraService)

1.1、APP層傳遞攝像頭id來打開攝像頭
//這里的callback是回調(diào)給APP的攝像頭打開的結果
//handler這里主要是設置上面的回調(diào)所在的線程度气。該參數(shù)可以為空,為空framework會內(nèi)部創(chuàng)建一個當前線程的Handler膨报。
openCamera(@NonNull String cameraId, @NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler)
1.2磷籍、調(diào)用到CameraManager內(nèi)部的openCameraForUid
openCameraForUid(cameraId, callback, CameraDeviceImpl.checkAndWrapHandler(handler), USE_CALLING_UID);
1.3、進一步調(diào)用內(nèi)部函數(shù)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的服務端的實現(xiàn)對象现柠,傳遞給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的代理過后就調(diào)用connectDevice()函數(shù)來打開攝像頭
                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的具體實現(xiàn)對象傳遞給CameraDeviceImpl對象院领。
            // 這樣可以在CameraDeviceImpl對象中調(diào)用CameraService進程的CameraDeviceClient對象
            deviceImpl.setRemoteDevice(cameraUser);
            device = deviceImpl;
        }
        return device;
    }

framework層的API中最后通過AIDL機制通過代碼cameraService.connectDevice() 讓軟件執(zhí)行到了CameraService進程中的CameraService.cpp中

2.1、cameraService.connectDevice()

framework層的API中最后通過調(diào)用到了下面:

//這里的cameraCb是一個AIDL文件  它的實現(xiàn)(服務端)是在上面Framework中的CameraDeviceImpl中
Status CameraService::connectDevice(const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb, const String16& cameraId,
    const String16& clientPackageName,int clientUid,
     /*out 函數(shù)的輸出對象*/
    sp<hardware::camera2::ICameraDeviceUser>* device) {
    ATRACE_CALL();
    Status ret = Status::ok();
    String8 id = String8(cameraId);
    sp<CameraDeviceClient> client = nullptr;
    //此處調(diào)用的 connectHelper 方法才真正實現(xiàn)了連接邏輯(HAL1 時最終也調(diào)用到這個方法)
    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;
}

上面的函數(shù)主要是做了一些聲明和初始化的操作够吩。

2.2比然、CameraService::connectHelper()

繼續(xù)往下分析就來到了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强法、調(diào)用 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()函數(shù)生成的tmp對象強轉(zhuǎn)成CLIENT*也就是CameraDeviceClient*
        //3湾笛、這里會調(diào)用到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) { //該值是上一個函數(shù)傳遞過來的該值為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轉(zhuǎn)換成ClientDescriptor添加到ClientManager對象中的mClients列表中
            finishConnectLocked(client, partial);
        }
    } // lock is destroyed, allow further connect calls
    device = client;
    return ret;
}

上面函數(shù)進來首先做一些同步機制和權限驗證,然后調(diào)用到handleEvictionsLocked()函數(shù)嚎研。這個函數(shù)主要是來處理Camera多進程使用攝像頭沖突的蓖墅。在執(zhí)行完handleEvictionsLocked()函數(shù)后,和當前客戶端打開攝像頭的操作沖突的進程會去關閉或者斷開攝像頭的操作嘉赎。然后去調(diào)用makeClient()函數(shù)去創(chuàng)建一個CameraDeviceClient對象置媳。然后會調(diào)用client->initialize()函數(shù)對創(chuàng)建的CameraDeviceClient這個對象去進行一些初始化(主要是和CameraProvider進程的操作)和驗證于樟。如果驗證OK就會將該對象返回給上層函數(shù)最后通過IPC返回給上層APP(這里使用了匿名Binder的機制 -- framework層的ICameraDeviceUser是客戶端公条,CameraService進程中的ClientDeviceClient繼承了BnCameraDeviceUser所以是服務端)。

2.2.1迂曲、handleEvictionsLocked()
接下來我們看看這個函數(shù)是如何處理攝像頭沖突的靶橱。

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到這個數(shù)組中
        std::vector<int> priorityScores(ownerPids.size()); //優(yōu)先級列表
        std::vector<int> states(ownerPids.size());   //狀態(tài)列表
        // 調(diào)用到了IProcessInfoService里面,這個里面會進行IPC機制調(diào)用到系統(tǒng)服務,來給這些進程進行優(yōu)先級和狀態(tài)的賦值 关霸。
       // 一般不 會這里面的邏輯去修改來改變進程的優(yōu)先級传黄,一般是處理返回回來的優(yōu)先級和狀態(tài)來進行修改
        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;
        }
        // 將本地已經(jīng)打開了攝像頭的進程(不包含即將打開攝像頭的進程)的優(yōu)先級和狀態(tài)賦值給一個新的集合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集合中獲取要打開相機的狀態(tài)信息
        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 調(diào)用到ClientDescriptor的構造函數(shù),因為是即將打開攝像頭的進程所以這里的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>>>
        // 如果沖突列表中有即將開啟的進程,那么就說明有其他優(yōu)先級更高的進程正在使用攝像頭佳遣,所以當前進程就會打開失敗识埋。
        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;
        }
        //即將開啟的進程優(yōu)先級高可以開啟攝像頭  那么就把沖突列表中開了攝像頭的進程一一關閉其打開的攝像頭
        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向量進行賦值,這里會調(diào)用mActiveClientManager.getAllOwners()函數(shù)零渐,這里的mActiveClientManager是CameraService::CameraClientManager它繼承了ClientManager對象窒舟。所以這里的getAllOwners()會調(diào)用到ClientManager中:

// 通過遍歷ClientManager中的全局變量mClients(std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> mClients;)列表。
// 將列表元素ClientDescriptor中的mOwnerId(也就是pid)創(chuàng)建成一個集合返回
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列表后诵盼,調(diào)用到IProcessInfoService對應的系統(tǒng)服務來給這些進程進行優(yōu)先級和狀態(tài)進行賦值惠豺,并存放到priorityScores和states向量中。然后將進程向量ownerPids风宁、優(yōu)先級向量priorityScores和狀態(tài)向量states等信息中除了即將打開攝像頭的進程的其他進程的狀態(tài)和優(yōu)先級賦值到pidToPriorityMap集合中洁墙,并將這個集合給到mActiveClientManager(CameraManager)對象,用來更新其內(nèi)部的mClients列表中元素的優(yōu)先級的值戒财。
然后進一步通過本地的mCameraStates列表獲取即將開啟攝像頭的狀態(tài)信息扫俺。并通過上面的信息,來創(chuàng)建即將開啟攝像頭進程對ClientDescriptor對象 clientDescriptor = CameraClientManager::makeClientDescriptor()固翰。

2.2.1.1 mActiveClientManager.wouldEvict(clientDescriptor)
創(chuàng)建完成之后會調(diào)用mActiveClientManager.wouldEvict(clientDescriptor)將該對象給到mActiveClientManager對象調(diào)用進行計算狼纬,得到一個攝像頭使用沖突列表。計算代碼如下:

// 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是在上面函數(shù)傳遞過來的 是即將開啟攝像頭進程匹配的ClientDescriptor對象
    const KEY& key = client->getKey();  //將要開啟攝像頭的cameraId
    int32_t cost = client->getCost(); //對應的攝像頭支持的最大數(shù)骂际,通過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放到?jīng)_突列表中
        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;
}

該函數(shù)主要是將當前應用的ClientDescriptor對象通過和本地已經(jīng)打開了攝像頭的應用對應的ClientDescriptor對象列表(該列表在上面connectHelper()中打開攝像頭成功過后就會調(diào)用finishConnectLocked(client, partial)保存到本地的mClients中) 進行對比來得到一個沖突列表(意思是這個列表里面可能有當前應用)疗琉。
得到這個當前列表之后繼續(xù)回到上面2.2.1 handleEvictionsLocked()的代碼流程中,然后繼續(xù)往下執(zhí)行歉铝。在得到了沖突列表之后盈简,如果當前進程在沖突列表中,就會返回失敗太示,整個openCamera流程就到這結束了柠贤。如果當前進程不在沖突列表中,就遍歷沖突列表把其中的進程操作的攝像頭流程進行終止类缤。
解決萬沖突之后臼勉,就會去創(chuàng)建ICameraDeviceUser的實例。

2.2.2 CameraService::makeClient()**

解決沖突過后就是去新建一個CameraDeviceClient(CameraDeviceClient是ICameraDeviceClient的實現(xiàn))對象餐弱。

/ 主要是根據(jù) 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();
}

這個里面的邏輯比較簡單就是根據(jù)當前使用的API的版本來創(chuàng)建一個ICameraDeviceUser的實例對象瓢谢,這里創(chuàng)建的是CameraDeviceClient這個對象畸写。
2.2.2.1 CameraDeviceClient()的構造函數(shù)
這里結合類圖我們可以知道下面的這一層繼承關系
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());
}

------------------------------------------------------------------------------------------------
上面的構造函數(shù)中主動調(diào)用了其父類Camera2ClientBase的構造函數(shù)
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;
    // 就是在這里創(chuàng)建了一個Camera3Device對象 這個對象對后面的Session和Capture的流程起到關鍵作用
    mDevice = new Camera3Device(cameraId); 
    LOG_ALWAYS_FATAL_IF(mDevice == 0, "Device should never be NULL here.");
}

-------------------------------------------------------------------------------------------------------------
上面的代碼有執(zhí)行了其父類CameraDeviceClientBase的構造函數(shù)

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;
}

-------------------------------------------------------------------------------------------------
然后繼續(xù)調(diào)用父類BaseClient的構造函數(shù)
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];
    }
}

執(zhí)行完上面的構造函數(shù)之后就可以獲取生成CameraDeviceClient對象。以上構造函數(shù)沒有什么特別的邏輯主要是將構造函數(shù)中的參數(shù)進行保存和一些變量的初始化氓扛。最重要的一個操作就是在Camera2ClientBase的構造函數(shù)中new了一個Camera3Device對象枯芬。cmaeraid --- CameraDeviceClient --- Camera3Device 這是1對1的關系。

對象創(chuàng)建完成之后讓我們繼續(xù)回調(diào)2.2 connectHelper() 函數(shù)中繼續(xù)分析下面的代碼會執(zhí)行到 client->initialize(mCameraProviderManager, mMonitorTags)對上面創(chuàng)建的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;
}

該函數(shù)第一個就是調(diào)用 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  調(diào)用到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;
}

上面首先就是對當前應用打開攝像頭這一操作進行權限鑒權破停,然后調(diào)用了mDevice->initialize(providerPtr, monitorTags);繼續(xù)進行初始化的操作,這樣程序就來到了我們上面說的比較重要的一個對象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");
    // 這里調(diào)用到CameraProviderManager的openSession主要是給session賦值(在這里面會去打開攝像頭)
   //  this 在這是ICameraDeviceCallback.hal 回調(diào)接口的數(shù)據(jù)接收端 因為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;
    }
    // 調(diào)用 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;
}
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末真慢,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子理茎,更是在濱河造成了極大的恐慌黑界,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件皂林,死亡現(xiàn)場離奇詭異朗鸠,居然都是意外死亡,警方通過查閱死者的電腦和手機础倍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門烛占,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人沟启,你說我怎么就攤上這事忆家。” “怎么了德迹?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵芽卿,是天一觀的道長。 經(jīng)常有香客問我胳搞,道長卸例,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任肌毅,我火速辦了婚禮筷转,結果婚禮上,老公的妹妹穿的比我還像新娘悬而。我一直安慰自己呜舒,他們只是感情好,可當我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布摊滔。 她就那樣靜靜地躺著阴绢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪艰躺。 梳的紋絲不亂的頭發(fā)上呻袭,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天,我揣著相機與錄音腺兴,去河邊找鬼左电。 笑死,一個胖子當著我的面吹牛页响,可吹牛的內(nèi)容都是我干的篓足。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼闰蚕,長吁一口氣:“原來是場噩夢啊……” “哼栈拖!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起没陡,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤涩哟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后盼玄,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贴彼,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年埃儿,在試婚紗的時候發(fā)現(xiàn)自己被綠了器仗。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡童番,死狀恐怖精钮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情剃斧,我是刑警寧澤杂拨,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站悯衬,受9級特大地震影響弹沽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜筋粗,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一策橘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧娜亿,春花似錦丽已、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吼畏。三九已至,卻和暖如春嘁灯,著一層夾襖步出監(jiān)牢的瞬間泻蚊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工丑婿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留性雄,地道東北人。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓羹奉,卻偏偏與公主長得像秒旋,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子诀拭,可洞房花燭夜當晚...
    茶點故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容