Make Camera3Device transport agnostic.

Add HidlCamera3Device* which seperates out hidl transport specific
functionality from Camera3Device* and related classes.

Bug: 196432585

Test: Camera CTS

Change-Id: Iee940614e261c345202144b9a0ea22a70a6e887b
Signed-off-by: Jayant Chowdhary <jchowdhary@google.com>
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index 4c079e1..8428881 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -81,6 +81,9 @@
         "device3/Camera3DeviceInjectionMethods.cpp",
         "device3/UHRCropAndMeteringRegionMapper.cpp",
         "device3/PreviewFrameScheduler.cpp",
+        "device3/hidl/HidlCamera3Device.cpp",
+        "device3/hidl/HidlCamera3OfflineSession.cpp",
+        "device3/hidl/HidlCamera3OutputUtils.cpp",
         "gui/RingBufferConsumer.cpp",
         "hidl/AidlCameraDeviceCallbacks.cpp",
         "hidl/AidlCameraServiceListener.cpp",
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 5d17c11..55c7579 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -34,6 +34,7 @@
 #include "api2/CameraDeviceClient.h"
 
 #include "device3/Camera3Device.h"
+#include "device3/hidl/HidlCamera3Device.h"
 #include "utils/CameraThreadState.h"
 #include "utils/CameraServiceProxyWrapper.h"
 
@@ -62,14 +63,14 @@
                 servicePid),
         mSharedCameraCallbacks(remoteCallback),
         mDeviceVersion(cameraService->getDeviceVersion(TClientBase::mCameraIdStr)),
-        mDevice(new Camera3Device(cameraId, overrideForPerfClass, legacyClient)),
         mDeviceActive(false), mApi1CameraId(api1CameraId)
 {
     ALOGI("Camera %s: Opened. Client: %s (PID %d, UID %d)", cameraId.string(),
             String8(clientPackageName).string(), clientPid, clientUid);
 
     mInitialClientPid = clientPid;
-    LOG_ALWAYS_FATAL_IF(mDevice == 0, "Device should never be NULL here.");
+    mOverrideForPerfClass = overrideForPerfClass;
+    mLegacyClient = legacyClient;
 }
 
 template <typename TClientBase>
@@ -104,7 +105,26 @@
     if (res != OK) {
         return res;
     }
-
+    IPCTransport providerTransport = IPCTransport::INVALID;
+    res = providerPtr->getCameraIdIPCTransport(TClientBase::mCameraIdStr.string(),
+            &providerTransport);
+    if (res != OK) {
+        return res;
+    }
+    switch (providerTransport) {
+        case IPCTransport::HIDL:
+            mDevice =
+                    new HidlCamera3Device(TClientBase::mCameraIdStr, mOverrideForPerfClass,
+                            mLegacyClient);
+            break;
+        case IPCTransport::AIDL:
+            ALOGE("%s: AIDL camera3Devices not available yet", __FUNCTION__);
+            return NO_INIT;
+        default:
+            ALOGE("%s Invalid transport for camera id %s", __FUNCTION__,
+                    TClientBase::mCameraIdStr.string());
+            return NO_INIT;
+    }
     if (mDevice == NULL) {
         ALOGE("%s: Camera %s: No device connected",
                 __FUNCTION__, TClientBase::mCameraIdStr.string());
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index 4688502..296ef43 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -126,6 +126,8 @@
 
     // The PID provided in the constructor call
     pid_t mInitialClientPid;
+    bool mOverrideForPerfClass = false;
+    bool mLegacyClient = false;
 
     virtual sp<IBinder> asBinderWrapper() {
         return IInterface::asBinder(this);
@@ -145,9 +147,12 @@
 
     const int mDeviceVersion;
 
-    // Set to const to avoid mDevice being updated (update of sp<> is racy) during
-    // dumpDevice (which is important to be lock free for debugging purpose)
-    const sp<CameraDeviceBase>  mDevice;
+    // Note: This was previously set to const to avoid mDevice being updated -
+    // b/112639939 (update of sp<> is racy) during dumpDevice (which is important to be lock free
+    // for debugging purpose). The const has been removed since CameraDeviceBase
+    // needs to be set during initializeImpl(). This must not be set / cleared
+    // anywhere else.
+    sp<CameraDeviceBase>  mDevice;
 
     /** Utility members */
 
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 4c9adfb..4227d28 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -278,6 +278,21 @@
     return deviceInfo->isSessionConfigurationSupported(configuration, overrideForPerfClass, status);
 }
 
+status_t CameraProviderManager::getCameraIdIPCTransport(const std::string &id,
+        IPCTransport *providerTransport) const {
+    std::lock_guard<std::mutex> lock(mInterfaceMutex);
+    auto deviceInfo = findDeviceInfoLocked(id);
+    if (deviceInfo == nullptr) {
+        return NAME_NOT_FOUND;
+    }
+    sp<ProviderInfo> parentProvider = deviceInfo->mParentProvider.promote();
+    if (parentProvider == nullptr) {
+        return DEAD_OBJECT;
+    }
+    *providerTransport = parentProvider->getIPCTransport();
+    return OK;
+}
+
 status_t CameraProviderManager::getCameraCharacteristics(const std::string &id,
         bool overrideForPerfClass, CameraMetadata* characteristics) const {
     std::lock_guard<std::mutex> lock(mInterfaceMutex);
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 4bf5dee..64f5abf 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -189,6 +189,9 @@
     status_t initialize(wp<StatusListener> listener,
             HidlServiceInteractionProxy *hidlProxy = &sHidlServiceInteractionProxy);
 
+    status_t getCameraIdIPCTransport(const std::string &id,
+            IPCTransport *providerTransport) const;
+
     /**
      * Retrieve the total number of available cameras.
      * This value may change dynamically as cameras are added or removed.
diff --git a/services/camera/libcameraservice/device3/BufferUtils.cpp b/services/camera/libcameraservice/device3/BufferUtils.cpp
index f3adf20..c0d47d5 100644
--- a/services/camera/libcameraservice/device3/BufferUtils.cpp
+++ b/services/camera/libcameraservice/device3/BufferUtils.cpp
@@ -28,16 +28,6 @@
 namespace android {
 namespace camera3 {
 
-camera_buffer_status_t mapHidlBufferStatus(hardware::camera::device::V3_2::BufferStatus status) {
-    using hardware::camera::device::V3_2::BufferStatus;
-
-    switch (status) {
-        case BufferStatus::OK: return CAMERA_BUFFER_STATUS_OK;
-        case BufferStatus::ERROR: return CAMERA_BUFFER_STATUS_ERROR;
-    }
-    return CAMERA_BUFFER_STATUS_ERROR;
-}
-
 void BufferRecords::takeInflightBufferMap(BufferRecords& other) {
     std::lock_guard<std::mutex> oLock(other.mInflightLock);
     std::lock_guard<std::mutex> lock(mInflightLock);
diff --git a/services/camera/libcameraservice/device3/BufferUtils.h b/services/camera/libcameraservice/device3/BufferUtils.h
index 03112ec..96fc111 100644
--- a/services/camera/libcameraservice/device3/BufferUtils.h
+++ b/services/camera/libcameraservice/device3/BufferUtils.h
@@ -154,9 +154,6 @@
     }; // class BufferRecords
 
     static const uint64_t BUFFER_ID_NO_BUFFER = 0;
-
-    camera_buffer_status_t mapHidlBufferStatus(
-            hardware::camera::device::V3_2::BufferStatus status);
 } // namespace camera3
 
 } // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 738cf53..992027a 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -114,164 +114,6 @@
     return mId;
 }
 
-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;
-
-    sp<ICameraDeviceSession> session;
-    ATRACE_BEGIN("CameraHal::openSession");
-    status_t res = manager->openHidlSession(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;
-    }
-
-    res = manager->getCameraCharacteristics(mId.string(), mOverrideForPerfClass, &mDeviceInfo);
-    if (res != OK) {
-        SET_ERR_L("Could not retrieve camera characteristics: %s (%d)", strerror(-res), res);
-        session->close();
-        return res;
-    }
-    mSupportNativeZoomRatio = manager->supportNativeZoomRatio(mId.string());
-
-    std::vector<std::string> physicalCameraIds;
-    bool isLogical = manager->isLogicalCamera(mId.string(), &physicalCameraIds);
-    if (isLogical) {
-        for (auto& physicalId : physicalCameraIds) {
-            // Do not override characteristics for physical cameras
-            res = manager->getCameraCharacteristics(
-                    physicalId, /*overrideForPerfClass*/false, &mPhysicalDeviceInfoMap[physicalId]);
-            if (res != OK) {
-                SET_ERR_L("Could not retrieve camera %s characteristics: %s (%d)",
-                        physicalId.c_str(), strerror(-res), res);
-                session->close();
-                return res;
-            }
-
-            bool usePrecorrectArray =
-                    DistortionMapper::isDistortionSupported(mPhysicalDeviceInfoMap[physicalId]);
-            if (usePrecorrectArray) {
-                res = mDistortionMappers[physicalId].setupStaticInfo(
-                        mPhysicalDeviceInfoMap[physicalId]);
-                if (res != OK) {
-                    SET_ERR_L("Unable to read camera %s's calibration fields for distortion "
-                            "correction", physicalId.c_str());
-                    session->close();
-                    return res;
-                }
-            }
-
-            mZoomRatioMappers[physicalId] = ZoomRatioMapper(
-                    &mPhysicalDeviceInfoMap[physicalId],
-                    mSupportNativeZoomRatio, usePrecorrectArray);
-
-            if (SessionConfigurationUtils::isUltraHighResolutionSensor(
-                    mPhysicalDeviceInfoMap[physicalId])) {
-                mUHRCropAndMeteringRegionMappers[physicalId] =
-                        UHRCropAndMeteringRegionMapper(mPhysicalDeviceInfoMap[physicalId],
-                                usePrecorrectArray);
-            }
-        }
-    }
-
-    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 (const auto& iface : interfaceChain) {
-                    ALOGV("  %s", iface.c_str());
-                }
-            });
-    }
-
-    camera_metadata_entry bufMgrMode =
-            mDeviceInfo.find(ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION);
-    if (bufMgrMode.count > 0) {
-         mUseHalBufManager = (bufMgrMode.data.u8[0] ==
-            ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
-    }
-
-    camera_metadata_entry_t capabilities = mDeviceInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
-    for (size_t i = 0; i < capabilities.count; i++) {
-        uint8_t capability = capabilities.data.u8[i];
-        if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING) {
-            mSupportOfflineProcessing = true;
-        }
-    }
-
-    mInterface = new HalInterface(session, queue, mUseHalBufManager, mSupportOfflineProcessing);
-    std::string providerType;
-    mVendorTagId = manager->getProviderTagIdLocked(mId.string());
-    mTagMonitor.initialize(mVendorTagId);
-    if (!monitorTags.isEmpty()) {
-        mTagMonitor.parseTagsToMonitor(String8(monitorTags));
-    }
-
-    // Metadata tags needs fixup for monochrome camera device version less
-    // than 3.5.
-    hardware::hidl_version maxVersion{0,0};
-    res = manager->getHighestSupportedVersion(mId.string(), &maxVersion);
-    if (res != OK) {
-        ALOGE("%s: Error in getting camera device version id: %s (%d)",
-                __FUNCTION__, strerror(-res), res);
-        return res;
-    }
-    int deviceVersion = HARDWARE_DEVICE_API_VERSION(
-            maxVersion.get_major(), maxVersion.get_minor());
-
-    bool isMonochrome = false;
-    for (size_t i = 0; i < capabilities.count; i++) {
-        uint8_t capability = capabilities.data.u8[i];
-        if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) {
-            isMonochrome = true;
-        }
-    }
-    mNeedFixupMonochromeTags = (isMonochrome && deviceVersion < CAMERA_DEVICE_API_VERSION_3_5);
-
-    return initializeCommonLocked();
-}
-
 status_t Camera3Device::initializeCommonLocked() {
 
     /** Start up status tracker thread */
@@ -325,7 +167,7 @@
     }
 
     /** Start up request queue thread */
-    mRequestThread = new RequestThread(
+    mRequestThread = createNewRequestThread(
             this, mStatusTracker, mInterface, sessionParamKeys,
             mUseHalBufManager, mSupportCameraMute);
     res = mRequestThread->run(String8::format("C3Dev-%s-ReqQueue", mId.string()).string());
@@ -383,7 +225,8 @@
         mRotateAndCropMappers.emplace(mId.c_str(), &mDeviceInfo);
     }
 
-    mInjectionMethods = new Camera3DeviceInjectionMethods(this);
+    // Hidl/AidlCamera3DeviceInjectionMethods
+    mInjectionMethods = createCamera3DeviceInjectionMethods(this);
 
     return OK;
 }
@@ -533,83 +376,6 @@
     return measured;
 }
 
-CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap
-Camera3Device::mapToHidlDynamicProfile(int dynamicRangeProfile) {
-    return static_cast<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap>(
-            dynamicRangeProfile);
-}
-
-hardware::graphics::common::V1_0::PixelFormat Camera3Device::mapToPixelFormat(
-        int frameworkFormat) {
-    return (hardware::graphics::common::V1_0::PixelFormat) frameworkFormat;
-}
-
-DataspaceFlags Camera3Device::mapToHidlDataspace(
-        android_dataspace dataSpace) {
-    return dataSpace;
-}
-
-BufferUsageFlags Camera3Device::mapToConsumerUsage(
-        uint64_t usage) {
-    return usage;
-}
-
-StreamRotation Camera3Device::mapToStreamRotation(camera_stream_rotation_t rotation) {
-    switch (rotation) {
-        case CAMERA_STREAM_ROTATION_0:
-            return StreamRotation::ROTATION_0;
-        case CAMERA_STREAM_ROTATION_90:
-            return StreamRotation::ROTATION_90;
-        case CAMERA_STREAM_ROTATION_180:
-            return StreamRotation::ROTATION_180;
-        case CAMERA_STREAM_ROTATION_270:
-            return StreamRotation::ROTATION_270;
-    }
-    ALOGE("%s: Unknown stream rotation %d", __FUNCTION__, rotation);
-    return StreamRotation::ROTATION_0;
-}
-
-status_t Camera3Device::mapToStreamConfigurationMode(
-        camera_stream_configuration_mode_t operationMode, StreamConfigurationMode *mode) {
-    if (mode == nullptr) return BAD_VALUE;
-    if (operationMode < CAMERA_VENDOR_STREAM_CONFIGURATION_MODE_START) {
-        switch(operationMode) {
-            case CAMERA_STREAM_CONFIGURATION_NORMAL_MODE:
-                *mode = StreamConfigurationMode::NORMAL_MODE;
-                break;
-            case CAMERA_STREAM_CONFIGURATION_CONSTRAINED_HIGH_SPEED_MODE:
-                *mode = StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE;
-                break;
-            default:
-                ALOGE("%s: Unknown stream configuration mode %d", __FUNCTION__, operationMode);
-                return BAD_VALUE;
-        }
-    } else {
-        *mode = static_cast<StreamConfigurationMode>(operationMode);
-    }
-    return OK;
-}
-
-int Camera3Device::mapToFrameworkFormat(
-        hardware::graphics::common::V1_0::PixelFormat pixelFormat) {
-    return static_cast<uint32_t>(pixelFormat);
-}
-
-android_dataspace Camera3Device::mapToFrameworkDataspace(
-        DataspaceFlags dataSpace) {
-    return static_cast<android_dataspace>(dataSpace);
-}
-
-uint64_t Camera3Device::mapConsumerToFrameworkUsage(
-        BufferUsageFlags usage) {
-    return usage;
-}
-
-uint64_t Camera3Device::mapProducerToFrameworkUsage(
-        BufferUsageFlags usage) {
-    return usage;
-}
-
 ssize_t Camera3Device::getJpegBufferSize(const CameraMetadata &info, uint32_t width,
         uint32_t height) const {
     // Get max jpeg size (area-wise) for default sensor pixel mode
@@ -1052,186 +818,6 @@
     return res;
 }
 
