Android 8.0系統源碼分析--Camera RequestThread預覽循環源碼分析

     本節我們來看一下Camera預覽是如何循環的,大家使用API2開發相機APP時都清楚,我們起預覽時調用CameraCaptureSession類的setRepeatingRequest方法,該方法的實現是由CameraCaptureSessionImpl來完成的,CameraCaptureSessionImpl文件路徑爲frameworks\base\core\java\android\hardware\camera2\impl\CameraCaptureSessionImpl.java,setRepeatingRequest方法的源碼如下:

    @Override
    public synchronized int setRepeatingRequest(CaptureRequest request, CaptureCallback callback,
            Handler handler) throws CameraAccessException {
        if (request == null) {
            throw new IllegalArgumentException("request must not be null");
        } else if (request.isReprocess()) {
            throw new IllegalArgumentException("repeating reprocess requests are not supported");
        }

        checkNotClosed();

        handler = checkHandler(handler, callback);

        if (DEBUG) {
            Log.v(TAG, mIdString + "setRepeatingRequest - request " + request + ", callback " +
                    callback + " handler" + " " + handler);
        }

        return addPendingSequence(mDeviceImpl.setRepeatingRequest(request,
                createCaptureCallbackProxy(handler, callback), mDeviceHandler));
    }

     這裏需要注意,第一個參數CaptureRequest只有一個Request,而在後面會將它包裝成List,那麼很明顯,List的元素個數就只有一個,也就是我們這裏傳下去的參數了。可以看到該方法中又調用了mDeviceImpl.setRepeatingRequest,mDeviceImpl成員變量的類型就是CameraDeviceImpl,和當前文件在同級目錄下,我們繼續看一下它的setRepeatingRequest方法的實現,源碼如下:

    public int setRepeatingRequest(CaptureRequest request, CaptureCallback callback,
                                   Handler handler) throws CameraAccessException {
        List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
        requestList.add(request);
        return submitCaptureRequest(requestList, callback, handler, /*streaming*/true);
    }

     這裏就看到了,我們上層傳下來的Request被進一步包裝成List,而List的元素只有一個,然後繼續調用submitCaptureRequest方法進行處理,submitCaptureRequest方法的源碼如下:

    private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureCallback callback,
                                     Handler handler, boolean repeating) throws CameraAccessException {

        // Need a valid handler, or current thread needs to have a looper, if
        // callback is valid
        handler = checkHandler(handler, callback);

        // Make sure that there all requests have at least 1 surface; all surfaces are non-null
        for (CaptureRequest request : requestList) {
            if (request.getTargets().isEmpty()) {
                throw new IllegalArgumentException(
                        "Each request must have at least one Surface target");
            }

            for (Surface surface : request.getTargets()) {
                if (surface == null) {
                    throw new IllegalArgumentException("Null Surface targets are not allowed");
                }
            }
        }

        synchronized (mInterfaceLock) {
            checkIfCameraClosedOrInError();
            if (repeating) {
                stopRepeating();
            }

            SubmitInfo requestInfo;

            CaptureRequest[] requestArray = requestList.toArray(new CaptureRequest[requestList.size()]);
            requestInfo = mRemoteDevice.submitRequestList(requestArray, repeating);
            if (DEBUG) {
                Log.v(TAG, "last frame number " + requestInfo.getLastFrameNumber());
            }

            if (callback != null) {
                mCaptureCallbackMap.put(requestInfo.getRequestId(),
                        new CaptureCallbackHolder(
                                callback, requestList, handler, repeating, mNextSessionId - 1));
            } else {
                if (DEBUG) {
                    Log.d(TAG, "Listen for request " + requestInfo.getRequestId() + " is null");
                }
            }

            if (repeating) {
                if (mRepeatingRequestId != REQUEST_ID_NONE) {
                    checkEarlyTriggerSequenceComplete(mRepeatingRequestId,
                            requestInfo.getLastFrameNumber());
                }
                mRepeatingRequestId = requestInfo.getRequestId();
            } else {
                mRequestLastFrameNumbersList.add(
                        new RequestLastFrameNumbersHolder(requestList, requestInfo));
            }

            if (mIdle) {
                mDeviceHandler.post(mCallOnActive);
            }
            mIdle = false;

            return requestInfo.getRequestId();
        }
    }

     該方法先對handler、Surface參數進行檢查,如果檢查出錯,就直接拋出異常,request.getTargets()得到的就是我們在APP層放進去的Surface對象了;參數檢查完成後,又將它轉換成數組,然後調用mRemoteDevice.submitRequestList(requestArray, repeating)提交到CameraServer進程當中。第二個參數repeating表示是否重複,也就是預覽的意思,該參數的兩種取值爲true就表示是預覽請求,需要重複;爲false表示是拍照,只有一幀,不需要重複,該參數往下傳遞,會在CameraServer中決定當前Request插入到哪個隊列當中,我們等下就可以看到了。這裏的mRemoteDevice我們在之前Android 8.0系統源碼分析--openCamera啓動過程源碼分析一文中已經詳細的分析過了,它是CameraServer進程當中執行openCamera成功後返回給Client端Binder對象的代理,它和CameraServer進程當中的CameraDeviceClient對象是對應的,只不過這裏的mRemoteDevice還經過了Framework一點包裝處理而已,所以這裏的mRemoteDevice.submitRequestList(requestArray, repeating)就會通過Binder進程間通信調用到CameraDeviceClient對象中了。

     到處都是Binder,所以還是請大家用心學習,打好基礎,我們才能理解底層到底是怎麼實現的。

     好,我們繼續看CameraDeviceClient類的submitRequestList方法,CameraDeviceClient文件的路徑爲frameworks\av\services\camera\libcameraservice\api2\CameraDeviceClient.cpp,submitRequestList方法的源碼如下:

binder::Status CameraDeviceClient::submitRequestList(
        const std::vector<hardware::camera2::CaptureRequest>& requests,
        bool streaming,
        /*out*/
        hardware::camera2::utils::SubmitInfo *submitInfo) {
    ATRACE_CALL();
    ALOGV("%s-start of function. Request list size %zu", __FUNCTION__, requests.size());

    binder::Status res = binder::Status::ok();
    status_t err;
    if ( !(res = checkPidStatus(__FUNCTION__) ).isOk()) {
        return res;
    }

    Mutex::Autolock icl(mBinderSerializationLock);

    if (!mDevice.get()) {
        return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
    }

    if (requests.empty()) {
        ALOGE("%s: Camera %s: Sent null request. Rejecting request.",
              __FUNCTION__, mCameraIdStr.string());
        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, "Empty request list");
    }

    List<const CameraMetadata> metadataRequestList;
    std::list<const SurfaceMap> surfaceMapList;
    submitInfo->mRequestId = mRequestIdCounter;
    uint32_t loopCounter = 0;

    for (auto&& request: requests) {
        if (request.mIsReprocess) {
            if (!mInputStream.configured) {
                ALOGE("%s: Camera %s: no input stream is configured.", __FUNCTION__,
                        mCameraIdStr.string());
                return STATUS_ERROR_FMT(CameraService::ERROR_ILLEGAL_ARGUMENT,
                        "No input configured for camera %s but request is for reprocessing",
                        mCameraIdStr.string());
            } else if (streaming) {
                ALOGE("%s: Camera %s: streaming reprocess requests not supported.", __FUNCTION__,
                        mCameraIdStr.string());
                return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
                        "Repeating reprocess requests not supported");
            }
        }

        CameraMetadata metadata(request.mMetadata);
        if (metadata.isEmpty()) {
            ALOGE("%s: Camera %s: Sent empty metadata packet. Rejecting request.",
                   __FUNCTION__, mCameraIdStr.string());
            return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
                    "Request settings are empty");
        } else if (request.mSurfaceList.isEmpty()) {
            ALOGE("%s: Camera %s: Requests must have at least one surface target. "
                    "Rejecting request.", __FUNCTION__, mCameraIdStr.string());
            return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
                    "Request has no output targets");
        }

        if (!enforceRequestPermissions(metadata)) {
            // Callee logs
            return STATUS_ERROR(CameraService::ERROR_PERMISSION_DENIED,
                    "Caller does not have permission to change restricted controls");
        }

        /**
         * Write in the output stream IDs and map from stream ID to surface ID
         * which we calculate from the capture request's list of surface target
         */
        SurfaceMap surfaceMap;
        Vector<int32_t> outputStreamIds;
        for (sp<Surface> surface : request.mSurfaceList) {
            if (surface == 0) continue;

            sp<IGraphicBufferProducer> gbp = surface->getIGraphicBufferProducer();
            int idx = mStreamMap.indexOfKey(IInterface::asBinder(gbp));

            // Trying to submit request with surface that wasn't created
            if (idx == NAME_NOT_FOUND) {
                ALOGE("%s: Camera %s: Tried to submit a request with a surface that"
                        " we have not called createStream on",
                        __FUNCTION__, mCameraIdStr.string());
                return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
                        "Request targets Surface that is not part of current capture session");
            }

            const StreamSurfaceId& streamSurfaceId = mStreamMap.valueAt(idx);
            if (surfaceMap.find(streamSurfaceId.streamId()) == surfaceMap.end()) {
                surfaceMap[streamSurfaceId.streamId()] = std::vector<size_t>();
                outputStreamIds.push_back(streamSurfaceId.streamId());
            }
            surfaceMap[streamSurfaceId.streamId()].push_back(streamSurfaceId.surfaceId());

            ALOGV("%s: Camera %s: Appending output stream %d surface %d to request",
                    __FUNCTION__, mCameraIdStr.string(), streamSurfaceId.streamId(),
                    streamSurfaceId.surfaceId());
        }

        metadata.update(ANDROID_REQUEST_OUTPUT_STREAMS, &outputStreamIds[0],
                        outputStreamIds.size());

        if (request.mIsReprocess) {
            metadata.update(ANDROID_REQUEST_INPUT_STREAMS, &mInputStream.id, 1);
        }

        metadata.update(ANDROID_REQUEST_ID, &(submitInfo->mRequestId), /*size*/1);
        loopCounter++; // loopCounter starts from 1
        ALOGV("%s: Camera %s: Creating request with ID %d (%d of %zu)",
                __FUNCTION__, mCameraIdStr.string(), submitInfo->mRequestId,
                loopCounter, requests.size());

        metadataRequestList.push_back(metadata);
        surfaceMapList.push_back(surfaceMap);
    }
    mRequestIdCounter++;

    if (streaming) {
        err = mDevice->setStreamingRequestList(metadataRequestList, surfaceMapList,
                &(submitInfo->mLastFrameNumber));
        if (err != OK) {
            String8 msg = String8::format(
                "Camera %s:  Got error %s (%d) after trying to set streaming request",
                mCameraIdStr.string(), strerror(-err), err);
            ALOGE("%s: %s", __FUNCTION__, msg.string());
            res = STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
                    msg.string());
        } else {
            Mutex::Autolock idLock(mStreamingRequestIdLock);
            mStreamingRequestId = submitInfo->mRequestId;
        }
    } else {
        err = mDevice->captureList(metadataRequestList, surfaceMapList,
                &(submitInfo->mLastFrameNumber));
        if (err != OK) {
            String8 msg = String8::format(
                "Camera %s: Got error %s (%d) after trying to submit capture request",
                mCameraIdStr.string(), strerror(-err), err);
            ALOGE("%s: %s", __FUNCTION__, msg.string());
            res = STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
                    msg.string());
        }
        ALOGV("%s: requestId = %d ", __FUNCTION__, submitInfo->mRequestId);
    }

    ALOGV("%s: Camera %s: End of function", __FUNCTION__, mCameraIdStr.string());
    return res;
}

     進來還是先進行參數檢查,mDevice成員變量是在構造參數時賦值好的,是在父類Camera2ClientBase對象的構造函數中new出來的;要提交request,那麼參數requests肯定不能爲空了。接下來的for循環是對函數入參requests的一些檢查,完成後填充到局部變量metadataRequestList、surfaceMapList中,作爲參數繼續調用mDevice的方法進一步處理,進一步處理的分類判斷條件非常明確,就是我們在Framework中傳入的參數repeating,如果是預覽,就調用mDevice->setStreamingRequestList(metadataRequestList, surfaceMapList, &(submitInfo->mLastFrameNumber)),如果是拍照就調用mDevice->captureList(metadataRequestList, surfaceMapList, &(submitInfo->mLastFrameNumber))。

     下面的內容就到了我們本節的重點了,我們要講的就是爲什麼我們在上層只調用了一次setRepeatingRequest,而且只有一個Request,但是預覽幀數據卻源源不斷的輸出上來,我們就從這裏往下分析一下Request循環的原理。

     mDevice成員變量是sp<CameraDeviceBase>類型,是在父類Camera2ClientBase構造函數中通過new賦值的,實際上是一個Camera3Device類型的對象,所以我們繼續看一下Camera3Device類中setStreamingRequestList、captureList方法的實現,Camera3Device文件的路徑爲frameworks\av\services\camera\libcameraservice\device3\Camera3Device.cpp,captureList方法和setStreamingRequestList方法的源碼如下:

status_t Camera3Device::captureList(const List<const CameraMetadata> &requests,
                                    const std::list<const SurfaceMap> &surfaceMaps,
                                    int64_t *lastFrameNumber) {
    ATRACE_CALL();

    return submitRequestsHelper(requests, surfaceMaps, /*repeating*/false, lastFrameNumber);
}

status_t Camera3Device::setStreamingRequest(const CameraMetadata &request,
                                            int64_t* /*lastFrameNumber*/) {
    ATRACE_CALL();

    List<const CameraMetadata> requests;
    std::list<const SurfaceMap> surfaceMaps;
    convertToRequestList(requests, surfaceMaps, request);

    return setStreamingRequestList(requests, /*surfaceMap*/surfaceMaps,
                                   /*lastFrameNumber*/NULL);
}

status_t Camera3Device::setStreamingRequestList(const List<const CameraMetadata> &requests,
                                                const std::list<const SurfaceMap> &surfaceMaps,
                                                int64_t *lastFrameNumber) {
    ATRACE_CALL();

    return submitRequestsHelper(requests, surfaceMaps, /*repeating*/true, lastFrameNumber);
}

     很簡單,都是直接調用submitRequestsHelper方法來進一步處理的,submitRequestsHelper方法的源碼如下:

status_t Camera3Device::submitRequestsHelper(
        const List<const CameraMetadata> &requests,
        const std::list<const SurfaceMap> &surfaceMaps,
        bool repeating,
        /*out*/
        int64_t *lastFrameNumber) {
    ATRACE_CALL();
    Mutex::Autolock il(mInterfaceLock);
    Mutex::Autolock l(mLock);

    status_t res = checkStatusOkToCaptureLocked();
    if (res != OK) {
        // error logged by previous call
        return res;
    }

    RequestList requestList;

    res = convertMetadataListToRequestListLocked(requests, surfaceMaps,
            repeating, /*out*/&requestList);
    if (res != OK) {
        // error logged by previous call
        return res;
    }

    if (repeating) {
        res = mRequestThread->setRepeatingRequests(requestList, lastFrameNumber);
    } else {
        res = mRequestThread->queueRequestList(requestList, lastFrameNumber);
    }

    if (res == OK) {
        waitUntilStateThenRelock(/*active*/true, kActiveTimeout);
        if (res != OK) {
            SET_ERR_L("Can't transition to active in %f seconds!",
                    kActiveTimeout/1e9);
        }
        ALOGV("Camera %s: Capture request %" PRId32 " enqueued", mId.string(),
              (*(requestList.begin()))->mResultExtras.requestId);
    } else {
        CLOGE("Cannot queue request. Impossible.");
        return BAD_VALUE;
    }

    return res;
}

     這裏有一個convertMetadataListToRequestListLocked方法,是進行Metadata轉換的,我們就不深究了,大家有興趣可以看己看一下。轉換完成後,根據repeating的值分別調用mRequestThread成員變量的setRepeatingRequests、queueRequestList方法。我們先來看一下拍照時的queueRequestList方法,源碼如下:

status_t Camera3Device::RequestThread::queueRequestList(
        List<sp<CaptureRequest> > &requests,
        /*out*/
        int64_t *lastFrameNumber) {
    Mutex::Autolock l(mRequestLock);
    for (List<sp<CaptureRequest> >::iterator it = requests.begin(); it != requests.end();
            ++it) {
        mRequestQueue.push_back(*it);
    }

    if (lastFrameNumber != NULL) {
        *lastFrameNumber = mFrameNumber + mRequestQueue.size() - 1;
        ALOGV("%s: requestId %d, mFrameNumber %" PRId32 ", lastFrameNumber %" PRId64 ".",
              __FUNCTION__, (*(requests.begin()))->mResultExtras.requestId, mFrameNumber,
              *lastFrameNumber);
    }

    unpauseForNewRequests();

    return OK;
}

     該方法中的邏輯非常清晰,for循環中就是將入參requests放入到成員變量mRequestQueue當中,所以這裏大家一定要注意,mRequestQueue是存儲拍照Request的,然後給輸出參數lastFrameNumber賦值,mFrameNumber就是當前的幀號,它是從0開始遞增的一個整數,它的遞增也是在有效的預覽循環開始後開始遞增的,等會我們就會看到了。

     接着看setRepeatingRequests方法,源碼如下:

status_t Camera3Device::RequestThread::setRepeatingRequests(
        const RequestList &requests,
        /*out*/
        int64_t *lastFrameNumber) {
    Mutex::Autolock l(mRequestLock);
    if (lastFrameNumber != NULL) {
        *lastFrameNumber = mRepeatingLastFrameNumber;
    }
    mRepeatingRequests.clear();
    mRepeatingRequests.insert(mRepeatingRequests.begin(),
            requests.begin(), requests.end());

    unpauseForNewRequests();

    mRepeatingLastFrameNumber = hardware::camera2::ICameraDeviceUser::NO_IN_FLIGHT_REPEATING_FRAMES;
    return OK;
}

     這裏是把mRepeatingLastFrameNumber賦值給輸出參數lastFrameNumber,然後將mRepeatingRequests清空,再將入參requests放入到mRepeatingRequests當中,從這裏和queueRequestList方法的實現對比,就可以看出來,mRepeatingRequests是用來存儲預覽Request的,這就是兩個成員變量不同的作用了,一定要分清楚。這裏有些奇怪,爲什麼只是將requests插入到隊列中就完了呢?我們來看一下RequestThread就明白了。

     RequestThread就是我們本節最重點的對象了,它是一條線程,是在Camera3Device構造成功,調用initializeCommonLocked進行初始化時構造的,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();

    mTagMonitor.initialize(mVendorTagId);

    /** Start up request queue thread */
    mRequestThread = new RequestThread(this, mStatusTracker, mInterface.get());
    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]));
        }
    }

    return OK;
}

     調用mRequestThread->run(String8::format("C3Dev-%s-ReqQueue", mId.string()).string())方法時,傳入的參數就是當前線程的名字,所以我們也可以使用ps -T 【pid】來查看當前進程的所有線程,就可以看到有一條以“ReqQueue”名字結尾的線程,也就是RequestThread了,而且它是在Camera3Device初始化時就啓動的了,它也是我們預覽循環的主體。

     RequestThread是繼承Android的Thread類的,主函數就是threadLoop,我們來看一下RequestThread的threadLoop函數的實現,源碼如下:

bool Camera3Device::RequestThread::threadLoop() {
    ATRACE_CALL();
    status_t res;

    // Handle paused state.
    if (waitIfPaused()) {
        return true;
    }

    // Wait for the next batch of requests.
    waitForNextRequestBatch();
    if (mNextRequests.size() == 0) {
        return true;
    }

    // Get the latest request ID, if any
    int latestRequestId;
    camera_metadata_entry_t requestIdEntry = mNextRequests[mNextRequests.size() - 1].
            captureRequest->mSettings.find(ANDROID_REQUEST_ID);
    if (requestIdEntry.count > 0) {
        latestRequestId = requestIdEntry.data.i32[0];
    } else {
        ALOGW("%s: Did not have android.request.id set in the request.", __FUNCTION__);
        latestRequestId = NAME_NOT_FOUND;
    }

    // Prepare a batch of HAL requests and output buffers.
    res = prepareHalRequests();
    if (res == TIMED_OUT) {
        // Not a fatal error if getting output buffers time out.
        cleanUpFailedRequests(/*sendRequestError*/ true);
        // Check if any stream is abandoned.
        checkAndStopRepeatingRequest();
        return true;
    } else if (res != OK) {
        cleanUpFailedRequests(/*sendRequestError*/ false);
        return false;
    }

    // Inform waitUntilRequestProcessed thread of a new request ID
    {
        Mutex::Autolock al(mLatestRequestMutex);

        mLatestRequestId = latestRequestId;
        mLatestRequestSignal.signal();
    }

    // Submit a batch of requests to HAL.
    // Use flush lock only when submitting multilple requests in a batch.
    // TODO: The problem with flush lock is flush() will be blocked by process_capture_request()
    // which may take a long time to finish so synchronizing flush() and
    // process_capture_request() defeats the purpose of cancelling requests ASAP with flush().
    // For now, only synchronize for high speed recording and we should figure something out for
    // removing the synchronization.
    bool useFlushLock = mNextRequests.size() > 1;

    if (useFlushLock) {
        mFlushLock.lock();
    }

    ALOGVV("%s: %d: submitting %zu requests in a batch.", __FUNCTION__, __LINE__,
            mNextRequests.size());

    bool submitRequestSuccess = false;
    nsecs_t tRequestStart = systemTime(SYSTEM_TIME_MONOTONIC);
    if (mInterface->supportBatchRequest()) {
        submitRequestSuccess = sendRequestsBatch();
    } else {
        submitRequestSuccess = sendRequestsOneByOne();
    }
    nsecs_t tRequestEnd = systemTime(SYSTEM_TIME_MONOTONIC);
    mRequestLatency.add(tRequestStart, tRequestEnd);

    if (useFlushLock) {
        mFlushLock.unlock();
    }

    // Unset as current request
    {
        Mutex::Autolock l(mRequestLock);
        mNextRequests.clear();
    }

    return submitRequestSuccess;
}

     waitIfPaused方法表示如果是pause狀態的話,就什麼不作,直接返回true,剛好該返回值就決定了線程是否要繼續循環,所以如果是pause狀態的話,就繼續進行線程循環,這裏就會有疑問了?剛開始初始化完成,預覽還未下發的時候,這裏就會一直空處理,啥邏輯也沒有,直接返回,那不是白白浪費CPU時間片嗎?不急,我們耐心看一下waitIfPaused方法的實現就明白了,Google的精英們是絕不會犯這樣低級的錯誤的,waitIfPaused方法的源碼如下:

bool Camera3Device::RequestThread::waitIfPaused() {
    status_t res;
    Mutex::Autolock l(mPauseLock);
    while (mDoPause) {
        if (mPaused == false) {
            mPaused = true;
            ALOGV("%s: RequestThread: Paused", __FUNCTION__);
            // Let the tracker know
            sp<StatusTracker> statusTracker = mStatusTracker.promote();
            if (statusTracker != 0) {
                statusTracker->markComponentIdle(mStatusId, Fence::NO_FENCE);
            }
        }

        res = mDoPauseSignal.waitRelative(mPauseLock, kRequestTimeout);
        if (res == TIMED_OUT || exitPending()) {
            return true;
        }
    }
    // We don't set mPaused to false here, because waitForNextRequest needs
    // to further manage the paused state in case of starvation.
    return false;
}

     如果是上面所說的情況下,就會執行mDoPauseSignal.waitRelative(mPauseLock, kRequestTimeout)等待,kRequestTimeout是定義在Camera3Device.h頭文件中,定義的源碼如下:

static const nsecs_t kRequestTimeout = 50e6; // 50 ms

     所以這裏就可以看到,如果沒有Request請求時,將會等待50ms,再進行下一次判斷。我們繼續回到threadLoop方法中,我們先不細看,根據該方法中的實現理一下大體的思路,有幾個比較關鍵的點:waitForNextRequestBatch準備下一次的Request請求;prepareHalRequests爲上一步準備好的Request請求的hal_request賦值,繼續完善這個Request;最後根據mInterface->supportBatchRequest()是否支持批處理,分別調用sendRequestsBatch、sendRequestsOneByOne將準備好的Request發送到HAL進程,也就是CameraHalServer當中去處理了,最終返回submitRequestSuccess,如果該值爲true,那麼繼續循環,如果爲false,那麼肯定是中間出問題,RequestThread線程就會退出了。

     理清了這個思路,我們大體也就明白了,相機整個預覽循環的工作就是在這裏完成的,也全部是圍繞着mNextRequests成員變量來進行的。下面我們就來仔細看一下waitForNextRequestBatch、prepareHalRequests、sendRequestsBatch(我們假定支持批處理)三個函數的實現。

     waitForNextRequestBatch方法的源碼如下:

void Camera3Device::RequestThread::waitForNextRequestBatch() {
    // Optimized a bit for the simple steady-state case (single repeating
    // request), to avoid putting that request in the queue temporarily.
    Mutex::Autolock l(mRequestLock);

    assert(mNextRequests.empty());

    NextRequest nextRequest;
    nextRequest.captureRequest = waitForNextRequestLocked();
    if (nextRequest.captureRequest == nullptr) {
        return;
    }

    nextRequest.halRequest = camera3_capture_request_t();
    nextRequest.submitted = false;
    mNextRequests.add(nextRequest);

    // Wait for additional requests
    const size_t batchSize = nextRequest.captureRequest->mBatchSize;

    for (size_t i = 1; i < batchSize; i++) {
        NextRequest additionalRequest;
        additionalRequest.captureRequest = waitForNextRequestLocked();
        if (additionalRequest.captureRequest == nullptr) {
            break;
        }

        additionalRequest.halRequest = camera3_capture_request_t();
        additionalRequest.submitted = false;
        mNextRequests.add(additionalRequest);
    }

    if (mNextRequests.size() < batchSize) {
        ALOGE("RequestThread: only get %zu out of %zu requests. Skipping requests.",
                mNextRequests.size(), batchSize);
        cleanUpFailedRequests(/*sendRequestError*/true);
    }

    return;
}

     首先斷言成員變量mNextRequests中的元素爲空,從這個邏輯我們也可以想到,每一幀處理完成後,肯定會把它清空,它的作用非常明確,就是將下一幀需要處理的Request添加進來,每一幀處理完成後直接清空,下一幀再繼續添加。然後定義一個局部變量nextRequest,它就是要添加到mNextRequests當中的目標,調用waitForNextRequestLocked方法來給它的captureRequest成員變量賦值,halRequest成員變量是通過camera3_capture_request_t結構體構造的,但是它當中的所有參數都沒有賦值,所以在這裏它還只是個空殼子。submitted表示是否提交處理了,在這裏肯定是false了,那麼它什麼時候爲true呢?很明確,分界線就是我們最後將該Request提交給HAL進程進行處理,處理了之後,它纔會爲true。batchSize一般都爲1,這是我加日誌明確看過的,但是它所表示的具體的意思,暫時還沒搞清楚。另外,這裏請大家一定要看清楚,for循環的判斷條件是for (size_t i = 1; i < batchSize; i++),i 的初始值爲1,而batchSize也等於1,所以for循環是不會進入的,也就是說經過這裏的處理,mNextRequests只添加了一個nextRequest,它的size就是1。

     我們繼續來看它所調用的waitForNextRequestLocked方法,源碼如下:

sp<Camera3Device::CaptureRequest>
        Camera3Device::RequestThread::waitForNextRequestLocked() {
    status_t res;
    sp<CaptureRequest> nextRequest;

    while (mRequestQueue.empty()) {
        if (!mRepeatingRequests.empty()) {
            // Always atomically enqueue all requests in a repeating request
            // list. Guarantees a complete in-sequence set of captures to
            // application.
            const RequestList &requests = mRepeatingRequests;
            RequestList::const_iterator firstRequest =
                    requests.begin();
            nextRequest = *firstRequest;
            mRequestQueue.insert(mRequestQueue.end(),
                    ++firstRequest,
                    requests.end());
            // No need to wait any longer

            mRepeatingLastFrameNumber = mFrameNumber + requests.size() - 1;

            break;
        }

        res = mRequestSignal.waitRelative(mRequestLock, kRequestTimeout);

        if ((mRequestQueue.empty() && mRepeatingRequests.empty()) ||
                exitPending()) {
            Mutex::Autolock pl(mPauseLock);
            if (mPaused == false) {
                ALOGV("%s: RequestThread: Going idle", __FUNCTION__);
                mPaused = true;
                // Let the tracker know
                sp<StatusTracker> statusTracker = mStatusTracker.promote();
                if (statusTracker != 0) {
                    statusTracker->markComponentIdle(mStatusId, Fence::NO_FENCE);
                }
            }
            // Stop waiting for now and let thread management happen
            return NULL;
        }
    }

    if (nextRequest == NULL) {
        // Don't have a repeating request already in hand, so queue
        // must have an entry now.
        RequestList::iterator firstRequest =
                mRequestQueue.begin();
        nextRequest = *firstRequest;
        mRequestQueue.erase(firstRequest);
        if (mRequestQueue.empty() && !nextRequest->mRepeating) {
            sp<NotificationListener> listener = mListener.promote();
            if (listener != NULL) {
                listener->notifyRequestQueueEmpty();
            }
        }
    }

    // In case we've been unpaused by setPaused clearing mDoPause, need to
    // update internal pause state (capture/setRepeatingRequest unpause
    // directly).
    Mutex::Autolock pl(mPauseLock);
    if (mPaused) {
        ALOGV("%s: RequestThread: Unpaused", __FUNCTION__);
        sp<StatusTracker> statusTracker = mStatusTracker.promote();
        if (statusTracker != 0) {
            statusTracker->markComponentActive(mStatusId);
        }
    }
    mPaused = false;

    // Check if we've reconfigured since last time, and reset the preview
    // request if so. Can't use 'NULL request == repeat' across configure calls.
    if (mReconfigured) {
        mPrevRequest.clear();
        mReconfigured = false;
    }

    if (nextRequest != NULL) {
        nextRequest->mResultExtras.frameNumber = mFrameNumber++;
        nextRequest->mResultExtras.afTriggerId = mCurrentAfTriggerId;
        nextRequest->mResultExtras.precaptureTriggerId = mCurrentPreCaptureTriggerId;

        // Since RequestThread::clear() removes buffers from the input stream,
        // get the right buffer here before unlocking mRequestLock
        if (nextRequest->mInputStream != NULL) {
            res = nextRequest->mInputStream->getInputBuffer(&nextRequest->mInputBuffer);
            if (res != OK) {
                // Can't get input buffer from gralloc queue - this could be due to
                // disconnected queue or other producer misbehavior, so not a fatal
                // error
                ALOGE("%s: Can't get input buffer, skipping request:"
                        " %s (%d)", __FUNCTION__, strerror(-res), res);

                sp<NotificationListener> listener = mListener.promote();
                if (listener != NULL) {
                    listener->notifyError(
                            hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST,
                            nextRequest->mResultExtras);
                }
                return NULL;
            }
        }
    }

    return nextRequest;
}

     方法一開始的while循環可以很直接的看到,先從mRequestQueue隊列取數據,那麼意思很明白,拍照請求的優先級肯定是高於預覽請求的,比如當前RequestThread的拍照隊列和預覽隊列都有一個Request,此時threadloop循環要取一幀進行處理,在這裏的while進行判斷時,拍照隊列不爲空,則while循環直接跳過,if (nextRequest == NULL)判斷爲true,就直接從拍照隊列中取數據了。好,我們結合當前預覽的場景來分析一下,當前拍照隊列爲請求爲空,而if (!mRepeatingRequests.empty())判斷成立,因爲我們在前面是通過setRepeatingRequest調用下來的,在那裏已經把當時封裝好的Request插入到預覽隊列中了。然後從預覽隊列中取頭節點賦值給局部變量nextRequest,接着爲什麼將其插入到拍照隊列中?這步邏輯看來看去都沒搞清楚是什麼意思。最後給mRepeatingLastFrameNumber預覽幀變量賦值,此時局部變量nextRequest不爲空,該方法結尾處if (nextRequest != NULL)判斷爲true,if判斷中第一句就是給幀號賦值,可以看到mFrameNumber++,先賦值後自增,這就是前面我們所說的幀號遞增的出處了,這個幀號大家一定要非常重視,從CameraServer到CameraHalServer,一個幀號對應一個結果,也就是說我發一個請求給你,你就必須回覆一個結果給我,我才能根據這個結果進行相應的預覽或者拍照後處理,所以這個變量非常重要,它是對標兩個進程之間請求的一個核心變量。剩下的還有一些其他參數的賦值,填充完成後將nextRequest返回。

     那麼它準備好了NextRequest,再往上回到waitForNextRequestBatch方法當中,下一幀的請求Request也就添加到成員變量mNextRequests當中了。繼續往上,回到threadLoop方法當中,當時size等於1,接下來執行prepareHalRequests方法,上一行的註釋寫的也非常清楚了,“Prepare a batch of HAL requests and output buffers”,準備下一批的HAL請求和輸出的Buffer。

     我們就繼續看一下prepareHalRequests方法的實現,源碼如下:

status_t Camera3Device::RequestThread::prepareHalRequests() {
    ATRACE_CALL();

    for (size_t i = 0; i < mNextRequests.size(); i++) {
        auto& nextRequest = mNextRequests.editItemAt(i);
        sp<CaptureRequest> captureRequest = nextRequest.captureRequest;
        camera3_capture_request_t* halRequest = &nextRequest.halRequest;
        Vector<camera3_stream_buffer_t>* outputBuffers = &nextRequest.outputBuffers;

        // Prepare a request to HAL
        halRequest->frame_number = captureRequest->mResultExtras.frameNumber;

        // Insert any queued triggers (before metadata is locked)
        status_t res = insertTriggers(captureRequest);

        if (res < 0) {
            SET_ERR("RequestThread: Unable to insert triggers "
                    "(capture request %d, HAL device: %s (%d)",
                    halRequest->frame_number, strerror(-res), res);
            return INVALID_OPERATION;
        }
        int triggerCount = res;
        bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0);
        mPrevTriggers = triggerCount;

        // If the request is the same as last, or we had triggers last time
        if (mPrevRequest != captureRequest || triggersMixedIn) {
            /**
             * HAL workaround:
             * Insert a dummy trigger ID if a trigger is set but no trigger ID is
             */
            res = addDummyTriggerIds(captureRequest);
            if (res != OK) {
                SET_ERR("RequestThread: Unable to insert dummy trigger IDs "
                        "(capture request %d, HAL device: %s (%d)",
                        halRequest->frame_number, strerror(-res), res);
                return INVALID_OPERATION;
            }

            /**
             * The request should be presorted so accesses in HAL
             *   are O(logn). Sidenote, sorting a sorted metadata is nop.
             */
            captureRequest->mSettings.sort();
            halRequest->settings = captureRequest->mSettings.getAndLock();
            mPrevRequest = captureRequest;
            ALOGVV("%s: Request settings are NEW", __FUNCTION__);

            IF_ALOGV() {
                camera_metadata_ro_entry_t e = camera_metadata_ro_entry_t();
                find_camera_metadata_ro_entry(
                        halRequest->settings,
                        ANDROID_CONTROL_AF_TRIGGER,
                        &e
                );
                if (e.count > 0) {
                    ALOGV("%s: Request (frame num %d) had AF trigger 0x%x",
                          __FUNCTION__,
                          halRequest->frame_number,
                          e.data.u8[0]);
                }
            }
        } else {
            // leave request.settings NULL to indicate 'reuse latest given'
            ALOGVV("%s: Request settings are REUSED",
                   __FUNCTION__);
        }

        uint32_t totalNumBuffers = 0;

        // Fill in buffers
        if (captureRequest->mInputStream != NULL) {
            halRequest->input_buffer = &captureRequest->mInputBuffer;
            totalNumBuffers += 1;
        } else {
            halRequest->input_buffer = NULL;
        }

        outputBuffers->insertAt(camera3_stream_buffer_t(), 0,
                captureRequest->mOutputStreams.size());
        halRequest->output_buffers = outputBuffers->array();
        for (size_t j = 0; j < captureRequest->mOutputStreams.size(); j++) {
            sp<Camera3OutputStreamInterface> outputStream = captureRequest->mOutputStreams.editItemAt(j);

            // Prepare video buffers for high speed recording on the first video request.
            if (mPrepareVideoStream && outputStream->isVideoStream()) {
                // Only try to prepare video stream on the first video request.
                mPrepareVideoStream = false;

                res = outputStream->startPrepare(Camera3StreamInterface::ALLOCATE_PIPELINE_MAX);
                while (res == NOT_ENOUGH_DATA) {
                    res = outputStream->prepareNextBuffer();
                }
                if (res != OK) {
                    ALOGW("%s: Preparing video buffers for high speed failed: %s (%d)",
                        __FUNCTION__, strerror(-res), res);
                    outputStream->cancelPrepare();
                }
            }

            res = outputStream->getBuffer(&outputBuffers->editItemAt(j),
                    captureRequest->mOutputSurfaces[j]);
            if (res != OK) {
                // Can't get output buffer from gralloc queue - this could be due to
                // abandoned queue or other consumer misbehavior, so not a fatal
                // error
                ALOGE("RequestThread: Can't get output buffer, skipping request:"
                        " %s (%d)", strerror(-res), res);

                return TIMED_OUT;
            }
            halRequest->num_output_buffers++;

        }
        totalNumBuffers += halRequest->num_output_buffers;

        // Log request in the in-flight queue
        sp<Camera3Device> parent = mParent.promote();
        if (parent == NULL) {
            // Should not happen, and nowhere to send errors to, so just log it
            CLOGE("RequestThread: Parent is gone");
            return INVALID_OPERATION;
        }

        // If this request list is for constrained high speed recording (not
        // preview), and the current request is not the last one in the batch,
        // do not send callback to the app.
        bool hasCallback = true;
        if (mNextRequests[0].captureRequest->mBatchSize > 1 && i != mNextRequests.size()-1) {
            hasCallback = false;
        }
        res = parent->registerInFlight(halRequest->frame_number,
                totalNumBuffers, captureRequest->mResultExtras,
                /*hasInput*/halRequest->input_buffer != NULL,
                hasCallback);
        ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64
               ", burstId = %" PRId32 ".",
                __FUNCTION__,
                captureRequest->mResultExtras.requestId, captureRequest->mResultExtras.frameNumber,
                captureRequest->mResultExtras.burstId);
        if (res != OK) {
            SET_ERR("RequestThread: Unable to register new in-flight request:"
                    " %s (%d)", strerror(-res), res);
            return INVALID_OPERATION;
        }
    }

    return OK;
}

     分析該方法前,我們一定要清楚,該方法中完成了一個非常重要的目的,就是output buffer的準備,HAL所有的工作都是圍繞輸出的Buffer來操作的,所以看完這個方法,我們必須搞清楚,output buffer是如何準備的,準備到哪裏去了。整個方法就一個for循環,對入參的每個Request進行處理,接下來的邏輯都是在給成員變量halRequest的子變量進行賦值,一步一步的完成halRequest的構建,輸出Buffer就是成員變量outputBuffers了,它的準備就是調用outputStream->getBuffer(&outputBuffers->editItemAt(j), captureRequest->mOutputSurfaces[j])實現的。這裏我們假定outputStream的類型爲Camera3OutputStream(還有其他類型的Stream,比如Camera3SharedOutputStream),getBuffer的方法是調用父類Camera3Stream的實現,Camera3Stream文件的路徑爲frameworks\av\services\camera\libcameraservice\device3\Camera3Stream.cpp,它的getBuffer方法的源碼如下:

status_t Camera3Stream::getBuffer(camera3_stream_buffer *buffer,
        const std::vector<size_t>& surface_ids) {
    ATRACE_CALL();
    Mutex::Autolock l(mLock);
    status_t res = OK;

    // This function should be only called when the stream is configured already.
    if (mState != STATE_CONFIGURED) {
        ALOGE("%s: Stream %d: Can't get buffers if stream is not in CONFIGURED state %d",
                __FUNCTION__, mId, mState);
        return INVALID_OPERATION;
    }

    // Wait for new buffer returned back if we are running into the limit.
    if (getHandoutOutputBufferCountLocked() == camera3_stream::max_buffers) {
        ALOGV("%s: Already dequeued max output buffers (%d), wait for next returned one.",
                        __FUNCTION__, camera3_stream::max_buffers);
        nsecs_t waitStart = systemTime(SYSTEM_TIME_MONOTONIC);
        res = mOutputBufferReturnedSignal.waitRelative(mLock, kWaitForBufferDuration);
        nsecs_t waitEnd = systemTime(SYSTEM_TIME_MONOTONIC);
        mBufferLimitLatency.add(waitStart, waitEnd);
        if (res != OK) {
            if (res == TIMED_OUT) {
                ALOGE("%s: wait for output buffer return timed out after %lldms (max_buffers %d)",
                        __FUNCTION__, kWaitForBufferDuration / 1000000LL,
                        camera3_stream::max_buffers);
            }
            return res;
        }
    }

    res = getBufferLocked(buffer, surface_ids);
    if (res == OK) {
        fireBufferListenersLocked(*buffer, /*acquired*/true, /*output*/true);
        if (buffer->buffer) {
            mOutstandingBuffers.push_back(*buffer->buffer);
        }
    }

    return res;
}

     這裏需要先說明一下,最後調用fireBufferListenersLocked進行回調處理,所有的回調都是針對API1的架構的,因爲該Listener的添加只有在API1的架構中才有,後面的已經沒有了,所以最後if (res == OK)條件判斷中的邏輯我們就不分析了。接着看getBufferLocked,該方法是由子類實現的,在Camera3OutputStream類中,源碼如下:

status_t Camera3OutputStream::getBufferLocked(camera3_stream_buffer *buffer,
        const std::vector<size_t>&) {
    ATRACE_CALL();

    ANativeWindowBuffer* anb;
    int fenceFd = -1;

    status_t res;
    res = getBufferLockedCommon(&anb, &fenceFd);
    if (res != OK) {
        return res;
    }

    /**
     * FenceFD now owned by HAL except in case of error,
     * in which case we reassign it to acquire_fence
     */
    handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd,
                        /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK, /*output*/true);

    return OK;
}

     要完成的目標就是給第一個入參buffer指針進行賦值,很直接,該方法繼續調用getBufferLockedCommon進一步處理,getBufferLockedCommon方法的源碼如下:

status_t Camera3OutputStream::getBufferLockedCommon(ANativeWindowBuffer** anb, int* fenceFd) {
    ATRACE_CALL();
    status_t res;

    if ((res = getBufferPreconditionCheckLocked()) != OK) {
        return res;
    }

    bool gotBufferFromManager = false;

    if (mUseBufferManager) {
        sp<GraphicBuffer> gb;
        res = mBufferManager->getBufferForStream(getId(), getStreamSetId(), &gb, fenceFd);
        if (res == OK) {
            // Attach this buffer to the bufferQueue: the buffer will be in dequeue state after a
            // successful return.
            *anb = gb.get();
            res = mConsumer->attachBuffer(*anb);
            if (res != OK) {
                ALOGE("%s: Stream %d: Can't attach the output buffer to this surface: %s (%d)",
                        __FUNCTION__, mId, strerror(-res), res);
                return res;
            }
            gotBufferFromManager = true;
            ALOGV("Stream %d: Attached new buffer", getId());
        } else if (res == ALREADY_EXISTS) {
            // Have sufficient free buffers already attached, can just
            // dequeue from buffer queue
            ALOGV("Stream %d: Reusing attached buffer", getId());
            gotBufferFromManager = false;
        } else if (res != OK) {
            ALOGE("%s: Stream %d: Can't get next output buffer from buffer manager: %s (%d)",
                    __FUNCTION__, mId, strerror(-res), res);
            return res;
        }
    }
    if (!gotBufferFromManager) {
        /**
         * Release the lock briefly to avoid deadlock for below scenario:
         * Thread 1: StreamingProcessor::startStream -> Camera3Stream::isConfiguring().
         * This thread acquired StreamingProcessor lock and try to lock Camera3Stream lock.
         * Thread 2: Camera3Stream::returnBuffer->StreamingProcessor::onFrameAvailable().
         * This thread acquired Camera3Stream lock and bufferQueue lock, and try to lock
         * StreamingProcessor lock.
         * Thread 3: Camera3Stream::getBuffer(). This thread acquired Camera3Stream lock
         * and try to lock bufferQueue lock.
         * Then there is circular locking dependency.
         */
        sp<ANativeWindow> currentConsumer = mConsumer;
        mLock.unlock();

        nsecs_t dequeueStart = systemTime(SYSTEM_TIME_MONOTONIC);
        res = currentConsumer->dequeueBuffer(currentConsumer.get(), anb, fenceFd);
        nsecs_t dequeueEnd = systemTime(SYSTEM_TIME_MONOTONIC);
        mDequeueBufferLatency.add(dequeueStart, dequeueEnd);

        mLock.lock();
        if (res != OK) {
            ALOGE("%s: Stream %d: Can't dequeue next output buffer: %s (%d)",
                    __FUNCTION__, mId, strerror(-res), res);

            // Only transition to STATE_ABANDONED from STATE_CONFIGURED. (If it is STATE_PREPARING,
            // let prepareNextBuffer handle the error.)
            if (res == NO_INIT && mState == STATE_CONFIGURED) {
                mState = STATE_ABANDONED;
            }

            return res;
        }
    }

    if (res == OK) {
        std::vector<sp<GraphicBuffer>> removedBuffers;
        res = mConsumer->getAndFlushRemovedBuffers(&removedBuffers);
        if (res == OK) {
            onBuffersRemovedLocked(removedBuffers);

            if (mUseBufferManager && removedBuffers.size() > 0) {
                mBufferManager->onBuffersRemoved(getId(), getStreamSetId(), removedBuffers.size());
            }
        }
    }

    return res;
}

     這裏就是最終給buffer賦值的地方了,還是要重點說明一下,mUseBufferManager的值一直是false,我開始也不理解,在加日誌調試時,我認爲它在這裏肯定是爲true的,但是通過分析才知道,它一直是false,我們來追究一下,它的值要爲true,只有在configureConsumerQueueLocked配置流的方法中的477行賦值爲true,其他情況下都是false,那麼我們繼續看一下進入這個 if 判斷的條件,if (mBufferManager != 0 && mSetId > CAMERA3_STREAM_SET_ID_INVALID),第一個mBufferManager是在構造Stream對象完成後,直接調用set賦值的,不爲空;mSetId是父類Camera3Stream定義的成員變量,是要構造函數中賦值的,而我們一直往上追,構造函數傳入的這個參數最根上是在CameraDeviceImpl類中調用configureStreamsChecked進行流的配置時,調用mRemoteDevice.createStream(outConfig)傳入的,它的值也就是outConfig入參的成員變量mSurfaceGroupId的值,outConfig的類型爲OutputConfiguration,而入參outConfig是直接調用new OutputConfiguration(Surface)帶一個Surface參數的構造方法構建的,OutputConfiguration文件的路徑爲frameworks\base\core\java\android\hardware\camera2\params\OutputConfiguration.java,該構造方法的源碼如下:

    public OutputConfiguration(@NonNull Surface surface) {
        this(SURFACE_GROUP_ID_NONE, surface, ROTATION_0);
    }

     它是繼續調用其他構造函數,源碼如下:

    @SystemApi
    public OutputConfiguration(int surfaceGroupId, @NonNull Surface surface, int rotation) {
        checkNotNull(surface, "Surface must not be null");
        checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
        mSurfaceGroupId = surfaceGroupId;
        mSurfaceType = SURFACE_TYPE_UNKNOWN;
        mSurfaces = new ArrayList<Surface>();
        mSurfaces.add(surface);
        mRotation = rotation;
        mConfiguredSize = SurfaceUtils.getSurfaceSize(surface);
        mConfiguredFormat = SurfaceUtils.getSurfaceFormat(surface);
        mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(surface);
        mConfiguredGenerationId = surface.getGenerationId();
        mIsDeferredConfig = false;
        mIsShared = false;
    }

     這裏就可以看到,第一個參數SURFACE_GROUP_ID_NONE(值爲-1)賦值給了成員變量mSurfaceGroupId,這也就是我們上面講的if (mBufferManager != 0 && mSetId > CAMERA3_STREAM_SET_ID_INVALID)判斷條件中的第二個條件爲false的原因了,所以這裏的buffer管理不是用的Camera3BufferManager,一定要搞清楚。

     繼續回到我們正路Camera3OutputStream類的getBufferLockedCommon方法當中,if (mUseBufferManager)判斷跳過,gotBufferFromManager啥也沒改,就是初始值false,所以進入到if (!gotBufferFromManager)分支中,看到currentConsumer->dequeueBuffer(currentConsumer.get(), anb, fenceFd),終於久違了!!!所有HAL層操作的Buffer就是這裏分配的,是通過configureStream時配置的Surface中,使用Android原生的Buffer管理系統取出來的,也就是原生定義的buffer_handle_t,這些Buffer全部是由gralloc驅動創建的,是使用共享內存的實現的,所以各進程間要操作的話,不需要拷貝,操作完釋放鎖就可以了!!!

     這裏看完了,往上回到Camera3Device::RequestThread類的prepareHalRequests方法中,這裏還需要聲明一下,此時準備好的buffer還只是在NextRequest當中,而HAL層能拿到的是halRequest,所以還需要再處理一步,這步工作是在後邊完成的,我們等下就會看到。

     再往上回到threadLoop方法中,最後來看一下第三步sendRequestsBatch,將準備好的Request發往HAL進程去處理,該方法的源碼如下:

bool Camera3Device::RequestThread::sendRequestsBatch() {
    status_t res;
    size_t batchSize = mNextRequests.size();
    std::vector<camera3_capture_request_t*> requests(batchSize);
    uint32_t numRequestProcessed = 0;
    for (size_t i = 0; i < batchSize; i++) {
        requests[i] = &mNextRequests.editItemAt(i).halRequest;
    }

    ATRACE_ASYNC_BEGIN("batch frame capture", mNextRequests[0].halRequest.frame_number);
    res = mInterface->processBatchCaptureRequests(requests, &numRequestProcessed);

    bool triggerRemoveFailed = false;
    NextRequest& triggerFailedRequest = mNextRequests.editItemAt(0);
    for (size_t i = 0; i < numRequestProcessed; i++) {
        NextRequest& nextRequest = mNextRequests.editItemAt(i);
        nextRequest.submitted = true;


        // Update the latest request sent to HAL
        if (nextRequest.halRequest.settings != NULL) { // Don't update if they were unchanged
            Mutex::Autolock al(mLatestRequestMutex);

            camera_metadata_t* cloned = clone_camera_metadata(nextRequest.halRequest.settings);
            mLatestRequest.acquire(cloned);

            sp<Camera3Device> parent = mParent.promote();
            if (parent != NULL) {
                parent->monitorMetadata(TagMonitor::REQUEST,
                        nextRequest.halRequest.frame_number,
                        0, mLatestRequest);
            }
        }

        if (nextRequest.halRequest.settings != NULL) {
            nextRequest.captureRequest->mSettings.unlock(nextRequest.halRequest.settings);
        }

        if (!triggerRemoveFailed) {
            // Remove any previously queued triggers (after unlock)
            status_t removeTriggerRes = removeTriggers(mPrevRequest);
            if (removeTriggerRes != OK) {
                triggerRemoveFailed = true;
                triggerFailedRequest = nextRequest;
            }
        }
    }

    if (triggerRemoveFailed) {
        SET_ERR("RequestThread: Unable to remove triggers "
              "(capture request %d, HAL device: %s (%d)",
              triggerFailedRequest.halRequest.frame_number, strerror(-res), res);
        cleanUpFailedRequests(/*sendRequestError*/ false);
        return false;
    }

    if (res != OK) {
        // Should only get a failure here for malformed requests or device-level
        // errors, so consider all errors fatal.  Bad metadata failures should
        // come through notify.
        SET_ERR("RequestThread: Unable to submit capture request %d to HAL device: %s (%d)",
                mNextRequests[numRequestProcessed].halRequest.frame_number,
                strerror(-res), res);
        cleanUpFailedRequests(/*sendRequestError*/ false);
        return false;
    }
    return true;
}

     所有的request都已經準備好了,所以就調用mInterface->processBatchCaptureRequests(requests, &numRequestProcessed)來處理請求了,mInterface的類型爲HalInterface,這裏也就是分水領了,從這句代碼往後,當前的Request就被處理了,所以nextRequest.submitted也就應該被賦值爲true了。我們繼續來看一下processBatchCaptureRequests的邏輯,源碼如下:

status_t Camera3Device::HalInterface::processBatchCaptureRequests(
        std::vector<camera3_capture_request_t*>& requests,/*out*/uint32_t* numRequestProcessed) {
    ATRACE_NAME("CameraHal::processBatchCaptureRequests");
    if (!valid()) return INVALID_OPERATION;

    hardware::hidl_vec<device::V3_2::CaptureRequest> captureRequests;
    size_t batchSize = requests.size();
    captureRequests.resize(batchSize);
    std::vector<native_handle_t*> handlesCreated;

    for (size_t i = 0; i < batchSize; i++) {
        wrapAsHidlRequest(requests[i], /*out*/&captureRequests[i], /*out*/&handlesCreated);
    }

    std::vector<device::V3_2::BufferCache> cachesToRemove;
    {
        std::lock_guard<std::mutex> lock(mBufferIdMapLock);
        for (auto& pair : mFreedBuffers) {
            // The stream might have been removed since onBufferFreed
            if (mBufferIdMaps.find(pair.first) != mBufferIdMaps.end()) {
                cachesToRemove.push_back({pair.first, pair.second});
            }
        }
        mFreedBuffers.clear();
    }

    common::V1_0::Status status = common::V1_0::Status::INTERNAL_ERROR;
    *numRequestProcessed = 0;

    // Write metadata to FMQ.
    for (size_t i = 0; i < batchSize; i++) {
        camera3_capture_request_t* request = requests[i];
        device::V3_2::CaptureRequest* captureRequest = &captureRequests[i];

        if (request->settings != nullptr) {
            size_t settingsSize = get_camera_metadata_size(request->settings);
            if (mRequestMetadataQueue != nullptr && mRequestMetadataQueue->write(
                    reinterpret_cast<const uint8_t*>(request->settings), settingsSize)) {
                captureRequest->settings.resize(0);
                captureRequest->fmqSettingsSize = settingsSize;
            } else {
                if (mRequestMetadataQueue != nullptr) {
                    ALOGW("%s: couldn't utilize fmq, fallback to hwbinder", __FUNCTION__);
                }
                captureRequest->settings.setToExternal(
                        reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(request->settings)),
                        get_camera_metadata_size(request->settings));
                captureRequest->fmqSettingsSize = 0u;
            }
        } else {
            // A null request settings maps to a size-0 CameraMetadata
            captureRequest->settings.resize(0);
            captureRequest->fmqSettingsSize = 0u;
        }
    }
    auto err = mHidlSession->processCaptureRequest(captureRequests, cachesToRemove,
            [&status, &numRequestProcessed] (auto s, uint32_t n) {
                status = s;
                *numRequestProcessed = n;
            });
    if (!err.isOk()) {
        ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
        return DEAD_OBJECT;
    }
    if (status == common::V1_0::Status::OK && *numRequestProcessed != batchSize) {
        ALOGE("%s: processCaptureRequest returns OK but processed %d/%zu requests",
                __FUNCTION__, *numRequestProcessed, batchSize);
        status = common::V1_0::Status::INTERNAL_ERROR;
    }

    for (auto& handle : handlesCreated) {
        native_handle_delete(handle);
    }
    return CameraProviderManager::mapToStatusT(status);
}

     這裏先調用wrapAsHidlRequest對每個Request進一步包裝,我們來看一下它的實現,源碼如下:

void Camera3Device::HalInterface::wrapAsHidlRequest(camera3_capture_request_t* request,
        /*out*/device::V3_2::CaptureRequest* captureRequest,
        /*out*/std::vector<native_handle_t*>* handlesCreated) {

    if (captureRequest == nullptr || handlesCreated == nullptr) {
        ALOGE("%s: captureRequest (%p) and handlesCreated (%p) must not be null",
                __FUNCTION__, captureRequest, handlesCreated);
        return;
    }

    captureRequest->frameNumber = request->frame_number;

    captureRequest->fmqSettingsSize = 0;

    {
        std::lock_guard<std::mutex> lock(mInflightLock);
        if (request->input_buffer != nullptr) {
            int32_t streamId = Camera3Stream::cast(request->input_buffer->stream)->getId();
            buffer_handle_t buf = *(request->input_buffer->buffer);
            auto pair = getBufferId(buf, streamId);
            bool isNewBuffer = pair.first;
            uint64_t bufferId = pair.second;
            captureRequest->inputBuffer.streamId = streamId;
            captureRequest->inputBuffer.bufferId = bufferId;
            captureRequest->inputBuffer.buffer = (isNewBuffer) ? buf : nullptr;
            captureRequest->inputBuffer.status = BufferStatus::OK;
            native_handle_t *acquireFence = nullptr;
            if (request->input_buffer->acquire_fence != -1) {
                acquireFence = native_handle_create(1,0);
                acquireFence->data[0] = request->input_buffer->acquire_fence;
                handlesCreated->push_back(acquireFence);
            }
            captureRequest->inputBuffer.acquireFence = acquireFence;
            captureRequest->inputBuffer.releaseFence = nullptr;

            pushInflightBufferLocked(captureRequest->frameNumber, streamId,
                    request->input_buffer->buffer,
                    request->input_buffer->acquire_fence);
        } else {
            captureRequest->inputBuffer.streamId = -1;
            captureRequest->inputBuffer.bufferId = BUFFER_ID_NO_BUFFER;
        }

        captureRequest->outputBuffers.resize(request->num_output_buffers);
        for (size_t i = 0; i < request->num_output_buffers; i++) {
            const camera3_stream_buffer_t *src = request->output_buffers + i;
            StreamBuffer &dst = captureRequest->outputBuffers[i];
            int32_t streamId = Camera3Stream::cast(src->stream)->getId();
            buffer_handle_t buf = *(src->buffer);
            auto pair = getBufferId(buf, streamId);
            bool isNewBuffer = pair.first;
            dst.streamId = streamId;
            dst.bufferId = pair.second;
            dst.buffer = isNewBuffer ? buf : nullptr;
            dst.status = BufferStatus::OK;
            native_handle_t *acquireFence = nullptr;
            if (src->acquire_fence != -1) {
                acquireFence = native_handle_create(1,0);
                acquireFence->data[0] = src->acquire_fence;
                handlesCreated->push_back(acquireFence);
            }
            dst.acquireFence = acquireFence;
            dst.releaseFence = nullptr;

            pushInflightBufferLocked(captureRequest->frameNumber, streamId,
                    src->buffer, src->acquire_fence);
        }
    }
}

     可以看到,captureRequest->frameNumber = request->frame_number幀號的賦值,第一位,說明非常重要!!下面就是對buffer處理了,在output buffer中,通過const camera3_stream_buffer_t *src = request->output_buffers + i 將上面我們已經分析過的Surface中取出的buffer拿出來,然後調用 dst.buffer = isNewBuffer ? buf : nullptr 將它操作賦值給dst,我在這裏打日誌觀察過,申請的幾個buffer一直是複用的,isNewBuffer肯定是true,要不然輸出buffer就爲空了,而複用的就是分配了幾個buffer,然後這幾個buffer一直不斷的輪轉,比如1、2、3、4、5、6,然後又1、2、3、4、5、6一直往復循環的,大家也可以自己加日誌研究一下這塊的邏輯。

     好,往上回到processBatchCaptureRequests方法中,所有的Request的參數都賦值完成了,最後調用mHidlSession->processCaptureRequest把Request發到HAL進程當中,這是通過HIDL來實現的,其實最根本的還是Binder框架!!第三個參數是lambda表達式,在HAL那邊直接就是個hidl_cb的回調接口。mHidlSession是在HAL打開的Session對象,高通和MTK等芯片公司都會有自己不同的實現,一般實現類的名字都是**CameraDevice3SessionImpl*.cpp類型的,大家如果有芯片公司的源碼,可以自己研究下。

     好,一層層往上再回到threadLoop方法當中,一幀請求處理完成,最後調用mNextRequests.clear()清空數據,成功返回true,繼續下一次循環。

     到這裏,大家應該就明白Camera預覽的RequestThread到底是怎麼一回事了吧,當我們收到APP的下預覽的請求時,往mRepeatingRequests隊列中添加了一個元素,後續的預覽都是在對這一個元素不斷的取出來處理的過程,或者有拍照請求時,就取拍照的元素,這樣在threadLoop無限循環就構成了不斷的預覽。中間涉及到一些比較重要的點就是HAL層buffer的申請和轉移的過程,這個大家要清楚一些。

     好了,本節就到這裏了,我們後面會繼續對Camera的東西進行詳細分析。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章