Camera: add batching support for HFR

Test: GCA slow motion recording workin
Bug: 34899394
Change-Id: Icf56458d3fa6f0b4a6b8cfffe6a61da0626e81ec
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 71e52af..eccaddb 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -933,8 +933,18 @@
     return res;
 }
 
+
 hardware::Return<void> Camera3Device::processCaptureResult(
-        const device::V3_2::CaptureResult& result) {
+        const hardware::hidl_vec<
+                hardware::camera::device::V3_2::CaptureResult>& results) {
+    for (const auto& result : results) {
+        processOneCaptureResult(result);
+    }
+    return hardware::Void();
+}
+
+void Camera3Device::processOneCaptureResult(
+        const hardware::camera::device::V3_2::CaptureResult& result) {
     camera3_capture_result r;
     status_t res;
     r.frame_number = result.frameNumber;
@@ -944,7 +954,7 @@
         if ((res = validate_camera_metadata_structure(r.result, &expected_metadata_size)) != OK) {
             ALOGE("%s: Frame %d: Invalid camera metadata received by camera service from HAL: %s (%d)",
                     __FUNCTION__, result.frameNumber, strerror(-res), res);
-            return hardware::Void();
+            return;
         }
     } else {
         r.result = nullptr;
@@ -960,7 +970,7 @@
         if (idx == -1) {
             ALOGE("%s: Frame %d: Buffer %zu: Invalid output stream id %d",
                     __FUNCTION__, result.frameNumber, i, bSrc.streamId);
-            return hardware::Void();
+            return;
         }
         bDst.stream = mOutputStreams.valueAt(idx)->asHalStream();
 
@@ -969,7 +979,7 @@
         if (res != OK) {
             ALOGE("%s: Frame %d: Buffer %zu: No in-flight buffer for stream %d",
                     __FUNCTION__, result.frameNumber, i, bSrc.streamId);
-            return hardware::Void();
+            return;
         }
         bDst.buffer = buffer;
         bDst.status = mapHidlBufferStatus(bSrc.status);
@@ -981,7 +991,7 @@
         } else {
             ALOGE("%s: Frame %d: Invalid release fence for buffer %zu, fd count is %d, not 1",
                     __FUNCTION__, result.frameNumber, i, bSrc.releaseFence->numFds);
-            return hardware::Void();
+            return;
         }
     }
     r.num_output_buffers = outputBuffers.size();
@@ -994,7 +1004,7 @@
         if (mInputStream->getId() != result.inputBuffer.streamId) {
             ALOGE("%s: Frame %d: Invalid input stream id %d", __FUNCTION__,
                     result.frameNumber, result.inputBuffer.streamId);
-            return hardware::Void();
+            return;
         }
         inputBuffer.stream = mInputStream->asHalStream();
         buffer_handle_t *buffer;
@@ -1003,7 +1013,7 @@
         if (res != OK) {
             ALOGE("%s: Frame %d: Input buffer: No in-flight buffer for stream %d",
                     __FUNCTION__, result.frameNumber, result.inputBuffer.streamId);
-            return hardware::Void();
+            return;
         }
         inputBuffer.buffer = buffer;
         inputBuffer.status = mapHidlBufferStatus(result.inputBuffer.status);
@@ -1015,7 +1025,7 @@
         } else {
             ALOGE("%s: Frame %d: Invalid release fence for input buffer, fd count is %d, not 1",
                     __FUNCTION__, result.frameNumber, result.inputBuffer.releaseFence->numFds);
-            return hardware::Void();
+            return;
         }
         r.input_buffer = &inputBuffer;
     }
@@ -1023,12 +1033,19 @@
     r.partial_result = result.partialResult;
 
     processCaptureResult(&r);