-hardware::Return<void> Camera3Device::requestStreamBuffers(
-        const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
-        requestStreamBuffers_cb _hidl_cb) {
-    RequestBufferStates states {
-        mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder,
-        *this, *mInterface, *this};
-    camera3::requestStreamBuffers(states, bufReqs, _hidl_cb);
-    return hardware::Void();
-}
-
-hardware::Return<void> Camera3Device::returnStreamBuffers(
-        const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) {
-    ReturnBufferStates states {
-        mId, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder, *mInterface};
-    camera3::returnStreamBuffers(states, buffers);
-    return hardware::Void();
-}
-
-hardware::Return<void> Camera3Device::processCaptureResult_3_4(
-        const hardware::hidl_vec<
-                hardware::camera::device::V3_4::CaptureResult>& results) {
-    // Ideally we should grab mLock, but that can lead to deadlock, and
-    // it's not super important to get up to date value of mStatus for this
-    // warning print, hence skipping the lock here
-    if (mStatus == STATUS_ERROR) {
-        // Per API contract, HAL should act as closed after device error
-        // But mStatus can be set to error by framework as well, so just log
-        // a warning here.
-        ALOGW("%s: received capture result in error state.", __FUNCTION__);
-    }
-
-    sp<NotificationListener> listener;
-    {
-        std::lock_guard<std::mutex> l(mOutputLock);
-        listener = mListener.promote();
-    }
-
-    if (mProcessCaptureResultLock.tryLock() != OK) {
-        // This should never happen; it indicates a wrong client implementation
-        // that doesn't follow the contract. But, we can be tolerant here.
-        ALOGE("%s: callback overlapped! waiting 1s...",
-                __FUNCTION__);
-        if (mProcessCaptureResultLock.timedLock(1000000000 /* 1s */) != OK) {
-            ALOGE("%s: cannot acquire lock in 1s, dropping results",
-                    __FUNCTION__);
-            // really don't know what to do, so bail out.
-            return hardware::Void();
-        }
-    }
-    CaptureOutputStates states {
-        mId,
-        mInFlightLock, mLastCompletedRegularFrameNumber,
-        mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
-        mInFlightMap, mOutputLock,  mResultQueue, mResultSignal,
-        mNextShutterFrameNumber,
-        mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
-        mNextResultFrameNumber,
-        mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
-        mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
-        mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
-        mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
-        mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
-        *mInterface, mLegacyClient
-    };
-
-    for (const auto& result : results) {
-        processOneCaptureResultLocked(states, result.v3_2, result.physicalCameraMetadata);
-    }
-    mProcessCaptureResultLock.unlock();
-    return hardware::Void();
-}
-
-// Only one processCaptureResult should be called at a time, so
-// the locks won't block. The locks are present here simply to enforce this.
-hardware::Return<void> Camera3Device::processCaptureResult(
-        const hardware::hidl_vec<
-                hardware::camera::device::V3_2::CaptureResult>& results) {
-    hardware::hidl_vec<hardware::camera::device::V3_4::PhysicalCameraMetadata> noPhysMetadata;
-
-    // Ideally we should grab mLock, but that can lead to deadlock, and
-    // it's not super important to get up to date value of mStatus for this
-    // warning print, hence skipping the lock here
-    if (mStatus == STATUS_ERROR) {
-        // Per API contract, HAL should act as closed after device error
-        // But mStatus can be set to error by framework as well, so just log
-        // a warning here.
-        ALOGW("%s: received capture result in error state.", __FUNCTION__);
-    }
-
-    sp<NotificationListener> listener;
-    {
-        std::lock_guard<std::mutex> l(mOutputLock);
-        listener = mListener.promote();
-    }
-
-    if (mProcessCaptureResultLock.tryLock() != OK) {
-        // This should never happen; it indicates a wrong client implementation
-        // that doesn't follow the contract. But, we can be tolerant here.
-        ALOGE("%s: callback overlapped! waiting 1s...",
-                __FUNCTION__);
-        if (mProcessCaptureResultLock.timedLock(1000000000 /* 1s */) != OK) {
-            ALOGE("%s: cannot acquire lock in 1s, dropping results",
-                    __FUNCTION__);
-            // really don't know what to do, so bail out.
-            return hardware::Void();
-        }
-    }
-
-    CaptureOutputStates states {
-        mId,
-        mInFlightLock, mLastCompletedRegularFrameNumber,
-        mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
-        mInFlightMap, mOutputLock,  mResultQueue, mResultSignal,
-        mNextShutterFrameNumber,
-        mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
-        mNextResultFrameNumber,
-        mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
-        mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
-        mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
-        mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
-        mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
-        *mInterface, mLegacyClient
-    };
-
-    for (const auto& result : results) {
-        processOneCaptureResultLocked(states, result, noPhysMetadata);
-    }
-    mProcessCaptureResultLock.unlock();
-    return hardware::Void();
-}
-
-hardware::Return<void> Camera3Device::notify(
-        const hardware::hidl_vec<hardware::camera::device::V3_2::NotifyMsg>& msgs) {
-    return notifyHelper<hardware::camera::device::V3_2::NotifyMsg>(msgs);
-}
-
-hardware::Return<void> Camera3Device::notify_3_8(
-        const hardware::hidl_vec<hardware::camera::device::V3_8::NotifyMsg>& msgs) {
-    return notifyHelper<hardware::camera::device::V3_8::NotifyMsg>(msgs);
-}
-
-template<typename NotifyMsgType>
-hardware::Return<void> Camera3Device::notifyHelper(const hardware::hidl_vec<NotifyMsgType>& msgs) {
-    // Ideally we should grab mLock, but that can lead to deadlock, and
-    // it's not super important to get up to date value of mStatus for this
-    // warning print, hence skipping the lock here
-    if (mStatus == STATUS_ERROR) {
-        // Per API contract, HAL should act as closed after device error
-        // But mStatus can be set to error by framework as well, so just log
-        // a warning here.
-        ALOGW("%s: received notify message in error state.", __FUNCTION__);
-    }
-
-    sp<NotificationListener> listener;
-    {
-        std::lock_guard<std::mutex> l(mOutputLock);
-        listener = mListener.promote();
-    }
-
-    CaptureOutputStates states {
-        mId,
-        mInFlightLock, mLastCompletedRegularFrameNumber,
-        mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
-        mInFlightMap, mOutputLock,  mResultQueue, mResultSignal,
-        mNextShutterFrameNumber,
-        mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
-        mNextResultFrameNumber,
-        mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
-        mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
-        mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
-        mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
-        mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
-        *mInterface, mLegacyClient
-    };
-    for (const auto& msg : msgs) {
-        camera3::notify(states, msg);
-    }
-    return hardware::Void();
-}
-
 status_t Camera3Device::captureList(const List<const PhysicalCameraSettingsList> &requestsList,
                                     const std::list<const SurfaceMap> &surfaceMaps,
                                     int64_t *lastFrameNumber) {
@@ -3143,733 +2729,6 @@
  * HalInterface inner class methods
  */
 
-Camera3Device::HalInterface::HalInterface(
-            sp<ICameraDeviceSession> &session,
-            std::shared_ptr<RequestMetadataQueue> queue,
-            bool useHalBufManager, bool supportOfflineProcessing) :
-        mHidlSession(session),
-        mRequestMetadataQueue(queue),
-        mUseHalBufManager(useHalBufManager),
-        mIsReconfigurationQuerySupported(true),
-        mSupportOfflineProcessing(supportOfflineProcessing) {
-    // Check with hardware service manager if we can downcast these interfaces
-    // Somewhat expensive, so cache the results at startup
-    auto castResult_3_8 = device::V3_8::ICameraDeviceSession::castFrom(mHidlSession);
-    if (castResult_3_8.isOk()) {
-        mHidlSession_3_8 = castResult_3_8;
-    }
-    auto castResult_3_7 = device::V3_7::ICameraDeviceSession::castFrom(mHidlSession);
-    if (castResult_3_7.isOk()) {
-        mHidlSession_3_7 = castResult_3_7;
-    }
-    auto castResult_3_6 = device::V3_6::ICameraDeviceSession::castFrom(mHidlSession);
-    if (castResult_3_6.isOk()) {
-        mHidlSession_3_6 = castResult_3_6;
-    }
-    auto castResult_3_5 = device::V3_5::ICameraDeviceSession::castFrom(mHidlSession);
-    if (castResult_3_5.isOk()) {
-        mHidlSession_3_5 = castResult_3_5;
-    }
-    auto castResult_3_4 = device::V3_4::ICameraDeviceSession::castFrom(mHidlSession);
-    if (castResult_3_4.isOk()) {
-        mHidlSession_3_4 = castResult_3_4;
-    }
-    auto castResult_3_3 = device::V3_3::ICameraDeviceSession::castFrom(mHidlSession);
-    if (castResult_3_3.isOk()) {
-        mHidlSession_3_3 = castResult_3_3;
-    }
-}
-
-Camera3Device::HalInterface::HalInterface() :
-        mUseHalBufManager(false),
-        mSupportOfflineProcessing(false) {}
-
-Camera3Device::HalInterface::HalInterface(const HalInterface& other) :
-        mHidlSession(other.mHidlSession),
-        mRequestMetadataQueue(other.mRequestMetadataQueue),
-        mUseHalBufManager(other.mUseHalBufManager),
-        mSupportOfflineProcessing(other.mSupportOfflineProcessing) {}
-
-bool Camera3Device::HalInterface::valid() {
-    return (mHidlSession != nullptr);
-}
-
-void Camera3Device::HalInterface::clear() {
-    mHidlSession_3_8.clear();
-    mHidlSession_3_7.clear();
-    mHidlSession_3_6.clear();
-    mHidlSession_3_5.clear();
-    mHidlSession_3_4.clear();
-    mHidlSession_3_3.clear();
-    mHidlSession.clear();
-}
-
-status_t Camera3Device::HalInterface::constructDefaultRequestSettings(
-        camera_request_template_t templateId,
-        /*out*/ camera_metadata_t **requestTemplate) {
-    ATRACE_NAME("CameraHal::constructDefaultRequestSettings");
-    if (!valid()) return INVALID_OPERATION;
-    status_t res = OK;
-
-    common::V1_0::Status status;
-
-    auto requestCallback = [&status, &requestTemplate]
-            (common::V1_0::Status s, const device::V3_2::CameraMetadata& request) {
-            status = s;
-            if (status == common::V1_0::Status::OK) {
-                const camera_metadata *r =
-                        reinterpret_cast<const camera_metadata_t*>(request.data());
-                size_t expectedSize = request.size();
-                int ret = validate_camera_metadata_structure(r, &expectedSize);
-                if (ret == OK || ret == CAMERA_METADATA_VALIDATION_SHIFTED) {
-                    *requestTemplate = clone_camera_metadata(r);
-                    if (*requestTemplate == nullptr) {
-                        ALOGE("%s: Unable to clone camera metadata received from HAL",
-                                __FUNCTION__);
-                        status = common::V1_0::Status::INTERNAL_ERROR;
-                    }
-                } else {
-                    ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
-                    status = common::V1_0::Status::INTERNAL_ERROR;
-                }
-            }
-        };
-    hardware::Return<void> err;
-    RequestTemplate id;
-    switch (templateId) {
-        case CAMERA_TEMPLATE_PREVIEW:
-            id = RequestTemplate::PREVIEW;
-            break;
-        case CAMERA_TEMPLATE_STILL_CAPTURE:
-            id = RequestTemplate::STILL_CAPTURE;
-            break;
-        case CAMERA_TEMPLATE_VIDEO_RECORD:
-            id = RequestTemplate::VIDEO_RECORD;
-            break;
-        case CAMERA_TEMPLATE_VIDEO_SNAPSHOT:
-            id = RequestTemplate::VIDEO_SNAPSHOT;
-            break;
-        case CAMERA_TEMPLATE_ZERO_SHUTTER_LAG:
-            id = RequestTemplate::ZERO_SHUTTER_LAG;
-            break;
-        case CAMERA_TEMPLATE_MANUAL:
-            id = RequestTemplate::MANUAL;
-            break;
-        default:
-            // Unknown template ID, or this HAL is too old to support it
-            return BAD_VALUE;
-    }
-    err = mHidlSession->constructDefaultRequestSettings(id, requestCallback);
-
-    if (!err.isOk()) {
-        ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
-        res = DEAD_OBJECT;
-    } else {
-        res = HidlProviderInfo::mapToStatusT(status);
-    }
-
-    return res;
-}
-
-bool Camera3Device::HalInterface::isReconfigurationRequired(CameraMetadata& oldSessionParams,
-        CameraMetadata& newSessionParams) {
-    // We do reconfiguration by default;
-    bool ret = true;
-    if ((mHidlSession_3_5 != nullptr) && mIsReconfigurationQuerySupported) {
-        android::hardware::hidl_vec<uint8_t> oldParams, newParams;
-        camera_metadata_t* oldSessioMeta = const_cast<camera_metadata_t*>(
-                oldSessionParams.getAndLock());
-        camera_metadata_t* newSessioMeta = const_cast<camera_metadata_t*>(
-                newSessionParams.getAndLock());
-        oldParams.setToExternal(reinterpret_cast<uint8_t*>(oldSessioMeta),
-                get_camera_metadata_size(oldSessioMeta));
-        newParams.setToExternal(reinterpret_cast<uint8_t*>(newSessioMeta),
-                get_camera_metadata_size(newSessioMeta));
-        hardware::camera::common::V1_0::Status callStatus;
-        bool required;
-        auto hidlCb = [&callStatus, &required] (hardware::camera::common::V1_0::Status s,
-                bool requiredFlag) {
-            callStatus = s;
-            required = requiredFlag;
-        };
-        auto err = mHidlSession_3_5->isReconfigurationRequired(oldParams, newParams, hidlCb);
-        oldSessionParams.unlock(oldSessioMeta);
-        newSessionParams.unlock(newSessioMeta);
-        if (err.isOk()) {
-            switch (callStatus) {
-                case hardware::camera::common::V1_0::Status::OK:
-                    ret = required;
-                    break;
-                case hardware::camera::common::V1_0::Status::METHOD_NOT_SUPPORTED:
-                    mIsReconfigurationQuerySupported = false;
-                    ret = true;
-                    break;
-                default:
-                    ALOGV("%s: Reconfiguration query failed: %d", __FUNCTION__, callStatus);
-                    ret = true;
-            }
-        } else {
-            ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, err.description().c_str());
-            ret = true;
-        }
-    }
-
-    return ret;
-}
-
-status_t Camera3Device::HalInterface::configureStreams(const camera_metadata_t *sessionParams,
-        camera_stream_configuration *config, const std::vector<uint32_t>& bufferSizes) {
-    ATRACE_NAME("CameraHal::configureStreams");
-    if (!valid()) return INVALID_OPERATION;
-    status_t res = OK;
-
-    if (config->input_is_multi_resolution && mHidlSession_3_7 == nullptr) {
-        ALOGE("%s: Camera device doesn't support multi-resolution input stream", __FUNCTION__);
-        return BAD_VALUE;
-    }
-
-    // Convert stream config to HIDL
-    std::set<int> activeStreams;
-    device::V3_2::StreamConfiguration requestedConfiguration3_2;
-    device::V3_4::StreamConfiguration requestedConfiguration3_4;
-    device::V3_7::StreamConfiguration requestedConfiguration3_7;
-    device::V3_8::StreamConfiguration requestedConfiguration3_8;
-    requestedConfiguration3_2.streams.resize(config->num_streams);
-    requestedConfiguration3_4.streams.resize(config->num_streams);
-    requestedConfiguration3_7.streams.resize(config->num_streams);
-    requestedConfiguration3_8.streams.resize(config->num_streams);
-    for (size_t i = 0; i < config->num_streams; i++) {
-        device::V3_2::Stream &dst3_2 = requestedConfiguration3_2.streams[i];
-        device::V3_4::Stream &dst3_4 = requestedConfiguration3_4.streams[i];
-        device::V3_7::Stream &dst3_7 = requestedConfiguration3_7.streams[i];
-        device::V3_8::Stream &dst3_8 = requestedConfiguration3_8.streams[i];
-        camera3::camera_stream_t *src = config->streams[i];
-
-        Camera3Stream* cam3stream = Camera3Stream::cast(src);
-        cam3stream->setBufferFreedListener(this);
-        int streamId = cam3stream->getId();
-        StreamType streamType;
-        switch (src->stream_type) {
-            case CAMERA_STREAM_OUTPUT:
-                streamType = StreamType::OUTPUT;
-                break;
-            case CAMERA_STREAM_INPUT:
-                streamType = StreamType::INPUT;
-                break;
-            default:
-                ALOGE("%s: Stream %d: Unsupported stream type %d",
-                        __FUNCTION__, streamId, config->streams[i]->stream_type);
-                return BAD_VALUE;
-        }
-        dst3_2.id = streamId;
-        dst3_2.streamType = streamType;
-        dst3_2.width = src->width;
-        dst3_2.height = src->height;
-        dst3_2.usage = mapToConsumerUsage(cam3stream->getUsage());
-        dst3_2.rotation = mapToStreamRotation((camera_stream_rotation_t) src->rotation);
-        // For HidlSession version 3.5 or newer, the format and dataSpace sent
-        // to HAL are original, not the overridden ones.
-        if (mHidlSession_3_5 != nullptr) {
-            dst3_2.format = mapToPixelFormat(cam3stream->isFormatOverridden() ?
-                    cam3stream->getOriginalFormat() : src->format);
-            dst3_2.dataSpace = mapToHidlDataspace(cam3stream->isDataSpaceOverridden() ?
-                    cam3stream->getOriginalDataSpace() : src->data_space);
-        } else {
-            dst3_2.format = mapToPixelFormat(src->format);
-            dst3_2.dataSpace = mapToHidlDataspace(src->data_space);
-        }
-        dst3_4.v3_2 = dst3_2;
-        dst3_4.bufferSize = bufferSizes[i];
-        if (src->physical_camera_id != nullptr) {
-            dst3_4.physicalCameraId = src->physical_camera_id;
-        }
-        dst3_7.v3_4 = dst3_4;
-        dst3_7.groupId = cam3stream->getHalStreamGroupId();
-        dst3_7.sensorPixelModesUsed.resize(src->sensor_pixel_modes_used.size());
-        size_t j = 0;
-        for (int mode : src->sensor_pixel_modes_used) {
-            dst3_7.sensorPixelModesUsed[j++] =
-                    static_cast<CameraMetadataEnumAndroidSensorPixelMode>(mode);
-        }
-        if ((src->dynamic_range_profile !=
-                    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) &&
-                (mHidlSession_3_8 == nullptr)) {
-            ALOGE("%s: Camera device doesn't support non-standard dynamic range profiles: %d",
-                    __FUNCTION__, src->dynamic_range_profile);
-            return BAD_VALUE;
-        }
-        dst3_8.v3_7 = dst3_7;
-        dst3_8.dynamicRangeProfile = mapToHidlDynamicProfile(src->dynamic_range_profile);
-        activeStreams.insert(streamId);
-        // Create Buffer ID map if necessary
-        mBufferRecords.tryCreateBufferCache(streamId);
-    }
-    // remove BufferIdMap for deleted streams
-    mBufferRecords.removeInactiveBufferCaches(activeStreams);
-
-    StreamConfigurationMode operationMode;
-    res = mapToStreamConfigurationMode(
-            (camera_stream_configuration_mode_t) config->operation_mode,
-            /*out*/ &operationMode);
-    if (res != OK) {
-        return res;
-    }
-    requestedConfiguration3_2.operationMode = operationMode;
-    requestedConfiguration3_4.operationMode = operationMode;
-    requestedConfiguration3_7.operationMode = operationMode;
-    size_t sessionParamSize = get_camera_metadata_size(sessionParams);
-    requestedConfiguration3_4.sessionParams.setToExternal(
-            reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
-            sessionParamSize);
-    requestedConfiguration3_7.operationMode = operationMode;
-    requestedConfiguration3_7.sessionParams.setToExternal(
-            reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
-            sessionParamSize);
-    requestedConfiguration3_8.operationMode = operationMode;
-    requestedConfiguration3_8.sessionParams.setToExternal(
-            reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
-            sessionParamSize);
-
-    // Invoke configureStreams
-    device::V3_3::HalStreamConfiguration finalConfiguration;
-    device::V3_4::HalStreamConfiguration finalConfiguration3_4;
-    device::V3_6::HalStreamConfiguration finalConfiguration3_6;
-    common::V1_0::Status status;
-
-    auto configStream34Cb = [&status, &finalConfiguration3_4]
-            (common::V1_0::Status s, const device::V3_4::HalStreamConfiguration& halConfiguration) {
-                finalConfiguration3_4 = halConfiguration;
-                status = s;
-            };
-
-    auto configStream36Cb = [&status, &finalConfiguration3_6]
-            (common::V1_0::Status s, const device::V3_6::HalStreamConfiguration& halConfiguration) {
-                finalConfiguration3_6 = halConfiguration;
-                status = s;
-            };
-
-    auto postprocConfigStream34 = [&finalConfiguration, &finalConfiguration3_4]
-            (hardware::Return<void>& err) -> status_t {
-                if (!err.isOk()) {
-                    ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
-                    return DEAD_OBJECT;
-                }
-                finalConfiguration.streams.resize(finalConfiguration3_4.streams.size());
-                for (size_t i = 0; i < finalConfiguration3_4.streams.size(); i++) {
-                    finalConfiguration.streams[i] = finalConfiguration3_4.streams[i].v3_3;
-                }
-                return OK;
-            };
-
-    auto postprocConfigStream36 = [&finalConfiguration, &finalConfiguration3_6]
-            (hardware::Return<void>& err) -> status_t {
-                if (!err.isOk()) {
-                    ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
-                    return DEAD_OBJECT;
-                }
-                finalConfiguration.streams.resize(finalConfiguration3_6.streams.size());
-                for (size_t i = 0; i < finalConfiguration3_6.streams.size(); i++) {
-                    finalConfiguration.streams[i] = finalConfiguration3_6.streams[i].v3_4.v3_3;
-                }
-                return OK;
-            };
-
-    // See which version of HAL we have
-    if (mHidlSession_3_8 != nullptr) {
-        ALOGV("%s: v3.8 device found", __FUNCTION__);
-        requestedConfiguration3_8.streamConfigCounter = mNextStreamConfigCounter++;
-        requestedConfiguration3_8.multiResolutionInputImage = config->input_is_multi_resolution;
-        auto err = mHidlSession_3_8->configureStreams_3_8(requestedConfiguration3_8,
-                configStream36Cb);
-        res = postprocConfigStream36(err);
-        if (res != OK) {
-            return res;
-        }
-    } else if (mHidlSession_3_7 != nullptr) {
-        ALOGV("%s: v3.7 device found", __FUNCTION__);
-        requestedConfiguration3_7.streamConfigCounter = mNextStreamConfigCounter++;
-        requestedConfiguration3_7.multiResolutionInputImage = config->input_is_multi_resolution;
-        auto err = mHidlSession_3_7->configureStreams_3_7(
-                requestedConfiguration3_7, configStream36Cb);
-        res = postprocConfigStream36(err);
-        if (res != OK) {
-            return res;
-        }
-    } else if (mHidlSession_3_6 != nullptr) {
-        ALOGV("%s: v3.6 device found", __FUNCTION__);
-        device::V3_5::StreamConfiguration requestedConfiguration3_5;
-        requestedConfiguration3_5.v3_4 = requestedConfiguration3_4;
-        requestedConfiguration3_5.streamConfigCounter = mNextStreamConfigCounter++;
-        auto err = mHidlSession_3_6->configureStreams_3_6(
-                requestedConfiguration3_5, configStream36Cb);
-        res = postprocConfigStream36(err);
-        if (res != OK) {
-            return res;
-        }
-    } else if (mHidlSession_3_5 != nullptr) {
-        ALOGV("%s: v3.5 device found", __FUNCTION__);
-        device::V3_5::StreamConfiguration requestedConfiguration3_5;
-        requestedConfiguration3_5.v3_4 = requestedConfiguration3_4;
-        requestedConfiguration3_5.streamConfigCounter = mNextStreamConfigCounter++;
-        auto err = mHidlSession_3_5->configureStreams_3_5(
-                requestedConfiguration3_5, configStream34Cb);
-        res = postprocConfigStream34(err);
-        if (res != OK) {
-            return res;
-        }
-    } else if (mHidlSession_3_4 != nullptr) {
-        // We do; use v3.4 for the call
-        ALOGV("%s: v3.4 device found", __FUNCTION__);
-        auto err = mHidlSession_3_4->configureStreams_3_4(
-                requestedConfiguration3_4, configStream34Cb);
-        res = postprocConfigStream34(err);
-        if (res != OK) {
-            return res;
-        }
-    } else if (mHidlSession_3_3 != nullptr) {
-        // We do; use v3.3 for the call
-        ALOGV("%s: v3.3 device found", __FUNCTION__);
-        auto err = mHidlSession_3_3->configureStreams_3_3(requestedConfiguration3_2,
-            [&status, &finalConfiguration]
-            (common::V1_0::Status s, const device::V3_3::HalStreamConfiguration& halConfiguration) {
-                finalConfiguration = halConfiguration;
-                status = s;
-            });
-        if (!err.isOk()) {
-            ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
-            return DEAD_OBJECT;
-        }
-    } else {
-        // We don't; use v3.2 call and construct a v3.3 HalStreamConfiguration
-        ALOGV("%s: v3.2 device found", __FUNCTION__);
-        HalStreamConfiguration finalConfiguration_3_2;
-        auto err = mHidlSession->configureStreams(requestedConfiguration3_2,
-                [&status, &finalConfiguration_3_2]
-                (common::V1_0::Status s, const HalStreamConfiguration& halConfiguration) {
-                    finalConfiguration_3_2 = halConfiguration;
-                    status = s;
-                });
-        if (!err.isOk()) {
-            ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
-            return DEAD_OBJECT;
-        }
-        finalConfiguration.streams.resize(finalConfiguration_3_2.streams.size());
-        for (size_t i = 0; i < finalConfiguration_3_2.streams.size(); i++) {
-            finalConfiguration.streams[i].v3_2 = finalConfiguration_3_2.streams[i];
-            finalConfiguration.streams[i].overrideDataSpace =
-                    requestedConfiguration3_2.streams[i].dataSpace;
-        }
-    }
-
-    if (status != common::V1_0::Status::OK ) {
-        return HidlProviderInfo::mapToStatusT(status);
-    }
-
-    // And convert output stream configuration from HIDL
-
-    for (size_t i = 0; i < config->num_streams; i++) {
-        camera3::camera_stream_t *dst = config->streams[i];
-        int streamId = Camera3Stream::cast(dst)->getId();
-
-        // Start scan at i, with the assumption that the stream order matches
-        size_t realIdx = i;
-        bool found = false;
-        size_t halStreamCount = finalConfiguration.streams.size();
-        for (size_t idx = 0; idx < halStreamCount; idx++) {
-            if (finalConfiguration.streams[realIdx].v3_2.id == streamId) {
-                found = true;
-                break;
-            }
-            realIdx = (realIdx >= halStreamCount - 1) ? 0 : realIdx + 1;
-        }
-        if (!found) {
-            ALOGE("%s: Stream %d not found in stream configuration response from HAL",
-                    __FUNCTION__, streamId);
-            return INVALID_OPERATION;
-        }
-        device::V3_3::HalStream &src = finalConfiguration.streams[realIdx];
-        device::V3_6::HalStream &src_36 = finalConfiguration3_6.streams[realIdx];
-
-        Camera3Stream* dstStream = Camera3Stream::cast(dst);
-        int overrideFormat = mapToFrameworkFormat(src.v3_2.overrideFormat);
-        android_dataspace overrideDataSpace = mapToFrameworkDataspace(src.overrideDataSpace);
-
-        if (mHidlSession_3_6 != nullptr) {
-            dstStream->setOfflineProcessingSupport(src_36.supportOffline);
-        }
-
-        if (dstStream->getOriginalFormat() != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
-            dstStream->setFormatOverride(false);
-            dstStream->setDataSpaceOverride(false);
-            if (dst->format != overrideFormat) {
-                ALOGE("%s: Stream %d: Format override not allowed for format 0x%x", __FUNCTION__,
-                        streamId, dst->format);
-            }
-            if (dst->data_space != overrideDataSpace) {
-                ALOGE("%s: Stream %d: DataSpace override not allowed for format 0x%x", __FUNCTION__,
-                        streamId, dst->format);
-            }
-        } else {
-            bool needFormatOverride =
-                    requestedConfiguration3_2.streams[i].format != src.v3_2.overrideFormat;
-            bool needDataspaceOverride =
-                    requestedConfiguration3_2.streams[i].dataSpace != src.overrideDataSpace;
-            // Override allowed with IMPLEMENTATION_DEFINED
-            dstStream->setFormatOverride(needFormatOverride);
-            dstStream->setDataSpaceOverride(needDataspaceOverride);
-            dst->format = overrideFormat;
-            dst->data_space = overrideDataSpace;
-        }
-
-        if (dst->stream_type == CAMERA_STREAM_INPUT) {
-            if (src.v3_2.producerUsage != 0) {
-                ALOGE("%s: Stream %d: INPUT streams must have 0 for producer usage",
-                        __FUNCTION__, streamId);
-                return INVALID_OPERATION;
-            }
-            dstStream->setUsage(
-                    mapConsumerToFrameworkUsage(src.v3_2.consumerUsage));
-        } else {
-            // OUTPUT
-            if (src.v3_2.consumerUsage != 0) {
-                ALOGE("%s: Stream %d: OUTPUT streams must have 0 for consumer usage",
-                        __FUNCTION__, streamId);
-                return INVALID_OPERATION;
-            }
-            dstStream->setUsage(
-                    mapProducerToFrameworkUsage(src.v3_2.producerUsage));
-        }
-        dst->max_buffers = src.v3_2.maxBuffers;
-    }
-
-    return res;
-}
-
-status_t Camera3Device::HalInterface::configureInjectedStreams(
-        const camera_metadata_t* sessionParams, camera_stream_configuration* config,
-        const std::vector<uint32_t>& bufferSizes,
-        const CameraMetadata& cameraCharacteristics) {
-    ATRACE_NAME("InjectionCameraHal::configureStreams");
-    if (!valid()) return INVALID_OPERATION;
-    status_t res = OK;
-
-    if (config->input_is_multi_resolution) {
-        ALOGE("%s: Injection camera device doesn't support multi-resolution input "
-                "stream", __FUNCTION__);
-        return BAD_VALUE;
-    }
-
-    // Convert stream config to HIDL
-    std::set<int> activeStreams;
-    device::V3_2::StreamConfiguration requestedConfiguration3_2;
-    device::V3_4::StreamConfiguration requestedConfiguration3_4;
-    device::V3_7::StreamConfiguration requestedConfiguration3_7;
-    requestedConfiguration3_2.streams.resize(config->num_streams);
-    requestedConfiguration3_4.streams.resize(config->num_streams);
-    requestedConfiguration3_7.streams.resize(config->num_streams);
-    for (size_t i = 0; i < config->num_streams; i++) {
-        device::V3_2::Stream& dst3_2 = requestedConfiguration3_2.streams[i];
-        device::V3_4::Stream& dst3_4 = requestedConfiguration3_4.streams[i];
-        device::V3_7::Stream& dst3_7 = requestedConfiguration3_7.streams[i];
-        camera3::camera_stream_t* src = config->streams[i];
-
-        Camera3Stream* cam3stream = Camera3Stream::cast(src);
-        cam3stream->setBufferFreedListener(this);
-        int streamId = cam3stream->getId();
-        StreamType streamType;
-        switch (src->stream_type) {
-            case CAMERA_STREAM_OUTPUT:
-                streamType = StreamType::OUTPUT;
-                break;
-            case CAMERA_STREAM_INPUT:
-                streamType = StreamType::INPUT;
-                break;
-            default:
-                ALOGE("%s: Stream %d: Unsupported stream type %d", __FUNCTION__,
-                        streamId, config->streams[i]->stream_type);
-            return BAD_VALUE;
-        }
-        dst3_2.id = streamId;
-        dst3_2.streamType = streamType;
-        dst3_2.width = src->width;
-        dst3_2.height = src->height;
-        dst3_2.usage = mapToConsumerUsage(cam3stream->getUsage());
-        dst3_2.rotation =
-                mapToStreamRotation((camera_stream_rotation_t)src->rotation);
-        // For HidlSession version 3.5 or newer, the format and dataSpace sent
-        // to HAL are original, not the overridden ones.
-        if (mHidlSession_3_5 != nullptr) {
-            dst3_2.format = mapToPixelFormat(cam3stream->isFormatOverridden()
-                                            ? cam3stream->getOriginalFormat()
-                                            : src->format);
-            dst3_2.dataSpace =
-                    mapToHidlDataspace(cam3stream->isDataSpaceOverridden()
-                                    ? cam3stream->getOriginalDataSpace()
-                                    : src->data_space);
-        } else {
-            dst3_2.format = mapToPixelFormat(src->format);
-            dst3_2.dataSpace = mapToHidlDataspace(src->data_space);
-        }
-        dst3_4.v3_2 = dst3_2;
-        dst3_4.bufferSize = bufferSizes[i];
-        if (src->physical_camera_id != nullptr) {
-            dst3_4.physicalCameraId = src->physical_camera_id;
-        }
-        dst3_7.v3_4 = dst3_4;
-        dst3_7.groupId = cam3stream->getHalStreamGroupId();
-        dst3_7.sensorPixelModesUsed.resize(src->sensor_pixel_modes_used.size());
-        size_t j = 0;
-        for (int mode : src->sensor_pixel_modes_used) {
-            dst3_7.sensorPixelModesUsed[j++] =
-                    static_cast<CameraMetadataEnumAndroidSensorPixelMode>(mode);
-        }
-        activeStreams.insert(streamId);
-        // Create Buffer ID map if necessary
-        mBufferRecords.tryCreateBufferCache(streamId);
-    }
-    // remove BufferIdMap for deleted streams
-    mBufferRecords.removeInactiveBufferCaches(activeStreams);
-
-    StreamConfigurationMode operationMode;
-    res = mapToStreamConfigurationMode(
-            (camera_stream_configuration_mode_t)config->operation_mode,
-            /*out*/ &operationMode);
-    if (res != OK) {
-        return res;
-    }
-    requestedConfiguration3_7.operationMode = operationMode;
-    size_t sessionParamSize = get_camera_metadata_size(sessionParams);
-    requestedConfiguration3_7.operationMode = operationMode;
-    requestedConfiguration3_7.sessionParams.setToExternal(
-            reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
-            sessionParamSize);
-
-    // See which version of HAL we have
-    if (mHidlSession_3_7 != nullptr) {
-        requestedConfiguration3_7.streamConfigCounter = mNextStreamConfigCounter++;
-        requestedConfiguration3_7.multiResolutionInputImage =
-                config->input_is_multi_resolution;
-
-        const camera_metadata_t* rawMetadata = cameraCharacteristics.getAndLock();
-        ::android::hardware::camera::device::V3_2::CameraMetadata hidlChars = {};
-        hidlChars.setToExternal(
-                reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(rawMetadata)),
-                get_camera_metadata_size(rawMetadata));
-        cameraCharacteristics.unlock(rawMetadata);
-
-        sp<hardware::camera::device::V3_7::ICameraInjectionSession>
-                hidlInjectionSession_3_7;
-        auto castInjectionResult_3_7 =
-                device::V3_7::ICameraInjectionSession::castFrom(mHidlSession_3_7);
-        if (castInjectionResult_3_7.isOk()) {
-            hidlInjectionSession_3_7 = castInjectionResult_3_7;
-        } else {
-            ALOGE("%s: Transaction error: %s", __FUNCTION__,
-                    castInjectionResult_3_7.description().c_str());
-            return DEAD_OBJECT;
-        }
-
-        auto err = hidlInjectionSession_3_7->configureInjectionStreams(
-                requestedConfiguration3_7, hidlChars);
-        if (!err.isOk()) {
-            ALOGE("%s: Transaction error: %s", __FUNCTION__,
-                    err.description().c_str());
-            return DEAD_OBJECT;
-        }
-    } else {
-        ALOGE("%s: mHidlSession_3_7 does not exist, the lowest version of injection "
-                "session is 3.7", __FUNCTION__);
-        return DEAD_OBJECT;
-    }
-
-    return res;
-}
-
-status_t Camera3Device::HalInterface::wrapAsHidlRequest(camera_capture_request_t* request,
-        /*out*/device::V3_2::CaptureRequest* captureRequest,
-        /*out*/std::vector<native_handle_t*>* handlesCreated,
-        /*out*/std::vector<std::pair<int32_t, int32_t>>* inflightBuffers) {
-    ATRACE_CALL();
-    if (captureRequest == nullptr || handlesCreated == nullptr || inflightBuffers == nullptr) {
-        ALOGE("%s: captureRequest (%p), handlesCreated (%p), and inflightBuffers(%p) "
-                "must not be null", __FUNCTION__, captureRequest, handlesCreated, inflightBuffers);
-        return BAD_VALUE;
-    }
-
-    captureRequest->frameNumber = request->frame_number;
-
-    captureRequest->fmqSettingsSize = 0;
-
-    {
-        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;
-
-            mBufferRecords.pushInflightBuffer(captureRequest->frameNumber, streamId,
-                    request->input_buffer->buffer);
-            inflightBuffers->push_back(std::make_pair(captureRequest->frameNumber, streamId));
-        } 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 camera_stream_buffer_t *src = request->output_buffers + i;
-            StreamBuffer &dst = captureRequest->outputBuffers[i];
-            int32_t streamId = Camera3Stream::cast(src->stream)->getId();
-            if (src->buffer != nullptr) {
-                buffer_handle_t buf = *(src->buffer);
-                auto pair = getBufferId(buf, streamId);
-                bool isNewBuffer = pair.first;
-                dst.bufferId = pair.second;
-                dst.buffer = isNewBuffer ? buf : nullptr;
-                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;
-            } else if (mUseHalBufManager) {
-                // HAL buffer management path
-                dst.bufferId = BUFFER_ID_NO_BUFFER;
-                dst.buffer = nullptr;
-                dst.acquireFence = nullptr;
-            } else {
-                ALOGE("%s: cannot send a null buffer in capture request!", __FUNCTION__);
-                return BAD_VALUE;
-            }
-            dst.streamId = streamId;
-            dst.status = BufferStatus::OK;
-            dst.releaseFence = nullptr;
-
-            // Output buffers are empty when using HAL buffer manager
-            if (!mUseHalBufManager) {
-                mBufferRecords.pushInflightBuffer(
-                        captureRequest->frameNumber, streamId, src->buffer);
-                inflightBuffers->push_back(std::make_pair(captureRequest->frameNumber, streamId));
-            }
-        }
-    }
-    return OK;
-}
-
 void Camera3Device::HalInterface::cleanupNativeHandles(
         std::vector<native_handle_t*> *handles, bool closeFd) {
     if (handles == nullptr) {
@@ -3887,314 +2746,6 @@
     return;
 }
 
-status_t Camera3Device::HalInterface::processBatchCaptureRequests(
-        std::vector<camera_capture_request_t*>& requests,/*out*/uint32_t* numRequestProcessed) {
-    ATRACE_NAME("CameraHal::processBatchCaptureRequests");
-    if (!valid()) return INVALID_OPERATION;
-
-    sp<device::V3_4::ICameraDeviceSession> hidlSession_3_4;
-    sp<device::V3_7::ICameraDeviceSession> hidlSession_3_7;
-    auto castResult_3_7 = device::V3_7::ICameraDeviceSession::castFrom(mHidlSession);
-    if (castResult_3_7.isOk()) {
-        hidlSession_3_7 = castResult_3_7;
-    }
-    auto castResult_3_4 = device::V3_4::ICameraDeviceSession::castFrom(mHidlSession);
-    if (castResult_3_4.isOk()) {
-        hidlSession_3_4 = castResult_3_4;
-    }
-
-    hardware::hidl_vec<device::V3_2::CaptureRequest> captureRequests;
-    hardware::hidl_vec<device::V3_4::CaptureRequest> captureRequests_3_4;
-    hardware::hidl_vec<device::V3_7::CaptureRequest> captureRequests_3_7;
-    size_t batchSize = requests.size();
-    if (hidlSession_3_7 != nullptr) {
-        captureRequests_3_7.resize(batchSize);
-    } else if (hidlSession_3_4 != nullptr) {
-        captureRequests_3_4.resize(batchSize);
-    } else {
-        captureRequests.resize(batchSize);
-    }
-    std::vector<native_handle_t*> handlesCreated;
-    std::vector<std::pair<int32_t, int32_t>> inflightBuffers;
-
-    status_t res = OK;
-    for (size_t i = 0; i < batchSize; i++) {
-        if (hidlSession_3_7 != nullptr) {
-            res = wrapAsHidlRequest(requests[i], /*out*/&captureRequests_3_7[i].v3_4.v3_2,
-                    /*out*/&handlesCreated, /*out*/&inflightBuffers);
-        } else if (hidlSession_3_4 != nullptr) {
-            res = wrapAsHidlRequest(requests[i], /*out*/&captureRequests_3_4[i].v3_2,
-                    /*out*/&handlesCreated, /*out*/&inflightBuffers);
-        } else {
-            res = wrapAsHidlRequest(requests[i], /*out*/&captureRequests[i],
-                    /*out*/&handlesCreated, /*out*/&inflightBuffers);
-        }
-        if (res != OK) {
-            mBufferRecords.popInflightBuffers(inflightBuffers);
-            cleanupNativeHandles(&handlesCreated);
-            return res;
-        }
-    }
-
-    std::vector<device::V3_2::BufferCache> cachesToRemove;
-    {
-        std::lock_guard<std::mutex> lock(mFreedBuffersLock);
-        for (auto& pair : mFreedBuffers) {
-            // The stream might have been removed since onBufferFreed
-            if (mBufferRecords.isStreamCached(pair.first)) {
-                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++) {
-        camera_capture_request_t* request = requests[i];
-        device::V3_2::CaptureRequest* captureRequest;
-        if (hidlSession_3_7 != nullptr) {
-            captureRequest = &captureRequests_3_7[i].v3_4.v3_2;
-        } else if (hidlSession_3_4 != nullptr) {
-            captureRequest = &captureRequests_3_4[i].v3_2;
-        } else {
-            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;
-        }
-
-        // hidl session 3.7 specific handling.
-        if (hidlSession_3_7 != nullptr) {
-            captureRequests_3_7[i].inputWidth = request->input_width;
-            captureRequests_3_7[i].inputHeight = request->input_height;
-        }
-
-        // hidl session 3.7 and 3.4 specific handling.
-        if (hidlSession_3_7 != nullptr || hidlSession_3_4 != nullptr) {
-            hardware::hidl_vec<device::V3_4::PhysicalCameraSetting>& physicalCameraSettings =
-                    (hidlSession_3_7 != nullptr) ?
-                    captureRequests_3_7[i].v3_4.physicalCameraSettings :
-                    captureRequests_3_4[i].physicalCameraSettings;
-            physicalCameraSettings.resize(request->num_physcam_settings);
-            for (size_t j = 0; j < request->num_physcam_settings; j++) {
-                if (request->physcam_settings != nullptr) {
-                    size_t settingsSize = get_camera_metadata_size(request->physcam_settings[j]);
-                    if (mRequestMetadataQueue != nullptr && mRequestMetadataQueue->write(
-                                reinterpret_cast<const uint8_t*>(request->physcam_settings[j]),
-                                settingsSize)) {
-                        physicalCameraSettings[j].settings.resize(0);
-                        physicalCameraSettings[j].fmqSettingsSize = settingsSize;
-                    } else {
-                        if (mRequestMetadataQueue != nullptr) {
-                            ALOGW("%s: couldn't utilize fmq, fallback to hwbinder", __FUNCTION__);
-                        }
-                        physicalCameraSettings[j].settings.setToExternal(
-                                reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(
-                                        request->physcam_settings[j])),
-                                get_camera_metadata_size(request->physcam_settings[j]));
-                        physicalCameraSettings[j].fmqSettingsSize = 0u;
-                    }
-                } else {
-                    physicalCameraSettings[j].fmqSettingsSize = 0u;
-                    physicalCameraSettings[j].settings.resize(0);
-                }
-                physicalCameraSettings[j].physicalCameraId = request->physcam_id[j];
-            }
-        }
-    }
-
-    hardware::details::return_status err;
-    auto resultCallback =
-        [&status, &numRequestProcessed] (auto s, uint32_t n) {
-                status = s;
-                *numRequestProcessed = n;
-        };
-    if (hidlSession_3_7 != nullptr) {
-        err = hidlSession_3_7->processCaptureRequest_3_7(captureRequests_3_7, cachesToRemove,
-                                                         resultCallback);
-    } else if (hidlSession_3_4 != nullptr) {
-        err = hidlSession_3_4->processCaptureRequest_3_4(captureRequests_3_4, cachesToRemove,
-                                                         resultCallback);
-    } else {
-        err = mHidlSession->processCaptureRequest(captureRequests, cachesToRemove,
-                                                  resultCallback);
-    }
-    if (!err.isOk()) {
-        ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
-        status = common::V1_0::Status::CAMERA_DISCONNECTED;
-    }
-
-    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;
-    }
-
-    res = HidlProviderInfo::mapToStatusT(status);
-    if (res == OK) {
-        if (mHidlSession->isRemote()) {
-            // Only close acquire fence FDs when the HIDL transaction succeeds (so the FDs have been
-            // sent to camera HAL processes)
-            cleanupNativeHandles(&handlesCreated, /*closeFd*/true);
-        } else {
-            // In passthrough mode the FDs are now owned by HAL
-            cleanupNativeHandles(&handlesCreated);
-        }
-    } else {
-        mBufferRecords.popInflightBuffers(inflightBuffers);
-        cleanupNativeHandles(&handlesCreated);
-    }
-    return res;
-}
-
-status_t Camera3Device::HalInterface::flush() {
-    ATRACE_NAME("CameraHal::flush");
-    if (!valid()) return INVALID_OPERATION;
-    status_t res = OK;
-
-    auto err = mHidlSession->flush();
-    if (!err.isOk()) {
-        ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
-        res = DEAD_OBJECT;
-    } else {
-        res = HidlProviderInfo::mapToStatusT(err);
-    }
-
-    return res;
-}
-
-status_t Camera3Device::HalInterface::dump(int /*fd*/) {
-    ATRACE_NAME("CameraHal::dump");
-    if (!valid()) return INVALID_OPERATION;
-
-    // Handled by CameraProviderManager::dump
-
-    return OK;
-}
-
-status_t Camera3Device::HalInterface::repeatingRequestEnd(uint32_t frameNumber,
-        hardware::hidl_vec<int32_t> streamIds) {
-    ATRACE_NAME("CameraHal::repeatingRequestEnd");
-    if (!valid()) return INVALID_OPERATION;
-
-    if (mHidlSession_3_8.get() != nullptr) {
-        mHidlSession_3_8->repeatingRequestEnd(frameNumber, streamIds);
-    }
-
-    return OK;
-}
-
-status_t Camera3Device::HalInterface::close() {
-    ATRACE_NAME("CameraHal::close()");
-    if (!valid()) return INVALID_OPERATION;
-    status_t res = OK;
-
-    auto err = mHidlSession->close();
-    // Interface will be dead shortly anyway, so don't log errors
-    if (!err.isOk()) {
-        res = DEAD_OBJECT;
-    }
-
-    return res;
-}
-
-void Camera3Device::HalInterface::signalPipelineDrain(const std::vector<int>& streamIds) {
-    ATRACE_NAME("CameraHal::signalPipelineDrain");
-    if (!valid() || mHidlSession_3_5 == nullptr) {
-        ALOGE("%s called on invalid camera!", __FUNCTION__);
-        return;
-    }
-
-    auto err = mHidlSession_3_5->signalStreamFlush(streamIds, mNextStreamConfigCounter - 1);
-    if (!err.isOk()) {
-        ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
-        return;
-    }
-}
-
-status_t Camera3Device::HalInterface::switchToOffline(
-        const std::vector<int32_t>& streamsToKeep,
-        /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
-        /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
-        /*out*/camera3::BufferRecords* bufferRecords) {
-    ATRACE_NAME("CameraHal::switchToOffline");
-    if (!valid() || mHidlSession_3_6 == nullptr) {
-        ALOGE("%s called on invalid camera!", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
-
-    if (offlineSessionInfo == nullptr || offlineSession == nullptr || bufferRecords == nullptr) {
-        ALOGE("%s: output arguments must not be null!", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
-
-    common::V1_0::Status status = common::V1_0::Status::INTERNAL_ERROR;
-    auto resultCallback =
-        [&status, &offlineSessionInfo, &offlineSession] (auto s, auto info, auto session) {
-                status = s;
-                *offlineSessionInfo = info;
-                *offlineSession = session;
-        };
-    auto err = mHidlSession_3_6->switchToOffline(streamsToKeep, resultCallback);
-
-    if (!err.isOk()) {
-        ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
-        return DEAD_OBJECT;
-    }
-
-    status_t ret = HidlProviderInfo::mapToStatusT(status);
-    if (ret != OK) {
-        return ret;
-    }
-
-    // TODO: assert no ongoing requestBuffer/returnBuffer call here
-    // TODO: update RequestBufferStateMachine to block requestBuffer/returnBuffer once HAL
-    //       returns from switchToOffline.
-
-
-    // Validate buffer caches
-    std::vector<int32_t> streams;
-    streams.reserve(offlineSessionInfo->offlineStreams.size());
-    for (auto offlineStream : offlineSessionInfo->offlineStreams) {
-        int32_t id = offlineStream.id;
-        streams.push_back(id);
-        // Verify buffer caches
-        std::vector<uint64_t> bufIds(offlineStream.circulatingBufferIds.begin(),
-                offlineStream.circulatingBufferIds.end());
-        if (!verifyBufferIds(id, bufIds)) {
-            ALOGE("%s: stream ID %d buffer cache records mismatch!", __FUNCTION__, id);
-            return UNKNOWN_ERROR;
-        }
-    }
-
-    // Move buffer records
-    bufferRecords->takeBufferCaches(mBufferRecords, streams);
-    bufferRecords->takeInflightBufferMap(mBufferRecords);
-    bufferRecords->takeRequestedBufferMap(mBufferRecords);
-    return ret;
-}
-
 void Camera3Device::HalInterface::getInflightBufferKeys(
         std::vector<std::pair<int32_t, int32_t>>* out) {
     mBufferRecords.getInflightBufferKeys(out);
@@ -5417,38 +3968,6 @@
     mPrevRequest.clear();
 }
 
-status_t Camera3Device::RequestThread::switchToOffline(
-        const std::vector<int32_t>& streamsToKeep,
-        /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
-        /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
-        /*out*/camera3::BufferRecords* bufferRecords) {
-    Mutex::Autolock l(mRequestLock);
-    clearRepeatingRequestsLocked(/*lastFrameNumber*/nullptr);
-
-    // Wait until request thread is fully stopped
-    // TBD: check if request thread is being paused by other APIs (shouldn't be)
-
-    // We could also check for mRepeatingRequests.empty(), but the API interface
-    // is serialized by Camera3Device::mInterfaceLock so no one should be able to submit any
-    // new requests during the call; hence skip that check.
-    bool queueEmpty = mNextRequests.empty() && mRequestQueue.empty();
-    while (!queueEmpty) {
-        status_t res = mRequestSubmittedSignal.waitRelative(mRequestLock, kRequestSubmitTimeout);
-        if (res == TIMED_OUT) {
-            ALOGE("%s: request thread failed to submit one request within timeout!", __FUNCTION__);
-            return res;
-        } else if (res != OK) {
-            ALOGE("%s: request thread failed to submit a request: %s (%d)!",
-                    __FUNCTION__, strerror(-res), res);
-            return res;
-        }
-        queueEmpty = mNextRequests.empty() && mRequestQueue.empty();
-    }
-
-    return mInterface->switchToOffline(
-            streamsToKeep, offlineSessionInfo, offlineSession, bufferRecords);
-}
-
 status_t Camera3Device::RequestThread::setRotateAndCropAutoBehavior(
         camera_metadata_enum_android_scaler_rotate_and_crop_t rotateAndCropValue) {
     ATRACE_CALL();
@@ -6479,220 +4998,6 @@
     return ret;
 }
 
-status_t Camera3Device::switchToOffline(
-        const std::vector<int32_t>& streamsToKeep,
-        /*out*/ sp<CameraOfflineSessionBase>* session) {
-    ATRACE_CALL();
-    if (session == nullptr) {
-        ALOGE("%s: session must not be null", __FUNCTION__);
-        return BAD_VALUE;
-    }
-
-    Mutex::Autolock il(mInterfaceLock);
-
-    bool hasInputStream = mInputStream != nullptr;
-    int32_t inputStreamId = hasInputStream ? mInputStream->getId() : -1;
-    bool inputStreamSupportsOffline = hasInputStream ?
-            mInputStream->getOfflineProcessingSupport() : false;
-    auto outputStreamIds = mOutputStreams.getStreamIds();
-    auto streamIds = outputStreamIds;
-    if (hasInputStream) {
-        streamIds.push_back(mInputStream->getId());
-    }
-
-    // Check all streams in streamsToKeep supports offline mode
-    for (auto id : streamsToKeep) {
-        if (std::find(streamIds.begin(), streamIds.end(), id) == streamIds.end()) {
-            ALOGE("%s: Unknown stream ID %d", __FUNCTION__, id);
-            return BAD_VALUE;
-        } else if (id == inputStreamId) {
-            if (!inputStreamSupportsOffline) {
-                ALOGE("%s: input stream %d cannot be switched to offline",
-                        __FUNCTION__, id);
-                return BAD_VALUE;
-            }
-        } else {
-            sp<camera3::Camera3OutputStreamInterface> stream = mOutputStreams.get(id);
-            if (!stream->getOfflineProcessingSupport()) {
-                ALOGE("%s: output stream %d cannot be switched to offline",
-                        __FUNCTION__, id);
-                return BAD_VALUE;
-            }
-        }
-    }
-
-    // TODO: block surface sharing and surface group streams until we can support them
-
-    // Stop repeating request, wait until all remaining requests are submitted, then call into
-    // HAL switchToOffline
-    hardware::camera::device::V3_6::CameraOfflineSessionInfo offlineSessionInfo;
-    sp<hardware::camera::device::V3_6::ICameraOfflineSession> offlineSession;
-    camera3::BufferRecords bufferRecords;
-    status_t ret = mRequestThread->switchToOffline(
-            streamsToKeep, &offlineSessionInfo, &offlineSession, &bufferRecords);
-
-    if (ret != OK) {
-        SET_ERR("Switch to offline failed: %s (%d)", strerror(-ret), ret);
-        return ret;
-    }
-
-    bool succ = mRequestBufferSM.onSwitchToOfflineSuccess();
-    if (!succ) {
-        SET_ERR("HAL must not be calling requestStreamBuffers call");
-        // TODO: block ALL callbacks from HAL till app configured new streams?
-        return UNKNOWN_ERROR;
-    }
-
-    // Verify offlineSessionInfo
-    std::vector<int32_t> offlineStreamIds;
-    offlineStreamIds.reserve(offlineSessionInfo.offlineStreams.size());
-    for (auto offlineStream : offlineSessionInfo.offlineStreams) {
-        // verify stream IDs
-        int32_t id = offlineStream.id;
-        if (std::find(streamIds.begin(), streamIds.end(), id) == streamIds.end()) {
-            SET_ERR("stream ID %d not found!", id);
-            return UNKNOWN_ERROR;
-        }
-
-        // When not using HAL buf manager, only allow streams requested by app to be preserved
-        if (!mUseHalBufManager) {
-            if (std::find(streamsToKeep.begin(), streamsToKeep.end(), id) == streamsToKeep.end()) {
-                SET_ERR("stream ID %d must not be switched to offline!", id);
-                return UNKNOWN_ERROR;
-            }
-        }
-
-        offlineStreamIds.push_back(id);
-        sp<Camera3StreamInterface> stream = (id == inputStreamId) ?
-                static_cast<sp<Camera3StreamInterface>>(mInputStream) :
-                static_cast<sp<Camera3StreamInterface>>(mOutputStreams.get(id));
-        // Verify number of outstanding buffers
-        if (stream->getOutstandingBuffersCount() != offlineStream.numOutstandingBuffers) {
-            SET_ERR("Offline stream %d # of remaining buffer mismatch: (%zu,%d) (service/HAL)",
-                    id, stream->getOutstandingBuffersCount(), offlineStream.numOutstandingBuffers);
-            return UNKNOWN_ERROR;
-        }
-    }
-
-    // Verify all streams to be deleted don't have any outstanding buffers
-    if (hasInputStream && std::find(offlineStreamIds.begin(), offlineStreamIds.end(),
-                inputStreamId) == offlineStreamIds.end()) {
-        if (mInputStream->hasOutstandingBuffers()) {
-            SET_ERR("Input stream %d still has %zu outstanding buffer!",
-                    inputStreamId, mInputStream->getOutstandingBuffersCount());
-            return UNKNOWN_ERROR;
-        }
-    }
-
-    for (const auto& outStreamId : outputStreamIds) {
-        if (std::find(offlineStreamIds.begin(), offlineStreamIds.end(),
-                outStreamId) == offlineStreamIds.end()) {
-            auto outStream = mOutputStreams.get(outStreamId);
-            if (outStream->hasOutstandingBuffers()) {
-                SET_ERR("Output stream %d still has %zu outstanding buffer!",
-                        outStreamId, outStream->getOutstandingBuffersCount());
-                return UNKNOWN_ERROR;
-            }
-        }
-    }
-
-    InFlightRequestMap offlineReqs;
-    // Verify inflight requests and their pending buffers
-    {
-        std::lock_guard<std::mutex> l(mInFlightLock);
-        for (auto offlineReq : offlineSessionInfo.offlineRequests) {
-            int idx = mInFlightMap.indexOfKey(offlineReq.frameNumber);
-            if (idx == NAME_NOT_FOUND) {
-                SET_ERR("Offline request frame number %d not found!", offlineReq.frameNumber);
-                return UNKNOWN_ERROR;
-            }
-
-            const auto& inflightReq = mInFlightMap.valueAt(idx);
-            // TODO: check specific stream IDs
-            size_t numBuffersLeft = static_cast<size_t>(inflightReq.numBuffersLeft);
-            if (numBuffersLeft != offlineReq.pendingStreams.size()) {
-                SET_ERR("Offline request # of remaining buffer mismatch: (%d,%d) (service/HAL)",
-                        inflightReq.numBuffersLeft, offlineReq.pendingStreams.size());
-                return UNKNOWN_ERROR;
-            }
-            offlineReqs.add(offlineReq.frameNumber, inflightReq);
-        }
-    }
-
-    // Create Camera3OfflineSession and transfer object ownership
-    //   (streams, inflight requests, buffer caches)
-    camera3::StreamSet offlineStreamSet;
-    sp<camera3::Camera3Stream> inputStream;
-    for (auto offlineStream : offlineSessionInfo.offlineStreams) {
-        int32_t id = offlineStream.id;
-        if (mInputStream != nullptr && id == mInputStream->getId()) {
-            inputStream = mInputStream;
-        } else {
-            offlineStreamSet.add(id, mOutputStreams.get(id));
-        }
-    }
-
-    // TODO: check if we need to lock before copying states
-    //       though technically no other thread should be talking to Camera3Device at this point
-    Camera3OfflineStates offlineStates(
-            mTagMonitor, mVendorTagId, mUseHalBufManager, mNeedFixupMonochromeTags,
-            mUsePartialResult, mNumPartialResults, mLastCompletedRegularFrameNumber,
-            mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
-            mNextResultFrameNumber, mNextReprocessResultFrameNumber,
-            mNextZslStillResultFrameNumber, mNextShutterFrameNumber,
-            mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
-            mDeviceInfo, mPhysicalDeviceInfoMap, mDistortionMappers,
-            mZoomRatioMappers, mRotateAndCropMappers);
-
-    *session = new Camera3OfflineSession(mId, inputStream, offlineStreamSet,
-            std::move(bufferRecords), offlineReqs, offlineStates, offlineSession);
-
-    // Delete all streams that has been transferred to offline session
-    Mutex::Autolock l(mLock);
-    for (auto offlineStream : offlineSessionInfo.offlineStreams) {
-        int32_t id = offlineStream.id;
-        if (mInputStream != nullptr && id == mInputStream->getId()) {
-            mInputStream.clear();
-        } else {
-            mOutputStreams.remove(id);
-        }
-    }
-
-    // disconnect all other streams and switch to UNCONFIGURED state
-    if (mInputStream != nullptr) {
-        ret = mInputStream->disconnect();
-        if (ret != OK) {
-            SET_ERR_L("disconnect input stream failed!");
-            return UNKNOWN_ERROR;
-        }
-    }
-
-    for (auto streamId : mOutputStreams.getStreamIds()) {
-        sp<Camera3StreamInterface> stream = mOutputStreams.get(streamId);
-        ret = stream->disconnect();
-        if (ret != OK) {
-            SET_ERR_L("disconnect output stream %d failed!", streamId);
-            return UNKNOWN_ERROR;
-        }
-    }
-
-    mInputStream.clear();
-    mOutputStreams.clear();
-    mNeedConfig = true;
-    internalUpdateStatusLocked(STATUS_UNCONFIGURED);
-    mOperatingMode = NO_MODE;
-    mIsConstrainedHighSpeedConfiguration = false;
-    mRequestThread->clearPreviousRequest();
-
-    return OK;
-    // TO be done by CameraDeviceClient/Camera3OfflineSession
-    // register the offline client to camera service
-    // Setup result passthing threads etc
-    // Initialize offline session so HAL can start sending callback to it (result Fmq)
-    // TODO: check how many onIdle callback will be sent
-    // Java side to make sure the CameraCaptureSession is properly closed
-}
-
 void Camera3Device::getOfflineStreamIds(std::vector<int> *offlineStreamIds) {
     ATRACE_CALL();
 
@@ -6779,7 +5084,7 @@
         }
     }
 
-    res = mInjectionMethods->injectionInitialize(injectedCamId, manager, this);
+    res = injectionCameraInitialize(injectedCamId, manager);
     if (res != OK) {
         ALOGE("%s: Failed to initialize the injection camera! ret != NO_ERROR: %d",
                 __FUNCTION__, res);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 3ce17f9..6c4ba49 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -29,20 +29,6 @@
 #include <utils/KeyedVector.h>
 #include <utils/Timers.h>
 
-#include <android/hardware/camera/device/3.2/ICameraDevice.h>
-#include <android/hardware/camera/device/3.2/ICameraDeviceSession.h>
-#include <android/hardware/camera/device/3.3/ICameraDeviceSession.h>
-#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
-#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
-#include <android/hardware/camera/device/3.6/ICameraDeviceSession.h>
-#include <android/hardware/camera/device/3.7/ICameraDeviceSession.h>
-#include <android/hardware/camera/device/3.8/ICameraDeviceSession.h>
-#include <android/hardware/camera/device/3.2/ICameraDeviceCallback.h>
-#include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
-#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
-#include <android/hardware/camera/device/3.8/ICameraDeviceCallback.h>
-#include <fmq/MessageQueue.h>
-
 #include <camera/CaptureResult.h>
 
 #include "android/hardware/camera/metadata/3.8/types.h"
@@ -59,6 +45,7 @@
 #include "device3/Camera3OfflineSession.h"
 #include "device3/Camera3StreamInterface.h"
 #include "utils/TagMonitor.h"
+#include "utils/IPCTransport.h"
 #include "utils/LatencyHistogram.h"
 #include <camera_metadata_hidden.h>
 
@@ -70,7 +57,6 @@
 using android::camera3::camera_stream_configuration_mode_t;
 using android::camera3::CAMERA_TEMPLATE_COUNT;
 using android::camera3::OutputStreamInfo;
-using android::hardware::camera::metadata::V3_8::CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap;
 
 namespace android {
 
@@ -87,11 +73,11 @@
  */
 class Camera3Device :
             public CameraDeviceBase,
-            virtual public hardware::camera::device::V3_8::ICameraDeviceCallback,
             public camera3::SetErrorInterface,
             public camera3::InflightRequestUpdateInterface,
             public camera3::RequestBufferInterface,
             public camera3::FlushBufferInterface {
+  friend class HidlCamera3Device;
   public:
 
     explicit Camera3Device(const String8& id, bool overrideForPerfClass, bool legacyClient = false);
@@ -107,7 +93,9 @@
     metadata_vendor_id_t getVendorTagId() const override { return mVendorTagId; }
 
     // Transitions to idle state on success.
-    status_t initialize(sp<CameraProviderManager> manager, const String8& monitorTags) override;
+    virtual status_t initialize(sp<CameraProviderManager> /*manager*/,
+            const String8& /*monitorTags*/) = 0;
+
     status_t disconnect() override;
     status_t dump(int fd, const Vector<String16> &args) override;
     status_t startWatchingTags(const String8 &tags) override;
@@ -236,8 +224,10 @@
 
     nsecs_t getExpectedInFlightDuration() override;
 
-    status_t switchToOffline(const std::vector<int32_t>& streamsToKeep,
-            /*out*/ sp<CameraOfflineSessionBase>* session) override;
+    virtual status_t switchToOffline(const std::vector<int32_t>& ,
+            /*out*/ sp<CameraOfflineSessionBase>* )  override {
+      return INVALID_OPERATION;
+    };
 
     // RequestBufferInterface
     bool startRequestBuffer() override;
@@ -288,35 +278,10 @@
      */
     status_t stopInjection();
 
-    /**
-     * Helper functions to map between framework and HIDL values
-     */
-    static hardware::graphics::common::V1_0::PixelFormat mapToPixelFormat(int frameworkFormat);
-    static hardware::camera::device::V3_2::DataspaceFlags mapToHidlDataspace(
-            android_dataspace dataSpace);
-    static CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap mapToHidlDynamicProfile(
-            int dynamicRangeProfile);
-    static hardware::camera::device::V3_2::BufferUsageFlags mapToConsumerUsage(uint64_t usage);
-    static hardware::camera::device::V3_2::StreamRotation mapToStreamRotation(
-            camera_stream_rotation_t rotation);
-    // Returns a negative error code if the passed-in operation mode is not valid.
-    static status_t mapToStreamConfigurationMode(camera_stream_configuration_mode_t operationMode,
-            /*out*/ hardware::camera::device::V3_2::StreamConfigurationMode *mode);
-    static int mapToFrameworkFormat(hardware::graphics::common::V1_0::PixelFormat pixelFormat);
-    static android_dataspace mapToFrameworkDataspace(
-            hardware::camera::device::V3_2::DataspaceFlags);
-    static uint64_t mapConsumerToFrameworkUsage(
-            hardware::camera::device::V3_2::BufferUsageFlags usage);
-    static uint64_t mapProducerToFrameworkUsage(
-            hardware::camera::device::V3_2::BufferUsageFlags usage);
-
-  private:
+  protected:
     status_t disconnectImpl();
     static status_t removeFwkOnlyRegionKeys(CameraMetadata *request);
 
-    // internal typedefs
-    using RequestMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
-
     static const size_t        kDumpLockAttempts  = 10;
     static const size_t        kDumpSleepDuration = 100000; // 0.10 sec
     static const nsecs_t       kActiveTimeout     = 500000000;  // 500 ms
@@ -362,70 +327,65 @@
     // Flag indicating is the current active stream configuration is constrained high speed.
     bool                       mIsConstrainedHighSpeedConfiguration;
 
-    // FMQ to write result on. Must be guarded by mProcessCaptureResultLock.
-    std::unique_ptr<ResultMetadataQueue> mResultMetadataQueue;
-
     /**** Scope for mLock ****/
 
-    /**
-     * Adapter for legacy HAL / HIDL HAL interface calls; calls either into legacy HALv3 or the
-     * HIDL HALv3 interfaces.
-     */
     class HalInterface : public camera3::Camera3StreamBufferFreedListener,
             public camera3::BufferRecordsInterface {
       public:
-        HalInterface(sp<hardware::camera::device::V3_2::ICameraDeviceSession> &session,
-                     std::shared_ptr<RequestMetadataQueue> queue,
-                     bool useHalBufManager, bool supportOfflineProcessing);
+        HalInterface(bool useHalBufManager, bool supportOfflineProcessing) :
+              mUseHalBufManager(useHalBufManager),
+              mIsReconfigurationQuerySupported(true),
+              mSupportOfflineProcessing(supportOfflineProcessing)
+               {};
         HalInterface(const HalInterface &other);
         HalInterface();
 
+        virtual IPCTransport getTransportType() = 0;
+
         // Returns true if constructed with a valid device or session, and not yet cleared
-        bool valid();
+        virtual bool valid() = 0;
 
         // Reset this HalInterface object (does not call close())
-        void clear();
+        virtual void clear() = 0;
 
         // Calls into the HAL interface
 
         // Caller takes ownership of requestTemplate
-        status_t constructDefaultRequestSettings(camera_request_template templateId,
-                /*out*/ camera_metadata_t **requestTemplate);
-        status_t configureStreams(const camera_metadata_t *sessionParams,
-                /*inout*/ camera_stream_configuration_t *config,
-                const std::vector<uint32_t>& bufferSizes);
+        virtual status_t constructDefaultRequestSettings(camera_request_template templateId,
+                /*out*/ camera_metadata_t **requestTemplate) = 0;
+
+        virtual status_t configureStreams(const camera_metadata_t * sessionParams,
+                /*inout*/ camera_stream_configuration_t * config,
+                const std::vector<uint32_t>& bufferSizes) = 0;
 
         // The injection camera configures the streams to hal.
-        status_t configureInjectedStreams(
+        virtual status_t configureInjectedStreams(
                 const camera_metadata_t* sessionParams,
                 /*inout*/ camera_stream_configuration_t* config,
                 const std::vector<uint32_t>& bufferSizes,
-                const CameraMetadata& cameraCharacteristics);
+                const CameraMetadata& cameraCharacteristics) = 0;
 
         // When the call succeeds, the ownership of acquire fences in requests is transferred to
         // HalInterface. More specifically, the current implementation will send the fence to
         // HAL process and close the FD in cameraserver process. When the call fails, the ownership
         // of the acquire fence still belongs to the caller.
-        status_t processBatchCaptureRequests(
+        virtual status_t processBatchCaptureRequests(
                 std::vector<camera_capture_request_t*>& requests,
-                /*out*/uint32_t* numRequestProcessed);
-        status_t flush();
-        status_t dump(int fd);
-        status_t close();
+                /*out*/uint32_t* numRequestProcessed) = 0;
 
-        void signalPipelineDrain(const std::vector<int>& streamIds);
-        bool isReconfigurationRequired(CameraMetadata& oldSessionParams,
-                CameraMetadata& newSessionParams);
+        virtual status_t flush() = 0;
 
-        // Upon successful return, HalInterface will return buffer maps needed for offline
-        // processing, and clear all its internal buffer maps.
-        status_t switchToOffline(
-                const std::vector<int32_t>& streamsToKeep,
-                /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
-                /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
-                /*out*/camera3::BufferRecords* bufferRecords);
+        virtual status_t dump(int fd) = 0;
 
-        status_t repeatingRequestEnd(uint32_t frameNumber, hardware::hidl_vec<int32_t> streamIds);
+        virtual status_t close() = 0;
+
+        virtual void signalPipelineDrain(const std::vector<int>& streamIds) = 0;
+
+        virtual bool isReconfigurationRequired(CameraMetadata& oldSessionParams,
+                CameraMetadata& newSessionParams) = 0;
+
+        virtual status_t repeatingRequestEnd(uint32_t frameNumber,
+                const std::vector<int32_t> &streamIds) = 0;
 
         /////////////////////////////////////////////////////////////////////
         // Implements BufferRecordsInterface
@@ -456,40 +416,36 @@
 
         void onStreamReConfigured(int streamId);
 
-      private:
-        // Always valid
-        sp<hardware::camera::device::V3_2::ICameraDeviceSession> mHidlSession;
-        // Valid if ICameraDeviceSession is @3.3 or newer
-        sp<hardware::camera::device::V3_3::ICameraDeviceSession> mHidlSession_3_3;
-        // Valid if ICameraDeviceSession is @3.4 or newer
-        sp<hardware::camera::device::V3_4::ICameraDeviceSession> mHidlSession_3_4;
-        // Valid if ICameraDeviceSession is @3.5 or newer
-        sp<hardware::camera::device::V3_5::ICameraDeviceSession> mHidlSession_3_5;
-        // Valid if ICameraDeviceSession is @3.6 or newer
-        sp<hardware::camera::device::V3_6::ICameraDeviceSession> mHidlSession_3_6;
-        // Valid if ICameraDeviceSession is @3.7 or newer
-        sp<hardware::camera::device::V3_7::ICameraDeviceSession> mHidlSession_3_7;
-        // Valid if ICameraDeviceSession is @3.8 or newer
-        sp<hardware::camera::device::V3_8::ICameraDeviceSession> mHidlSession_3_8;
-
-        std::shared_ptr<RequestMetadataQueue> mRequestMetadataQueue;
-
-        // The output HIDL request still depends on input camera_capture_request_t
-        // Do not free input camera_capture_request_t before output HIDL request
-        status_t wrapAsHidlRequest(camera_capture_request_t* in,
-                /*out*/hardware::camera::device::V3_2::CaptureRequest* out,
-                /*out*/std::vector<native_handle_t*>* handlesCreated,
-                /*out*/std::vector<std::pair<int32_t, int32_t>>* inflightBuffers);
-
-        status_t pushInflightBufferLocked(int32_t frameNumber, int32_t streamId,
-                buffer_handle_t *buffer);
-
-        // Pop inflight buffers based on pairs of (frameNumber,streamId)
-        void popInflightBuffers(const std::vector<std::pair<int32_t, int32_t>>& buffers);
+      protected:
 
         // Return true if the input caches match what we have; otherwise false
         bool verifyBufferIds(int32_t streamId, std::vector<uint64_t>& inBufIds);
 
+        template <typename OfflineSessionInfoT>
+        status_t verifyBufferCaches(
+            const OfflineSessionInfoT *offlineSessionInfo, camera3::BufferRecords *bufferRecords) {
+            // Validate buffer caches
+            std::vector<int32_t> streams;
+            streams.reserve(offlineSessionInfo->offlineStreams.size());
+            for (auto offlineStream : offlineSessionInfo->offlineStreams) {
+                int32_t id = offlineStream.id;
+                streams.push_back(id);
+                // Verify buffer caches
+                std::vector<uint64_t> bufIds(offlineStream.circulatingBufferIds.begin(),
+                        offlineStream.circulatingBufferIds.end());
+                if (!verifyBufferIds(id, bufIds)) {
+                    ALOGE("%s: stream ID %d buffer cache records mismatch!", __FUNCTION__, id);
+                    return UNKNOWN_ERROR;
+                }
+            }
+
+            // Move buffer records
+            bufferRecords->takeBufferCaches(mBufferRecords, streams);
+            bufferRecords->takeInflightBufferMap(mBufferRecords);
+            bufferRecords->takeRequestedBufferMap(mBufferRecords);
+            return OK;
+        }
+
         // Delete and optionally close native handles and clear the input vector afterward
         static void cleanupNativeHandles(
                 std::vector<native_handle_t*> *handles, bool closeFd = false);
@@ -508,7 +464,7 @@
         bool mIsReconfigurationQuerySupported;
 
         const bool mSupportOfflineProcessing;
-    };
+    }; // class HalInterface
 
     sp<HalInterface> mInterface;
 
@@ -634,41 +590,6 @@
                                   bool repeating,
                                   int64_t *lastFrameNumber = NULL);
 
-
-    /**
-     * Implementation of android::hardware::camera::device::V3_5::ICameraDeviceCallback
-     */
-
-    hardware::Return<void> processCaptureResult_3_4(
-            const hardware::hidl_vec<
-                    hardware::camera::device::V3_4::CaptureResult>& results) override;
-    hardware::Return<void> processCaptureResult(
-            const hardware::hidl_vec<
-                    hardware::camera::device::V3_2::CaptureResult>& results) override;
-    hardware::Return<void> notify(
-            const hardware::hidl_vec<
-                    hardware::camera::device::V3_2::NotifyMsg>& msgs) override;
-
-    hardware::Return<void> requestStreamBuffers(
-            const hardware::hidl_vec<
-                    hardware::camera::device::V3_5::BufferRequest>& bufReqs,
-            requestStreamBuffers_cb _hidl_cb) override;
-
-    hardware::Return<void> returnStreamBuffers(
-            const hardware::hidl_vec<
-                    hardware::camera::device::V3_2::StreamBuffer>& buffers) override;
-
-    hardware::Return<void> notify_3_8(
-            const hardware::hidl_vec<
-                    hardware::camera::device::V3_8::NotifyMsg>& msgs) override;
-
-    template<typename NotifyMsgType>
-    hardware::Return<void> notifyHelper(
-            const hardware::hidl_vec<NotifyMsgType>& msgs);
-
-    // Handle one notify message
-    void notify(const hardware::camera::device::V3_2::NotifyMsg& msg);
-
     // lock to ensure only one processCaptureResult is called at a time.
     Mutex mProcessCaptureResultLock;
 
@@ -686,6 +607,9 @@
      */
     virtual CameraMetadata getLatestRequestLocked();
 
+    virtual status_t injectionCameraInitialize(const String8 &injectCamId,
+            sp<CameraProviderManager> manager) = 0;
+
     /**
      * Update the current device status and wake all waiting threads.
      *
@@ -934,12 +858,6 @@
         void signalPipelineDrain(const std::vector<int>& streamIds);
         void resetPipelineDrain();
 
-        status_t switchToOffline(
-                const std::vector<int32_t>& streamsToKeep,
-                /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
-                /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
-                /*out*/camera3::BufferRecords* bufferRecords);
-
         void clearPreviousRequest();
 
         status_t setRotateAndCropAutoBehavior(
@@ -954,7 +872,6 @@
 
         virtual bool threadLoop();
 
-      private:
         static const String8& getId(const wp<Camera3Device> &device);
 
         status_t           queueTriggerLocked(RequestTrigger trigger);
@@ -1119,6 +1036,14 @@
         const bool         mUseHalBufManager;
         const bool         mSupportCameraMute;
     };
+
+    virtual sp<RequestThread> createNewRequestThread(wp<Camera3Device> /*parent*/,
+                sp<camera3::StatusTracker> /*statusTracker*/,
+                sp<HalInterface> /*interface*/,
+                const Vector<int32_t>& /*sessionParamKeys*/,
+                bool /*useHalBufManager*/,
+                bool /*supportCameraMute*/) = 0;
+
     sp<RequestThread> mRequestThread;
 
     /**
@@ -1394,13 +1319,6 @@
 
         ~Camera3DeviceInjectionMethods();
 
-        // Initialize the injection camera and generate an hal interface.
-        status_t injectionInitialize(
-                const String8& injectedCamId, sp<CameraProviderManager> manager,
-                const sp<
-                    android::hardware::camera::device::V3_2 ::ICameraDeviceCallback>&
-                    callback);
-
         // Injection camera will replace the internal camera and configure streams
         // when device is IDLE and request thread is paused.
         status_t injectCamera(
@@ -1426,7 +1344,7 @@
                 const camera3::camera_stream_configuration& injectionConfig,
                 const std::vector<uint32_t>& injectionBufferSizes);
 
-      private:
+      protected:
         // Configure the streams of injection camera, it need wait until the
         // output streams are created and configured to the original camera before
         // proceeding.
@@ -1439,8 +1357,8 @@
 
         // Use injection camera hal interface to replace and backup original
         // camera hal interface.
-        status_t replaceHalInterface(sp<HalInterface> newHalInterface,
-                bool keepBackup);
+        virtual status_t replaceHalInterface(sp<HalInterface> /*newHalInterface*/,
+                bool /*keepBackup*/) = 0;
 
         wp<Camera3Device> mParent;
 
@@ -1450,13 +1368,6 @@
         // Generated injection camera hal interface.
         sp<HalInterface> mInjectedCamHalInterface;
 
-        // Backup of the original camera hal result FMQ.
-        std::unique_ptr<ResultMetadataQueue> mBackupResultMetadataQueue;
-
-        // FMQ writes the result for the injection camera. Must be guarded by
-        // mProcessCaptureResultLock.
-        std::unique_ptr<ResultMetadataQueue> mInjectionResultMetadataQueue;
-
         // The flag indicates that the stream configuration is complete, the camera device is
         // active, but the injection camera has not yet been injected.
         bool mIsStreamConfigCompleteButNotInjected = false;
@@ -1477,6 +1388,10 @@
         // The injection camera ID.
         String8 mInjectedCamId;
     };
+
+    virtual sp<Camera3DeviceInjectionMethods>
+            createCamera3DeviceInjectionMethods(wp<Camera3Device>) = 0;
+
     sp<Camera3DeviceInjectionMethods> mInjectionMethods;
 
 }; // class Camera3Device
diff --git a/services/camera/libcameraservice/device3/Camera3DeviceInjectionMethods.cpp b/services/camera/libcameraservice/device3/Camera3DeviceInjectionMethods.cpp
index f9b0284..6818acf 100644
--- a/services/camera/libcameraservice/device3/Camera3DeviceInjectionMethods.cpp
+++ b/services/camera/libcameraservice/device3/Camera3DeviceInjectionMethods.cpp
@@ -39,92 +39,6 @@
     injectionDisconnectImpl();
 }
 