-
-    return hardware::Void();
 }
 
 hardware::Return<void> Camera3Device::notify(
-        const NotifyMsg& msg) {
+        const hardware::hidl_vec<hardware::camera::device::V3_2::NotifyMsg>& msgs) {
+    for (const auto& msg : msgs) {
+        notify(msg);
+    }
+    return hardware::Void();
+}
+
+void Camera3Device::notify(
+        const hardware::camera::device::V3_2::NotifyMsg& msg) {
+
     camera3_notify_msg m;
     switch (msg.type) {
         case MsgType::ERROR:
@@ -1039,7 +1056,7 @@
                 if (idx == -1) {
                     ALOGE("%s: Frame %d: Invalid error stream id %d",
                             __FUNCTION__, m.message.error.frame_number, msg.msg.error.errorStreamId);
-                    return hardware::Void();
+                    return;
                 }
                 m.message.error.error_stream = mOutputStreams.valueAt(idx)->asHalStream();
             } else {
@@ -1067,8 +1084,6 @@
             break;
     }
     notify(&m);
-
-    return hardware::Void();
 }
 
 status_t Camera3Device::captureList(const List<const CameraMetadata> &requests,
@@ -3036,7 +3051,8 @@
         mHal3Device(nullptr) {}
 
 Camera3Device::HalInterface::HalInterface(const HalInterface& other) :
-        mHal3Device(other.mHal3Device), mHidlSession(other.mHidlSession) {}
+        mHal3Device(other.mHal3Device),
+        mHidlSession(other.mHidlSession) {}
 
 bool Camera3Device::HalInterface::valid() {
     return (mHal3Device != nullptr) || (mHidlSession != nullptr);
@@ -3047,6 +3063,10 @@
     mHidlSession.clear();
 }
 
+bool Camera3Device::HalInterface::supportBatchRequest() {
+    return mHidlSession != nullptr;
+}
+
 status_t Camera3Device::HalInterface::constructDefaultRequestSettings(
         camera3_request_template_t templateId,
         /*out*/ camera_metadata_t **requestTemplate) {
@@ -3251,6 +3271,114 @@
     return res;
 }
 
+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;
+    // A null request settings maps to a size-0 CameraMetadata
+    if (request->settings != nullptr) {
+        captureRequest->settings.setToExternal(
+                reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(request->settings)),
+                get_camera_metadata_size(request->settings));
+    }
+
+    {
+        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);
+        }
+    }
+}
+
+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);
+    }
+
+    common::V1_0::Status status = common::V1_0::Status::INTERNAL_ERROR;
+    *numRequestProcessed = 0;
+    mHidlSession->processCaptureRequest(captureRequests,
+            [&status, &numRequestProcessed] (auto s, uint32_t n) {
+                status = s;
+                *numRequestProcessed = n;
+            });
+
+    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);
+}
+
 status_t Camera3Device::HalInterface::processCaptureRequest(
         camera3_capture_request_t *request) {
     ATRACE_NAME("CameraHal::processCaptureRequest");
@@ -3260,76 +3388,10 @@
     if (mHal3Device != nullptr) {
         res = mHal3Device->ops->process_capture_request(mHal3Device, request);
     } else {
-        device::V3_2::CaptureRequest captureRequest;
-        captureRequest.frameNumber = request->frame_number;
-        std::vector<native_handle_t*> handlesCreated;
-        // A null request settings maps to a size-0 CameraMetadata
-        if (request->settings != nullptr) {
-            captureRequest.settings.setToExternal(
-                    reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(request->settings)),
-                    get_camera_metadata_size(request->settings));
-        }
-
-        {
-            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);
-            }
-        }
-        common::V1_0::Status status = mHidlSession->processCaptureRequest(captureRequest);
-
-        for (auto& handle : handlesCreated) {
-            native_handle_delete(handle);
-        }
-        res = CameraProviderManager::mapToStatusT(status);
+        uint32_t numRequestProcessed = 0;
+        std::vector<camera3_capture_request_t*> requests(1);
+        requests[0] = request;
+        res = processBatchCaptureRequests(requests, &numRequestProcessed);
     }
     return res;
 }
@@ -3757,6 +3819,128 @@
     }
 }
 
+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;
+}
+
+bool Camera3Device::RequestThread::sendRequestsOneByOne() {
+    status_t res;
+
+    for (auto& nextRequest : mNextRequests) {
+        // Submit request and block until ready for next one
+        ATRACE_ASYNC_BEGIN("frame capture", nextRequest.halRequest.frame_number);
+        res = mInterface->processCaptureRequest(&nextRequest.halRequest);
+
+        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)", nextRequest.halRequest.frame_number, strerror(-res),
+                    res);
+            cleanUpFailedRequests(/*sendRequestError*/ false);
+            return false;
+        }
+
+        // Mark that the request has be submitted successfully.
+        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);
+        }
+
+        // Remove any previously queued triggers (after unlock)
+        res = removeTriggers(mPrevRequest);
+        if (res != OK) {
+            SET_ERR("RequestThread: Unable to remove triggers "
+                  "(capture request %d, HAL device: %s (%d)",
+                  nextRequest.halRequest.frame_number, strerror(-res), res);
+            cleanUpFailedRequests(/*sendRequestError*/ false);
+            return false;
+        }
+    }
+    return true;
+}
+
 bool Camera3Device::RequestThread::threadLoop() {
     ATRACE_CALL();
     status_t res;
@@ -3819,58 +4003,12 @@
 
     ALOGVV("%s: %d: submitting %zu requests in a batch.", __FUNCTION__, __LINE__,
             mNextRequests.size());
-    for (auto& nextRequest : mNextRequests) {
-        // Submit request and block until ready for next one
-        ATRACE_ASYNC_BEGIN("frame capture", nextRequest.halRequest.frame_number);
-        res = mInterface->processCaptureRequest(&nextRequest.halRequest);
 
-        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)", nextRequest.halRequest.frame_number, strerror(-res),
-                    res);
-            cleanUpFailedRequests(/*sendRequestError*/ false);
-            if (useFlushLock) {
-                mFlushLock.unlock();
-            }
-            return false;
-        }
-
-        // Mark that the request has be submitted successfully.
-        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);
-        }
-
-        // Remove any previously queued triggers (after unlock)
-        res = removeTriggers(mPrevRequest);
-        if (res != OK) {
-            SET_ERR("RequestThread: Unable to remove triggers "
-                  "(capture request %d, HAL device: %s (%d)",
-                  nextRequest.halRequest.frame_number, strerror(-res), res);
-            cleanUpFailedRequests(/*sendRequestError*/ false);
-            if (useFlushLock) {
-                mFlushLock.unlock();
-            }
-            return false;
-        }
+    bool submitRequestSuccess = false;
+    if (mInterface->supportBatchRequest()) {
+        submitRequestSuccess = sendRequestsBatch();
+    } else {
+        submitRequestSuccess = sendRequestsOneByOne();
     }
 
     if (useFlushLock) {
@@ -3883,7 +4021,7 @@
         mNextRequests.clear();
     }
 
-    return true;
+    return submitRequestSuccess;
 }
 
 status_t Camera3Device::RequestThread::prepareHalRequests() {
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index c10b1b4..d873b27 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -241,6 +241,9 @@
         // Reset this HalInterface object (does not call close())
         void clear();
 
+        // Check if HalInterface support sending requests in batch
+        bool supportBatchRequest();
+
         // Calls into the HAL interface
 
         // Caller takes ownership of requestTemplate
@@ -248,6 +251,9 @@
                 /*out*/ camera_metadata_t **requestTemplate);
         status_t configureStreams(/*inout*/ camera3_stream_configuration *config);
         status_t processCaptureRequest(camera3_capture_request_t *request);
+        status_t processBatchCaptureRequests(
+                std::vector<camera3_capture_request_t*>& requests,
+                /*out*/uint32_t* numRequestProcessed);
         status_t flush();
         status_t dump(int fd);
         status_t close();
@@ -262,6 +268,12 @@
 
         std::mutex mInflightLock;
 
+        // The output HIDL request still depends on input camera3_capture_request_t
+        // Do not free input camera3_capture_request_t before output HIDL request
+        void wrapAsHidlRequest(camera3_capture_request_t* in,
+                /*out*/hardware::camera::device::V3_2::CaptureRequest* out,
+                /*out*/std::vector<native_handle_t*>* handlesCreated);
+
         status_t pushInflightBufferLocked(int32_t frameNumber, int32_t streamId,
                 buffer_handle_t *buffer, int acquireFence);
         // Cache of buffer handles keyed off (frameNumber << 32 | streamId)
@@ -438,9 +450,17 @@
      */
 
     hardware::Return<void> processCaptureResult(
-            const hardware::camera::device::V3_2::CaptureResult& result) override;
+            const hardware::hidl_vec<
+                    hardware::camera::device::V3_2::CaptureResult>& results) override;
     hardware::Return<void> notify(
-            const hardware::camera::device::V3_2::NotifyMsg& msg) override;
+            const hardware::hidl_vec<
+                    hardware::camera::device::V3_2::NotifyMsg>& msgs) override;
+
+    // Handle one capture result
+    void processOneCaptureResult(
+            const hardware::camera::device::V3_2::CaptureResult& results);
+    // Handle one notify message
+    void notify(const hardware::camera::device::V3_2::NotifyMsg& msg);
 
     /**
      * Common initialization code shared by both HAL paths
@@ -759,6 +779,12 @@
         // Clear repeating requests. Must be called with mRequestLock held.
         status_t clearRepeatingRequestsLocked(/*out*/ int64_t *lastFrameNumber = NULL);
 
+        // send request in mNextRequests to HAL one by one. Return true = sucssess
+        bool sendRequestsOneByOne();
+
+        // send request in mNextRequests to HAL in a batch. Return true = sucssess
+        bool sendRequestsBatch();
+
         wp<Camera3Device>  mParent;
         wp<camera3::StatusTracker>  mStatusTracker;
         HalInterface*      mInterface;