-status_t Camera3Device::Camera3DeviceInjectionMethods::injectionInitialize(
-        const String8& injectedCamId, sp<CameraProviderManager> manager,
-        const sp<android::hardware::camera::device::V3_2::ICameraDeviceCallback>&
-                callback) {
-    ATRACE_CALL();
-    Mutex::Autolock lock(mInjectionLock);
-
-    if (manager == nullptr) {
-        ALOGE("%s: manager does not exist!", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
-
-    sp<Camera3Device> parent = mParent.promote();
-    if (parent == nullptr) {
-        ALOGE("%s: parent does not exist!", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
-
-    mInjectedCamId = injectedCamId;
-    sp<ICameraDeviceSession> session;
-    ATRACE_BEGIN("Injection CameraHal::openSession");
-    status_t res = manager->openHidlSession(injectedCamId.string(), callback,
-                                          /*out*/ &session);
-    ATRACE_END();
-    if (res != OK) {
-        ALOGE("Injection camera could not open camera session: %s (%d)",
-                strerror(-res), res);
-        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("Injection camera HAL returns empty request metadata fmq, not "
-                        "use it");
-                queue = nullptr;
-                // don't use the queue onwards.
-            }
-        });
-    if (!requestQueueRet.isOk()) {
-        ALOGE("Injection camera transaction error when getting request metadata fmq: "
-                "%s, not use it", requestQueueRet.description().c_str());
-        return DEAD_OBJECT;
-    }
-
-    std::unique_ptr<ResultMetadataQueue>& resQueue = mInjectionResultMetadataQueue;
-    auto resultQueueRet = session->getCaptureResultMetadataQueue(
-        [&resQueue](const auto& descriptor) {
-            resQueue = std::make_unique<ResultMetadataQueue>(descriptor);
-            if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
-                ALOGE("Injection camera HAL returns empty result metadata fmq, not use "
-                        "it");
-                resQueue = nullptr;
-                // Don't use the resQueue onwards.
-            }
-        });
-    if (!resultQueueRet.isOk()) {
-        ALOGE("Injection camera 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("Injection camera session interface chain:");
-                        for (const auto& iface : interfaceChain) {
-                            ALOGV("  %s", iface.c_str());
-                        }
-                });
-    }
-
-    ALOGV("%s: Injection camera interface = new HalInterface()", __FUNCTION__);
-    mInjectedCamHalInterface =
-            new HalInterface(session, queue, parent->mUseHalBufManager,
-                       parent->mSupportOfflineProcessing);
-    if (mInjectedCamHalInterface == nullptr) {
-        ALOGE("%s: mInjectedCamHalInterface does not exist!", __FUNCTION__);
-        return DEAD_OBJECT;
-    }
-
-    return OK;
-}
-
 status_t Camera3Device::Camera3DeviceInjectionMethods::injectCamera(
         camera3::camera_stream_configuration& injectionConfig,
         const std::vector<uint32_t>& injectionBufferSizes) {
@@ -379,37 +293,4 @@
     }
 }
 
-status_t Camera3Device::Camera3DeviceInjectionMethods::replaceHalInterface(
-        sp<HalInterface> newHalInterface, bool keepBackup) {
-    Mutex::Autolock lock(mInjectionLock);
-    if (newHalInterface.get() == nullptr) {
-        ALOGE("%s: The newHalInterface does not exist, to stop replacing.",
-                __FUNCTION__);
-        return DEAD_OBJECT;
-    }
-
-    sp<Camera3Device> parent = mParent.promote();
-    if (parent == nullptr) {
-        ALOGE("%s: parent does not exist!", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
-
-    if (keepBackup) {
-        if (mBackupHalInterface == nullptr) {
-            mBackupHalInterface = parent->mInterface;
-        }
-        if (mBackupResultMetadataQueue == nullptr) {
-            mBackupResultMetadataQueue = std::move(parent->mResultMetadataQueue);
-            parent->mResultMetadataQueue = std::move(mInjectionResultMetadataQueue);
-        }
-    } else {
-        mBackupHalInterface = nullptr;
-        parent->mResultMetadataQueue = std::move(mBackupResultMetadataQueue);
-        mBackupResultMetadataQueue = nullptr;
-    }
-    parent->mInterface = newHalInterface;
-
-    return OK;
-}
-
 };  // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp b/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp
index b702e20..7cfa255 100644
--- a/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp
@@ -47,14 +47,12 @@
         const camera3::StreamSet& offlineStreamSet,
         camera3::BufferRecords&& bufferRecords,
         const camera3::InFlightRequestMap& offlineReqs,
-        const Camera3OfflineStates& offlineStates,
-        sp<hardware::camera::device::V3_6::ICameraOfflineSession> offlineSession) :
+        const Camera3OfflineStates& offlineStates) :
         mId(id),
         mInputStream(inputStream),
         mOutputStreams(offlineStreamSet),
         mBufferRecords(std::move(bufferRecords)),
         mOfflineReqs(offlineReqs),
-        mSession(offlineSession),
         mTagMonitor(offlineStates.mTagMonitor),
         mVendorTagId(offlineStates.mVendorTagId),
         mUseHalBufManager(offlineStates.mUseHalBufManager),
@@ -90,43 +88,6 @@
     return mId;
 }
 
-status_t Camera3OfflineSession::initialize(wp<NotificationListener> listener) {
-    ATRACE_CALL();
-
-    if (mSession == nullptr) {
-        ALOGE("%s: HIDL session is null!", __FUNCTION__);
-        return DEAD_OBJECT;
-    }
-
-    {
-        std::lock_guard<std::mutex> lock(mLock);
-
-        mListener = listener;
-
-        // setup result FMQ
-        std::unique_ptr<ResultMetadataQueue>& resQueue = mResultMetadataQueue;
-        auto resultQueueRet = mSession->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 resQueue onwards.
-                }
-            });
-        if (!resultQueueRet.isOk()) {
-            ALOGE("Transaction error when getting result metadata queue from camera session: %s",
-                    resultQueueRet.description().c_str());
-            return DEAD_OBJECT;
-        }
-        mStatus = STATUS_ACTIVE;
-    }
-
-    mSession->setCallback(this);
-
-    return OK;
-}
-
 status_t Camera3OfflineSession::dump(int /*fd*/) {
     ATRACE_CALL();
     std::lock_guard<std::mutex> il(mInterfaceLock);
@@ -135,6 +96,7 @@
 
 status_t Camera3OfflineSession::disconnect() {
     ATRACE_CALL();
+    disconnectSession();
     return disconnectImpl();
 }
 
@@ -170,10 +132,6 @@
         streams.push_back(mInputStream);
     }
 
-    if (mSession != nullptr) {
-        mSession->close();
-    }
-
     FlushInflightReqStates states {
         mId, mOfflineReqsLock, mOfflineReqs, mUseHalBufManager,
         listener, *this, mBufferRecords, *this, mSessionStatsBuilder};
@@ -182,7 +140,6 @@
 
     {
         std::lock_guard<std::mutex> lock(mLock);
-        mSession.clear();
         mOutputStreams.clear();
         mInputStream.clear();
         mStatus = STATUS_CLOSED;
@@ -235,149 +192,6 @@
     return OK;
 }
 
-hardware::Return<void> Camera3OfflineSession::processCaptureResult_3_4(
-        const hardware::hidl_vec<
-                hardware::camera::device::V3_4::CaptureResult>& results) {
-    sp<NotificationListener> listener;
-    {
-        std::lock_guard<std::mutex> lock(mLock);
-        if (mStatus != STATUS_ACTIVE) {
-            ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
-            return hardware::Void();
-        }
-        listener = mListener.promote();
-    }
-
-    CaptureOutputStates states {
-        mId,
-        mOfflineReqsLock, mLastCompletedRegularFrameNumber,
-        mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
-        mOfflineReqs, mOutputLock, mResultQueue, mResultSignal,
-        mNextShutterFrameNumber,
-        mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
-        mNextResultFrameNumber,
-        mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
-        mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
-        mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
-        mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
-        mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
-        mBufferRecords, /*legacyClient*/ false
-    };
-
-    std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
-    for (const auto& result : results) {
-        processOneCaptureResultLocked(states, result.v3_2, result.physicalCameraMetadata);
-    }
-    return hardware::Void();
-}
-
-hardware::Return<void> Camera3OfflineSession::processCaptureResult(
-        const hardware::hidl_vec<
-                hardware::camera::device::V3_2::CaptureResult>& results) {
-    // TODO: changed impl to call into processCaptureResult_3_4 instead?
-    //       might need to figure how to reduce copy though.
-    sp<NotificationListener> listener;
-    {
-        std::lock_guard<std::mutex> lock(mLock);
-        if (mStatus != STATUS_ACTIVE) {
-            ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
-            return hardware::Void();
-        }
-        listener = mListener.promote();
-    }
-
-    hardware::hidl_vec<hardware::camera::device::V3_4::PhysicalCameraMetadata> noPhysMetadata;
-
-    CaptureOutputStates states {
-        mId,
-        mOfflineReqsLock, mLastCompletedRegularFrameNumber,
-        mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
-        mOfflineReqs, mOutputLock, mResultQueue, mResultSignal,
-        mNextShutterFrameNumber,
-        mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
-        mNextResultFrameNumber,
-        mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
-        mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
-        mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
-        mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
-        mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
-        mBufferRecords, /*legacyClient*/ false
-    };
-
-    std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
-    for (const auto& result : results) {
-        processOneCaptureResultLocked(states, result, noPhysMetadata);
-    }
-    return hardware::Void();
-}
-
-hardware::Return<void> Camera3OfflineSession::notify(
-        const hardware::hidl_vec<hardware::camera::device::V3_2::NotifyMsg>& msgs) {
-    sp<NotificationListener> listener;
-    {
-        std::lock_guard<std::mutex> lock(mLock);
-        if (mStatus != STATUS_ACTIVE) {
-            ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
-            return hardware::Void();
-        }
-        listener = mListener.promote();
-    }
-
-    CaptureOutputStates states {
-        mId,
-        mOfflineReqsLock, mLastCompletedRegularFrameNumber,
-        mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
-        mOfflineReqs, mOutputLock, mResultQueue, mResultSignal,
-        mNextShutterFrameNumber,
-        mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
-        mNextResultFrameNumber,
-        mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
-        mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
-        mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
-        mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
-        mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
-        mBufferRecords, /*legacyClient*/ false
-    };
-    for (const auto& msg : msgs) {
-        camera3::notify(states, msg);
-    }
-    return hardware::Void();
-}
-
-hardware::Return<void> Camera3OfflineSession::requestStreamBuffers(
-        const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
-        requestStreamBuffers_cb _hidl_cb) {
-    {
-        std::lock_guard<std::mutex> lock(mLock);
-        if (mStatus != STATUS_ACTIVE) {
-            ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
-            return hardware::Void();
-        }
-    }
-
-    RequestBufferStates states {
-        mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder,
-        *this, mBufferRecords, *this};
-    camera3::requestStreamBuffers(states, bufReqs, _hidl_cb);
-    return hardware::Void();
-}
-
-hardware::Return<void> Camera3OfflineSession::returnStreamBuffers(
-        const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) {
-    {
-        std::lock_guard<std::mutex> lock(mLock);
-        if (mStatus != STATUS_ACTIVE) {
-            ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
-            return hardware::Void();
-        }
-    }
-
-    ReturnBufferStates states {
-        mId, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder, mBufferRecords};
-    camera3::returnStreamBuffers(states, buffers);
-    return hardware::Void();
-}
-
 void Camera3OfflineSession::setErrorState(const char *fmt, ...) {
     ATRACE_CALL();
     std::lock_guard<std::mutex> lock(mLock);
diff --git a/services/camera/libcameraservice/device3/Camera3OfflineSession.h b/services/camera/libcameraservice/device3/Camera3OfflineSession.h
index 5581964..0f7d145 100644
--- a/services/camera/libcameraservice/device3/Camera3OfflineSession.h
+++ b/services/camera/libcameraservice/device3/Camera3OfflineSession.h
@@ -131,7 +131,6 @@
  */
 class Camera3OfflineSession :
             public CameraOfflineSessionBase,
-            virtual public hardware::camera::device::V3_5::ICameraDeviceCallback,
             public camera3::SetErrorInterface,
             public camera3::InflightRequestUpdateInterface,
             public camera3::RequestBufferInterface,
@@ -144,12 +143,11 @@
             const camera3::StreamSet& offlineStreamSet,
             camera3::BufferRecords&& bufferRecords,
             const camera3::InFlightRequestMap& offlineReqs,
-            const Camera3OfflineStates& offlineStates,
-            sp<hardware::camera::device::V3_6::ICameraOfflineSession> offlineSession);
+            const Camera3OfflineStates& offlineStates);
 
     virtual ~Camera3OfflineSession();
 
-    virtual status_t initialize(wp<NotificationListener> listener) override;
+    virtual status_t initialize(wp<NotificationListener> /*listener*/) = 0;
 
     /**
      * CameraOfflineSessionBase interface
@@ -171,38 +169,7 @@
      * End of CameraOfflineSessionBase interface
      */
 
-    /**
-     * HIDL ICameraDeviceCallback interface
-     */
-
-    /**
-     * Implementation of android::hardware::camera::device::V3_5::ICameraDeviceCallback
-     */
-
-    hardware::Return<void> processCaptureResult_3_4(
-            const hardware::hidl_vec<
-                    hardware::camera::device::V3_4::CaptureResult>& results) override;
-    hardware::Return<void> processCaptureResult(
-            const hardware::hidl_vec<
-                    hardware::camera::device::V3_2::CaptureResult>& results) override;
-    hardware::Return<void> notify(
-            const hardware::hidl_vec<
-                    hardware::camera::device::V3_2::NotifyMsg>& msgs) override;
-
-    hardware::Return<void> requestStreamBuffers(
-            const hardware::hidl_vec<
-                    hardware::camera::device::V3_5::BufferRequest>& bufReqs,
-            requestStreamBuffers_cb _hidl_cb) override;
-
-    hardware::Return<void> returnStreamBuffers(
-            const hardware::hidl_vec<
-                    hardware::camera::device::V3_2::StreamBuffer>& buffers) override;
-
-    /**
-     * End of CameraOfflineSessionBase interface
-     */
-
-  private:
+  protected:
     // Camera device ID
     const String8 mId;
     sp<camera3::Camera3Stream> mInputStream;
@@ -213,8 +180,6 @@
     std::mutex mOfflineReqsLock;
     camera3::InFlightRequestMap mOfflineReqs;
 
-    sp<hardware::camera::device::V3_6::ICameraOfflineSession> mSession;
-
     TagMonitor mTagMonitor;
     const metadata_vendor_id_t mVendorTagId;
 
@@ -269,8 +234,6 @@
     // End of mLock protect scope
 
     std::mutex mProcessCaptureResultLock;
-    // FMQ to write result on. Must be guarded by mProcessCaptureResultLock.
-    std::unique_ptr<ResultMetadataQueue> mResultMetadataQueue;
 
     // Tracking cause of fatal errors when in STATUS_ERROR
     String8 mErrorCause;
@@ -305,6 +268,8 @@
     void setErrorStateLockedV(const char *fmt, va_list args);
 
     status_t disconnectImpl();
+    virtual void disconnectSession() = 0;
+
 }; // class Camera3OfflineSession
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
index 24f81f3..d8cc685 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
@@ -376,43 +376,6 @@
     insertResultLocked(states, &captureResult, frameNumber);
 }
 
-// Reading one camera metadata from result argument via fmq or from the result
-// Assuming the fmq is protected by a lock already
-status_t readOneCameraMetadataLocked(
-        std::unique_ptr<ResultMetadataQueue>& fmq,
-        uint64_t fmqResultSize,
-        hardware::camera::device::V3_2::CameraMetadata& resultMetadata,
-        const hardware::camera::device::V3_2::CameraMetadata& result) {
-    if (fmqResultSize > 0) {
-        resultMetadata.resize(fmqResultSize);
-        if (fmq == nullptr) {
-            return NO_MEMORY; // logged in initialize()
-        }
-        if (!fmq->read(resultMetadata.data(), fmqResultSize)) {
-            ALOGE("%s: Cannot read camera metadata from fmq, size = %" PRIu64,
-                    __FUNCTION__, fmqResultSize);
-            return INVALID_OPERATION;
-        }
-    } else {
-        resultMetadata.setToExternal(const_cast<uint8_t *>(result.data()),
-                result.size());
-    }
-
-    if (resultMetadata.size() != 0) {
-        status_t res;
-        const camera_metadata_t* metadata =
-                reinterpret_cast<const camera_metadata_t*>(resultMetadata.data());
-        size_t expected_metadata_size = resultMetadata.size();
-        if ((res = validate_camera_metadata_structure(metadata, &expected_metadata_size)) != OK) {
-            ALOGE("%s: Invalid camera metadata received by camera service from HAL: %s (%d)",
-                    __FUNCTION__, strerror(-res), res);
-            return INVALID_OPERATION;
-        }
-    }
-
-    return OK;
-}
-
 void removeInFlightMapEntryLocked(CaptureOutputStates& states, int idx) {
     ATRACE_CALL();
     InFlightRequestMap& inflightMap = states.inflightMap;
@@ -719,153 +682,6 @@
     }
 }
 
-void processOneCaptureResultLocked(
-        CaptureOutputStates& states,
-        const hardware::camera::device::V3_2::CaptureResult& result,
-        const hardware::hidl_vec<
-                hardware::camera::device::V3_4::PhysicalCameraMetadata> physicalCameraMetadata) {
-    using hardware::camera::device::V3_2::StreamBuffer;
-    using hardware::camera::device::V3_2::BufferStatus;
-    std::unique_ptr<ResultMetadataQueue>& fmq = states.fmq;
-    BufferRecordsInterface& bufferRecords = states.bufferRecordsIntf;
-    camera_capture_result r;
-    status_t res;
-    r.frame_number = result.frameNumber;
-
-    // Read and validate the result metadata.
-    hardware::camera::device::V3_2::CameraMetadata resultMetadata;
-    res = readOneCameraMetadataLocked(
-            fmq, result.fmqResultSize,
-            resultMetadata, result.result);
-    if (res != OK) {
-        ALOGE("%s: Frame %d: Failed to read capture result metadata",
-                __FUNCTION__, result.frameNumber);
-        return;
-    }
-    r.result = reinterpret_cast<const camera_metadata_t*>(resultMetadata.data());
-
-    // Read and validate physical camera metadata
-    size_t physResultCount = physicalCameraMetadata.size();
-    std::vector<const char*> physCamIds(physResultCount);
-    std::vector<const camera_metadata_t *> phyCamMetadatas(physResultCount);
-    std::vector<hardware::camera::device::V3_2::CameraMetadata> physResultMetadata;
-    physResultMetadata.resize(physResultCount);
-    for (size_t i = 0; i < physicalCameraMetadata.size(); i++) {
-        res = readOneCameraMetadataLocked(fmq, physicalCameraMetadata[i].fmqMetadataSize,
-                physResultMetadata[i], physicalCameraMetadata[i].metadata);
-        if (res != OK) {
-            ALOGE("%s: Frame %d: Failed to read capture result metadata for camera %s",
-                    __FUNCTION__, result.frameNumber,
-                    physicalCameraMetadata[i].physicalCameraId.c_str());
-            return;
-        }
-        physCamIds[i] = physicalCameraMetadata[i].physicalCameraId.c_str();
-        phyCamMetadatas[i] = reinterpret_cast<const camera_metadata_t*>(
-                physResultMetadata[i].data());
-    }
-    r.num_physcam_metadata = physResultCount;
-    r.physcam_ids = physCamIds.data();
-    r.physcam_metadata = phyCamMetadatas.data();
-
-    std::vector<camera_stream_buffer_t> outputBuffers(result.outputBuffers.size());
-    std::vector<buffer_handle_t> outputBufferHandles(result.outputBuffers.size());
-    for (size_t i = 0; i < result.outputBuffers.size(); i++) {
-        auto& bDst = outputBuffers[i];
-        const StreamBuffer &bSrc = result.outputBuffers[i];
-
-        sp<Camera3StreamInterface> stream = states.outputStreams.get(bSrc.streamId);
-        if (stream == nullptr) {
-            ALOGE("%s: Frame %d: Buffer %zu: Invalid output stream id %d",
-                    __FUNCTION__, result.frameNumber, i, bSrc.streamId);
-            return;
-        }
-        bDst.stream = stream->asHalStream();
-
-        bool noBufferReturned = false;
-        buffer_handle_t *buffer = nullptr;
-        if (states.useHalBufManager) {
-            // This is suspicious most of the time but can be correct during flush where HAL
-            // has to return capture result before a buffer is requested
-            if (bSrc.bufferId == BUFFER_ID_NO_BUFFER) {
-                if (bSrc.status == BufferStatus::OK) {
-                    ALOGE("%s: Frame %d: Buffer %zu: No bufferId for stream %d",
-                            __FUNCTION__, result.frameNumber, i, bSrc.streamId);
-                    // Still proceeds so other buffers can be returned
-                }
-                noBufferReturned = true;
-            }
-            if (noBufferReturned) {
-                res = OK;
-            } else {
-                res = bufferRecords.popInflightRequestBuffer(bSrc.bufferId, &buffer);
-            }
-        } else {
-            res = bufferRecords.popInflightBuffer(result.frameNumber, bSrc.streamId, &buffer);
-        }
-
-        if (res != OK) {
-            ALOGE("%s: Frame %d: Buffer %zu: No in-flight buffer for stream %d",
-                    __FUNCTION__, result.frameNumber, i, bSrc.streamId);
-            return;
-        }
-
-        bDst.buffer = buffer;
-        bDst.status = mapHidlBufferStatus(bSrc.status);
-        bDst.acquire_fence = -1;
-        if (bSrc.releaseFence == nullptr) {
-            bDst.release_fence = -1;
-        } else if (bSrc.releaseFence->numFds == 1) {
-            if (noBufferReturned) {
-                ALOGE("%s: got releaseFence without output buffer!", __FUNCTION__);
-            }
-            bDst.release_fence = dup(bSrc.releaseFence->data[0]);
-        } 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;
-        }
-    }
-    r.num_output_buffers = outputBuffers.size();
-    r.output_buffers = outputBuffers.data();
-
-    camera_stream_buffer_t inputBuffer;
-    if (result.inputBuffer.streamId == -1) {
-        r.input_buffer = nullptr;
-    } else {
-        if (states.inputStream->getId() != result.inputBuffer.streamId) {
-            ALOGE("%s: Frame %d: Invalid input stream id %d", __FUNCTION__,
-                    result.frameNumber, result.inputBuffer.streamId);
-            return;
-        }
-        inputBuffer.stream = states.inputStream->asHalStream();
-        buffer_handle_t *buffer;
-        res = bufferRecords.popInflightBuffer(result.frameNumber, result.inputBuffer.streamId,
-                &buffer);
-        if (res != OK) {
-            ALOGE("%s: Frame %d: Input buffer: No in-flight buffer for stream %d",
-                    __FUNCTION__, result.frameNumber, result.inputBuffer.streamId);
-            return;
-        }
-        inputBuffer.buffer = buffer;
-        inputBuffer.status = mapHidlBufferStatus(result.inputBuffer.status);
-        inputBuffer.acquire_fence = -1;
-        if (result.inputBuffer.releaseFence == nullptr) {
-            inputBuffer.release_fence = -1;
-        } else if (result.inputBuffer.releaseFence->numFds == 1) {
-            inputBuffer.release_fence = dup(result.inputBuffer.releaseFence->data[0]);
-        } 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;
-        }
-        r.input_buffer = &inputBuffer;
-    }
-
-    r.partial_result = result.partialResult;
-
-    processCaptureResult(states, &r);
-}
-
 void returnOutputBuffers(
         bool useHalBufManager,
         sp<NotificationListener> listener,
@@ -1194,330 +1010,6 @@
     }
 }
 
-void notify(CaptureOutputStates& states,
-        const hardware::camera::device::V3_8::NotifyMsg& msg) {
-    using android::hardware::camera::device::V3_2::MsgType;
-
-    hardware::camera::device::V3_2::NotifyMsg msg_3_2;
-    msg_3_2.type = msg.type;
-    bool hasReadoutTime = false;
-    uint64_t readoutTime = 0;
-    switch (msg.type) {
-        case MsgType::ERROR:
-            msg_3_2.msg.error = msg.msg.error;
-            break;
-        case MsgType::SHUTTER:
-            msg_3_2.msg.shutter = msg.msg.shutter.v3_2;
-            hasReadoutTime = true;
-            readoutTime = msg.msg.shutter.readoutTimestamp;
-            break;
-    }
-    notify(states, msg_3_2, hasReadoutTime, readoutTime);
-}
-
-void notify(CaptureOutputStates& states,
-        const hardware::camera::device::V3_2::NotifyMsg& msg,
-        bool hasReadoutTime, uint64_t readoutTime) {
-
-    using android::hardware::camera::device::V3_2::MsgType;
-    using android::hardware::camera::device::V3_2::ErrorCode;
-
-    ATRACE_CALL();
-    camera_notify_msg m;
-    switch (msg.type) {
-        case MsgType::ERROR:
-            m.type = CAMERA_MSG_ERROR;
-            m.message.error.frame_number = msg.msg.error.frameNumber;
-            if (msg.msg.error.errorStreamId >= 0) {
-                sp<Camera3StreamInterface> stream =
-                        states.outputStreams.get(msg.msg.error.errorStreamId);
-                if (stream == nullptr) {
-                    ALOGE("%s: Frame %d: Invalid error stream id %d", __FUNCTION__,
-                            m.message.error.frame_number, msg.msg.error.errorStreamId);
-                    return;
-                }
-                m.message.error.error_stream = stream->asHalStream();
-            } else {
-                m.message.error.error_stream = nullptr;
-            }
-            switch (msg.msg.error.errorCode) {
-                case ErrorCode::ERROR_DEVICE:
-                    m.message.error.error_code = CAMERA_MSG_ERROR_DEVICE;
-                    break;
-                case ErrorCode::ERROR_REQUEST:
-                    m.message.error.error_code = CAMERA_MSG_ERROR_REQUEST;
-                    break;
-                case ErrorCode::ERROR_RESULT:
-                    m.message.error.error_code = CAMERA_MSG_ERROR_RESULT;
-                    break;
-                case ErrorCode::ERROR_BUFFER:
-                    m.message.error.error_code = CAMERA_MSG_ERROR_BUFFER;
-                    break;
-            }
-            break;
-        case MsgType::SHUTTER:
-            m.type = CAMERA_MSG_SHUTTER;
-            m.message.shutter.frame_number = msg.msg.shutter.frameNumber;
-            m.message.shutter.timestamp = msg.msg.shutter.timestamp;
-            m.message.shutter.readout_timestamp = hasReadoutTime ?
-                    readoutTime : m.message.shutter.timestamp;
-            break;
-    }
-    notify(states, &m);
-}
-
-// The buffers requested through this call are not tied to any CaptureRequest in
-// particular. They may used by the hal for a particular frame's output buffer
-// or for its internal use as well. In the case that the hal does use any buffer
-// from the requested list here, for a particular frame's output buffer, the
-// buffer will be returned with the processCaptureResult call corresponding to
-// the frame. The other buffers will be returned through returnStreamBuffers.
-// The buffers returned via returnStreamBuffers will not have a valid
-// timestamp(0) and will be dropped by the bufferqueue.
-void requestStreamBuffers(RequestBufferStates& states,
-        const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
-        hardware::camera::device::V3_5::ICameraDeviceCallback::requestStreamBuffers_cb _hidl_cb) {
-    using android::hardware::camera::device::V3_2::BufferStatus;
-    using android::hardware::camera::device::V3_2::StreamBuffer;
-    using android::hardware::camera::device::V3_5::BufferRequestStatus;
-    using android::hardware::camera::device::V3_5::StreamBufferRet;
-    using android::hardware::camera::device::V3_5::StreamBufferRequestError;
-
-    std::lock_guard<std::mutex> lock(states.reqBufferLock);
-
-    hardware::hidl_vec<StreamBufferRet> bufRets;
-    if (!states.useHalBufManager) {
-        ALOGE("%s: Camera %s does not support HAL buffer management",
-                __FUNCTION__, states.cameraId.string());
-        _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
-        return;
-    }
-
-    SortedVector<int32_t> streamIds;
-    ssize_t sz = streamIds.setCapacity(bufReqs.size());
-    if (sz < 0 || static_cast<size_t>(sz) != bufReqs.size()) {
-        ALOGE("%s: failed to allocate memory for %zu buffer requests",
-                __FUNCTION__, bufReqs.size());
-        _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
-        return;
-    }
-
-    if (bufReqs.size() > states.outputStreams.size()) {
-        ALOGE("%s: too many buffer requests (%zu > # of output streams %zu)",
-                __FUNCTION__, bufReqs.size(), states.outputStreams.size());
-        _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
-        return;
-    }
-
-    // Check for repeated streamId
-    for (const auto& bufReq : bufReqs) {
-        if (streamIds.indexOf(bufReq.streamId) != NAME_NOT_FOUND) {
-            ALOGE("%s: Stream %d appear multiple times in buffer requests",
-                    __FUNCTION__, bufReq.streamId);
-            _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
-            return;
-        }
-        streamIds.add(bufReq.streamId);
-    }
-
-    if (!states.reqBufferIntf.startRequestBuffer()) {
-        ALOGE("%s: request buffer disallowed while camera service is configuring",
-                __FUNCTION__);
-        _hidl_cb(BufferRequestStatus::FAILED_CONFIGURING, bufRets);
-        return;
-    }
-
-    bufRets.resize(bufReqs.size());
-
-    bool allReqsSucceeds = true;
-    bool oneReqSucceeds = false;
-    for (size_t i = 0; i < bufReqs.size(); i++) {
-        const auto& bufReq = bufReqs[i];
-        auto& bufRet = bufRets[i];
-        int32_t streamId = bufReq.streamId;
-        sp<Camera3OutputStreamInterface> outputStream = states.outputStreams.get(streamId);
-        if (outputStream == nullptr) {
-            ALOGE("%s: Output stream id %d not found!", __FUNCTION__, streamId);
-            hardware::hidl_vec<StreamBufferRet> emptyBufRets;
-            _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, emptyBufRets);
-            states.reqBufferIntf.endRequestBuffer();
-            return;
-        }
-
-        bufRet.streamId = streamId;
-        if (outputStream->isAbandoned()) {
-            bufRet.val.error(StreamBufferRequestError::STREAM_DISCONNECTED);
-            allReqsSucceeds = false;
-            continue;
-        }
-
-        size_t handOutBufferCount = outputStream->getOutstandingBuffersCount();
-        uint32_t numBuffersRequested = bufReq.numBuffersRequested;
-        size_t totalHandout = handOutBufferCount + numBuffersRequested;
-        uint32_t maxBuffers = outputStream->asHalStream()->max_buffers;
-        if (totalHandout > maxBuffers) {
-            // Not able to allocate enough buffer. Exit early for this stream
-            ALOGE("%s: request too much buffers for stream %d: at HAL: %zu + requesting: %d"
-                    " > max: %d", __FUNCTION__, streamId, handOutBufferCount,
-                    numBuffersRequested, maxBuffers);
-            bufRet.val.error(StreamBufferRequestError::MAX_BUFFER_EXCEEDED);
-            allReqsSucceeds = false;
-            continue;
-        }
-
-        hardware::hidl_vec<StreamBuffer> tmpRetBuffers(numBuffersRequested);
-        bool currentReqSucceeds = true;
-        std::vector<camera_stream_buffer_t> streamBuffers(numBuffersRequested);
-        std::vector<buffer_handle_t> newBuffers;
-        size_t numAllocatedBuffers = 0;
-        size_t numPushedInflightBuffers = 0;
-        for (size_t b = 0; b < numBuffersRequested; b++) {
-            camera_stream_buffer_t& sb = streamBuffers[b];
-            // Since this method can run concurrently with request thread
-            // We need to update the wait duration everytime we call getbuffer
-            nsecs_t waitDuration =  states.reqBufferIntf.getWaitDuration();
-            status_t res = outputStream->getBuffer(&sb, waitDuration);
-            if (res != OK) {
-                if (res == NO_INIT || res == DEAD_OBJECT) {
-                    ALOGV("%s: Can't get output buffer for stream %d: %s (%d)",
-                            __FUNCTION__, streamId, strerror(-res), res);
-                    bufRet.val.error(StreamBufferRequestError::STREAM_DISCONNECTED);
-                    states.sessionStatsBuilder.stopCounter(streamId);
-                } else {
-                    ALOGE("%s: Can't get output buffer for stream %d: %s (%d)",
-                            __FUNCTION__, streamId, strerror(-res), res);
-                    if (res == TIMED_OUT || res == NO_MEMORY) {
-                        bufRet.val.error(StreamBufferRequestError::NO_BUFFER_AVAILABLE);
-                    } else {
-                        bufRet.val.error(StreamBufferRequestError::UNKNOWN_ERROR);
-                    }
-                }
-                currentReqSucceeds = false;
-                break;
-            }
-            numAllocatedBuffers++;
-
-            buffer_handle_t *buffer = sb.buffer;
-            auto pair = states.bufferRecordsIntf.getBufferId(*buffer, streamId);
-            bool isNewBuffer = pair.first;
-            uint64_t bufferId = pair.second;
-            StreamBuffer& hBuf = tmpRetBuffers[b];
-
-            hBuf.streamId = streamId;
-            hBuf.bufferId = bufferId;
-            hBuf.buffer = (isNewBuffer) ? *buffer : nullptr;
-            hBuf.status = BufferStatus::OK;
-            hBuf.releaseFence = nullptr;
-            if (isNewBuffer) {
-                newBuffers.push_back(*buffer);
-            }
-
-            native_handle_t *acquireFence = nullptr;
-            if (sb.acquire_fence != -1) {
-                acquireFence = native_handle_create(1,0);
-                acquireFence->data[0] = sb.acquire_fence;
-            }
-            hBuf.acquireFence.setTo(acquireFence, /*shouldOwn*/true);
-            hBuf.releaseFence = nullptr;
-
-            res = states.bufferRecordsIntf.pushInflightRequestBuffer(bufferId, buffer, streamId);
-            if (res != OK) {
-                ALOGE("%s: Can't get register request buffers for stream %d: %s (%d)",
-                        __FUNCTION__, streamId, strerror(-res), res);
-                bufRet.val.error(StreamBufferRequestError::UNKNOWN_ERROR);
-                currentReqSucceeds = false;
-                break;
-            }
-            numPushedInflightBuffers++;
-        }
-        if (currentReqSucceeds) {
-            bufRet.val.buffers(std::move(tmpRetBuffers));
-            oneReqSucceeds = true;
-        } else {
-            allReqsSucceeds = false;
-            for (size_t b = 0; b < numPushedInflightBuffers; b++) {
-                StreamBuffer& hBuf = tmpRetBuffers[b];
-                buffer_handle_t* buffer;
-                status_t res = states.bufferRecordsIntf.popInflightRequestBuffer(
-                        hBuf.bufferId, &buffer);
-                if (res != OK) {
-                    SET_ERR("%s: popInflightRequestBuffer failed for stream %d: %s (%d)",
-                            __FUNCTION__, streamId, strerror(-res), res);
-                }
-            }
-            for (size_t b = 0; b < numAllocatedBuffers; b++) {
-                camera_stream_buffer_t& sb = streamBuffers[b];
-                sb.acquire_fence = -1;
-                sb.status = CAMERA_BUFFER_STATUS_ERROR;
-            }
-            returnOutputBuffers(states.useHalBufManager, /*listener*/nullptr,
-                    streamBuffers.data(), numAllocatedBuffers, /*timestamp*/0,
-                    /*readoutTimestamp*/0, /*requested*/false,
-                    /*requestTimeNs*/0, states.sessionStatsBuilder);
-            for (auto buf : newBuffers) {
-                states.bufferRecordsIntf.removeOneBufferCache(streamId, buf);
-            }
-        }
-    }
-
-    _hidl_cb(allReqsSucceeds ? BufferRequestStatus::OK :
-            oneReqSucceeds ? BufferRequestStatus::FAILED_PARTIAL :
-                             BufferRequestStatus::FAILED_UNKNOWN,
-            bufRets);
-    states.reqBufferIntf.endRequestBuffer();
-}
-
-void returnStreamBuffers(ReturnBufferStates& states,
-        const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) {
-    if (!states.useHalBufManager) {
-        ALOGE("%s: Camera %s does not support HAL buffer managerment",
-                __FUNCTION__, states.cameraId.string());
-        return;
-    }
-
-    for (const auto& buf : buffers) {
-        if (buf.bufferId == BUFFER_ID_NO_BUFFER) {
-            ALOGE("%s: cannot return a buffer without bufferId", __FUNCTION__);
-            continue;
-        }
-
-        buffer_handle_t* buffer;
-        status_t res = states.bufferRecordsIntf.popInflightRequestBuffer(buf.bufferId, &buffer);
-
-        if (res != OK) {
-            ALOGE("%s: cannot find in-flight buffer %" PRIu64 " for stream %d",
-                    __FUNCTION__, buf.bufferId, buf.streamId);
-            continue;
-        }
-
-        camera_stream_buffer_t streamBuffer;
-        streamBuffer.buffer = buffer;
-        streamBuffer.status = CAMERA_BUFFER_STATUS_ERROR;
-        streamBuffer.acquire_fence = -1;
-        streamBuffer.release_fence = -1;
-
-        if (buf.releaseFence == nullptr) {
-            streamBuffer.release_fence = -1;
-        } else if (buf.releaseFence->numFds == 1) {
-            streamBuffer.release_fence = dup(buf.releaseFence->data[0]);
-        } else {
-            ALOGE("%s: Invalid release fence, fd count is %d, not 1",
-                    __FUNCTION__, buf.releaseFence->numFds);
-            continue;
-        }
-
-        sp<Camera3StreamInterface> stream = states.outputStreams.get(buf.streamId);
-        if (stream == nullptr) {
-            ALOGE("%s: Output stream id %d not found!", __FUNCTION__, buf.streamId);
-            continue;
-        }
-        streamBuffer.stream = stream->asHalStream();
-        returnOutputBuffers(states.useHalBufManager, /*listener*/nullptr,
-                &streamBuffer, /*size*/1, /*timestamp*/ 0, /*readoutTimestamp*/0,
-                /*requested*/false, /*requestTimeNs*/0, states.sessionStatsBuilder);
-    }
-}
-
 void flushInflightRequests(FlushInflightReqStates& states) {
     ATRACE_CALL();
     { // First return buffers cached in inFlightMap
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.h b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
index 51899ee..4d1eb75 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
@@ -40,8 +40,6 @@
 
 namespace android {
 
-using ResultMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
-
 namespace camera3 {
 
     /**
@@ -97,7 +95,6 @@
         const metadata_vendor_id_t vendorTagId;
         const CameraMetadata& deviceInfo;
         const std::unordered_map<std::string, CameraMetadata>& physicalDeviceInfoMap;
-        std::unique_ptr<ResultMetadataQueue>& fmq;
         std::unordered_map<std::string, camera3::DistortionMapper>& distortionMappers;
         std::unordered_map<std::string, camera3::ZoomRatioMapper>& zoomRatioMappers;
         std::unordered_map<std::string, camera3::RotateAndCropMapper>& rotateAndCropMappers;
@@ -112,20 +109,8 @@
         bool legacyClient;
     };
 
-    // Handle one capture result. Assume callers hold the lock to serialize all
-    // processCaptureResult calls
-    void processOneCaptureResultLocked(
-            CaptureOutputStates& states,
-            const hardware::camera::device::V3_2::CaptureResult& result,
-            const hardware::hidl_vec<
-                    hardware::camera::device::V3_4::PhysicalCameraMetadata> physicalCameraMetadata);
-
-    // Handle one notify message
-    void notify(CaptureOutputStates& states,
-            const hardware::camera::device::V3_2::NotifyMsg& msg,
-            bool hasReadoutTime = false, uint64_t readoutTime = 0LL);
-    void notify(CaptureOutputStates& states,
-            const hardware::camera::device::V3_8::NotifyMsg& msg);
+    void processCaptureResult(CaptureOutputStates& states, const camera_capture_result *result);
+    void notify(CaptureOutputStates& states, const camera_notify_msg *msg);
 
     struct RequestBufferStates {
         const String8& cameraId;
@@ -138,10 +123,6 @@
         RequestBufferInterface& reqBufferIntf;
     };
 
-    void requestStreamBuffers(RequestBufferStates& states,
-            const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
-            hardware::camera::device::V3_5::ICameraDeviceCallback::requestStreamBuffers_cb _hidl_cb);
-
     struct ReturnBufferStates {
         const String8& cameraId;
         const bool useHalBufManager;
@@ -150,9 +131,6 @@
         BufferRecordsInterface& bufferRecordsIntf;
     };
 
-    void returnStreamBuffers(ReturnBufferStates& states,
-            const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers);
-
     struct FlushInflightReqStates {
         const String8& cameraId;
         std::mutex& inflightLock;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h b/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h
new file mode 100644
index 0000000..7dc8e10
--- /dev/null
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA3_OUTPUT_TEMPLUTILS_H
+#define ANDROID_SERVERS_CAMERA3_OUTPUT_TEMPLUTILS_H
+
+#include <inttypes.h>
+
+#include <utils/Log.h>
+#include <utils/SortedVector.h>
+#include <utils/Trace.h>
+
+#include <aidl/android/hardware/common/NativeHandle.h>
+#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
+
+#include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
+
+#include <camera/CameraUtils.h>
+#include <camera_metadata_hidden.h>
+
+#include "device3/Camera3OutputUtils.h"
+
+#include "system/camera_metadata.h"
+
+using namespace android::camera3;
+using namespace android::hardware::camera;
+
+namespace android {
+namespace camera3 {
+
+template <class BufferStatusType>
+camera_buffer_status_t mapBufferStatus(BufferStatusType status) {
+    switch (status) {
+        case BufferStatusType::OK: return CAMERA_BUFFER_STATUS_OK;
+        case BufferStatusType::ERROR: return CAMERA_BUFFER_STATUS_ERROR;
+    }
+    return CAMERA_BUFFER_STATUS_ERROR;
+}
+
+inline void readBufferFromVec(hardware::hidl_vec<uint8_t> &dst,
+        const hardware::hidl_vec<uint8_t> &src) {
+    // Not cloning here since that will be done in processCaptureResult whil
+    // assigning to CameraMetadata.
+    dst.setToExternal(const_cast<uint8_t *>(src.data()), src.size());
+}
+
+inline void readBufferFromVec(std::vector<uint8_t> &dst, const std::vector<uint8_t> &src) {
+    // TODO: Check if we're really supposed to copy
+    dst = src;
+}
+// Reading one camera metadata from result argument via fmq or from the result
+// Assuming the fmq is protected by a lock already
+template <class FmqType, class MetadataType>
+status_t readOneCameraMetadataLockedT(
+        std::unique_ptr<FmqType>& fmq,
+        uint64_t fmqResultSize,
+        MetadataType& resultMetadata,
+        const MetadataType& result) {
+    if (fmqResultSize > 0) {
+        resultMetadata.resize(fmqResultSize);
+        if (fmq == nullptr) {
+            return NO_MEMORY; // logged in initialize()
+        }
+        if (!fmq->read(resultMetadata.data(), fmqResultSize)) {
+            ALOGE("%s: Cannot read camera metadata from fmq, size = %" PRIu64,
+                    __FUNCTION__, fmqResultSize);
+            return INVALID_OPERATION;
+        }
+    } else {
+        readBufferFromVec(resultMetadata, result);
+    }
+
+    if (resultMetadata.size() != 0) {
+        status_t res;
+        const camera_metadata_t* metadata =
+                reinterpret_cast<const camera_metadata_t*>(resultMetadata.data());
+        size_t expected_metadata_size = resultMetadata.size();
+        if ((res = validate_camera_metadata_structure(metadata, &expected_metadata_size)) != OK) {
+            ALOGE("%s: Invalid camera metadata received by camera service from HAL: %s (%d)",
+                    __FUNCTION__, strerror(-res), res);
+            return INVALID_OPERATION;
+        }
+    }
+
+    return OK;
+}
+
+inline bool isHandleNull(const hardware::hidl_handle &handle) {
+    return handle == nullptr;
+}
+
+inline bool isHandleNull(const aidl::android::hardware::common::NativeHandle &handle) {
+    return (handle.fds.size() == 0) && (handle.ints.size() == 0);
+}
+
+inline size_t numFdsInHandle(const hardware::hidl_handle &handle) {
+    return handle->numFds;
+}
+
+inline size_t numFdsInHandle(const aidl::android::hardware::common::NativeHandle &handle) {
+    return handle.fds.size();
+}
+
+inline int32_t getHandleFirstFd(const hardware::hidl_handle &handle) {
+    if (handle->numFds != 1) {
+        return -1;
+    }
+    return handle->data[0];
+}
+
+inline int32_t getHandleFirstFd(const aidl::android::hardware::common::NativeHandle &handle) {
+    if (handle.fds.size() != 1) {
+        return -1;
+    }
+    return handle.fds[0].get();
+}
+
+template <class StatesType, class CaptureResultType, class PhysMetadataType, class MetadataType,
+        class FmqType, class BufferStatusType>
+void processOneCaptureResultLockedT(
+        StatesType& states,
+        const CaptureResultType& result,
+        const PhysMetadataType &physicalCameraMetadata) {
+    std::unique_ptr<FmqType>& fmq = states.fmq;
+    BufferRecordsInterface& bufferRecords = states.bufferRecordsIntf;
+    camera_capture_result r;
+    status_t res;
+    r.frame_number = result.frameNumber;
+
+    // Read and validate the result metadata.
+    MetadataType resultMetadata;
+    res = readOneCameraMetadataLockedT(
+            fmq, result.fmqResultSize,
+            resultMetadata, result.result);
+    if (res != OK) {
+        ALOGE("%s: Frame %d: Failed to read capture result metadata",
+                __FUNCTION__, result.frameNumber);
+        return;
+    }
+    r.result = reinterpret_cast<const camera_metadata_t*>(resultMetadata.data());
+
+    // Read and validate physical camera metadata
+    size_t physResultCount = physicalCameraMetadata.size();
+    std::vector<const char*> physCamIds(physResultCount);
+    std::vector<const camera_metadata_t *> phyCamMetadatas(physResultCount);
+    std::vector<MetadataType> physResultMetadata;
+    physResultMetadata.resize(physResultCount);
+    for (size_t i = 0; i < physicalCameraMetadata.size(); i++) {
+        res = readOneCameraMetadataLockedT(fmq, physicalCameraMetadata[i].fmqMetadataSize,
+                physResultMetadata[i], physicalCameraMetadata[i].metadata);
+        if (res != OK) {
+            ALOGE("%s: Frame %d: Failed to read capture result metadata for camera %s",
+                    __FUNCTION__, result.frameNumber,
+                    physicalCameraMetadata[i].physicalCameraId.c_str());
+            return;
+        }
+        physCamIds[i] = physicalCameraMetadata[i].physicalCameraId.c_str();
+        phyCamMetadatas[i] = reinterpret_cast<const camera_metadata_t*>(
+                physResultMetadata[i].data());
+    }
+    r.num_physcam_metadata = physResultCount;
+    r.physcam_ids = physCamIds.data();
+    r.physcam_metadata = phyCamMetadatas.data();
+
+    std::vector<camera_stream_buffer_t> outputBuffers(result.outputBuffers.size());
+    std::vector<buffer_handle_t> outputBufferHandles(result.outputBuffers.size());
+    for (size_t i = 0; i < result.outputBuffers.size(); i++) {
+        auto& bDst = outputBuffers[i];
+        const auto &bSrc = result.outputBuffers[i];
+
+        sp<Camera3StreamInterface> stream = states.outputStreams.get(bSrc.streamId);
+        if (stream == nullptr) {
+            ALOGE("%s: Frame %d: Buffer %zu: Invalid output stream id %d",
+                    __FUNCTION__, result.frameNumber, i, bSrc.streamId);
+            return;
+        }
+        bDst.stream = stream->asHalStream();
+
+        bool noBufferReturned = false;
+        buffer_handle_t *buffer = nullptr;
+        if (states.useHalBufManager) {
+            // This is suspicious most of the time but can be correct during flush where HAL
+            // has to return capture result before a buffer is requested
+            if (bSrc.bufferId == BUFFER_ID_NO_BUFFER) {
+                if (bSrc.status == BufferStatusType::OK) {
+                    ALOGE("%s: Frame %d: Buffer %zu: No bufferId for stream %d",
+                            __FUNCTION__, result.frameNumber, i, bSrc.streamId);
+                    // Still proceeds so other buffers can be returned
+                }
+                noBufferReturned = true;
+            }
+            if (noBufferReturned) {
+                res = OK;
+            } else {
+                res = bufferRecords.popInflightRequestBuffer(bSrc.bufferId, &buffer);
+            }
+        } else {
+            res = bufferRecords.popInflightBuffer(result.frameNumber, bSrc.streamId, &buffer);
+        }
+
+        if (res != OK) {
+            ALOGE("%s: Frame %d: Buffer %zu: No in-flight buffer for stream %d",
+                    __FUNCTION__, result.frameNumber, i, bSrc.streamId);
+            return;
+        }
+
+        bDst.buffer = buffer;
+        bDst.status = mapBufferStatus<BufferStatusType>(bSrc.status);
+        bDst.acquire_fence = -1;
+        if (isHandleNull(bSrc.releaseFence)) {
+            bDst.release_fence = -1;
+        } else if (numFdsInHandle(bSrc.releaseFence) == 1) {
+            if (noBufferReturned) {
+                ALOGE("%s: got releaseFence without output buffer!", __FUNCTION__);
+            }
+            bDst.release_fence = dup(getHandleFirstFd(bSrc.releaseFence));
+        } else {
+            ALOGE("%s: Frame %d: Invalid release fence for buffer %zu, fd count is %d, not 1",
+                    __FUNCTION__, result.frameNumber, i, (int)numFdsInHandle(bSrc.releaseFence));
+            return;
+        }
+    }
+    r.num_output_buffers = outputBuffers.size();
+    r.output_buffers = outputBuffers.data();
+
+    camera_stream_buffer_t inputBuffer;
+    if (result.inputBuffer.streamId == -1) {
+        r.input_buffer = nullptr;
+    } else {
+        if (states.inputStream->getId() != result.inputBuffer.streamId) {
+            ALOGE("%s: Frame %d: Invalid input stream id %d", __FUNCTION__,
+                    result.frameNumber, result.inputBuffer.streamId);
+            return;
+        }
+        inputBuffer.stream = states.inputStream->asHalStream();
+        buffer_handle_t *buffer;
+        res = bufferRecords.popInflightBuffer(result.frameNumber, result.inputBuffer.streamId,
+                &buffer);
+        if (res != OK) {
+            ALOGE("%s: Frame %d: Input buffer: No in-flight buffer for stream %d",
+                    __FUNCTION__, result.frameNumber, result.inputBuffer.streamId);
+            return;
+        }
+        inputBuffer.buffer = buffer;
+        inputBuffer.status = mapBufferStatus<BufferStatusType>(result.inputBuffer.status);
+        inputBuffer.acquire_fence = -1;
+        if (isHandleNull(result.inputBuffer.releaseFence)) {
+            inputBuffer.release_fence = -1;
+        } else if (numFdsInHandle(result.inputBuffer.releaseFence) == 1) {
+            inputBuffer.release_fence = dup(getHandleFirstFd(result.inputBuffer.releaseFence));
+        } else {
+            ALOGE("%s: Frame %d: Invalid release fence for input buffer, fd count is %d, not 1",
+                    __FUNCTION__, result.frameNumber,
+                    (int)numFdsInHandle(result.inputBuffer.releaseFence));
+            return;
+        }
+        r.input_buffer = &inputBuffer;
+    }
+
+    r.partial_result = result.partialResult;
+
+    processCaptureResult(states, &r);
+}
+
+template <class VecStreamBufferType>
+void returnStreamBuffersT(ReturnBufferStates& states,
+        const VecStreamBufferType& buffers) {
+    if (!states.useHalBufManager) {
+        ALOGE("%s: Camera %s does not support HAL buffer managerment",
+                __FUNCTION__, states.cameraId.string());
+        return;
+    }
+
+    for (const auto& buf : buffers) {
+        if (buf.bufferId == BUFFER_ID_NO_BUFFER) {
+            ALOGE("%s: cannot return a buffer without bufferId", __FUNCTION__);
+            continue;
+        }
+
+        buffer_handle_t* buffer;
+        status_t res = states.bufferRecordsIntf.popInflightRequestBuffer(buf.bufferId, &buffer);
+
+        if (res != OK) {
+            ALOGE("%s: cannot find in-flight buffer %" PRIu64 " for stream %d",
+                    __FUNCTION__, buf.bufferId, buf.streamId);
+            continue;
+        }
+
+        camera_stream_buffer_t streamBuffer;
+        streamBuffer.buffer = buffer;
+        streamBuffer.status = CAMERA_BUFFER_STATUS_ERROR;
+        streamBuffer.acquire_fence = -1;
+        streamBuffer.release_fence = -1;
+
+        if (isHandleNull(buf.releaseFence)) {
+            streamBuffer.release_fence = -1;
+        } else if (numFdsInHandle(buf.releaseFence) == 1) {
+            streamBuffer.release_fence = dup(getHandleFirstFd(buf.releaseFence));
+        } else {
+            ALOGE("%s: Invalid release fence, fd count is %d, not 1",
+                    __FUNCTION__, (int)numFdsInHandle(buf.releaseFence));
+            continue;
+        }
+
+        sp<Camera3StreamInterface> stream = states.outputStreams.get(buf.streamId);
+        if (stream == nullptr) {
+            ALOGE("%s: Output stream id %d not found!", __FUNCTION__, buf.streamId);
+            continue;
+        }
+        streamBuffer.stream = stream->asHalStream();
+        returnOutputBuffers(states.useHalBufManager, /*listener*/nullptr,
+                &streamBuffer, /*size*/1, /*timestamp*/ 0, /*readoutTimestamp*/0,
+                /*requested*/false, /*requestTimeNs*/0, states.sessionStatsBuilder);
+    }
+}
+
+} // camera3
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
new file mode 100644
index 0000000..7b7a2a2
--- /dev/null
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
@@ -0,0 +1,1893 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "HidlCamera3-Device"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+//#define LOG_NNDEBUG 0  // Per-frame verbose logging
+
+#ifdef LOG_NNDEBUG
+#define ALOGVV(...) ALOGV(__VA_ARGS__)
+#else
+#define ALOGVV(...) ((void)0)
+#endif
+
+// Convenience macro for transient errors
+#define CLOGE(fmt, ...) ALOGE("Camera %s: %s: " fmt, mId.string(), __FUNCTION__, \
+            ##__VA_ARGS__)
+
+// Convenience macros for transitioning to the error state
+#define SET_ERR(fmt, ...) setErrorState(   \
+    "%s: " fmt, __FUNCTION__,              \
+    ##__VA_ARGS__)
+#define SET_ERR_L(fmt, ...) setErrorStateLocked( \
+    "%s: " fmt, __FUNCTION__,                    \
+    ##__VA_ARGS__)
+
+
+#include <inttypes.h>
+
+#include <utility>
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include <utils/Timers.h>
+#include <cutils/properties.h>
+
+#include <android/hardware/camera/device/3.7/ICameraInjectionSession.h>
+#include <android/hardware/camera2/ICameraDeviceUser.h>
+
+#include "device3/hidl/HidlCamera3OutputUtils.h"
+#include "device3/hidl/HidlCamera3OfflineSession.h"
+#include "utils/SessionConfigurationUtils.h"
+#include "utils/TraceHFR.h"
+
+#include "../../common/hidl/HidlProviderInfo.h"
+#include "HidlCamera3Device.h"
+
+#include <algorithm>
+#include <tuple>
+
+using namespace android::camera3;
+using namespace android::hardware::camera;
+using namespace android::hardware::camera::device::V3_2;
+using android::hardware::camera::metadata::V3_6::CameraMetadataEnumAndroidSensorPixelMode;
+
+namespace android {
+
+CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap
+HidlCamera3Device::mapToHidlDynamicProfile(int dynamicRangeProfile) {
+    return static_cast<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap>(
+            dynamicRangeProfile);
+}
+
+hardware::graphics::common::V1_0::PixelFormat HidlCamera3Device::mapToPixelFormat(
+        int frameworkFormat) {
+    return (hardware::graphics::common::V1_0::PixelFormat) frameworkFormat;
+}
+
+DataspaceFlags HidlCamera3Device::mapToHidlDataspace(
+        android_dataspace dataSpace) {
+    return dataSpace;
+}
+
+BufferUsageFlags HidlCamera3Device::mapToConsumerUsage(
+        uint64_t usage) {
+    return usage;
+}
+
+StreamRotation HidlCamera3Device::mapToStreamRotation(camera_stream_rotation_t rotation) {
+    switch (rotation) {
+        case CAMERA_STREAM_ROTATION_0:
+            return StreamRotation::ROTATION_0;
+        case CAMERA_STREAM_ROTATION_90:
+            return StreamRotation::ROTATION_90;
+        case CAMERA_STREAM_ROTATION_180:
+            return StreamRotation::ROTATION_180;
+        case CAMERA_STREAM_ROTATION_270:
+            return StreamRotation::ROTATION_270;
+    }
+    ALOGE("%s: Unknown stream rotation %d", __FUNCTION__, rotation);
+    return StreamRotation::ROTATION_0;
+}
+
+status_t HidlCamera3Device::mapToStreamConfigurationMode(
+        camera_stream_configuration_mode_t operationMode, StreamConfigurationMode *mode) {
+    if (mode == nullptr) return BAD_VALUE;
+    if (operationMode < CAMERA_VENDOR_STREAM_CONFIGURATION_MODE_START) {
+        switch(operationMode) {
+            case CAMERA_STREAM_CONFIGURATION_NORMAL_MODE:
+                *mode = StreamConfigurationMode::NORMAL_MODE;
+                break;
+            case CAMERA_STREAM_CONFIGURATION_CONSTRAINED_HIGH_SPEED_MODE:
+                *mode = StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE;
+                break;
+            default:
+                ALOGE("%s: Unknown stream configuration mode %d", __FUNCTION__, operationMode);
+                return BAD_VALUE;
+        }
+    } else {
+        *mode = static_cast<StreamConfigurationMode>(operationMode);
+    }
+    return OK;
+}
+
+int HidlCamera3Device::mapToFrameworkFormat(
+        hardware::graphics::common::V1_0::PixelFormat pixelFormat) {
+    return static_cast<uint32_t>(pixelFormat);
+}
+
+android_dataspace HidlCamera3Device::mapToFrameworkDataspace(
+        DataspaceFlags dataSpace) {
+    return static_cast<android_dataspace>(dataSpace);
+}
+
+uint64_t HidlCamera3Device::mapConsumerToFrameworkUsage(
+        BufferUsageFlags usage) {
+    return usage;
+}
+
+uint64_t HidlCamera3Device::mapProducerToFrameworkUsage(
+        BufferUsageFlags usage) {
+    return usage;
+}
+
+status_t HidlCamera3Device::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;
+
+    sp<ICameraDeviceSession> session;
+    ATRACE_BEGIN("CameraHal::openSession");
+    status_t res = manager->openHidlSession(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;
+    }
+
+    res = manager->getCameraCharacteristics(mId.string(), mOverrideForPerfClass, &mDeviceInfo);
+    if (res != OK) {
+        SET_ERR_L("Could not retrieve camera characteristics: %s (%d)", strerror(-res), res);
+        session->close();
+        return res;
+    }
+    mSupportNativeZoomRatio = manager->supportNativeZoomRatio(mId.string());
+
+    std::vector<std::string> physicalCameraIds;
+    bool isLogical = manager->isLogicalCamera(mId.string(), &physicalCameraIds);
+    if (isLogical) {
+        for (auto& physicalId : physicalCameraIds) {
+            // Do not override characteristics for physical cameras
+            res = manager->getCameraCharacteristics(
+                    physicalId, /*overrideForPerfClass*/false, &mPhysicalDeviceInfoMap[physicalId]);
+            if (res != OK) {
+                SET_ERR_L("Could not retrieve camera %s characteristics: %s (%d)",
+                        physicalId.c_str(), strerror(-res), res);
+                session->close();
+                return res;
+            }
+
+            bool usePrecorrectArray =
+                    DistortionMapper::isDistortionSupported(mPhysicalDeviceInfoMap[physicalId]);
+            if (usePrecorrectArray) {
+                res = mDistortionMappers[physicalId].setupStaticInfo(
+                        mPhysicalDeviceInfoMap[physicalId]);
+                if (res != OK) {
+                    SET_ERR_L("Unable to read camera %s's calibration fields for distortion "
+                            "correction", physicalId.c_str());
+                    session->close();
+                    return res;
+                }
+            }
+
+            mZoomRatioMappers[physicalId] = ZoomRatioMapper(
+                    &mPhysicalDeviceInfoMap[physicalId],
+                    mSupportNativeZoomRatio, usePrecorrectArray);
+
+            if (SessionConfigurationUtils::isUltraHighResolutionSensor(
+                    mPhysicalDeviceInfoMap[physicalId])) {
+                mUHRCropAndMeteringRegionMappers[physicalId] =
+                        UHRCropAndMeteringRegionMapper(mPhysicalDeviceInfoMap[physicalId],
+                                usePrecorrectArray);
+            }
+        }
+    }
+
+    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 (const auto& iface : interfaceChain) {
+                    ALOGV("  %s", iface.c_str());
+                }
+            });
+    }
+
+    camera_metadata_entry bufMgrMode =
+            mDeviceInfo.find(ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION);
+    if (bufMgrMode.count > 0) {
+         mUseHalBufManager = (bufMgrMode.data.u8[0] ==
+            ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
+    }
+
+    camera_metadata_entry_t capabilities = mDeviceInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+    for (size_t i = 0; i < capabilities.count; i++) {
+        uint8_t capability = capabilities.data.u8[i];
+        if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING) {
+            mSupportOfflineProcessing = true;
+        }
+    }
+
+    mInterface = new HidlHalInterface(session, queue, mUseHalBufManager, mSupportOfflineProcessing);
+
+    std::string providerType;
+    mVendorTagId = manager->getProviderTagIdLocked(mId.string());
+    mTagMonitor.initialize(mVendorTagId);
+    if (!monitorTags.isEmpty()) {
+        mTagMonitor.parseTagsToMonitor(String8(monitorTags));
+    }
+
+    // Metadata tags needs fixup for monochrome camera device version less
+    // than 3.5.
+    hardware::hidl_version maxVersion{0,0};
+    res = manager->getHighestSupportedVersion(mId.string(), &maxVersion);
+    if (res != OK) {
+        ALOGE("%s: Error in getting camera device version id: %s (%d)",
+                __FUNCTION__, strerror(-res), res);
+        return res;
+    }
+    int deviceVersion = HARDWARE_DEVICE_API_VERSION(
+            maxVersion.get_major(), maxVersion.get_minor());
+
+    bool isMonochrome = false;
+    for (size_t i = 0; i < capabilities.count; i++) {
+        uint8_t capability = capabilities.data.u8[i];
+        if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) {
+            isMonochrome = true;
+        }
+    }
+    mNeedFixupMonochromeTags = (isMonochrome && deviceVersion < CAMERA_DEVICE_API_VERSION_3_5);
+
+    return initializeCommonLocked();
+}
+
+hardware::Return<void> HidlCamera3Device::requestStreamBuffers(
+        const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
+        requestStreamBuffers_cb _hidl_cb) {
+    RequestBufferStates states {
+        mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder,
+        *this, *mInterface, *this};
+    camera3::requestStreamBuffers(states, bufReqs, _hidl_cb);
+    return hardware::Void();
+}
+
+hardware::Return<void> HidlCamera3Device::returnStreamBuffers(
+        const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) {
+    ReturnBufferStates states {
+        mId, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder, *mInterface};
+    camera3::returnStreamBuffers(states, buffers);
+    return hardware::Void();
+}
+
+hardware::Return<void> HidlCamera3Device::processCaptureResult_3_4(
+        const hardware::hidl_vec<
+                hardware::camera::device::V3_4::CaptureResult>& results) {
+    // Ideally we should grab mLock, but that can lead to deadlock, and
+    // it's not super important to get up to date value of mStatus for this
+    // warning print, hence skipping the lock here
+    if (mStatus == STATUS_ERROR) {
+        // Per API contract, HAL should act as closed after device error
+        // But mStatus can be set to error by framework as well, so just log
+        // a warning here.
+        ALOGW("%s: received capture result in error state.", __FUNCTION__);
+    }
+
+    sp<NotificationListener> listener;
+    {
+        std::lock_guard<std::mutex> l(mOutputLock);
+        listener = mListener.promote();
+    }
+
+    if (mProcessCaptureResultLock.tryLock() != OK) {
+        // This should never happen; it indicates a wrong client implementation
+        // that doesn't follow the contract. But, we can be tolerant here.
+        ALOGE("%s: callback overlapped! waiting 1s...",
+                __FUNCTION__);
+        if (mProcessCaptureResultLock.timedLock(1000000000 /* 1s */) != OK) {
+            ALOGE("%s: cannot acquire lock in 1s, dropping results",
+                    __FUNCTION__);
+            // really don't know what to do, so bail out.
+            return hardware::Void();
+        }
+    }
+    HidlCaptureOutputStates states {
+       {
+        mId,
+        mInFlightLock, mLastCompletedRegularFrameNumber,
+        mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+        mInFlightMap, mOutputLock,  mResultQueue, mResultSignal,
+        mNextShutterFrameNumber,
+        mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+        mNextResultFrameNumber,
+        mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+        mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+        mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+        mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+        mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
+        *mInterface, mLegacyClient}, mResultMetadataQueue
+    };
+
+    //HidlCaptureOutputStates hidlStates {
+    //}
+
+    for (const auto& result : results) {
+        processOneCaptureResultLocked(states, result.v3_2, result.physicalCameraMetadata);
+    }
+    mProcessCaptureResultLock.unlock();
+    return hardware::Void();
+}
+
+// Only one processCaptureResult should be called at a time, so
+// the locks won't block. The locks are present here simply to enforce this.
+hardware::Return<void> HidlCamera3Device::processCaptureResult(
+        const hardware::hidl_vec<
+                hardware::camera::device::V3_2::CaptureResult>& results) {
+    hardware::hidl_vec<hardware::camera::device::V3_4::PhysicalCameraMetadata> noPhysMetadata;
+
+    // Ideally we should grab mLock, but that can lead to deadlock, and
+    // it's not super important to get up to date value of mStatus for this
+    // warning print, hence skipping the lock here
+    if (mStatus == STATUS_ERROR) {
+        // Per API contract, HAL should act as closed after device error
+        // But mStatus can be set to error by framework as well, so just log
+        // a warning here.
+        ALOGW("%s: received capture result in error state.", __FUNCTION__);
+    }
+
+    sp<NotificationListener> listener;
+    {
+        std::lock_guard<std::mutex> l(mOutputLock);
+        listener = mListener.promote();
+    }
+
+    if (mProcessCaptureResultLock.tryLock() != OK) {
+        // This should never happen; it indicates a wrong client implementation
+        // that doesn't follow the contract. But, we can be tolerant here.
+        ALOGE("%s: callback overlapped! waiting 1s...",
+                __FUNCTION__);
+        if (mProcessCaptureResultLock.timedLock(1000000000 /* 1s */) != OK) {
+            ALOGE("%s: cannot acquire lock in 1s, dropping results",
+                    __FUNCTION__);
+            // really don't know what to do, so bail out.
+            return hardware::Void();
+        }
+    }
+
+    HidlCaptureOutputStates states {
+      {mId,
+        mInFlightLock, mLastCompletedRegularFrameNumber,
+        mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+        mInFlightMap, mOutputLock,  mResultQueue, mResultSignal,
+        mNextShutterFrameNumber,
+        mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+        mNextResultFrameNumber,
+        mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+        mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+        mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+        mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+        mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
+        *mInterface, mLegacyClient}, mResultMetadataQueue
+    };
+
+    for (const auto& result : results) {
+        processOneCaptureResultLocked(states, result, noPhysMetadata);
+    }
+    mProcessCaptureResultLock.unlock();
+    return hardware::Void();
+}
+
+hardware::Return<void> HidlCamera3Device::notify(
+        const hardware::hidl_vec<hardware::camera::device::V3_2::NotifyMsg>& msgs) {
+    return notifyHelper<hardware::camera::device::V3_2::NotifyMsg>(msgs);
+}
+
+hardware::Return<void> HidlCamera3Device::notify_3_8(
+        const hardware::hidl_vec<hardware::camera::device::V3_8::NotifyMsg>& msgs) {
+    return notifyHelper<hardware::camera::device::V3_8::NotifyMsg>(msgs);
+}
+
+template<typename NotifyMsgType>
+hardware::Return<void> HidlCamera3Device::notifyHelper(
+        const hardware::hidl_vec<NotifyMsgType>& msgs) {
+    // Ideally we should grab mLock, but that can lead to deadlock, and
+    // it's not super important to get up to date value of mStatus for this
+    // warning print, hence skipping the lock here
+    if (mStatus == STATUS_ERROR) {
+        // Per API contract, HAL should act as closed after device error
+        // But mStatus can be set to error by framework as well, so just log
+        // a warning here.
+        ALOGW("%s: received notify message in error state.", __FUNCTION__);
+    }
+
+    sp<NotificationListener> listener;
+    {
+        std::lock_guard<std::mutex> l(mOutputLock);
+        listener = mListener.promote();
+    }
+
+    HidlCaptureOutputStates states {
+      {mId,
+        mInFlightLock, mLastCompletedRegularFrameNumber,
+        mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+        mInFlightMap, mOutputLock,  mResultQueue, mResultSignal,
+        mNextShutterFrameNumber,
+        mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+        mNextResultFrameNumber,
+        mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+        mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+        mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+        mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+        mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
+        *mInterface, mLegacyClient}, mResultMetadataQueue
+    };
+    for (const auto& msg : msgs) {
+        camera3::notify(states, msg);
+    }
+    return hardware::Void();
+}
+
+status_t HidlCamera3Device::switchToOffline(
+        const std::vector<int32_t>& streamsToKeep,
+        /*out*/ sp<CameraOfflineSessionBase>* session) {
+    ATRACE_CALL();
+    if (session == nullptr) {
+        ALOGE("%s: session must not be null", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock il(mInterfaceLock);
+
+    bool hasInputStream = mInputStream != nullptr;
+    int32_t inputStreamId = hasInputStream ? mInputStream->getId() : -1;
+    bool inputStreamSupportsOffline = hasInputStream ?
+            mInputStream->getOfflineProcessingSupport() : false;
+    auto outputStreamIds = mOutputStreams.getStreamIds();
+    auto streamIds = outputStreamIds;
+    if (hasInputStream) {
+        streamIds.push_back(mInputStream->getId());
+    }
+
+    // Check all streams in streamsToKeep supports offline mode
+    for (auto id : streamsToKeep) {
+        if (std::find(streamIds.begin(), streamIds.end(), id) == streamIds.end()) {
+            ALOGE("%s: Unknown stream ID %d", __FUNCTION__, id);
+            return BAD_VALUE;
+        } else if (id == inputStreamId) {
+            if (!inputStreamSupportsOffline) {
+                ALOGE("%s: input stream %d cannot be switched to offline",
+                        __FUNCTION__, id);
+                return BAD_VALUE;
+            }
+        } else {
+            sp<camera3::Camera3OutputStreamInterface> stream = mOutputStreams.get(id);
+            if (!stream->getOfflineProcessingSupport()) {
+                ALOGE("%s: output stream %d cannot be switched to offline",
+                        __FUNCTION__, id);
+                return BAD_VALUE;
+            }
+        }
+    }
+    // TODO: block surface sharing and surface group streams until we can support them
+
+    // Stop repeating request, wait until all remaining requests are submitted, then call into
+    // HAL switchToOffline
+    hardware::camera::device::V3_6::CameraOfflineSessionInfo offlineSessionInfo;
+    sp<hardware::camera::device::V3_6::ICameraOfflineSession> offlineSession;
+    camera3::BufferRecords bufferRecords;
+    status_t ret = static_cast<HidlRequestThread *>(mRequestThread.get())->switchToOffline(
+            streamsToKeep, &offlineSessionInfo, &offlineSession, &bufferRecords);
+
+    if (ret != OK) {
+        SET_ERR("Switch to offline failed: %s (%d)", strerror(-ret), ret);
+        return ret;
+    }
+
+    bool succ = mRequestBufferSM.onSwitchToOfflineSuccess();
+    if (!succ) {
+        SET_ERR("HAL must not be calling requestStreamBuffers call");
+        // TODO: block ALL callbacks from HAL till app configured new streams?
+        return UNKNOWN_ERROR;
+    }
+
+    // Verify offlineSessionInfo
+    std::vector<int32_t> offlineStreamIds;
+    offlineStreamIds.reserve(offlineSessionInfo.offlineStreams.size());
+    for (auto offlineStream : offlineSessionInfo.offlineStreams) {
+        // verify stream IDs
+        int32_t id = offlineStream.id;
+        if (std::find(streamIds.begin(), streamIds.end(), id) == streamIds.end()) {
+            SET_ERR("stream ID %d not found!", id);
+            return UNKNOWN_ERROR;
+        }
+
+        // When not using HAL buf manager, only allow streams requested by app to be preserved
+        if (!mUseHalBufManager) {
+            if (std::find(streamsToKeep.begin(), streamsToKeep.end(), id) == streamsToKeep.end()) {
+                SET_ERR("stream ID %d must not be switched to offline!", id);
+                return UNKNOWN_ERROR;
+            }
+        }
+
+        offlineStreamIds.push_back(id);
+        sp<Camera3StreamInterface> stream = (id == inputStreamId) ?
+                static_cast<sp<Camera3StreamInterface>>(mInputStream) :
+                static_cast<sp<Camera3StreamInterface>>(mOutputStreams.get(id));
+        // Verify number of outstanding buffers
+        if (stream->getOutstandingBuffersCount() != offlineStream.numOutstandingBuffers) {
+            SET_ERR("Offline stream %d # of remaining buffer mismatch: (%zu,%d) (service/HAL)",
+                    id, stream->getOutstandingBuffersCount(), offlineStream.numOutstandingBuffers);
+            return UNKNOWN_ERROR;
+        }
+    }
+
+    // Verify all streams to be deleted don't have any outstanding buffers
+    if (hasInputStream && std::find(offlineStreamIds.begin(), offlineStreamIds.end(),
+                inputStreamId) == offlineStreamIds.end()) {
+        if (mInputStream->hasOutstandingBuffers()) {
+            SET_ERR("Input stream %d still has %zu outstanding buffer!",
+                    inputStreamId, mInputStream->getOutstandingBuffersCount());
+            return UNKNOWN_ERROR;
+        }
+    }
+
+    for (const auto& outStreamId : outputStreamIds) {
+        if (std::find(offlineStreamIds.begin(), offlineStreamIds.end(),
+                outStreamId) == offlineStreamIds.end()) {
+            auto outStream = mOutputStreams.get(outStreamId);
+            if (outStream->hasOutstandingBuffers()) {
+                SET_ERR("Output stream %d still has %zu outstanding buffer!",
+                        outStreamId, outStream->getOutstandingBuffersCount());
+                return UNKNOWN_ERROR;
+            }
+        }
+    }
+
+    InFlightRequestMap offlineReqs;
+    // Verify inflight requests and their pending buffers
+    {
+        std::lock_guard<std::mutex> l(mInFlightLock);
+        for (auto offlineReq : offlineSessionInfo.offlineRequests) {
+            int idx = mInFlightMap.indexOfKey(offlineReq.frameNumber);
+            if (idx == NAME_NOT_FOUND) {
+                SET_ERR("Offline request frame number %d not found!", offlineReq.frameNumber);
+                return UNKNOWN_ERROR;
+            }
+
+            const auto& inflightReq = mInFlightMap.valueAt(idx);
+            // TODO: check specific stream IDs
+            size_t numBuffersLeft = static_cast<size_t>(inflightReq.numBuffersLeft);
+            if (numBuffersLeft != offlineReq.pendingStreams.size()) {
+                SET_ERR("Offline request # of remaining buffer mismatch: (%d,%d) (service/HAL)",
+                        inflightReq.numBuffersLeft, offlineReq.pendingStreams.size());
+                return UNKNOWN_ERROR;
+            }
+            offlineReqs.add(offlineReq.frameNumber, inflightReq);
+        }
+    }
+
+    // Create Camera3OfflineSession and transfer object ownership
+    //   (streams, inflight requests, buffer caches)
+    camera3::StreamSet offlineStreamSet;
+    sp<camera3::Camera3Stream> inputStream;
+    for (auto offlineStream : offlineSessionInfo.offlineStreams) {
+        int32_t id = offlineStream.id;
+        if (mInputStream != nullptr && id == mInputStream->getId()) {
+            inputStream = mInputStream;
+        } else {
+            offlineStreamSet.add(id, mOutputStreams.get(id));
+        }
+    }
+
+    // TODO: check if we need to lock before copying states
+    //       though technically no other thread should be talking to Camera3Device at this point
+    Camera3OfflineStates offlineStates(
+            mTagMonitor, mVendorTagId, mUseHalBufManager, mNeedFixupMonochromeTags,
+            mUsePartialResult, mNumPartialResults, mLastCompletedRegularFrameNumber,
+            mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+            mNextResultFrameNumber, mNextReprocessResultFrameNumber,
+            mNextZslStillResultFrameNumber, mNextShutterFrameNumber,
+            mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+            mDeviceInfo, mPhysicalDeviceInfoMap, mDistortionMappers,
+            mZoomRatioMappers, mRotateAndCropMappers);
+
+    *session = new HidlCamera3OfflineSession(mId, inputStream, offlineStreamSet,
+            std::move(bufferRecords), offlineReqs, offlineStates, offlineSession);
+
+    // Delete all streams that has been transferred to offline session
+    Mutex::Autolock l(mLock);
+    for (auto offlineStream : offlineSessionInfo.offlineStreams) {
+        int32_t id = offlineStream.id;
+        if (mInputStream != nullptr && id == mInputStream->getId()) {
+            mInputStream.clear();
+        } else {
+            mOutputStreams.remove(id);
+        }
+    }
+
+    // disconnect all other streams and switch to UNCONFIGURED state
+    if (mInputStream != nullptr) {
+        ret = mInputStream->disconnect();
+        if (ret != OK) {
+            SET_ERR_L("disconnect input stream failed!");
+            return UNKNOWN_ERROR;
+        }
+    }
+
+    for (auto streamId : mOutputStreams.getStreamIds()) {
+        sp<Camera3StreamInterface> stream = mOutputStreams.get(streamId);
+        ret = stream->disconnect();
+        if (ret != OK) {
+            SET_ERR_L("disconnect output stream %d failed!", streamId);
+            return UNKNOWN_ERROR;
+        }
+    }
+
+    mInputStream.clear();
+    mOutputStreams.clear();
+    mNeedConfig = true;
+    internalUpdateStatusLocked(STATUS_UNCONFIGURED);
+    mOperatingMode = NO_MODE;
+    mIsConstrainedHighSpeedConfiguration = false;
+    mRequestThread->clearPreviousRequest();
+
+    return OK;
+    // TO be done by CameraDeviceClient/Camera3OfflineSession
+    // register the offline client to camera service
+    // Setup result passthing threads etc
+    // Initialize offline session so HAL can start sending callback to it (result Fmq)
+    // TODO: check how many onIdle callback will be sent
+    // Java side to make sure the CameraCaptureSession is properly closed
+}
+
+sp<Camera3Device::RequestThread> HidlCamera3Device::createNewRequestThread(
+                wp<Camera3Device> parent, sp<camera3::StatusTracker> statusTracker,
+                sp<Camera3Device::HalInterface> interface,
+                const Vector<int32_t>& sessionParamKeys,
+                bool useHalBufManager,
+                bool supportCameraMute) {
+        return new HidlRequestThread(parent, statusTracker, interface, sessionParamKeys,
+                useHalBufManager, supportCameraMute);
+};
+
+sp<Camera3Device::Camera3DeviceInjectionMethods>
+HidlCamera3Device::createCamera3DeviceInjectionMethods(wp<Camera3Device> parent) {
+    return new HidlCamera3DeviceInjectionMethods(parent);
+}
+
+status_t HidlCamera3Device::injectionCameraInitialize(const String8 &injectedCamId,
+            sp<CameraProviderManager> manager) {
+        return (static_cast<HidlCamera3DeviceInjectionMethods *>(
+                mInjectionMethods.get()))->injectionInitialize(injectedCamId, manager, this);
+};
+
+
+HidlCamera3Device::HidlHalInterface::HidlHalInterface(
+            sp<device::V3_2::ICameraDeviceSession> &session,
+            std::shared_ptr<RequestMetadataQueue> queue,
+            bool useHalBufManager, bool supportOfflineProcessing) :
+        HalInterface(useHalBufManager, supportOfflineProcessing),
+        mHidlSession(session),
+        mRequestMetadataQueue(queue) {
+    // Check with hardware service manager if we can downcast these interfaces
+    // Somewhat expensive, so cache the results at startup
+    auto castResult_3_8 = device::V3_8::ICameraDeviceSession::castFrom(mHidlSession);
+    if (castResult_3_8.isOk()) {
+        mHidlSession_3_8 = castResult_3_8;
+    }
+    auto castResult_3_7 = device::V3_7::ICameraDeviceSession::castFrom(mHidlSession);
+    if (castResult_3_7.isOk()) {
+        mHidlSession_3_7 = castResult_3_7;
+    }
+    auto castResult_3_6 = device::V3_6::ICameraDeviceSession::castFrom(mHidlSession);
+    if (castResult_3_6.isOk()) {
+        mHidlSession_3_6 = castResult_3_6;
+    }
+    auto castResult_3_5 = device::V3_5::ICameraDeviceSession::castFrom(mHidlSession);
+    if (castResult_3_5.isOk()) {
+        mHidlSession_3_5 = castResult_3_5;
+    }
+    auto castResult_3_4 = device::V3_4::ICameraDeviceSession::castFrom(mHidlSession);
+    if (castResult_3_4.isOk()) {
+        mHidlSession_3_4 = castResult_3_4;
+    }
+    auto castResult_3_3 = device::V3_3::ICameraDeviceSession::castFrom(mHidlSession);
+    if (castResult_3_3.isOk()) {
+        mHidlSession_3_3 = castResult_3_3;
+    }
+}
+
+bool HidlCamera3Device::HidlHalInterface::valid() {
+    return (mHidlSession != nullptr);
+}
+
+void HidlCamera3Device::HidlHalInterface::clear() {
+    mHidlSession_3_8.clear();
+    mHidlSession_3_7.clear();
+    mHidlSession_3_6.clear();
+    mHidlSession_3_5.clear();
+    mHidlSession_3_4.clear();
+    mHidlSession_3_3.clear();
+    mHidlSession.clear();
+}
+
+status_t HidlCamera3Device::HidlHalInterface::constructDefaultRequestSettings(
+        camera_request_template_t templateId,
+        /*out*/ camera_metadata_t **requestTemplate) {
+    ATRACE_NAME("CameraHidlHal::constructDefaultRequestSettings");
+    if (!valid()) return INVALID_OPERATION;
+    status_t res = OK;
+
+    common::V1_0::Status status;
+
+    auto requestCallback = [&status, &requestTemplate]
+            (common::V1_0::Status s, const device::V3_2::CameraMetadata& request) {
+            status = s;
+            if (status == common::V1_0::Status::OK) {
+                const camera_metadata *r =
+                        reinterpret_cast<const camera_metadata_t*>(request.data());
+                size_t expectedSize = request.size();
+                int ret = validate_camera_metadata_structure(r, &expectedSize);
+                if (ret == OK || ret == CAMERA_METADATA_VALIDATION_SHIFTED) {
+                    *requestTemplate = clone_camera_metadata(r);
+                    if (*requestTemplate == nullptr) {
+                        ALOGE("%s: Unable to clone camera metadata received from HAL",
+                                __FUNCTION__);
+                        status = common::V1_0::Status::INTERNAL_ERROR;
+                    }
+                } else {
+                    ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
+                    status = common::V1_0::Status::INTERNAL_ERROR;
+                }
+            }
+        };
+    hardware::Return<void> err;
+    RequestTemplate id;
+    switch (templateId) {
+        case CAMERA_TEMPLATE_PREVIEW:
+            id = RequestTemplate::PREVIEW;
+            break;
+        case CAMERA_TEMPLATE_STILL_CAPTURE:
+            id = RequestTemplate::STILL_CAPTURE;
+            break;
+        case CAMERA_TEMPLATE_VIDEO_RECORD:
+            id = RequestTemplate::VIDEO_RECORD;
+            break;
+        case CAMERA_TEMPLATE_VIDEO_SNAPSHOT:
+            id = RequestTemplate::VIDEO_SNAPSHOT;
+            break;
+        case CAMERA_TEMPLATE_ZERO_SHUTTER_LAG:
+            id = RequestTemplate::ZERO_SHUTTER_LAG;
+            break;
+        case CAMERA_TEMPLATE_MANUAL:
+            id = RequestTemplate::MANUAL;
+            break;
+        default:
+            // Unknown template ID, or this HAL is too old to support it
+            return BAD_VALUE;
+    }
+    err = mHidlSession->constructDefaultRequestSettings(id, requestCallback);
+
+    if (!err.isOk()) {
+        ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+        res = DEAD_OBJECT;
+    } else {
+        res = HidlProviderInfo::mapToStatusT(status);
+    }
+
+    return res;
+}
+
+bool HidlCamera3Device::HidlHalInterface::isReconfigurationRequired(
+        CameraMetadata& oldSessionParams, CameraMetadata& newSessionParams) {
+    // We do reconfiguration by default;
+    bool ret = true;
+    if ((mHidlSession_3_5 != nullptr) && mIsReconfigurationQuerySupported) {
+        android::hardware::hidl_vec<uint8_t> oldParams, newParams;
+        camera_metadata_t* oldSessioMeta = const_cast<camera_metadata_t*>(
+                oldSessionParams.getAndLock());
+        camera_metadata_t* newSessioMeta = const_cast<camera_metadata_t*>(
+                newSessionParams.getAndLock());
+        oldParams.setToExternal(reinterpret_cast<uint8_t*>(oldSessioMeta),
+                get_camera_metadata_size(oldSessioMeta));
+        newParams.setToExternal(reinterpret_cast<uint8_t*>(newSessioMeta),
+                get_camera_metadata_size(newSessioMeta));
+        hardware::camera::common::V1_0::Status callStatus;
+        bool required;
+        auto hidlCb = [&callStatus, &required] (hardware::camera::common::V1_0::Status s,
+                bool requiredFlag) {
+            callStatus = s;
+            required = requiredFlag;
+        };
+        auto err = mHidlSession_3_5->isReconfigurationRequired(oldParams, newParams, hidlCb);
+        oldSessionParams.unlock(oldSessioMeta);
+        newSessionParams.unlock(newSessioMeta);
+        if (err.isOk()) {
+            switch (callStatus) {
+                case hardware::camera::common::V1_0::Status::OK:
+                    ret = required;
+                    break;
+                case hardware::camera::common::V1_0::Status::METHOD_NOT_SUPPORTED:
+                    mIsReconfigurationQuerySupported = false;
+                    ret = true;
+                    break;
+                default:
+                    ALOGV("%s: Reconfiguration query failed: %d", __FUNCTION__, callStatus);
+                    ret = true;
+            }
+        } else {
+            ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, err.description().c_str());
+            ret = true;
+        }
+    }
+
+    return ret;
+}
+
+status_t HidlCamera3Device::HidlHalInterface::configureStreams(
+        const camera_metadata_t *sessionParams,
+        camera_stream_configuration *config, const std::vector<uint32_t>& bufferSizes) {
+    ATRACE_NAME("CameraHal::configureStreams");
+    if (!valid()) return INVALID_OPERATION;
+    status_t res = OK;
+
+    if (config->input_is_multi_resolution && mHidlSession_3_7 == nullptr) {
+        ALOGE("%s: Camera device doesn't support multi-resolution input stream", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    // Convert stream config to HIDL
+    std::set<int> activeStreams;
+    device::V3_2::StreamConfiguration requestedConfiguration3_2;
+    device::V3_4::StreamConfiguration requestedConfiguration3_4;
+    device::V3_7::StreamConfiguration requestedConfiguration3_7;
+    device::V3_8::StreamConfiguration requestedConfiguration3_8;
+    requestedConfiguration3_2.streams.resize(config->num_streams);
+    requestedConfiguration3_4.streams.resize(config->num_streams);
+    requestedConfiguration3_7.streams.resize(config->num_streams);
+    requestedConfiguration3_8.streams.resize(config->num_streams);
+    for (size_t i = 0; i < config->num_streams; i++) {
+        device::V3_2::Stream &dst3_2 = requestedConfiguration3_2.streams[i];
+        device::V3_4::Stream &dst3_4 = requestedConfiguration3_4.streams[i];
+        device::V3_7::Stream &dst3_7 = requestedConfiguration3_7.streams[i];
+        device::V3_8::Stream &dst3_8 = requestedConfiguration3_8.streams[i];
+        camera3::camera_stream_t *src = config->streams[i];
+
+        Camera3Stream* cam3stream = Camera3Stream::cast(src);
+        cam3stream->setBufferFreedListener(this);
+        int streamId = cam3stream->getId();
+        StreamType streamType;
+        switch (src->stream_type) {
+            case CAMERA_STREAM_OUTPUT:
+                streamType = StreamType::OUTPUT;
+                break;
+            case CAMERA_STREAM_INPUT:
+                streamType = StreamType::INPUT;
+                break;
+            default:
+                ALOGE("%s: Stream %d: Unsupported stream type %d",
+                        __FUNCTION__, streamId, config->streams[i]->stream_type);
+                return BAD_VALUE;
+        }
+        dst3_2.id = streamId;
+        dst3_2.streamType = streamType;
+        dst3_2.width = src->width;
+        dst3_2.height = src->height;
+        dst3_2.usage = mapToConsumerUsage(cam3stream->getUsage());
+        dst3_2.rotation = mapToStreamRotation((camera_stream_rotation_t) src->rotation);
+        // For HidlSession version 3.5 or newer, the format and dataSpace sent
+        // to HAL are original, not the overridden ones.
+        if (mHidlSession_3_5 != nullptr) {
+            dst3_2.format = mapToPixelFormat(cam3stream->isFormatOverridden() ?
+                    cam3stream->getOriginalFormat() : src->format);
+            dst3_2.dataSpace = mapToHidlDataspace(cam3stream->isDataSpaceOverridden() ?
+                    cam3stream->getOriginalDataSpace() : src->data_space);
+        } else {
+            dst3_2.format = mapToPixelFormat(src->format);
+            dst3_2.dataSpace = mapToHidlDataspace(src->data_space);
+        }
+        dst3_4.v3_2 = dst3_2;
+        dst3_4.bufferSize = bufferSizes[i];
+        if (src->physical_camera_id != nullptr) {
+            dst3_4.physicalCameraId = src->physical_camera_id;
+        }
+        dst3_7.v3_4 = dst3_4;
+        dst3_7.groupId = cam3stream->getHalStreamGroupId();
+        dst3_7.sensorPixelModesUsed.resize(src->sensor_pixel_modes_used.size());
+        size_t j = 0;
+        for (int mode : src->sensor_pixel_modes_used) {
+            dst3_7.sensorPixelModesUsed[j++] =
+                    static_cast<CameraMetadataEnumAndroidSensorPixelMode>(mode);
+        }
+        if ((src->dynamic_range_profile !=
+                    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) &&
+                (mHidlSession_3_8 == nullptr)) {
+            ALOGE("%s: Camera device doesn't support non-standard dynamic range profiles: %d",
+                    __FUNCTION__, src->dynamic_range_profile);
+            return BAD_VALUE;
+        }
+        dst3_8.v3_7 = dst3_7;
+        dst3_8.dynamicRangeProfile = mapToHidlDynamicProfile(src->dynamic_range_profile);
+        activeStreams.insert(streamId);
+        // Create Buffer ID map if necessary
+        mBufferRecords.tryCreateBufferCache(streamId);
+    }
+    // remove BufferIdMap for deleted streams
+    mBufferRecords.removeInactiveBufferCaches(activeStreams);
+
+    StreamConfigurationMode operationMode;
+    res = mapToStreamConfigurationMode(
+            (camera_stream_configuration_mode_t) config->operation_mode,
+            /*out*/ &operationMode);
+    if (res != OK) {
+        return res;
+    }
+    requestedConfiguration3_2.operationMode = operationMode;
+    requestedConfiguration3_4.operationMode = operationMode;
+    requestedConfiguration3_7.operationMode = operationMode;
+    size_t sessionParamSize = get_camera_metadata_size(sessionParams);
+    requestedConfiguration3_4.sessionParams.setToExternal(
+            reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
+            sessionParamSize);
+    requestedConfiguration3_7.operationMode = operationMode;
+    requestedConfiguration3_7.sessionParams.setToExternal(
+            reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
+            sessionParamSize);
+    requestedConfiguration3_8.operationMode = operationMode;
+    requestedConfiguration3_8.sessionParams.setToExternal(
+            reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
+            sessionParamSize);
+
+    // Invoke configureStreams
+    device::V3_3::HalStreamConfiguration finalConfiguration;
+    device::V3_4::HalStreamConfiguration finalConfiguration3_4;
+    device::V3_6::HalStreamConfiguration finalConfiguration3_6;
+    common::V1_0::Status status;
+
+    auto configStream34Cb = [&status, &finalConfiguration3_4]
+            (common::V1_0::Status s, const device::V3_4::HalStreamConfiguration& halConfiguration) {
+                finalConfiguration3_4 = halConfiguration;
+                status = s;
+            };
+
+    auto configStream36Cb = [&status, &finalConfiguration3_6]
+            (common::V1_0::Status s, const device::V3_6::HalStreamConfiguration& halConfiguration) {
+                finalConfiguration3_6 = halConfiguration;
+                status = s;
+            };
+
+    auto postprocConfigStream34 = [&finalConfiguration, &finalConfiguration3_4]
+            (hardware::Return<void>& err) -> status_t {
+                if (!err.isOk()) {
+                    ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+                    return DEAD_OBJECT;
+                }
+                finalConfiguration.streams.resize(finalConfiguration3_4.streams.size());
+                for (size_t i = 0; i < finalConfiguration3_4.streams.size(); i++) {
+                    finalConfiguration.streams[i] = finalConfiguration3_4.streams[i].v3_3;
+                }
+                return OK;
+            };
+
+    auto postprocConfigStream36 = [&finalConfiguration, &finalConfiguration3_6]
+            (hardware::Return<void>& err) -> status_t {
+                if (!err.isOk()) {
+                    ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+                    return DEAD_OBJECT;
+                }
+                finalConfiguration.streams.resize(finalConfiguration3_6.streams.size());
+                for (size_t i = 0; i < finalConfiguration3_6.streams.size(); i++) {
+                    finalConfiguration.streams[i] = finalConfiguration3_6.streams[i].v3_4.v3_3;
+                }
+                return OK;
+            };
+
+    // See which version of HAL we have
+    if (mHidlSession_3_8 != nullptr) {
+        ALOGV("%s: v3.8 device found", __FUNCTION__);
+        requestedConfiguration3_8.streamConfigCounter = mNextStreamConfigCounter++;
+        requestedConfiguration3_8.multiResolutionInputImage = config->input_is_multi_resolution;
+        auto err = mHidlSession_3_8->configureStreams_3_8(requestedConfiguration3_8,
+                configStream36Cb);
+        res = postprocConfigStream36(err);
+        if (res != OK) {
+            return res;
+        }
+    } else if (mHidlSession_3_7 != nullptr) {
+        ALOGV("%s: v3.7 device found", __FUNCTION__);
+        requestedConfiguration3_7.streamConfigCounter = mNextStreamConfigCounter++;
+        requestedConfiguration3_7.multiResolutionInputImage = config->input_is_multi_resolution;
+        auto err = mHidlSession_3_7->configureStreams_3_7(
+                requestedConfiguration3_7, configStream36Cb);
+        res = postprocConfigStream36(err);
+        if (res != OK) {
+            return res;
+        }
+    } else if (mHidlSession_3_6 != nullptr) {
+        ALOGV("%s: v3.6 device found", __FUNCTION__);
+        device::V3_5::StreamConfiguration requestedConfiguration3_5;
+        requestedConfiguration3_5.v3_4 = requestedConfiguration3_4;
+        requestedConfiguration3_5.streamConfigCounter = mNextStreamConfigCounter++;
+        auto err = mHidlSession_3_6->configureStreams_3_6(
+                requestedConfiguration3_5, configStream36Cb);
+        res = postprocConfigStream36(err);
+        if (res != OK) {
+            return res;
+        }
+    } else if (mHidlSession_3_5 != nullptr) {
+        ALOGV("%s: v3.5 device found", __FUNCTION__);
+        device::V3_5::StreamConfiguration requestedConfiguration3_5;
+        requestedConfiguration3_5.v3_4 = requestedConfiguration3_4;
+        requestedConfiguration3_5.streamConfigCounter = mNextStreamConfigCounter++;
+        auto err = mHidlSession_3_5->configureStreams_3_5(
+                requestedConfiguration3_5, configStream34Cb);
+        res = postprocConfigStream34(err);
+        if (res != OK) {
+            return res;
+        }
+    } else if (mHidlSession_3_4 != nullptr) {
+        // We do; use v3.4 for the call
+        ALOGV("%s: v3.4 device found", __FUNCTION__);
+        auto err = mHidlSession_3_4->configureStreams_3_4(
+                requestedConfiguration3_4, configStream34Cb);
+        res = postprocConfigStream34(err);
+        if (res != OK) {
+            return res;
+        }
+    } else if (mHidlSession_3_3 != nullptr) {
+        // We do; use v3.3 for the call
+        ALOGV("%s: v3.3 device found", __FUNCTION__);
+        auto err = mHidlSession_3_3->configureStreams_3_3(requestedConfiguration3_2,
+            [&status, &finalConfiguration]
+            (common::V1_0::Status s, const device::V3_3::HalStreamConfiguration& halConfiguration) {
+                finalConfiguration = halConfiguration;
+                status = s;
+            });
+        if (!err.isOk()) {
+            ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+            return DEAD_OBJECT;
+        }
+    } else {
+        // We don't; use v3.2 call and construct a v3.3 HalStreamConfiguration
+        ALOGV("%s: v3.2 device found", __FUNCTION__);
+        HalStreamConfiguration finalConfiguration_3_2;
+        auto err = mHidlSession->configureStreams(requestedConfiguration3_2,
+                [&status, &finalConfiguration_3_2]
+                (common::V1_0::Status s, const HalStreamConfiguration& halConfiguration) {
+                    finalConfiguration_3_2 = halConfiguration;
+                    status = s;
+                });
+        if (!err.isOk()) {
+            ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+            return DEAD_OBJECT;
+        }
+        finalConfiguration.streams.resize(finalConfiguration_3_2.streams.size());
+        for (size_t i = 0; i < finalConfiguration_3_2.streams.size(); i++) {
+            finalConfiguration.streams[i].v3_2 = finalConfiguration_3_2.streams[i];
+            finalConfiguration.streams[i].overrideDataSpace =
+                    requestedConfiguration3_2.streams[i].dataSpace;
+        }
+    }
+
+    if (status != common::V1_0::Status::OK ) {
+        return HidlProviderInfo::mapToStatusT(status);
+    }
+
+    // And convert output stream configuration from HIDL
+
+    for (size_t i = 0; i < config->num_streams; i++) {
+        camera3::camera_stream_t *dst = config->streams[i];
+        int streamId = Camera3Stream::cast(dst)->getId();
+
+        // Start scan at i, with the assumption that the stream order matches
+        size_t realIdx = i;
+        bool found = false;
+        size_t halStreamCount = finalConfiguration.streams.size();
+        for (size_t idx = 0; idx < halStreamCount; idx++) {
+            if (finalConfiguration.streams[realIdx].v3_2.id == streamId) {
+                found = true;
+                break;
+            }
+            realIdx = (realIdx >= halStreamCount - 1) ? 0 : realIdx + 1;
+        }
+        if (!found) {
+            ALOGE("%s: Stream %d not found in stream configuration response from HAL",
+                    __FUNCTION__, streamId);
+            return INVALID_OPERATION;
+        }
+        device::V3_3::HalStream &src = finalConfiguration.streams[realIdx];
+        device::V3_6::HalStream &src_36 = finalConfiguration3_6.streams[realIdx];
+
+        Camera3Stream* dstStream = Camera3Stream::cast(dst);
+        int overrideFormat = mapToFrameworkFormat(src.v3_2.overrideFormat);
+        android_dataspace overrideDataSpace = mapToFrameworkDataspace(src.overrideDataSpace);
+
+        if (mHidlSession_3_6 != nullptr) {
+            dstStream->setOfflineProcessingSupport(src_36.supportOffline);
+        }
+
+        if (dstStream->getOriginalFormat() != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+            dstStream->setFormatOverride(false);
+            dstStream->setDataSpaceOverride(false);
+            if (dst->format != overrideFormat) {
+                ALOGE("%s: Stream %d: Format override not allowed for format 0x%x", __FUNCTION__,
+                        streamId, dst->format);
+            }
+            if (dst->data_space != overrideDataSpace) {
+                ALOGE("%s: Stream %d: DataSpace override not allowed for format 0x%x", __FUNCTION__,
+                        streamId, dst->format);
+            }
+        } else {
+            bool needFormatOverride =
+                    requestedConfiguration3_2.streams[i].format != src.v3_2.overrideFormat;
+            bool needDataspaceOverride =
+                    requestedConfiguration3_2.streams[i].dataSpace != src.overrideDataSpace;
+            // Override allowed with IMPLEMENTATION_DEFINED
+            dstStream->setFormatOverride(needFormatOverride);
+            dstStream->setDataSpaceOverride(needDataspaceOverride);
+            dst->format = overrideFormat;
+            dst->data_space = overrideDataSpace;
+        }
+
+        if (dst->stream_type == CAMERA_STREAM_INPUT) {
+            if (src.v3_2.producerUsage != 0) {
+                ALOGE("%s: Stream %d: INPUT streams must have 0 for producer usage",
+                        __FUNCTION__, streamId);
+                return INVALID_OPERATION;
+            }
+            dstStream->setUsage(
+                    mapConsumerToFrameworkUsage(src.v3_2.consumerUsage));
+        } else {
+            // OUTPUT
+            if (src.v3_2.consumerUsage != 0) {
+                ALOGE("%s: Stream %d: OUTPUT streams must have 0 for consumer usage",
+                        __FUNCTION__, streamId);
+                return INVALID_OPERATION;
+            }
+            dstStream->setUsage(
+                    mapProducerToFrameworkUsage(src.v3_2.producerUsage));
+        }
+        dst->max_buffers = src.v3_2.maxBuffers;
+    }
+
+    return res;
+}
+
+status_t HidlCamera3Device::HidlHalInterface::configureInjectedStreams(
+        const camera_metadata_t* sessionParams, camera_stream_configuration* config,
+        const std::vector<uint32_t>& bufferSizes,
+        const CameraMetadata& cameraCharacteristics) {
+    ATRACE_NAME("InjectionCameraHal::configureStreams");
+    if (!valid()) return INVALID_OPERATION;
+    status_t res = OK;
+
+    if (config->input_is_multi_resolution) {
+        ALOGE("%s: Injection camera device doesn't support multi-resolution input "
+                "stream", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    // Convert stream config to HIDL
+    std::set<int> activeStreams;
+    device::V3_2::StreamConfiguration requestedConfiguration3_2;
+    device::V3_4::StreamConfiguration requestedConfiguration3_4;
+    device::V3_7::StreamConfiguration requestedConfiguration3_7;
+    requestedConfiguration3_2.streams.resize(config->num_streams);
+    requestedConfiguration3_4.streams.resize(config->num_streams);
+    requestedConfiguration3_7.streams.resize(config->num_streams);
+    for (size_t i = 0; i < config->num_streams; i++) {
+        device::V3_2::Stream& dst3_2 = requestedConfiguration3_2.streams[i];
+        device::V3_4::Stream& dst3_4 = requestedConfiguration3_4.streams[i];
+        device::V3_7::Stream& dst3_7 = requestedConfiguration3_7.streams[i];
+        camera3::camera_stream_t* src = config->streams[i];
+
+        Camera3Stream* cam3stream = Camera3Stream::cast(src);
+        cam3stream->setBufferFreedListener(this);
+        int streamId = cam3stream->getId();
+        StreamType streamType;
+        switch (src->stream_type) {
+            case CAMERA_STREAM_OUTPUT:
+                streamType = StreamType::OUTPUT;
+                break;
+            case CAMERA_STREAM_INPUT:
+                streamType = StreamType::INPUT;
+                break;
+            default:
+                ALOGE("%s: Stream %d: Unsupported stream type %d", __FUNCTION__,
+                        streamId, config->streams[i]->stream_type);
+            return BAD_VALUE;
+        }
+        dst3_2.id = streamId;
+        dst3_2.streamType = streamType;
+        dst3_2.width = src->width;
+        dst3_2.height = src->height;
+        dst3_2.usage = mapToConsumerUsage(cam3stream->getUsage());
+        dst3_2.rotation =
+                mapToStreamRotation((camera_stream_rotation_t)src->rotation);
+        // For HidlSession version 3.5 or newer, the format and dataSpace sent
+        // to HAL are original, not the overridden ones.
+        if (mHidlSession_3_5 != nullptr) {
+            dst3_2.format = mapToPixelFormat(cam3stream->isFormatOverridden()
+                                            ? cam3stream->getOriginalFormat()
+                                            : src->format);
+            dst3_2.dataSpace =
+                    mapToHidlDataspace(cam3stream->isDataSpaceOverridden()
+                                    ? cam3stream->getOriginalDataSpace()
+                                    : src->data_space);
+        } else {
+            dst3_2.format = mapToPixelFormat(src->format);
+            dst3_2.dataSpace = mapToHidlDataspace(src->data_space);
+        }
+        dst3_4.v3_2 = dst3_2;
+        dst3_4.bufferSize = bufferSizes[i];
+        if (src->physical_camera_id != nullptr) {
+            dst3_4.physicalCameraId = src->physical_camera_id;
+        }
+        dst3_7.v3_4 = dst3_4;
+        dst3_7.groupId = cam3stream->getHalStreamGroupId();
+        dst3_7.sensorPixelModesUsed.resize(src->sensor_pixel_modes_used.size());
+        size_t j = 0;
+        for (int mode : src->sensor_pixel_modes_used) {
+            dst3_7.sensorPixelModesUsed[j++] =
+                    static_cast<CameraMetadataEnumAndroidSensorPixelMode>(mode);
+        }
+        activeStreams.insert(streamId);
+        // Create Buffer ID map if necessary
+        mBufferRecords.tryCreateBufferCache(streamId);
+    }
+    // remove BufferIdMap for deleted streams
+    mBufferRecords.removeInactiveBufferCaches(activeStreams);
+
+    StreamConfigurationMode operationMode;
+    res = mapToStreamConfigurationMode(
+            (camera_stream_configuration_mode_t)config->operation_mode,
+            /*out*/ &operationMode);
+    if (res != OK) {
+        return res;
+    }
+    requestedConfiguration3_7.operationMode = operationMode;
+    size_t sessionParamSize = get_camera_metadata_size(sessionParams);
+    requestedConfiguration3_7.operationMode = operationMode;
+    requestedConfiguration3_7.sessionParams.setToExternal(
+            reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
+            sessionParamSize);
+
+    // See which version of HAL we have
+    if (mHidlSession_3_7 != nullptr) {
+        requestedConfiguration3_7.streamConfigCounter = mNextStreamConfigCounter++;
+        requestedConfiguration3_7.multiResolutionInputImage =
+                config->input_is_multi_resolution;
+
+        const camera_metadata_t* rawMetadata = cameraCharacteristics.getAndLock();
+        ::android::hardware::camera::device::V3_2::CameraMetadata hidlChars = {};
+        hidlChars.setToExternal(
+                reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(rawMetadata)),
+                get_camera_metadata_size(rawMetadata));
+        cameraCharacteristics.unlock(rawMetadata);
+
+        sp<hardware::camera::device::V3_7::ICameraInjectionSession>
+                hidlInjectionSession_3_7;
+        auto castInjectionResult_3_7 =
+                device::V3_7::ICameraInjectionSession::castFrom(mHidlSession_3_7);
+        if (castInjectionResult_3_7.isOk()) {
+            hidlInjectionSession_3_7 = castInjectionResult_3_7;
+        } else {
+            ALOGE("%s: Transaction error: %s", __FUNCTION__,
+                    castInjectionResult_3_7.description().c_str());
+            return DEAD_OBJECT;
+        }
+
+        auto err = hidlInjectionSession_3_7->configureInjectionStreams(
+                requestedConfiguration3_7, hidlChars);
+        if (!err.isOk()) {
+            ALOGE("%s: Transaction error: %s", __FUNCTION__,
+                    err.description().c_str());
+            return DEAD_OBJECT;
+        }
+    } else {
+        ALOGE("%s: mHidlSession_3_7 does not exist, the lowest version of injection "
+                "session is 3.7", __FUNCTION__);
+        return DEAD_OBJECT;
+    }
+
+    return res;
+}
+
+status_t HidlCamera3Device::HidlHalInterface::wrapAsHidlRequest(camera_capture_request_t* request,
+        /*out*/device::V3_2::CaptureRequest* captureRequest,
+        /*out*/std::vector<native_handle_t*>* handlesCreated,
+        /*out*/std::vector<std::pair<int32_t, int32_t>>* inflightBuffers) {
+    ATRACE_CALL();
+    if (captureRequest == nullptr || handlesCreated == nullptr || inflightBuffers == nullptr) {
+        ALOGE("%s: captureRequest (%p), handlesCreated (%p), and inflightBuffers(%p) "
+                "must not be null", __FUNCTION__, captureRequest, handlesCreated, inflightBuffers);
+        return BAD_VALUE;
+    }
+
+    captureRequest->frameNumber = request->frame_number;
+
+    captureRequest->fmqSettingsSize = 0;
+
+    {
+        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;
+
+            mBufferRecords.pushInflightBuffer(captureRequest->frameNumber, streamId,
+                    request->input_buffer->buffer);
+            inflightBuffers->push_back(std::make_pair(captureRequest->frameNumber, streamId));
+        } 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 camera_stream_buffer_t *src = request->output_buffers + i;
+            StreamBuffer &dst = captureRequest->outputBuffers[i];
+            int32_t streamId = Camera3Stream::cast(src->stream)->getId();
+            if (src->buffer != nullptr) {
+                buffer_handle_t buf = *(src->buffer);
+                auto pair = getBufferId(buf, streamId);
+                bool isNewBuffer = pair.first;
+                dst.bufferId = pair.second;
+                dst.buffer = isNewBuffer ? buf : nullptr;
+                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;
+            } else if (mUseHalBufManager) {
+                // HAL buffer management path
+                dst.bufferId = BUFFER_ID_NO_BUFFER;
+                dst.buffer = nullptr;
+                dst.acquireFence = nullptr;
+            } else {
+                ALOGE("%s: cannot send a null buffer in capture request!", __FUNCTION__);
+                return BAD_VALUE;
+            }
+            dst.streamId = streamId;
+            dst.status = BufferStatus::OK;
+            dst.releaseFence = nullptr;
+
+            // Output buffers are empty when using HAL buffer manager
+            if (!mUseHalBufManager) {
+                mBufferRecords.pushInflightBuffer(
+                        captureRequest->frameNumber, streamId, src->buffer);
+                inflightBuffers->push_back(std::make_pair(captureRequest->frameNumber, streamId));
+            }
+        }
+    }
+    return OK;
+}
+
+status_t HidlCamera3Device::HidlHalInterface::flush() {
+    ATRACE_NAME("CameraHal::flush");
+    if (!valid()) return INVALID_OPERATION;
+    status_t res = OK;
+
+    auto err = mHidlSession->flush();
+    if (!err.isOk()) {
+        ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+        res = DEAD_OBJECT;
+    } else {
+        res = HidlProviderInfo::mapToStatusT(err);
+    }
+
+    return res;
+}
+
+status_t HidlCamera3Device::HidlHalInterface::dump(int /*fd*/) {
+    ATRACE_NAME("CameraHal::dump");
+    if (!valid()) return INVALID_OPERATION;
+
+    // Handled by CameraProviderManager::dump
+
+    return OK;
+}
+
+status_t HidlCamera3Device::HidlHalInterface::repeatingRequestEnd(uint32_t frameNumber,
+        const std::vector<int32_t> &streamIds) {
+    ATRACE_NAME("CameraHal::repeatingRequestEnd");
+    if (!valid()) return INVALID_OPERATION;
+
+    if (mHidlSession_3_8.get() != nullptr) {
+        mHidlSession_3_8->repeatingRequestEnd(frameNumber, streamIds);
+    }
+    return OK;
+}
+
+status_t HidlCamera3Device::HidlHalInterface::close() {
+    ATRACE_NAME("CameraHal::close()");
+    if (!valid()) return INVALID_OPERATION;
+    status_t res = OK;
+
+    auto err = mHidlSession->close();
+    // Interface will be dead shortly anyway, so don't log errors
+    if (!err.isOk()) {
+        res = DEAD_OBJECT;
+    }
+
+    return res;
+}
+
+void HidlCamera3Device::HidlHalInterface::signalPipelineDrain(const std::vector<int>& streamIds) {
+    ATRACE_NAME("CameraHal::signalPipelineDrain");
+    if (!valid() || mHidlSession_3_5 == nullptr) {
+        ALOGE("%s called on invalid camera!", __FUNCTION__);
+        return;
+    }
+
+    auto err = mHidlSession_3_5->signalStreamFlush(streamIds, mNextStreamConfigCounter - 1);
+    if (!err.isOk()) {
+        ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+        return;
+    }
+}
+
+status_t HidlCamera3Device::HidlHalInterface::processBatchCaptureRequests(
+        std::vector<camera_capture_request_t*>& requests,/*out*/uint32_t* numRequestProcessed) {
+    ATRACE_NAME("CameraHal::processBatchCaptureRequests");
+    if (!valid()) return INVALID_OPERATION;
+
+    sp<device::V3_4::ICameraDeviceSession> hidlSession_3_4;
+    sp<device::V3_7::ICameraDeviceSession> hidlSession_3_7;
+    auto castResult_3_7 = device::V3_7::ICameraDeviceSession::castFrom(mHidlSession);
+    if (castResult_3_7.isOk()) {
+        hidlSession_3_7 = castResult_3_7;
+    }
+    auto castResult_3_4 = device::V3_4::ICameraDeviceSession::castFrom(mHidlSession);
+    if (castResult_3_4.isOk()) {
+        hidlSession_3_4 = castResult_3_4;
+    }
+
+    hardware::hidl_vec<device::V3_2::CaptureRequest> captureRequests;
+    hardware::hidl_vec<device::V3_4::CaptureRequest> captureRequests_3_4;
+    hardware::hidl_vec<device::V3_7::CaptureRequest> captureRequests_3_7;
+    size_t batchSize = requests.size();
+    if (hidlSession_3_7 != nullptr) {
+        captureRequests_3_7.resize(batchSize);
+    } else if (hidlSession_3_4 != nullptr) {
+        captureRequests_3_4.resize(batchSize);
+    } else {
+        captureRequests.resize(batchSize);
+    }
+    std::vector<native_handle_t*> handlesCreated;
+    std::vector<std::pair<int32_t, int32_t>> inflightBuffers;
+
+    status_t res = OK;
+    for (size_t i = 0; i < batchSize; i++) {
+        if (hidlSession_3_7 != nullptr) {
+            res = wrapAsHidlRequest(requests[i], /*out*/&captureRequests_3_7[i].v3_4.v3_2,
+                    /*out*/&handlesCreated, /*out*/&inflightBuffers);
+        } else if (hidlSession_3_4 != nullptr) {
+            res = wrapAsHidlRequest(requests[i], /*out*/&captureRequests_3_4[i].v3_2,
+                    /*out*/&handlesCreated, /*out*/&inflightBuffers);
+        } else {
+            res = wrapAsHidlRequest(requests[i], /*out*/&captureRequests[i],
+                    /*out*/&handlesCreated, /*out*/&inflightBuffers);
+        }
+        if (res != OK) {
+            mBufferRecords.popInflightBuffers(inflightBuffers);
+            cleanupNativeHandles(&handlesCreated);
+            return res;
+        }
+    }
+
+    std::vector<device::V3_2::BufferCache> cachesToRemove;
+    {
+        std::lock_guard<std::mutex> lock(mFreedBuffersLock);
+        for (auto& pair : mFreedBuffers) {
+            // The stream might have been removed since onBufferFreed
+            if (mBufferRecords.isStreamCached(pair.first)) {
+                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++) {
+        camera_capture_request_t* request = requests[i];
+        device::V3_2::CaptureRequest* captureRequest;
+        if (hidlSession_3_7 != nullptr) {
+            captureRequest = &captureRequests_3_7[i].v3_4.v3_2;
+        } else if (hidlSession_3_4 != nullptr) {
+            captureRequest = &captureRequests_3_4[i].v3_2;
+        } else {
+            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;
+        }
+
+        // hidl session 3.7 specific handling.
+        if (hidlSession_3_7 != nullptr) {
+            captureRequests_3_7[i].inputWidth = request->input_width;
+            captureRequests_3_7[i].inputHeight = request->input_height;
+        }
+
+        // hidl session 3.7 and 3.4 specific handling.
+        if (hidlSession_3_7 != nullptr || hidlSession_3_4 != nullptr) {
+            hardware::hidl_vec<device::V3_4::PhysicalCameraSetting>& physicalCameraSettings =
+                    (hidlSession_3_7 != nullptr) ?
+                    captureRequests_3_7[i].v3_4.physicalCameraSettings :
+                    captureRequests_3_4[i].physicalCameraSettings;
+            physicalCameraSettings.resize(request->num_physcam_settings);
+            for (size_t j = 0; j < request->num_physcam_settings; j++) {
+                if (request->physcam_settings != nullptr) {
+                    size_t settingsSize = get_camera_metadata_size(request->physcam_settings[j]);
+                    if (mRequestMetadataQueue != nullptr && mRequestMetadataQueue->write(
+                                reinterpret_cast<const uint8_t*>(request->physcam_settings[j]),
+                                settingsSize)) {
+                        physicalCameraSettings[j].settings.resize(0);
+                        physicalCameraSettings[j].fmqSettingsSize = settingsSize;
+                    } else {
+                        if (mRequestMetadataQueue != nullptr) {
+                            ALOGW("%s: couldn't utilize fmq, fallback to hwbinder", __FUNCTION__);
+                        }
+                        physicalCameraSettings[j].settings.setToExternal(
+                                reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(
+                                        request->physcam_settings[j])),
+                                get_camera_metadata_size(request->physcam_settings[j]));
+                        physicalCameraSettings[j].fmqSettingsSize = 0u;
+                    }
+                } else {
+                    physicalCameraSettings[j].fmqSettingsSize = 0u;
+                    physicalCameraSettings[j].settings.resize(0);
+                }
+                physicalCameraSettings[j].physicalCameraId = request->physcam_id[j];
+            }
+        }
+    }
+
+    hardware::details::return_status err;
+    auto resultCallback =
+        [&status, &numRequestProcessed] (auto s, uint32_t n) {
+                status = s;
+                *numRequestProcessed = n;
+        };
+    if (hidlSession_3_7 != nullptr) {
+        err = hidlSession_3_7->processCaptureRequest_3_7(captureRequests_3_7, cachesToRemove,
+                                                         resultCallback);
+    } else if (hidlSession_3_4 != nullptr) {
+        err = hidlSession_3_4->processCaptureRequest_3_4(captureRequests_3_4, cachesToRemove,
+                                                         resultCallback);
+    } else {
+        err = mHidlSession->processCaptureRequest(captureRequests, cachesToRemove,
+                                                  resultCallback);
+    }
+    if (!err.isOk()) {
+        ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+        status = common::V1_0::Status::CAMERA_DISCONNECTED;
+    }
+
+    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;
+    }
+
+    res = HidlProviderInfo::mapToStatusT(status);
+    if (res == OK) {
+        if (mHidlSession->isRemote()) {
+            // Only close acquire fence FDs when the HIDL transaction succeeds (so the FDs have been
+            // sent to camera HAL processes)
+            cleanupNativeHandles(&handlesCreated, /*closeFd*/true);
+        } else {
+            // In passthrough mode the FDs are now owned by HAL
+            cleanupNativeHandles(&handlesCreated);
+        }
+    } else {
+        mBufferRecords.popInflightBuffers(inflightBuffers);
+        cleanupNativeHandles(&handlesCreated);
+    }
+    return res;
+}
+
+status_t HidlCamera3Device::HidlHalInterface::switchToOffline(
+        const std::vector<int32_t>& streamsToKeep,
+        /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
+        /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
+        /*out*/camera3::BufferRecords* bufferRecords) {
+    ATRACE_NAME("CameraHal::switchToOffline");
+    if (!valid() || mHidlSession_3_6 == nullptr) {
+        ALOGE("%s called on invalid camera!", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    if (offlineSessionInfo == nullptr || offlineSession == nullptr || bufferRecords == nullptr) {
+        ALOGE("%s: output arguments must not be null!", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    common::V1_0::Status status = common::V1_0::Status::INTERNAL_ERROR;
+    auto resultCallback =
+        [&status, &offlineSessionInfo, &offlineSession] (auto s, auto info, auto session) {
+                status = s;
+                *offlineSessionInfo = info;
+                *offlineSession = session;
+        };
+    auto err = mHidlSession_3_6->switchToOffline(streamsToKeep, resultCallback);
+
+    if (!err.isOk()) {
+        ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+        return DEAD_OBJECT;
+    }
+
+    status_t ret = HidlProviderInfo::mapToStatusT(status);
+    if (ret != OK) {
+        return ret;
+    }
+
+    return verifyBufferCaches(offlineSessionInfo, bufferRecords);
+}
+
+HidlCamera3Device::HidlRequestThread::HidlRequestThread(wp<Camera3Device> parent,
+                sp<camera3::StatusTracker> statusTracker,
+                sp<HalInterface> interface,
+                const Vector<int32_t>& sessionParamKeys,
+                bool useHalBufManager,
+                bool supportCameraMute) :
+          RequestThread(parent, statusTracker, interface, sessionParamKeys, useHalBufManager,
+                  supportCameraMute) {}
+
+status_t HidlCamera3Device::HidlRequestThread::switchToOffline(
+        const std::vector<int32_t>& streamsToKeep,
+        /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
+        /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
+        /*out*/camera3::BufferRecords* bufferRecords) {
+    Mutex::Autolock l(mRequestLock);
+    clearRepeatingRequestsLocked(/*lastFrameNumber*/nullptr);
+
+    // Wait until request thread is fully stopped
+    // TBD: check if request thread is being paused by other APIs (shouldn't be)
+
+    // We could also check for mRepeatingRequests.empty(), but the API interface
+    // is serialized by Camera3Device::mInterfaceLock so no one should be able to submit any
+    // new requests during the call; hence skip that check.
+    bool queueEmpty = mNextRequests.empty() && mRequestQueue.empty();
+    while (!queueEmpty) {
+        status_t res = mRequestSubmittedSignal.waitRelative(mRequestLock, kRequestSubmitTimeout);
+        if (res == TIMED_OUT) {
+            ALOGE("%s: request thread failed to submit one request within timeout!", __FUNCTION__);
+            return res;
+        } else if (res != OK) {
+            ALOGE("%s: request thread failed to submit a request: %s (%d)!",
+                    __FUNCTION__, strerror(-res), res);
+            return res;
+        }
+        queueEmpty = mNextRequests.empty() && mRequestQueue.empty();
+    }
+    return (static_cast<HidlHalInterface *>(mInterface.get()))->switchToOffline(
+            streamsToKeep, offlineSessionInfo, offlineSession, bufferRecords);
+}
+
+status_t HidlCamera3Device::HidlCamera3DeviceInjectionMethods::injectionInitialize(
+        const String8& injectedCamId, sp<CameraProviderManager> manager,
+        const sp<android::hardware::camera::device::V3_2::ICameraDeviceCallback>&
+                callback) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mInjectionLock);
+
+    if (manager == nullptr) {
+        ALOGE("%s: manager does not exist!", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    sp<Camera3Device> parent = mParent.promote();
+    if (parent == nullptr) {
+        ALOGE("%s: parent does not exist!", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    mInjectedCamId = injectedCamId;
+    sp<ICameraDeviceSession> session;
+    ATRACE_BEGIN("Injection CameraHal::openSession");
+    status_t res = manager->openHidlSession(injectedCamId.string(), callback,
+                                          /*out*/ &session);
+    ATRACE_END();
+    if (res != OK) {
+        ALOGE("Injection camera could not open camera session: %s (%d)",
+                strerror(-res), res);
+        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("Injection camera HAL returns empty request metadata fmq, not "
+                        "use it");
+                queue = nullptr;
+                // don't use the queue onwards.
+            }
+        });
+    if (!requestQueueRet.isOk()) {
+        ALOGE("Injection camera transaction error when getting request metadata fmq: "
+                "%s, not use it", requestQueueRet.description().c_str());
+        return DEAD_OBJECT;
+    }
+
+    std::unique_ptr<ResultMetadataQueue>& resQueue = mInjectionResultMetadataQueue;
+    auto resultQueueRet = session->getCaptureResultMetadataQueue(
+        [&resQueue](const auto& descriptor) {
+            resQueue = std::make_unique<ResultMetadataQueue>(descriptor);
+            if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
+                ALOGE("Injection camera HAL returns empty result metadata fmq, not use "
+                        "it");
+                resQueue = nullptr;
+                // Don't use the resQueue onwards.
+            }
+        });
+    if (!resultQueueRet.isOk()) {
+        ALOGE("Injection camera 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("Injection camera session interface chain:");
+                        for (const auto& iface : interfaceChain) {
+                            ALOGV("  %s", iface.c_str());
+                        }
+                });
+    }
+
+    ALOGV("%s: Injection camera interface = new HalInterface()", __FUNCTION__);
+
+    mInjectedCamHalInterface =
+            new HidlHalInterface(session, queue, parent->mUseHalBufManager,
+                       parent->mSupportOfflineProcessing);
+    if (mInjectedCamHalInterface == nullptr) {
+        ALOGE("%s: mInjectedCamHalInterface does not exist!", __FUNCTION__);
+        return DEAD_OBJECT;
+    }
+
+    return OK;
+}
+
+status_t HidlCamera3Device::HidlCamera3DeviceInjectionMethods::replaceHalInterface(
+        sp<HalInterface> newHalInterface, bool keepBackup) {
+    Mutex::Autolock lock(mInjectionLock);
+    if (newHalInterface.get() == nullptr) {
+        ALOGE("%s: The newHalInterface does not exist, to stop replacing.",
+                __FUNCTION__);
+        return DEAD_OBJECT;
+    }
+
+    sp<Camera3Device> parent = mParent.promote();
+    if (parent == nullptr) {
+        ALOGE("%s: parent does not exist!", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    if (newHalInterface->getTransportType() != IPCTransport::HIDL) {
+        ALOGE("%s Replacing HIDL HalInterface with another transport unsupported", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    HidlCamera3Device *hidlParent = static_cast<HidlCamera3Device *>(parent.get());
+    if (keepBackup) {
+        if (mBackupHalInterface == nullptr) {
+            mBackupHalInterface = parent->mInterface;
+        }
+        if (mBackupResultMetadataQueue == nullptr) {
+            mBackupResultMetadataQueue = std::move(hidlParent->mResultMetadataQueue);
+            hidlParent->mResultMetadataQueue = std::move(mInjectionResultMetadataQueue);
+        }
+    } else {
+        mBackupHalInterface = nullptr;
+        hidlParent->mResultMetadataQueue = std::move(mBackupResultMetadataQueue);
+        mBackupResultMetadataQueue = nullptr;
+    }
+    parent->mInterface = newHalInterface;
+
+    return OK;
+}
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h
new file mode 100644
index 0000000..a83080b
--- /dev/null
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SERVERS_HIDLCAMERA3DEVICE_H
+#define ANDROID_SERVERS_HIDLCAMERA3DEVICE_H
+
+#include "../Camera3Device.h"
+#include "HidlCamera3OutputUtils.h"
+
+namespace android {
+
+using android::hardware::camera::metadata::V3_8::CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap;
+
+/**
+ * CameraDevice for HIDL HAL devices with version CAMERA_DEVICE_API_VERSION_3_0 or higher.
+ */
+class HidlCamera3Device :
+            virtual public hardware::camera::device::V3_8::ICameraDeviceCallback,
+            public Camera3Device {
+  public:
+
+   explicit HidlCamera3Device(const String8& id, bool overrideForPerfClass,
+          bool legacyClient = false) : Camera3Device(id, overrideForPerfClass, legacyClient) { }
+
+    virtual ~HidlCamera3Device() {}
+
+   /**
+     * Helper functions to map between framework and HIDL values
+     */
+    static hardware::graphics::common::V1_0::PixelFormat mapToPixelFormat(int frameworkFormat);
+    static hardware::camera::device::V3_2::DataspaceFlags mapToHidlDataspace(
+            android_dataspace dataSpace);
+    static hardware::camera::device::V3_2::BufferUsageFlags mapToConsumerUsage(uint64_t usage);
+    static CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap mapToHidlDynamicProfile(
+                    int dynamicRangeProfile);
+    static hardware::camera::device::V3_2::StreamRotation mapToStreamRotation(
+            camera_stream_rotation_t rotation);
+    // Returns a negative error code if the passed-in operation mode is not valid.
+    static status_t mapToStreamConfigurationMode(camera_stream_configuration_mode_t operationMode,
+            /*out*/ hardware::camera::device::V3_2::StreamConfigurationMode *mode);
+    static int mapToFrameworkFormat(hardware::graphics::common::V1_0::PixelFormat pixelFormat);
+    static android_dataspace mapToFrameworkDataspace(
+            hardware::camera::device::V3_2::DataspaceFlags);
+    static uint64_t mapConsumerToFrameworkUsage(
+            hardware::camera::device::V3_2::BufferUsageFlags usage);
+    static uint64_t mapProducerToFrameworkUsage(
+            hardware::camera::device::V3_2::BufferUsageFlags usage);
+
+    status_t initialize(sp<CameraProviderManager> manager, const String8& monitorTags) override;
+
+    /**
+     * Implementation of android::hardware::camera::device::V3_5::ICameraDeviceCallback
+     */
+
+    hardware::Return<void> processCaptureResult_3_4(
+            const hardware::hidl_vec<
+                    hardware::camera::device::V3_4::CaptureResult>& results) override;
+    hardware::Return<void> processCaptureResult(
+            const hardware::hidl_vec<
+                    hardware::camera::device::V3_2::CaptureResult>& results) override;
+    hardware::Return<void> notify(
+            const hardware::hidl_vec<
+                    hardware::camera::device::V3_2::NotifyMsg>& msgs) override;
+
+    hardware::Return<void> requestStreamBuffers(
+            const hardware::hidl_vec<
+                    hardware::camera::device::V3_5::BufferRequest>& bufReqs,
+            requestStreamBuffers_cb _hidl_cb) override;
+
+    hardware::Return<void> returnStreamBuffers(
+            const hardware::hidl_vec<
+                    hardware::camera::device::V3_2::StreamBuffer>& buffers) override;
+
+    hardware::Return<void> notify_3_8(
+            const hardware::hidl_vec<
+                    hardware::camera::device::V3_8::NotifyMsg>& msgs) override;
+
+    // Handle one notify message
+    void notify(const hardware::camera::device::V3_2::NotifyMsg& msg);
+
+    status_t switchToOffline(const std::vector<int32_t>& streamsToKeep,
+            /*out*/ sp<CameraOfflineSessionBase>* session) override;
+
+    using RequestMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
+
+    class HidlHalInterface : public Camera3Device::HalInterface {
+     public:
+        HidlHalInterface(sp<hardware::camera::device::V3_2::ICameraDeviceSession> &session,
+                     std::shared_ptr<RequestMetadataQueue> queue,
+                     bool useHalBufManager, bool supportOfflineProcessing);
+
+        virtual IPCTransport getTransportType() override { return IPCTransport::HIDL; }
+        // Returns true if constructed with a valid device or session, and not yet cleared
+        virtual bool valid() override;
+
+        // Reset this HalInterface object (does not call close())
+        virtual void clear() override;
+
+        // Calls into the HAL interface
+
+        // Caller takes ownership of requestTemplate
+        virtual status_t constructDefaultRequestSettings(camera_request_template templateId,
+                /*out*/ camera_metadata_t **requestTemplate) override;
+
+        virtual status_t configureStreams(const camera_metadata_t *sessionParams,
+                /*inout*/ camera_stream_configuration_t *config,
+                const std::vector<uint32_t>& bufferSizes) override;
+
+        // The injection camera configures the streams to hal.
+        virtual status_t configureInjectedStreams(
+                const camera_metadata_t* sessionParams,
+                /*inout*/ camera_stream_configuration_t* config,
+                const std::vector<uint32_t>& bufferSizes,
+                const CameraMetadata& cameraCharacteristics) override;
+
+        // When the call succeeds, the ownership of acquire fences in requests is transferred to
+        // HalInterface. More specifically, the current implementation will send the fence to
+        // HAL process and close the FD in cameraserver process. When the call fails, the ownership
+        // of the acquire fence still belongs to the caller.
+        virtual status_t processBatchCaptureRequests(
+                std::vector<camera_capture_request_t*>& requests,
+                /*out*/uint32_t* numRequestProcessed) override;
+        virtual status_t flush() override;
+        virtual status_t dump(int fd) override;
+        virtual status_t close() override;
+
+        virtual void signalPipelineDrain(const std::vector<int>& streamIds) override;
+        virtual bool isReconfigurationRequired(CameraMetadata& oldSessionParams,
+                CameraMetadata& newSessionParams) override;
+
+        virtual status_t repeatingRequestEnd(uint32_t frameNumber,
+                const std::vector<int32_t> &streamIds) override;
+
+        status_t switchToOffline(
+        const std::vector<int32_t>& streamsToKeep,
+        /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
+        /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
+        /*out*/camera3::BufferRecords* bufferRecords);
+
+     private:
+
+        // Always valid
+        sp<hardware::camera::device::V3_2::ICameraDeviceSession> mHidlSession;
+        // Valid if ICameraDeviceSession is @3.3 or newer
+        sp<hardware::camera::device::V3_3::ICameraDeviceSession> mHidlSession_3_3;
+        // Valid if ICameraDeviceSession is @3.4 or newer
+        sp<hardware::camera::device::V3_4::ICameraDeviceSession> mHidlSession_3_4;
+        // Valid if ICameraDeviceSession is @3.5 or newer
+        sp<hardware::camera::device::V3_5::ICameraDeviceSession> mHidlSession_3_5;
+        // Valid if ICameraDeviceSession is @3.6 or newer
+        sp<hardware::camera::device::V3_6::ICameraDeviceSession> mHidlSession_3_6;
+        // Valid if ICameraDeviceSession is @3.7 or newer
+        sp<hardware::camera::device::V3_7::ICameraDeviceSession> mHidlSession_3_7;
+        // Valid if ICameraDeviceSession is @3.7 or newer
+        sp<hardware::camera::device::V3_8::ICameraDeviceSession> mHidlSession_3_8;
+
+        std::shared_ptr<RequestMetadataQueue> mRequestMetadataQueue;
+
+        // The output HIDL request still depends on input camera_capture_request_t
+        // Do not free input camera_capture_request_t before output HIDL request
+        status_t wrapAsHidlRequest(camera_capture_request_t* in,
+                /*out*/hardware::camera::device::V3_2::CaptureRequest* out,
+                /*out*/std::vector<native_handle_t*>* handlesCreated,
+                /*out*/std::vector<std::pair<int32_t, int32_t>>* inflightBuffers);
+    }; // class HidlHalInterface
+
+    class HidlRequestThread : public Camera3Device::RequestThread {
+      public:
+        HidlRequestThread(wp<Camera3Device> parent,
+                sp<camera3::StatusTracker> statusTracker,
+                sp<HalInterface> interface,
+                const Vector<int32_t>& sessionParamKeys,
+                bool useHalBufManager,
+                bool supportCameraMute);
+
+        status_t switchToOffline(
+                const std::vector<int32_t>& streamsToKeep,
+                /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
+                /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
+                /*out*/camera3::BufferRecords* bufferRecords);
+    }; // class HidlRequestThread
+
+    class HidlCamera3DeviceInjectionMethods : public Camera3DeviceInjectionMethods {
+     public:
+        // Initialize the injection camera and generate an hal interface.
+        status_t injectionInitialize(
+                const String8& injectedCamId, sp<CameraProviderManager> manager,
+                const sp<
+                    android::hardware::camera::device::V3_2 ::ICameraDeviceCallback>&
+                    callback);
+        HidlCamera3DeviceInjectionMethods(wp<Camera3Device> parent) :
+                Camera3DeviceInjectionMethods(parent) { };
+        ~HidlCamera3DeviceInjectionMethods() {}
+     private:
+        // Backup of the original camera hal result FMQ.
+        std::unique_ptr<ResultMetadataQueue> mBackupResultMetadataQueue;
+
+        // FMQ writes the result for the injection camera. Must be guarded by
+        // mProcessCaptureResultLock.
+        std::unique_ptr<ResultMetadataQueue> mInjectionResultMetadataQueue;
+
+        // Use injection camera hal interface to replace and backup original
+        // camera hal interface.
+        virtual status_t replaceHalInterface(sp<HalInterface> newHalInterface,
+                bool keepBackup) override;
+    };
+
+  private:
+    template<typename NotifyMsgType>
+    hardware::Return<void> notifyHelper(
+            const hardware::hidl_vec<NotifyMsgType>& msgs);
+
+    virtual status_t injectionCameraInitialize(const String8 &injectCamId,
+            sp<CameraProviderManager> manager) override;
+
+    virtual sp<RequestThread> createNewRequestThread(wp<Camera3Device> parent,
+                sp<camera3::StatusTracker> statusTracker,
+                sp<HalInterface> interface,
+                const Vector<int32_t>& sessionParamKeys,
+                bool useHalBufManager,
+                bool supportCameraMute) override;
+
+    virtual sp<Camera3DeviceInjectionMethods>
+            createCamera3DeviceInjectionMethods(wp<Camera3Device>) override;
+
+    // FMQ to write result on. Must be guarded by mProcessCaptureResultLock.
+    std::unique_ptr<ResultMetadataQueue> mResultMetadataQueue;
+
+}; // class HidlCamera3Device
+
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp
new file mode 100644
index 0000000..d517c8d
--- /dev/null
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Hidl-Camera3-OffLnSsn"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <inttypes.h>
+
+#include <utils/Trace.h>
+
+#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
+
+#include "device3/hidl/HidlCamera3OfflineSession.h"
+#include "device3/Camera3OutputStream.h"
+#include "device3/hidl/HidlCamera3OutputUtils.h"
+#include "device3/Camera3InputStream.h"
+#include "device3/Camera3SharedOutputStream.h"
+#include "utils/CameraTraces.h"
+
+using namespace android::camera3;
+using namespace android::hardware::camera;
+
+namespace android {
+
+HidlCamera3OfflineSession::~HidlCamera3OfflineSession() {
+    ATRACE_CALL();
+    ALOGV("%s: Tearing down hidl offline session for camera id %s", __FUNCTION__, mId.string());
+    HidlCamera3OfflineSession::disconnectSession();
+}
+
+status_t HidlCamera3OfflineSession::initialize(wp<NotificationListener> listener) {
+    ATRACE_CALL();
+
+    if (mSession == nullptr) {
+        ALOGE("%s: HIDL session is null!", __FUNCTION__);
+        return DEAD_OBJECT;
+    }
+
+    {
+        std::lock_guard<std::mutex> lock(mLock);
+
+        mListener = listener;
+
+        // setup result FMQ
+        std::unique_ptr<ResultMetadataQueue>& resQueue = mResultMetadataQueue;
+        auto resultQueueRet = mSession->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 resQueue onwards.
+                }
+            });
+        if (!resultQueueRet.isOk()) {
+            ALOGE("Transaction error when getting result metadata queue from camera session: %s",
+                    resultQueueRet.description().c_str());
+            return DEAD_OBJECT;
+        }
+        mStatus = STATUS_ACTIVE;
+    }
+
+    mSession->setCallback(this);
+
+    return OK;
+}
+
+hardware::Return<void> HidlCamera3OfflineSession::processCaptureResult_3_4(
+        const hardware::hidl_vec<
+                hardware::camera::device::V3_4::CaptureResult>& results) {
+    sp<NotificationListener> listener;
+    {
+        std::lock_guard<std::mutex> lock(mLock);
+        if (mStatus != STATUS_ACTIVE) {
+            ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+            return hardware::Void();
+        }
+        listener = mListener.promote();
+    }
+
+    HidlCaptureOutputStates states {
+      {mId,
+        mOfflineReqsLock, mLastCompletedRegularFrameNumber,
+        mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+        mOfflineReqs, mOutputLock, mResultQueue, mResultSignal,
+        mNextShutterFrameNumber,
+        mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+        mNextResultFrameNumber,
+        mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+        mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+        mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+        mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+        mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
+        mBufferRecords, /*legacyClient*/ false}, mResultMetadataQueue
+    };
+
+    std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
+    for (const auto& result : results) {
+        processOneCaptureResultLocked(states, result.v3_2, result.physicalCameraMetadata);
+    }
+    return hardware::Void();
+}
+
+hardware::Return<void> HidlCamera3OfflineSession::processCaptureResult(
+        const hardware::hidl_vec<
+                hardware::camera::device::V3_2::CaptureResult>& results) {
+    // TODO: changed impl to call into processCaptureResult_3_4 instead?
+    //       might need to figure how to reduce copy though.
+    sp<NotificationListener> listener;
+    {
+        std::lock_guard<std::mutex> lock(mLock);
+        if (mStatus != STATUS_ACTIVE) {
+            ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+            return hardware::Void();
+        }
+        listener = mListener.promote();
+    }
+
+    hardware::hidl_vec<hardware::camera::device::V3_4::PhysicalCameraMetadata> noPhysMetadata;
+
+    HidlCaptureOutputStates states {
+      {mId,
+        mOfflineReqsLock, mLastCompletedRegularFrameNumber,
+        mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+        mOfflineReqs, mOutputLock, mResultQueue, mResultSignal,
+        mNextShutterFrameNumber,
+        mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+        mNextResultFrameNumber,
+        mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+        mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+        mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+        mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+        mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
+        mBufferRecords, /*legacyClient*/ false}, mResultMetadataQueue
+    };
+
+    std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
+    for (const auto& result : results) {
+        processOneCaptureResultLocked(states, result, noPhysMetadata);
+    }
+    return hardware::Void();
+}
+
+hardware::Return<void> HidlCamera3OfflineSession::notify(
+        const hardware::hidl_vec<hardware::camera::device::V3_2::NotifyMsg>& msgs) {
+    sp<NotificationListener> listener;
+    {
+        std::lock_guard<std::mutex> lock(mLock);
+        if (mStatus != STATUS_ACTIVE) {
+            ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+            return hardware::Void();
+        }
+        listener = mListener.promote();
+    }
+
+    HidlCaptureOutputStates states {
+      {mId,
+        mOfflineReqsLock, mLastCompletedRegularFrameNumber,
+        mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+        mOfflineReqs, mOutputLock, mResultQueue, mResultSignal,
+        mNextShutterFrameNumber,
+        mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+        mNextResultFrameNumber,
+        mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+        mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+        mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+        mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+        mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
+        mBufferRecords, /*legacyClient*/ false}, mResultMetadataQueue
+    };
+    for (const auto& msg : msgs) {
+        camera3::notify(states, msg);
+    }
+    return hardware::Void();
+}
+
+hardware::Return<void> HidlCamera3OfflineSession::requestStreamBuffers(
+        const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
+        requestStreamBuffers_cb _hidl_cb) {
+    {
+        std::lock_guard<std::mutex> lock(mLock);
+        if (mStatus != STATUS_ACTIVE) {
+            ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+            return hardware::Void();
+        }
+    }
+
+    RequestBufferStates states {
+        mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder,
+        *this, mBufferRecords, *this};
+    camera3::requestStreamBuffers(states, bufReqs, _hidl_cb);
+    return hardware::Void();
+}
+
+hardware::Return<void> HidlCamera3OfflineSession::returnStreamBuffers(
+        const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) {
+    {
+        std::lock_guard<std::mutex> lock(mLock);
+        if (mStatus != STATUS_ACTIVE) {
+            ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+            return hardware::Void();
+        }
+    }
+
+    ReturnBufferStates states {
+        mId, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder, mBufferRecords};
+
+    camera3::returnStreamBuffers(states, buffers);
+    return hardware::Void();
+}
+
+void HidlCamera3OfflineSession::disconnectSession() {
+  // TODO: Make sure this locking is correct.
+  std::lock_guard<std::mutex> lock(mLock);
+  if (mSession != nullptr) {
+      mSession->close();
+  }
+  mSession.clear();
+}
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.h b/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.h
new file mode 100644
index 0000000..597cc5d
--- /dev/null
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SERVERS_HIDL_CAMERA3OFFLINESESSION_H
+#define ANDROID_SERVERS_HIDL_CAMERA3OFFLINESESSION_H
+
+#include <memory>
+#include <mutex>
+
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+#include <android/hardware/camera/device/3.6/ICameraOfflineSession.h>
+
+#include <fmq/MessageQueue.h>
+
+#include "HidlCamera3OutputUtils.h"
+#include "common/CameraOfflineSessionBase.h"
+
+#include "device3/Camera3BufferManager.h"
+#include "device3/Camera3OfflineSession.h"
+#include "device3/InFlightRequest.h"
+
+namespace android {
+
+namespace camera3 {
+
+class Camera3Stream;
+class Camera3OutputStreamInterface;
+class Camera3StreamInterface;
+
+} // namespace camera3
+
+/**
+ * HidlCamera3OfflineSession for offline session defined in HIDL ICameraOfflineSession@3.6 or higher
+ */
+class HidlCamera3OfflineSession :
+            public Camera3OfflineSession,
+            virtual public hardware::camera::device::V3_5::ICameraDeviceCallback {
+  public:
+
+    // initialize by Camera3Device.
+    explicit HidlCamera3OfflineSession(const String8& id,
+            const sp<camera3::Camera3Stream>& inputStream,
+            const camera3::StreamSet& offlineStreamSet,
+            camera3::BufferRecords&& bufferRecords,
+            const camera3::InFlightRequestMap& offlineReqs,
+            const Camera3OfflineStates& offlineStates,
+            sp<hardware::camera::device::V3_6::ICameraOfflineSession> offlineSession) :
+      Camera3OfflineSession(id, inputStream, offlineStreamSet, std::move(bufferRecords),
+              offlineReqs, offlineStates),
+      mSession(offlineSession) {};
+
+    virtual ~HidlCamera3OfflineSession();
+
+    virtual status_t initialize(wp<NotificationListener> listener) override;
+
+    /**
+     * HIDL ICameraDeviceCallback interface
+     * Implementation of android::hardware::camera::device::V3_5::ICameraDeviceCallback
+     */
+
+    hardware::Return<void> processCaptureResult_3_4(
+            const hardware::hidl_vec<
+                    hardware::camera::device::V3_4::CaptureResult>& results) override;
+    hardware::Return<void> processCaptureResult(
+            const hardware::hidl_vec<
+                    hardware::camera::device::V3_2::CaptureResult>& results) override;
+    hardware::Return<void> notify(
+            const hardware::hidl_vec<
+                    hardware::camera::device::V3_2::NotifyMsg>& msgs) override;
+
+    hardware::Return<void> requestStreamBuffers(
+            const hardware::hidl_vec<
+                    hardware::camera::device::V3_5::BufferRequest>& bufReqs,
+            requestStreamBuffers_cb _hidl_cb) override;
+
+    hardware::Return<void> returnStreamBuffers(
+            const hardware::hidl_vec<
+                    hardware::camera::device::V3_2::StreamBuffer>& buffers) override;
+
+    /**
+     * End of CameraOfflineSessionBase interface
+     */
+
+  private:
+    sp<hardware::camera::device::V3_6::ICameraOfflineSession> mSession;
+    // FMQ to write result on. Must be guarded by mProcessCaptureResultLock.
+    std::unique_ptr<ResultMetadataQueue> mResultMetadataQueue;
+
+    virtual void disconnectSession() override;
+}; // class Camera3OfflineSession
+
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3OutputUtils.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3OutputUtils.cpp
new file mode 100644
index 0000000..afe9d56
--- /dev/null
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3OutputUtils.cpp
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "HidlCamera3-OutputUtils"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+// Convenience macros for transitioning to the error state
+#define SET_ERR(fmt, ...) states.setErrIntf.setErrorState(   \
+    "%s: " fmt, __FUNCTION__,                         \
+    ##__VA_ARGS__)
+
+#include <inttypes.h>
+
+#include <utils/Log.h>
+#include <utils/SortedVector.h>
+#include <utils/Trace.h>
+
+#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
+
+#include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
+
+#include <camera/CameraUtils.h>
+#include <camera_metadata_hidden.h>
+
+#include "device3/hidl/HidlCamera3OutputUtils.h"
+#include "device3/Camera3OutputUtilsTemplated.h"
+
+#include "system/camera_metadata.h"
+
+using namespace android::camera3;
+using namespace android::hardware::camera;
+
+namespace android {
+namespace camera3 {
+
+void processOneCaptureResultLocked(
+        HidlCaptureOutputStates& states,
+        const hardware::camera::device::V3_2::CaptureResult& result,
+        const hardware::hidl_vec<
+                hardware::camera::device::V3_4::PhysicalCameraMetadata> &physicalCameraMetadata) {
+    processOneCaptureResultLockedT<HidlCaptureOutputStates,
+        hardware::camera::device::V3_2::CaptureResult,
+        hardware::hidl_vec<hardware::camera::device::V3_4::PhysicalCameraMetadata>,
+        hardware::hidl_vec<uint8_t>, ResultMetadataQueue,
+        hardware::camera::device::V3_2::BufferStatus>(states, result, physicalCameraMetadata);
+}
+
+void notify(CaptureOutputStates& states,
+        const hardware::camera::device::V3_8::NotifyMsg& msg) {
+    using android::hardware::camera::device::V3_2::MsgType;
+
+    hardware::camera::device::V3_2::NotifyMsg msg_3_2;
+    msg_3_2.type = msg.type;
+    bool hasReadoutTime = false;
+    uint64_t readoutTime = 0;
+    switch (msg.type) {
+        case MsgType::ERROR:
+            msg_3_2.msg.error = msg.msg.error;
+            break;
+        case MsgType::SHUTTER:
+            msg_3_2.msg.shutter = msg.msg.shutter.v3_2;
+            hasReadoutTime = true;
+            readoutTime = msg.msg.shutter.readoutTimestamp;
+            break;
+    }
+    notify(states, msg_3_2, hasReadoutTime, readoutTime);
+}
+
+void notify(CaptureOutputStates& states,
+        const hardware::camera::device::V3_2::NotifyMsg& msg,
+        bool hasReadoutTime, uint64_t readoutTime) {
+
+    using android::hardware::camera::device::V3_2::MsgType;
+    using android::hardware::camera::device::V3_2::ErrorCode;
+
+    ATRACE_CALL();
+    camera_notify_msg m;
+    switch (msg.type) {
+        case MsgType::ERROR:
+            m.type = CAMERA_MSG_ERROR;
+            m.message.error.frame_number = msg.msg.error.frameNumber;
+            if (msg.msg.error.errorStreamId >= 0) {
+                sp<Camera3StreamInterface> stream =
+                        states.outputStreams.get(msg.msg.error.errorStreamId);
+                if (stream == nullptr) {
+                    ALOGE("%s: Frame %d: Invalid error stream id %d", __FUNCTION__,
+                            m.message.error.frame_number, msg.msg.error.errorStreamId);
+                    return;
+                }
+                m.message.error.error_stream = stream->asHalStream();
+            } else {
+                m.message.error.error_stream = nullptr;
+            }
+            switch (msg.msg.error.errorCode) {
+                case ErrorCode::ERROR_DEVICE:
+                    m.message.error.error_code = CAMERA_MSG_ERROR_DEVICE;
+                    break;
+                case ErrorCode::ERROR_REQUEST:
+                    m.message.error.error_code = CAMERA_MSG_ERROR_REQUEST;
+                    break;
+                case ErrorCode::ERROR_RESULT:
+                    m.message.error.error_code = CAMERA_MSG_ERROR_RESULT;
+                    break;
+                case ErrorCode::ERROR_BUFFER:
+                    m.message.error.error_code = CAMERA_MSG_ERROR_BUFFER;
+                    break;
+            }
+            break;
+        case MsgType::SHUTTER:
+            m.type = CAMERA_MSG_SHUTTER;
+            m.message.shutter.frame_number = msg.msg.shutter.frameNumber;
+            m.message.shutter.timestamp = msg.msg.shutter.timestamp;
+            m.message.shutter.readout_timestamp = hasReadoutTime ?
+                    readoutTime : m.message.shutter.timestamp;
+            break;
+    }
+    notify(states, &m);
+}
+
+
+
+// The buffers requested through this call are not tied to any CaptureRequest in
+// particular. They may used by the hal for a particular frame's output buffer
+// or for its internal use as well. In the case that the hal does use any buffer
+// from the requested list here, for a particular frame's output buffer, the
+// buffer will be returned with the processCaptureResult call corresponding to
+// the frame. The other buffers will be returned through returnStreamBuffers.
+// The buffers returned via returnStreamBuffers will not have a valid
+// timestamp(0) and will be dropped by the bufferqueue.
+void requestStreamBuffers(RequestBufferStates& states,
+        const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
+        hardware::camera::device::V3_5::ICameraDeviceCallback::requestStreamBuffers_cb _hidl_cb) {
+    using android::hardware::camera::device::V3_2::BufferStatus;
+    using android::hardware::camera::device::V3_2::StreamBuffer;
+    using android::hardware::camera::device::V3_5::BufferRequestStatus;
+    using android::hardware::camera::device::V3_5::StreamBufferRet;
+    using android::hardware::camera::device::V3_5::StreamBufferRequestError;
+
+    std::lock_guard<std::mutex> lock(states.reqBufferLock);
+
+    hardware::hidl_vec<StreamBufferRet> bufRets;
+    if (!states.useHalBufManager) {
+        ALOGE("%s: Camera %s does not support HAL buffer management",
+                __FUNCTION__, states.cameraId.string());
+        _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
+        return;
+    }
+
+    SortedVector<int32_t> streamIds;
+    ssize_t sz = streamIds.setCapacity(bufReqs.size());
+    if (sz < 0 || static_cast<size_t>(sz) != bufReqs.size()) {
+        ALOGE("%s: failed to allocate memory for %zu buffer requests",
+                __FUNCTION__, bufReqs.size());
+        _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
+        return;
+    }
+
+    if (bufReqs.size() > states.outputStreams.size()) {
+        ALOGE("%s: too many buffer requests (%zu > # of output streams %zu)",
+                __FUNCTION__, bufReqs.size(), states.outputStreams.size());
+        _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
+        return;
+    }
+
+    // Check for repeated streamId
+    for (const auto& bufReq : bufReqs) {
+        if (streamIds.indexOf(bufReq.streamId) != NAME_NOT_FOUND) {
+            ALOGE("%s: Stream %d appear multiple times in buffer requests",
+                    __FUNCTION__, bufReq.streamId);
+            _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
+            return;
+        }
+        streamIds.add(bufReq.streamId);
+    }
+
+    if (!states.reqBufferIntf.startRequestBuffer()) {
+        ALOGE("%s: request buffer disallowed while camera service is configuring",
+                __FUNCTION__);
+        _hidl_cb(BufferRequestStatus::FAILED_CONFIGURING, bufRets);
+        return;
+    }
+
+    bufRets.resize(bufReqs.size());
+
+    bool allReqsSucceeds = true;
+    bool oneReqSucceeds = false;
+    for (size_t i = 0; i < bufReqs.size(); i++) {
+        const auto& bufReq = bufReqs[i];
+        auto& bufRet = bufRets[i];
+        int32_t streamId = bufReq.streamId;
+        sp<Camera3OutputStreamInterface> outputStream = states.outputStreams.get(streamId);
+        if (outputStream == nullptr) {
+            ALOGE("%s: Output stream id %d not found!", __FUNCTION__, streamId);
+            hardware::hidl_vec<StreamBufferRet> emptyBufRets;
+            _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, emptyBufRets);
+            states.reqBufferIntf.endRequestBuffer();
+            return;
+        }
+
+        bufRet.streamId = streamId;
+        if (outputStream->isAbandoned()) {
+            bufRet.val.error(StreamBufferRequestError::STREAM_DISCONNECTED);
+            allReqsSucceeds = false;
+            continue;
+        }
+
+        size_t handOutBufferCount = outputStream->getOutstandingBuffersCount();
+        uint32_t numBuffersRequested = bufReq.numBuffersRequested;
+        size_t totalHandout = handOutBufferCount + numBuffersRequested;
+        uint32_t maxBuffers = outputStream->asHalStream()->max_buffers;
+        if (totalHandout > maxBuffers) {
+            // Not able to allocate enough buffer. Exit early for this stream
+            ALOGE("%s: request too much buffers for stream %d: at HAL: %zu + requesting: %d"
+                    " > max: %d", __FUNCTION__, streamId, handOutBufferCount,
+                    numBuffersRequested, maxBuffers);
+            bufRet.val.error(StreamBufferRequestError::MAX_BUFFER_EXCEEDED);
+            allReqsSucceeds = false;
+            continue;
+        }
+
+        hardware::hidl_vec<StreamBuffer> tmpRetBuffers(numBuffersRequested);
+        bool currentReqSucceeds = true;
+        std::vector<camera_stream_buffer_t> streamBuffers(numBuffersRequested);
+        std::vector<buffer_handle_t> newBuffers;
+        size_t numAllocatedBuffers = 0;
+        size_t numPushedInflightBuffers = 0;
+        for (size_t b = 0; b < numBuffersRequested; b++) {
+            camera_stream_buffer_t& sb = streamBuffers[b];
+            // Since this method can run concurrently with request thread
+            // We need to update the wait duration everytime we call getbuffer
+            nsecs_t waitDuration =  states.reqBufferIntf.getWaitDuration();
+            status_t res = outputStream->getBuffer(&sb, waitDuration);
+            if (res != OK) {
+                if (res == NO_INIT || res == DEAD_OBJECT) {
+                    ALOGV("%s: Can't get output buffer for stream %d: %s (%d)",
+                            __FUNCTION__, streamId, strerror(-res), res);
+                    bufRet.val.error(StreamBufferRequestError::STREAM_DISCONNECTED);
+                    states.sessionStatsBuilder.stopCounter(streamId);
+                } else {
+                    ALOGE("%s: Can't get output buffer for stream %d: %s (%d)",
+                            __FUNCTION__, streamId, strerror(-res), res);
+                    if (res == TIMED_OUT || res == NO_MEMORY) {
+                        bufRet.val.error(StreamBufferRequestError::NO_BUFFER_AVAILABLE);
+                    } else {
+                        bufRet.val.error(StreamBufferRequestError::UNKNOWN_ERROR);
+                    }
+                }
+                currentReqSucceeds = false;
+                break;
+            }
+            numAllocatedBuffers++;
+
+            buffer_handle_t *buffer = sb.buffer;
+            auto pair = states.bufferRecordsIntf.getBufferId(*buffer, streamId);
+            bool isNewBuffer = pair.first;
+            uint64_t bufferId = pair.second;
+            StreamBuffer& hBuf = tmpRetBuffers[b];
+
+            hBuf.streamId = streamId;
+            hBuf.bufferId = bufferId;
+            hBuf.buffer = (isNewBuffer) ? *buffer : nullptr;
+            hBuf.status = BufferStatus::OK;
+            hBuf.releaseFence = nullptr;
+            if (isNewBuffer) {
+                newBuffers.push_back(*buffer);
+            }
+
+            native_handle_t *acquireFence = nullptr;
+            if (sb.acquire_fence != -1) {
+                acquireFence = native_handle_create(1,0);
+                acquireFence->data[0] = sb.acquire_fence;
+            }
+            hBuf.acquireFence.setTo(acquireFence, /*shouldOwn*/true);
+            hBuf.releaseFence = nullptr;
+
+            res = states.bufferRecordsIntf.pushInflightRequestBuffer(bufferId, buffer, streamId);
+            if (res != OK) {
+                ALOGE("%s: Can't get register request buffers for stream %d: %s (%d)",
+                        __FUNCTION__, streamId, strerror(-res), res);
+                bufRet.val.error(StreamBufferRequestError::UNKNOWN_ERROR);
+                currentReqSucceeds = false;
+                break;
+            }
+            numPushedInflightBuffers++;
+        }
+        if (currentReqSucceeds) {
+            bufRet.val.buffers(std::move(tmpRetBuffers));
+            oneReqSucceeds = true;
+        } else {
+            allReqsSucceeds = false;
+            for (size_t b = 0; b < numPushedInflightBuffers; b++) {
+                StreamBuffer& hBuf = tmpRetBuffers[b];
+                buffer_handle_t* buffer;
+                status_t res = states.bufferRecordsIntf.popInflightRequestBuffer(
+                        hBuf.bufferId, &buffer);
+                if (res != OK) {
+                    SET_ERR("%s: popInflightRequestBuffer failed for stream %d: %s (%d)",
+                            __FUNCTION__, streamId, strerror(-res), res);
+                }
+            }
+            for (size_t b = 0; b < numAllocatedBuffers; b++) {
+                camera_stream_buffer_t& sb = streamBuffers[b];
+                sb.acquire_fence = -1;
+                sb.status = CAMERA_BUFFER_STATUS_ERROR;
+            }
+            returnOutputBuffers(states.useHalBufManager, /*listener*/nullptr,
+                    streamBuffers.data(), numAllocatedBuffers, /*timestamp*/0,
+                    /*readoutTimestamp*/0, /*requested*/false,
+                    /*requestTimeNs*/0, states.sessionStatsBuilder);
+            for (auto buf : newBuffers) {
+                states.bufferRecordsIntf.removeOneBufferCache(streamId, buf);
+            }
+        }
+    }
+
+    _hidl_cb(allReqsSucceeds ? BufferRequestStatus::OK :
+            oneReqSucceeds ? BufferRequestStatus::FAILED_PARTIAL :
+                             BufferRequestStatus::FAILED_UNKNOWN,
+            bufRets);
+    states.reqBufferIntf.endRequestBuffer();
+}
+
+void returnStreamBuffers(ReturnBufferStates& states,
+        const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) {
+    returnStreamBuffersT(states, buffers);
+}
+
+} // camera3
+} // namespace android
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3OutputUtils.h b/services/camera/libcameraservice/device3/hidl/HidlCamera3OutputUtils.h
new file mode 100644
index 0000000..583d738
--- /dev/null
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3OutputUtils.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SERVERS_HIDL_CAMERA3_OUTPUT_UTILS_H
+#define ANDROID_SERVERS_HIDL_CAMERA3_OUTPUT_UTILS_H
+
+#include <memory>
+#include <mutex>
+
+#include <cutils/native_handle.h>
+
+#include <fmq/MessageQueue.h>
+
+#include <common/CameraDeviceBase.h>
+
+#include <android/hardware/camera/device/3.8/ICameraDeviceCallback.h>
+
+#include "device3/BufferUtils.h"
+//#include "device3/DistortionMapper.h"
+//#include "device3/ZoomRatioMapper.h"
+//#include "device3/RotateAndCropMapper.h"
+#include "device3/InFlightRequest.h"
+#include "device3/Camera3Stream.h"
+//#include "device3/Camera3OutputStreamInterface.h"
+#include "device3/Camera3OutputUtils.h"
+//#include "utils/SessionStatsBuilder.h"
+//#include "utils/TagMonitor.h"
+
+namespace android {
+
+using ResultMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
+
+namespace camera3 {
+
+    /**
+     * Helper methods shared between HidlCamera3Device/HidlCamera3OfflineSession for HAL callbacks
+     */
+    // Camera3Device/Camera3OfflineSession internal states used in notify/processCaptureResult
+    // callbacks
+    struct HidlCaptureOutputStates : public CaptureOutputStates {
+        std::unique_ptr<ResultMetadataQueue>& fmq;
+    };
+
+    // Handle one capture result. Assume callers hold the lock to serialize all
+    // processCaptureResult calls
+    void processOneCaptureResultLocked(
+            HidlCaptureOutputStates& states,
+            const hardware::camera::device::V3_2::CaptureResult& result,
+            const hardware::hidl_vec<
+                    hardware::camera::device::V3_4::PhysicalCameraMetadata>
+                            &physicalCameraMetadata);
+
+    // Handle one notify message
+    void notify(CaptureOutputStates& states,
+            const hardware::camera::device::V3_2::NotifyMsg& msg,
+            bool hasReadoutTime = false, uint64_t readoutTime = 0LL);
+    void notify(CaptureOutputStates& states,
+            const hardware::camera::device::V3_8::NotifyMsg& msg);
+
+    void requestStreamBuffers(RequestBufferStates& states,
+            const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
+            hardware::camera::device::V3_5::ICameraDeviceCallback::requestStreamBuffers_cb
+                    _hidl_cb);
+    void returnStreamBuffers(ReturnBufferStates& states,
+            const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers);
+
+} // namespace camera3
+
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
index a35e6f3..f826d83 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
@@ -22,7 +22,7 @@
 #include "android/hardware/camera/metadata/3.8/types.h"
 #include "common/CameraDeviceBase.h"
 #include "../CameraService.h"
-#include "device3/Camera3Device.h"
+#include "device3/hidl/HidlCamera3Device.h"
 #include "device3/Camera3OutputStream.h"
 #include "system/graphics-base-v1.1.h"
 
@@ -486,17 +486,18 @@
     stream->v3_7.v3_4.v3_2.streamType = hardware::camera::device::V3_2::StreamType::OUTPUT;
     stream->v3_7.v3_4.v3_2.width = streamInfo.width;
     stream->v3_7.v3_4.v3_2.height = streamInfo.height;
-    stream->v3_7.v3_4.v3_2.format = Camera3Device::mapToPixelFormat(streamInfo.format);
+    stream->v3_7.v3_4.v3_2.format = HidlCamera3Device::mapToPixelFormat(streamInfo.format);
     auto u = streamInfo.consumerUsage;
     camera3::Camera3OutputStream::applyZSLUsageQuirk(streamInfo.format, &u);
-    stream->v3_7.v3_4.v3_2.usage = Camera3Device::mapToConsumerUsage(u);
-    stream->v3_7.v3_4.v3_2.dataSpace = Camera3Device::mapToHidlDataspace(streamInfo.dataSpace);
-    stream->v3_7.v3_4.v3_2.rotation = Camera3Device::mapToStreamRotation(rotation);
+    stream->v3_7.v3_4.v3_2.usage = HidlCamera3Device::mapToConsumerUsage(u);
+    stream->v3_7.v3_4.v3_2.dataSpace = HidlCamera3Device::mapToHidlDataspace(streamInfo.dataSpace);
+    stream->v3_7.v3_4.v3_2.rotation = HidlCamera3Device::mapToStreamRotation(rotation);
     stream->v3_7.v3_4.v3_2.id = -1; // Invalid stream id
     stream->v3_7.v3_4.physicalCameraId = std::string(physicalId.string());
     stream->v3_7.v3_4.bufferSize = 0;
     stream->v3_7.groupId = groupId;
     stream->v3_7.sensorPixelModesUsed.resize(streamInfo.sensorPixelModesUsed.size());
+
     size_t idx = 0;
     for (auto mode : streamInfo.sensorPixelModesUsed) {
         stream->v3_7.sensorPixelModesUsed[idx++] =
@@ -599,7 +600,7 @@
         return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
     }
     *earlyExit = false;
-    auto ret = Camera3Device::mapToStreamConfigurationMode(
+    auto ret = HidlCamera3Device::mapToStreamConfigurationMode(
             static_cast<camera_stream_configuration_mode_t> (operatingMode),
             /*out*/ &streamConfiguration.operationMode);
     if (ret != OK) {
@@ -629,7 +630,7 @@
                 hardware::camera::device::V3_2::StreamType::INPUT,
                 static_cast<uint32_t> (sessionConfiguration.getInputWidth()),
                 static_cast<uint32_t> (sessionConfiguration.getInputHeight()),
-                Camera3Device::mapToPixelFormat(sessionConfiguration.getInputFormat()),
+                HidlCamera3Device::mapToPixelFormat(sessionConfiguration.getInputFormat()),
                 /*usage*/ 0, HAL_DATASPACE_UNKNOWN,
                 hardware::camera::device::V3_2::StreamRotation::ROTATION_0},
                 /*physicalId*/ nullptr, /*bufferSize*/0}, /*groupId*/-1, defaultSensorPixelModes};