Implement AidlCamera3Device implementation.

Bug: 196432585

Test: Camera CTS with AIDL provider

Change-Id: I67a6558a7d97b07b551c4614edca2e53770a955f
Signed-off-by: Jayant Chowdhary <jchowdhary@google.com>
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index 8cda830..3626378 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -85,6 +85,9 @@
         "device3/hidl/HidlCamera3Device.cpp",
         "device3/hidl/HidlCamera3OfflineSession.cpp",
         "device3/hidl/HidlCamera3OutputUtils.cpp",
+        "device3/aidl/AidlCamera3Device.cpp",
+        "device3/aidl/AidlCamera3OutputUtils.cpp",
+        "device3/aidl/AidlCamera3OfflineSession.cpp",
         "gui/RingBufferConsumer.cpp",
         "hidl/AidlCameraDeviceCallbacks.cpp",
         "hidl/AidlCameraServiceListener.cpp",
@@ -158,6 +161,7 @@
         "android.hardware.camera.device@3.6",
         "android.hardware.camera.device@3.7",
         "android.hardware.camera.device@3.8",
+        "android.hardware.camera.device-V1-ndk",
         "media_permission-aidl-cpp",
     ],
 
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 55c7579..727c265 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/aidl/AidlCamera3Device.h"
 #include "device3/hidl/HidlCamera3Device.h"
 #include "utils/CameraThreadState.h"
 #include "utils/CameraServiceProxyWrapper.h"
@@ -118,8 +119,10 @@
                             mLegacyClient);
             break;
         case IPCTransport::AIDL:
-            ALOGE("%s: AIDL camera3Devices not available yet", __FUNCTION__);
-            return NO_INIT;
+            mDevice =
+                    new AidlCamera3Device(TClientBase::mCameraIdStr, mOverrideForPerfClass,
+                            mLegacyClient);
+             break;
         default:
             ALOGE("%s Invalid transport for camera id %s", __FUNCTION__,
                     TClientBase::mCameraIdStr.string());
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 5cab157..1b8863a 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -647,6 +647,47 @@
     return OK;
 }
 
+status_t CameraProviderManager::openAidlInjectionSession(const std::string &id,
+        const std::shared_ptr<
+                aidl::android::hardware::camera::device::ICameraDeviceCallback>& callback,
+        /*out*/
+        std::shared_ptr<
+                aidl::android::hardware::camera::device::ICameraInjectionSession> *session) {
+
+    std::lock_guard<std::mutex> lock(mInterfaceMutex);
+
+    auto deviceInfo = findDeviceInfoLocked(id);
+    if (deviceInfo == nullptr) return NAME_NOT_FOUND;
+
+    auto *aidlDeviceInfo3 = static_cast<AidlProviderInfo::AidlDeviceInfo3*>(deviceInfo);
+    sp<ProviderInfo> parentProvider = deviceInfo->mParentProvider.promote();
+    if (parentProvider == nullptr) {
+        return DEAD_OBJECT;
+    }
+    auto provider =
+            static_cast<AidlProviderInfo *>(parentProvider.get())->startProviderInterface();
+    if (provider == nullptr) {
+        return DEAD_OBJECT;
+    }
+    std::shared_ptr<HalCameraProvider> halCameraProvider =
+            std::make_shared<AidlHalCameraProvider>(provider, provider->descriptor);
+    saveRef(DeviceMode::CAMERA, id, halCameraProvider);
+
+    auto interface = aidlDeviceInfo3->startDeviceInterface();
+    if (interface == nullptr) {
+        return DEAD_OBJECT;
+    }
+
+    auto ret = interface->openInjectionSession(callback, session);
+    if (!ret.isOk()) {
+        removeRef(DeviceMode::CAMERA, id);
+        ALOGE("%s: Transaction error opening a session for camera device %s: %s",
+                __FUNCTION__, id.c_str(), ret.getMessage());
+        return DEAD_OBJECT;
+    }
+    return OK;
+}
+
 status_t CameraProviderManager::openHidlSession(const std::string &id,
         const sp<device::V3_2::ICameraDeviceCallback>& callback,
         /*out*/
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index b67a7fa..3d108bd 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -344,6 +344,11 @@
         /*out*/
         std::shared_ptr<aidl::android::hardware::camera::device::ICameraDeviceSession> *session);
 
+    status_t openAidlInjectionSession(const std::string &id,
+        const std::shared_ptr<
+                aidl::android::hardware::camera::device::ICameraDeviceCallback>& callback,
+        /*out*/
+        std::shared_ptr<aidl::android::hardware::camera::device::ICameraInjectionSession> *session);
 
     /**
      * Open an active session to a camera device.
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index c8f6310..59b0305 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -65,8 +65,6 @@
 #include "utils/TraceHFR.h"
 #include "utils/CameraServiceProxyWrapper.h"
 
-#include "../common/hidl/HidlProviderInfo.h"
-
 #include <algorithm>
 #include <tuple>
 
@@ -2728,11 +2726,7 @@
             physicalMetadata, outputBuffers, numOutputBuffers, inputStreamId);
 }
 
-/**
- * HalInterface inner class methods
- */
-
-void Camera3Device::HalInterface::cleanupNativeHandles(
+void Camera3Device::cleanupNativeHandles(
         std::vector<native_handle_t*> *handles, bool closeFd) {
     if (handles == nullptr) {
         return;
@@ -2749,6 +2743,10 @@
     return;
 }
 
+/**
+ * HalInterface inner class methods
+ */
+
 void Camera3Device::HalInterface::getInflightBufferKeys(
         std::vector<std::pair<int32_t, int32_t>>* out) {
     mBufferRecords.getInflightBufferKeys(out);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index d466ae4..ba63c20 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -78,11 +78,17 @@
             public camera3::RequestBufferInterface,
             public camera3::FlushBufferInterface {
   friend class HidlCamera3Device;
+  friend class AidlCamera3Device;
   public:
 
     explicit Camera3Device(const String8& id, bool overrideForPerfClass, bool legacyClient = false);
 
     virtual ~Camera3Device();
+    // Delete and optionally close native handles and clear the input vector afterward
+    static void cleanupNativeHandles(
+            std::vector<native_handle_t*> *handles, bool closeFd = false);
+
+    IPCTransport getTransportType() { return mInterface->getTransportType(); }
 
     /**
      * CameraDeviceBase interface
@@ -448,10 +454,6 @@
             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);
-
         virtual void onBufferFreed(int streamId, const native_handle_t* handle) override;
 
         std::mutex mFreedBuffersLock;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h b/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h
index 7dc8e10..2e05dda 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h
@@ -60,12 +60,12 @@
 }
 
 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>
+template <class FmqType, class FmqPayloadType, class MetadataType>
 status_t readOneCameraMetadataLockedT(
         std::unique_ptr<FmqType>& fmq,
         uint64_t fmqResultSize,
@@ -76,7 +76,7 @@
         if (fmq == nullptr) {
             return NO_MEMORY; // logged in initialize()
         }
-        if (!fmq->read(resultMetadata.data(), fmqResultSize)) {
+        if (!fmq->read(reinterpret_cast<FmqPayloadType *>(resultMetadata.data()), fmqResultSize)) {
             ALOGE("%s: Cannot read camera metadata from fmq, size = %" PRIu64,
                     __FUNCTION__, fmqResultSize);
             return INVALID_OPERATION;
@@ -130,8 +130,21 @@
     return handle.fds[0].get();
 }
 
+inline const hardware::hidl_vec<uint8_t>&
+getResultMetadata(const android::hardware::camera::device::V3_2::CameraMetadata &result) {
+    return result;
+}
+
+inline const std::vector<uint8_t>&
+getResultMetadata(const aidl::android::hardware::camera::device::CameraMetadata &result) {
+    return result.metadata;
+}
+
+// Fmqpayload type is needed since AIDL generates an fmq of payload type int8_t
+// for a byte fmq vs MetadataType which is uint8_t. For HIDL, the same type is
+// generated for metadata and fmq payload : uint8_t.
 template <class StatesType, class CaptureResultType, class PhysMetadataType, class MetadataType,
-        class FmqType, class BufferStatusType>
+         class FmqType, class BufferStatusType, class FmqPayloadType = uint8_t>
 void processOneCaptureResultLockedT(
         StatesType& states,
         const CaptureResultType& result,
@@ -144,9 +157,9 @@
 
     // Read and validate the result metadata.
     MetadataType resultMetadata;
-    res = readOneCameraMetadataLockedT(
+    res = readOneCameraMetadataLockedT<FmqType, FmqPayloadType, MetadataType>(
             fmq, result.fmqResultSize,
-            resultMetadata, result.result);
+            resultMetadata, getResultMetadata(result.result));
     if (res != OK) {
         ALOGE("%s: Frame %d: Failed to read capture result metadata",
                 __FUNCTION__, result.frameNumber);
@@ -161,8 +174,9 @@
     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);
+        res = readOneCameraMetadataLockedT<FmqType, FmqPayloadType, MetadataType>(fmq,
+                physicalCameraMetadata[i].fmqMetadataSize,
+                physResultMetadata[i], getResultMetadata(physicalCameraMetadata[i].metadata));
         if (res != OK) {
             ALOGE("%s: Frame %d: Failed to read capture result metadata for camera %s",
                     __FUNCTION__, result.frameNumber,
@@ -170,8 +184,8 @@
             return;
         }
         physCamIds[i] = physicalCameraMetadata[i].physicalCameraId.c_str();
-        phyCamMetadatas[i] = reinterpret_cast<const camera_metadata_t*>(
-                physResultMetadata[i].data());
+        phyCamMetadatas[i] =
+                reinterpret_cast<const camera_metadata_t*>(physResultMetadata[i].data());
     }
     r.num_physcam_metadata = physResultCount;
     r.physcam_ids = physCamIds.data();
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
new file mode 100644
index 0000000..9ace0f9
--- /dev/null
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
@@ -0,0 +1,1580 @@
+/*
+ * 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 "AidlCamera3-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__)
+
+#define CLOGW(fmt, ...) ALOGW("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 <aidl/android/hardware/camera/device/ICameraInjectionSession.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android/hardware/camera2/ICameraDeviceUser.h>
+
+#include "utils/CameraTraces.h"
+#include "mediautils/SchedulingPolicyService.h"
+#include "device3/Camera3OutputStream.h"
+#include "device3/Camera3InputStream.h"
+#include "device3/Camera3FakeStream.h"
+#include "device3/Camera3SharedOutputStream.h"
+#include "device3/aidl/AidlCamera3OutputUtils.h"
+#include "device3/aidl/AidlCamera3OfflineSession.h"
+#include "CameraService.h"
+#include "utils/CameraThreadState.h"
+#include "utils/SessionConfigurationUtils.h"
+#include "utils/TraceHFR.h"
+#include "utils/CameraServiceProxyWrapper.h"
+
+#include "../../common/aidl/AidlProviderInfo.h"
+
+#include <algorithm>
+
+#include "AidlCamera3Device.h"
+
+using namespace android::camera3;
+using namespace aidl::android::hardware;
+using aidl::android::hardware::camera::metadata::SensorPixelMode;
+using aidl::android::hardware::camera::metadata::RequestAvailableDynamicRangeProfilesMap;
+using aidl::android::hardware::camera::metadata::ScalerAvailableStreamUseCases;
+
+namespace android {
+
+RequestAvailableDynamicRangeProfilesMap
+mapToAidlDynamicProfile(int dynamicRangeProfile) {
+    return static_cast<RequestAvailableDynamicRangeProfilesMap>(dynamicRangeProfile);
+}
+
+aidl::android::hardware::graphics::common::PixelFormat AidlCamera3Device::mapToAidlPixelFormat(
+        int frameworkFormat) {
+    return (aidl::android::hardware::graphics::common::PixelFormat) frameworkFormat;
+}
+
+aidl::android::hardware::graphics::common::Dataspace AidlCamera3Device::mapToAidlDataspace(
+        android_dataspace dataSpace) {
+    return (aidl::android::hardware::graphics::common::Dataspace)dataSpace;
+}
+
+aidl::android::hardware::graphics::common::BufferUsage AidlCamera3Device::mapToAidlConsumerUsage(
+        uint64_t usage) {
+    return (aidl::android::hardware::graphics::common::BufferUsage)usage;
+}
+
+aidl::android::hardware::camera::device::StreamRotation
+AidlCamera3Device::mapToAidlStreamRotation(camera_stream_rotation_t rotation) {
+    switch (rotation) {
+        case CAMERA_STREAM_ROTATION_0:
+            return aidl::android::hardware::camera::device::StreamRotation::ROTATION_0;
+        case CAMERA_STREAM_ROTATION_90:
+            return aidl::android::hardware::camera::device::StreamRotation::ROTATION_90;
+        case CAMERA_STREAM_ROTATION_180:
+            return aidl::android::hardware::camera::device::StreamRotation::ROTATION_180;
+        case CAMERA_STREAM_ROTATION_270:
+            return aidl::android::hardware::camera::device::StreamRotation::ROTATION_270;
+    }
+    ALOGE("%s: Unknown stream rotation %d", __FUNCTION__, rotation);
+    return aidl::android::hardware::camera::device::StreamRotation::ROTATION_0;
+}
+
+status_t AidlCamera3Device::mapToAidlStreamConfigurationMode(
+        camera_stream_configuration_mode_t operationMode,
+        aidl::android::hardware::camera::device::StreamConfigurationMode *mode) {
+    using StreamConfigurationMode =
+            aidl::android::hardware::camera::device::StreamConfigurationMode;
+    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 AidlCamera3Device::mapToFrameworkFormat(
+        aidl::android::hardware::graphics::common::PixelFormat pixelFormat) {
+    return static_cast<uint32_t>(pixelFormat);
+}
+
+android_dataspace AidlCamera3Device::mapToFrameworkDataspace(
+        aidl::android::hardware::graphics::common::Dataspace dataSpace) {
+    return static_cast<android_dataspace>(dataSpace);
+}
+
+uint64_t AidlCamera3Device::mapConsumerToFrameworkUsage(
+        aidl::android::hardware::graphics::common::BufferUsage usage) {
+    return (uint64_t)usage;
+}
+
+uint64_t AidlCamera3Device::mapProducerToFrameworkUsage(
+       aidl::android::hardware::graphics::common::BufferUsage usage) {
+    return (uint64_t)usage;
+}
+
+AidlCamera3Device::AidlCamera3Device(const String8& id, bool overrideForPerfClass,
+            bool legacyClient) : Camera3Device(id, overrideForPerfClass, legacyClient) {
+        mCallbacks = ndk::SharedRefBase::make<AidlCameraDeviceCallbacks>(this);
+}
+
+status_t AidlCamera3Device::initialize(sp<CameraProviderManager> manager,
+        const String8& monitorTags) {
+    ATRACE_CALL();
+    Mutex::Autolock il(mInterfaceLock);
+    Mutex::Autolock l(mLock);
+
+    ALOGV("%s: Initializing AIDL device for camera %s", __FUNCTION__, mId.string());
+    if (mStatus != STATUS_UNINITIALIZED) {
+        CLOGE("Already initialized!");
+        return INVALID_OPERATION;
+    }
+    if (manager == nullptr) return INVALID_OPERATION;
+
+    std::shared_ptr<camera::device::ICameraDeviceSession> session;
+    ATRACE_BEGIN("CameraHal::openSession");
+    status_t res = manager->openAidlSession(mId.string(), mCallbacks,
+            /*out*/ &session);
+    ATRACE_END();
+    if (res != OK) {
+        SET_ERR_L("Could not open camera session: %s (%d)", strerror(-res), res);
+        return res;
+    }
+    if (session == nullptr) {
+      ALOGE("JCLog: null session returned");
+      SET_ERR("Session iface returned is null");
+      return INVALID_OPERATION;
+    }
+    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<AidlRequestMetadataQueue> queue;
+    ::aidl::android::hardware::common::fmq::MQDescriptor<
+            int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite> desc;
+
+    ::ndk::ScopedAStatus requestQueueRet = session->getCaptureRequestMetadataQueue(&desc);
+    if (!requestQueueRet.isOk()) {
+        ALOGE("Transaction error when getting result metadata queue from camera session: %s",
+                requestQueueRet.getMessage());
+        return AidlProviderInfo::mapToStatusT(requestQueueRet);
+    }
+    queue = std::make_unique<AidlRequestMetadataQueue>(desc);
+    if (!queue->isValid() || queue->availableToWrite() <= 0) {
+        ALOGE("HAL returns empty result metadata fmq, not use it");
+        queue = nullptr;
+        // Don't use resQueue onwards.
+    }
+
+    std::unique_ptr<AidlResultMetadataQueue>& resQueue = mResultMetadataQueue;
+    ::aidl::android::hardware::common::fmq::MQDescriptor<
+        int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite> resDesc;
+    ::ndk::ScopedAStatus resultQueueRet = session->getCaptureResultMetadataQueue(&resDesc);
+    if (!resultQueueRet.isOk()) {
+        ALOGE("Transaction error when getting result metadata queue from camera session: %s",
+                resultQueueRet.getMessage());
+        return AidlProviderInfo::mapToStatusT(resultQueueRet);
+    }
+    resQueue = std::make_unique<AidlResultMetadataQueue>(resDesc);
+    if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
+        ALOGE("HAL returns empty result metadata fmq, not use it");
+        resQueue = nullptr;
+        // Don't use resQueue onwards.
+    }
+
+    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 AidlHalInterface(session, queue, mUseHalBufManager, mSupportOfflineProcessing);
+
+    std::string providerType;
+    mVendorTagId = manager->getProviderTagIdLocked(mId.string());
+    mTagMonitor.initialize(mVendorTagId);
+    if (!monitorTags.isEmpty()) {
+        mTagMonitor.parseTagsToMonitor(String8(monitorTags));
+    }
+
+    for (size_t i = 0; i < capabilities.count; i++) {
+        uint8_t capability = capabilities.data.u8[i];
+        if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) {
+            mNeedFixupMonochromeTags = true;
+        }
+    }
+
+    return initializeCommonLocked();
+}
+
+::ndk::ScopedAStatus AidlCamera3Device::AidlCameraDeviceCallbacks::processCaptureResult(
+            const std::vector<camera::device::CaptureResult>& results) {
+    sp<AidlCamera3Device> p = mParent.promote();
+    if (p == nullptr) {
+        ALOGE("%s Parent AidlCameraDevice not alive, can't process callbacks", __FUNCTION__);
+        return ::ndk::ScopedAStatus::ok();
+    }
+    return p->processCaptureResult(results);
+}
+
+::ndk::ScopedAStatus AidlCamera3Device::AidlCameraDeviceCallbacks::notify(
+        const std::vector<camera::device::NotifyMsg>& msgs) {
+    sp<AidlCamera3Device> p = mParent.promote();
+    if (p == nullptr) {
+        ALOGE("%s Parent AidlCameraDevice not alive, can't process callbacks", __FUNCTION__);
+        return ::ndk::ScopedAStatus::ok();
+    }
+    return p->notify(msgs);
+}
+
+::ndk::ScopedAStatus AidlCamera3Device::processCaptureResult(
+            const std::vector<camera::device::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 ::ndk::ScopedAStatus::ok();
+        }
+    }
+    AidlCaptureOutputStates 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, result.physicalCameraMetadata);
+    }
+    mProcessCaptureResultLock.unlock();
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus AidlCamera3Device::notify(
+        const std::vector<camera::device::NotifyMsg>& 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();
+    }
+
+    AidlCaptureOutputStates 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 ::ndk::ScopedAStatus::ok();
+
+}
+
+status_t AidlCamera3Device::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
+    camera::device::CameraOfflineSessionInfo offlineSessionInfo;
+    std::shared_ptr<camera::device::ICameraOfflineSession> offlineSession;
+    camera3::BufferRecords bufferRecords;
+    status_t ret = static_cast<AidlRequestThread *>(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() != (uint32_t)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 AidlCamera3OfflineSession(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
+}
+
+::ndk::ScopedAStatus AidlCamera3Device::AidlCameraDeviceCallbacks::requestStreamBuffers(
+        const std::vector<camera::device::BufferRequest>& bufReqs,
+        std::vector<aidl::android::hardware::camera::device::StreamBufferRet>* outBuffers,
+        aidl::android::hardware::camera::device::BufferRequestStatus* status) {
+
+    sp<AidlCamera3Device> p = mParent.promote();
+    if (p == nullptr) {
+        ALOGE("%s Parent AidlCameraDevice not alive, can't process callbacks", __FUNCTION__);
+        return ::ndk::ScopedAStatus::ok();
+    }
+    return p->requestStreamBuffers(bufReqs, outBuffers, status);
+}
+
+::ndk::ScopedAStatus AidlCamera3Device::requestStreamBuffers(
+        const std::vector<camera::device::BufferRequest>& bufReqs,
+        std::vector<aidl::android::hardware::camera::device::StreamBufferRet>* outBuffers,
+        aidl::android::hardware::camera::device::BufferRequestStatus* status) {
+
+    RequestBufferStates states {
+        mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams,
+        mSessionStatsBuilder, *this, *(mInterface), *this};
+    camera3::requestStreamBuffers(states, bufReqs, outBuffers, status);
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus AidlCamera3Device::AidlCameraDeviceCallbacks::returnStreamBuffers(
+        const std::vector<camera::device::StreamBuffer>& buffers) {
+    sp<AidlCamera3Device> p = mParent.promote();
+    if (p == nullptr) {
+        ALOGE("%s Parent AidlCameraDevice not alive, can't process callbacks", __FUNCTION__);
+        return ::ndk::ScopedAStatus::ok();
+    }
+    return p->returnStreamBuffers(buffers);
+}
+
+::ndk::ScopedAStatus AidlCamera3Device::returnStreamBuffers(
+        const std::vector<camera::device::StreamBuffer>& buffers) {
+    ReturnBufferStates states {
+        mId, mUseHalBufManager, mOutputStreams,  mSessionStatsBuilder,
+        *(mInterface)};
+    camera3::returnStreamBuffers(states, buffers);
+    return ::ndk::ScopedAStatus::ok();
+}
+
+AidlCamera3Device::AidlHalInterface::AidlHalInterface(
+            std::shared_ptr<aidl::android::hardware::camera::device::ICameraDeviceSession> &session,
+            std::shared_ptr<AidlRequestMetadataQueue> queue,
+            bool useHalBufManager, bool supportOfflineProcessing) :
+        HalInterface(useHalBufManager, supportOfflineProcessing),
+        mAidlSession(session),
+        mRequestMetadataQueue(queue) { }
+
+AidlCamera3Device::AidlHalInterface::AidlHalInterface(
+            std::shared_ptr<aidl::android::hardware::camera::device::ICameraDeviceSession>
+                    &deviceSession,
+            std::shared_ptr<aidl::android::hardware::camera::device::ICameraInjectionSession>
+                    &injectionSession, std::shared_ptr<AidlRequestMetadataQueue> queue,
+            bool useHalBufManager, bool supportOfflineProcessing) :
+        HalInterface(useHalBufManager, supportOfflineProcessing),
+        mAidlSession(deviceSession),
+        mAidlInjectionSession(injectionSession),
+        mRequestMetadataQueue(queue) { }
+
+bool AidlCamera3Device::AidlHalInterface::valid() {
+    return (mAidlSession != nullptr);
+}
+
+void AidlCamera3Device::AidlHalInterface::clear() {
+    mAidlSession.reset();
+}
+
+status_t AidlCamera3Device::AidlHalInterface::flush() {
+    ATRACE_NAME("CameraHal::flush");
+    if (!valid()) return INVALID_OPERATION;
+    status_t res = OK;
+
+    auto err = mAidlSession->flush();
+    if (!err.isOk()) {
+        ALOGE("%s: Transaction error: %s", __FUNCTION__, err.getMessage());
+        res = AidlProviderInfo::mapToStatusT(err);
+    }
+
+    return res;
+}
+
+status_t AidlCamera3Device::AidlHalInterface::dump(int /*fd*/) {
+    ATRACE_NAME("CameraHal::dump");
+    if (!valid()) return INVALID_OPERATION;
+
+    // Handled by CameraProviderManager::dump
+
+    return OK;
+}
+
+status_t AidlCamera3Device::AidlHalInterface::repeatingRequestEnd(uint32_t frameNumber,
+        const std::vector<int32_t> &streamIds) {
+    ATRACE_NAME("AidlCameraHal::repeatingRequestEnd");
+    if (!valid()) return INVALID_OPERATION;
+
+    mAidlSession->repeatingRequestEnd(frameNumber, streamIds);
+
+    return OK;
+}
+
+status_t AidlCamera3Device::AidlHalInterface::close() {
+    ATRACE_NAME("CameraHal::close()");
+    if (!valid()) return INVALID_OPERATION;
+    status_t res = OK;
+
+    auto err = mAidlSession->close();
+    // Interface will be dead shortly anyway, so don't log errors
+    if (!err.isOk()) {
+        res = DEAD_OBJECT;
+    }
+
+    return res;
+}
+
+void AidlCamera3Device::AidlHalInterface::signalPipelineDrain(const std::vector<int>& streamIds) {
+    ATRACE_NAME("CameraHal::signalPipelineDrain");
+    if (!valid()) {
+        ALOGE("%s called on invalid camera!", __FUNCTION__);
+        return;
+    }
+
+    auto err = mAidlSession->signalStreamFlush(streamIds, mNextStreamConfigCounter - 1);
+    if (!err.isOk()) {
+        ALOGE("%s: Transaction error: %s", __FUNCTION__, err.getMessage());
+        return;
+    }
+}
+
+bool AidlCamera3Device::AidlHalInterface::isReconfigurationRequired(
+        CameraMetadata& oldSessionParams, CameraMetadata& newSessionParams) {
+    // We do reconfiguration by default;
+    bool required = true;
+    if (mIsReconfigurationQuerySupported) {
+        aidl::android::hardware::camera::device::CameraMetadata oldParams, newParams;
+        camera_metadata_t* oldSessionMeta = const_cast<camera_metadata_t*>(
+                oldSessionParams.getAndLock());
+        uint8_t *oldSessionByteP = reinterpret_cast<uint8_t*>(oldSessionMeta);
+
+        camera_metadata_t* newSessionMeta = const_cast<camera_metadata_t*>(
+                newSessionParams.getAndLock());
+        uint8_t *newSessionByteP = reinterpret_cast<uint8_t*>(newSessionMeta);
+        // std::vector has no setToExternal, so we hacve to copy
+        oldParams.metadata.assign(oldSessionByteP,
+                oldSessionByteP + get_camera_metadata_size(oldSessionMeta));
+        newParams.metadata.assign(newSessionByteP,
+                newSessionByteP + get_camera_metadata_size(newSessionMeta));
+        auto err = mAidlSession->isReconfigurationRequired(oldParams, newParams, &required);
+        oldSessionParams.unlock(oldSessionMeta);
+        newSessionParams.unlock(newSessionMeta);
+        if (!err.isOk()) {
+            ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, err.getMessage());
+            return true;
+        }
+    }
+
+    return required;
+}
+
+status_t AidlCamera3Device::AidlHalInterface::constructDefaultRequestSettings(
+        camera_request_template_t templateId,
+        /*out*/ camera_metadata_t **requestTemplate) {
+    ATRACE_NAME("CameraAidlHal::constructDefaultRequestSettings");
+    using aidl::android::hardware::camera::device::RequestTemplate;
+    if (!valid()) return INVALID_OPERATION;
+    status_t res = OK;
+
+    RequestTemplate id;
+    aidl::android::hardware::camera::device::CameraMetadata request;
+    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;
+    }
+    auto err = mAidlSession->constructDefaultRequestSettings(id, &request);
+
+    if (!err.isOk()) {
+        ALOGE("%s: Transaction error: %s", __FUNCTION__, err.getMessage());
+        return AidlProviderInfo::mapToStatusT(err);
+    }
+    const camera_metadata *r =
+            reinterpret_cast<const camera_metadata_t*>(request.metadata.data());
+    size_t expectedSize = request.metadata.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__);
+            res = UNKNOWN_ERROR;
+        }
+    } else {
+        ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
+        res = UNKNOWN_ERROR;
+    }
+
+    return res;
+}
+
+status_t AidlCamera3Device::AidlHalInterface::configureStreams(
+    const camera_metadata_t *sessionParams,
+        camera_stream_configuration *config, const std::vector<uint32_t>& bufferSizes) {
+    using camera::device::StreamType;
+    using camera::device::StreamConfigurationMode;
+
+    ATRACE_NAME("CameraHal::configureStreams");
+    if (!valid()) return INVALID_OPERATION;
+    status_t res = OK;
+
+    // Convert stream config to AIDL
+    std::set<int> activeStreams;
+    camera::device::StreamConfiguration requestedConfiguration;
+    requestedConfiguration.streams.resize(config->num_streams);
+    for (size_t i = 0; i < config->num_streams; i++) {
+        camera::device::Stream &dst = requestedConfiguration.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;
+        }
+        dst.id = streamId;
+        dst.streamType = streamType;
+        dst.width = src->width;
+        dst.height = src->height;
+        dst.usage = mapToAidlConsumerUsage(cam3stream->getUsage());
+        dst.rotation = mapToAidlStreamRotation((camera_stream_rotation_t) src->rotation);
+        dst.format = mapToAidlPixelFormat(cam3stream->isFormatOverridden() ?
+                    cam3stream->getOriginalFormat() : src->format);
+        dst.dataSpace = mapToAidlDataspace(cam3stream->isDataSpaceOverridden() ?
+                    cam3stream->getOriginalDataSpace() : src->data_space);
+
+        dst.bufferSize = bufferSizes[i];
+        if (src->physical_camera_id != nullptr) {
+            dst.physicalCameraId = src->physical_camera_id;
+        }
+        dst.groupId = cam3stream->getHalStreamGroupId();
+        dst.sensorPixelModesUsed.resize(src->sensor_pixel_modes_used.size());
+        size_t j = 0;
+        for (int mode : src->sensor_pixel_modes_used) {
+            dst.sensorPixelModesUsed[j++] = static_cast<SensorPixelMode>(mode);
+        }
+        dst.dynamicRangeProfile = mapToAidlDynamicProfile(src->dynamic_range_profile);
+        dst.useCase = static_cast<ScalerAvailableStreamUseCases>(src->use_case);
+        activeStreams.insert(streamId);
+        // Create Buffer ID map if necessary
+        mBufferRecords.tryCreateBufferCache(streamId);
+    }
+    // remove BufferIdMap for deleted streams
+    mBufferRecords.removeInactiveBufferCaches(activeStreams);
+
+    StreamConfigurationMode operationMode;
+    res = mapToAidlStreamConfigurationMode(
+            (camera_stream_configuration_mode_t) config->operation_mode,
+            /*out*/ &operationMode);
+    if (res != OK) {
+        return res;
+    }
+    requestedConfiguration.operationMode = operationMode;
+    size_t sessionParamSize = get_camera_metadata_size(sessionParams);
+    uint8_t *sessionParamP =
+            reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams));
+
+    // std::vector has no setToExternal, so we have to copy
+    requestedConfiguration.sessionParams.metadata.assign(
+                sessionParamP, sessionParamP + sessionParamSize);
+    requestedConfiguration.operationMode = operationMode;
+
+    // Invoke configureStreams
+    std::vector<camera::device::HalStream> finalConfiguration;
+
+    requestedConfiguration.streamConfigCounter = mNextStreamConfigCounter++;
+    requestedConfiguration.multiResolutionInputImage = config->input_is_multi_resolution;
+    auto err = mAidlSession->configureStreams(requestedConfiguration, &finalConfiguration);
+    if (!err.isOk()) {
+        ALOGE("%s: Transaction error: %s", __FUNCTION__, err.getMessage());
+        return AidlProviderInfo::mapToStatusT(err);
+    }
+
+    // And convert output stream configuration from AIDL
+
+    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.size();
+        for (size_t idx = 0; idx < halStreamCount; idx++) {
+            if (finalConfiguration[realIdx].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;
+        }
+        camera::device::HalStream &src = finalConfiguration[realIdx];
+
+        Camera3Stream* dstStream = Camera3Stream::cast(dst);
+        int overrideFormat = mapToFrameworkFormat(src.overrideFormat);
+        android_dataspace overrideDataSpace = mapToFrameworkDataspace(src.overrideDataSpace);
+
+        dstStream->setOfflineProcessingSupport(src.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 =
+                    requestedConfiguration.streams[i].format != src.overrideFormat;
+            bool needDataspaceOverride =
+                    requestedConfiguration.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 (static_cast<int64_t>(src.producerUsage) != 0) {
+                ALOGE("%s: Stream %d: INPUT streams must have 0 for producer usage",
+                        __FUNCTION__, streamId);
+                return INVALID_OPERATION;
+            }
+            dstStream->setUsage(
+                    mapConsumerToFrameworkUsage(src.consumerUsage));
+        } else {
+            // OUTPUT
+            if (static_cast<int64_t>(src.consumerUsage) != 0) {
+                ALOGE("%s: Stream %d: OUTPUT streams must have 0 for consumer usage",
+                        __FUNCTION__, streamId);
+                return INVALID_OPERATION;
+            }
+            dstStream->setUsage(
+                    mapProducerToFrameworkUsage(src.producerUsage));
+        }
+        dst->max_buffers = src.maxBuffers;
+    }
+
+    return res;
+}
+
+status_t AidlCamera3Device::AidlHalInterface::configureInjectedStreams(
+        const camera_metadata_t* sessionParams, camera_stream_configuration* config,
+        const std::vector<uint32_t>& bufferSizes,
+        const CameraMetadata& cameraCharacteristics) {
+    using camera::device::StreamType;
+    using camera::device::StreamConfigurationMode;
+
+    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 AIDL
+    std::set<int> activeStreams;
+    camera::device::StreamConfiguration requestedConfiguration;
+    requestedConfiguration.streams.resize(config->num_streams);
+    for (size_t i = 0; i < config->num_streams; i++) {
+        camera::device::Stream& dst = requestedConfiguration.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;
+        }
+        dst.id = streamId;
+        dst.streamType = streamType;
+        dst.width = src->width;
+        dst.height = src->height;
+        dst.usage = mapToAidlConsumerUsage(cam3stream->getUsage());
+        dst.rotation = mapToAidlStreamRotation((camera_stream_rotation_t)src->rotation);
+        dst.format =
+            mapToAidlPixelFormat(cam3stream->isFormatOverridden() ? cam3stream->getOriginalFormat()
+                    : src->format);
+        dst.dataSpace =
+            mapToAidlDataspace(cam3stream->isDataSpaceOverridden() ?
+                    cam3stream->getOriginalDataSpace() : src->data_space);
+        dst.bufferSize = bufferSizes[i];
+        if (src->physical_camera_id != nullptr) {
+            dst.physicalCameraId = src->physical_camera_id;
+        }
+        dst.groupId = cam3stream->getHalStreamGroupId();
+        dst.sensorPixelModesUsed.resize(src->sensor_pixel_modes_used.size());
+        size_t j = 0;
+        for (int mode : src->sensor_pixel_modes_used) {
+            dst.sensorPixelModesUsed[j++] = static_cast<SensorPixelMode>(mode);
+        }
+        activeStreams.insert(streamId);
+        // Create Buffer ID map if necessary
+        mBufferRecords.tryCreateBufferCache(streamId);
+    }
+    // remove BufferIdMap for deleted streams
+    mBufferRecords.removeInactiveBufferCaches(activeStreams);
+
+    StreamConfigurationMode operationMode;
+    res = mapToAidlStreamConfigurationMode(
+            (camera_stream_configuration_mode_t)config->operation_mode,
+            /*out*/ &operationMode);
+    if (res != OK) {
+        return res;
+    }
+    requestedConfiguration.operationMode = operationMode;
+    size_t sessionParamSize = get_camera_metadata_size(sessionParams);
+    uint8_t *sessionParamP =
+            reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams));
+    requestedConfiguration.operationMode = operationMode;
+    requestedConfiguration.sessionParams.metadata.assign(
+            sessionParamP, sessionParamP + sessionParamSize);
+
+    // See which version of HAL we have
+    if (mAidlInjectionSession != nullptr) {
+        requestedConfiguration.streamConfigCounter = mNextStreamConfigCounter++;
+        requestedConfiguration.multiResolutionInputImage = config->input_is_multi_resolution;
+
+        const camera_metadata_t* rawMetadata = cameraCharacteristics.getAndLock();
+        uint8_t *aidlCharsP =
+                reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(rawMetadata));
+        aidl::android::hardware::camera::device::CameraMetadata aidlChars;
+        aidlChars.metadata.assign(aidlCharsP, aidlCharsP + get_camera_metadata_size(rawMetadata));
+        cameraCharacteristics.unlock(rawMetadata);
+
+        auto err = mAidlInjectionSession->configureInjectionStreams(requestedConfiguration,
+                aidlChars);
+        if (!err.isOk()) {
+            ALOGE("%s: Transaction error: %s", __FUNCTION__, err.getMessage());
+            return AidlProviderInfo::mapToStatusT(err);
+        }
+    } else {
+        ALOGE("%s: mAidlInjectionSession == nullptr, the injection not supported ", __FUNCTION__);
+        return INVALID_OPERATION;
+   }
+
+    return res;
+}
+
+status_t AidlCamera3Device::AidlHalInterface::processBatchCaptureRequests(
+        std::vector<camera_capture_request_t*>& requests,/*out*/uint32_t* numRequestProcessed) {
+    ATRACE_NAME("CameraHal::processBatchCaptureRequests");
+    if (!valid()) return INVALID_OPERATION;
+
+    std::vector<camera::device::CaptureRequest> captureRequests;
+    size_t batchSize = requests.size();
+    if (batchSize > INT_MAX) {
+        ALOGE("%s batchSize %zu > INT_MAX, aidl interface cannot handle batch size", __FUNCTION__,
+                  batchSize);
+        return BAD_VALUE;
+    }
+    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++) {
+       res = wrapAsAidlRequest(requests[i], /*out*/&captureRequests[i],
+                    /*out*/&handlesCreated, /*out*/&inflightBuffers);
+
+        if (res != OK) {
+            mBufferRecords.popInflightBuffers(inflightBuffers);
+            cleanupNativeHandles(&handlesCreated);
+            return res;
+        }
+    }
+
+    std::vector<camera::device::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, static_cast<int64_t>(pair.second)});
+            }
+        }
+        mFreedBuffers.clear();
+    }
+
+    *numRequestProcessed = 0;
+
+    // Write metadata to FMQ.
+    for (size_t i = 0; i < batchSize; i++) {
+        camera_capture_request_t* request = requests[i];
+        camera::device::CaptureRequest* captureRequest;
+        captureRequest = &captureRequests[i];
+
+        if (request->settings != nullptr) {
+            size_t settingsSize = get_camera_metadata_size(request->settings);
+            if (mRequestMetadataQueue != nullptr && mRequestMetadataQueue->write(
+                    reinterpret_cast<const int8_t*>(request->settings), settingsSize)) {
+                captureRequest->settings.metadata.resize(0);
+                captureRequest->fmqSettingsSize = settingsSize;
+            } else {
+                if (mRequestMetadataQueue != nullptr) {
+                    ALOGW("%s: couldn't utilize fmq, fallback to hwbinder", __FUNCTION__);
+                }
+                uint8_t *settingsP =
+                        reinterpret_cast<uint8_t*>(
+                                const_cast<camera_metadata_t*>(request->settings));
+                size_t settingsSize =  get_camera_metadata_size(request->settings);
+                captureRequest->settings.metadata.assign(settingsP, settingsP + settingsSize);
+                captureRequest->fmqSettingsSize = 0u;
+            }
+        } else {
+            // A null request settings maps to a size-0 CameraMetadata
+            captureRequest->settings.metadata.resize(0);
+            captureRequest->fmqSettingsSize = 0u;
+        }
+
+        captureRequest ->inputWidth = request->input_width;
+        captureRequest->inputHeight = request->input_height;
+
+        std::vector<camera::device::PhysicalCameraSetting>& physicalCameraSettings =
+                captureRequest->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 int8_t*>(request->physcam_settings[j]),
+                            settingsSize)) {
+                    physicalCameraSettings[j].settings.metadata.resize(0);
+                    physicalCameraSettings[j].fmqSettingsSize = settingsSize;
+                } else {
+                    if (mRequestMetadataQueue != nullptr) {
+                        ALOGW("%s: couldn't utilize fmq, fallback to hwbinder", __FUNCTION__);
+                    }
+                    uint8_t *physicalSettingsP =
+                            reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(
+                                    request->physcam_settings[j]));
+                    physicalCameraSettings[j].settings.metadata.assign(physicalSettingsP,
+                            physicalSettingsP + settingsSize);
+                    physicalCameraSettings[j].fmqSettingsSize = 0u;
+                }
+            } else {
+                physicalCameraSettings[j].fmqSettingsSize = 0u;
+                physicalCameraSettings[j].settings.metadata.resize(0);
+            }
+            physicalCameraSettings[j].physicalCameraId = request->physcam_id[j];
+        }
+    }
+
+    int32_t numRequests = 0;
+    auto retS = mAidlSession->processCaptureRequest(captureRequests, cachesToRemove,
+            &numRequests);
+    if (!retS.isOk()) {
+        res = AidlProviderInfo::mapToStatusT(retS);
+    }
+    if (res == OK) {
+        if (numRequests < 0) {
+            res = INVALID_OPERATION;
+        } else {
+            *numRequestProcessed = static_cast<uint32_t>(numRequests);
+        }
+
+    }
+    if (res == OK && *numRequestProcessed == batchSize) {
+        if (mAidlSession->isRemote()) {
+            // Only close acquire fence FDs when the AIDL 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 {
+        ALOGE("%s Error with processCaptureRequest %s ", __FUNCTION__, retS.getMessage());
+        mBufferRecords.popInflightBuffers(inflightBuffers);
+        cleanupNativeHandles(&handlesCreated);
+    }
+    return res;
+}
+
+status_t AidlCamera3Device::AidlHalInterface::wrapAsAidlRequest(camera_capture_request_t* request,
+        /*out*/camera::device::CaptureRequest* captureRequest,
+        /*out*/std::vector<native_handle_t*>* handlesCreated,
+        /*out*/std::vector<std::pair<int32_t, int32_t>>* inflightBuffers) {
+    using camera::device::BufferStatus;
+    using camera::device::StreamBuffer;
+    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) ? camera3::dupToAidlIfNotNull(buf) :
+                            aidl::android::hardware::common::NativeHandle();
+            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);
+            }
+            // duping here is okay, in aidl ownership is not given to aidl_handle
+            captureRequest->inputBuffer.acquireFence = camera3::dupToAidlIfNotNull(acquireFence);
+            captureRequest->inputBuffer.releaseFence =
+                    aidl::android::hardware::common::NativeHandle();
+
+            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 ?
+                        camera3::dupToAidlIfNotNull(buf) :
+                                aidl::android::hardware::common::NativeHandle();
+                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 = camera3::dupToAidlIfNotNull(acquireFence);
+            } else if (mUseHalBufManager) {
+                // HAL buffer management path
+                dst.bufferId = BUFFER_ID_NO_BUFFER;
+                dst.buffer = aidl::android::hardware::common::NativeHandle();
+                dst.acquireFence = aidl::android::hardware::common::NativeHandle();
+            } else {
+                ALOGE("%s: cannot send a null buffer in capture request!", __FUNCTION__);
+                return BAD_VALUE;
+            }
+            dst.streamId = streamId;
+            dst.status = BufferStatus::OK;
+            dst.releaseFence = aidl::android::hardware::common::NativeHandle();
+
+            // 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 AidlCamera3Device::AidlHalInterface::switchToOffline(
+        const std::vector<int32_t>& streamsToKeep,
+        /*out*/aidl::android::hardware::camera::device::CameraOfflineSessionInfo*
+                offlineSessionInfo,
+        /*out*/std::shared_ptr<aidl::android::hardware::camera::device::ICameraOfflineSession>*
+                offlineSession,
+        /*out*/camera3::BufferRecords* bufferRecords) {
+    ATRACE_NAME("CameraHal::switchToOffline");
+    if (!valid()) {
+        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;
+    }
+
+    auto err = mAidlSession->switchToOffline(streamsToKeep, offlineSessionInfo, offlineSession);
+
+    if (!err.isOk()) {
+        ALOGE("%s: Transaction error: %s", __FUNCTION__, err.getMessage());
+        return AidlProviderInfo::mapToStatusT(err);
+    }
+
+    return verifyBufferCaches(offlineSessionInfo, bufferRecords);
+}
+
+AidlCamera3Device::AidlRequestThread::AidlRequestThread(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 AidlCamera3Device::AidlRequestThread::switchToOffline(
+        const std::vector<int32_t>& streamsToKeep,
+        /*out*/camera::device::CameraOfflineSessionInfo* offlineSessionInfo,
+        /*out*/std::shared_ptr<camera::device::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<AidlHalInterface *>(mInterface.get()))->switchToOffline(
+            streamsToKeep, offlineSessionInfo, offlineSession, bufferRecords);
+}
+
+status_t AidlCamera3Device::AidlCamera3DeviceInjectionMethods::injectionInitialize(
+        const String8& injectedCamId, sp<CameraProviderManager> manager,
+        const std::shared_ptr<camera::device::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;
+    }
+
+    if (parent->getTransportType() != IPCTransport::AIDL) {
+        ALOGE("%s Parent transport not AIDL for injected camera id %s, aborting", __FUNCTION__,
+                  injectedCamId.c_str());
+        return INVALID_OPERATION;
+    }
+    mInjectedCamId = injectedCamId;
+    std::shared_ptr<camera::device::ICameraInjectionSession> injectionSession;
+    ATRACE_BEGIN("Injection CameraHal::openSession");
+    status_t res = manager->openAidlInjectionSession(injectedCamId.string(), callback,
+                                          /*out*/ &injectionSession);
+    ATRACE_END();
+    if (res != OK) {
+        ALOGE("Injection camera could not open camera session: %s (%d)",
+                strerror(-res), res);
+        return res;
+    }
+    std::shared_ptr<camera::device::ICameraDeviceSession> deviceSession = nullptr;
+    auto ret = injectionSession->getCameraDeviceSession(&deviceSession);
+    if (!ret.isOk() || deviceSession == nullptr) {
+        ALOGE("%s Camera injection session couldn't return ICameraDeviceSession", __FUNCTION__);
+        return AidlProviderInfo::mapToStatusT(ret);
+    }
+
+    std::shared_ptr<AidlRequestMetadataQueue> queue;
+    ::aidl::android::hardware::common::fmq::MQDescriptor<
+            int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite> desc;
+
+    ::ndk::ScopedAStatus requestQueueRet = deviceSession->getCaptureRequestMetadataQueue(&desc);
+    if (!requestQueueRet.isOk()) {
+        ALOGE("Injection camera transaction error when getting result metadata queue from camera"
+                " session: %s", requestQueueRet.getMessage());
+        return AidlProviderInfo::mapToStatusT(requestQueueRet);
+    }
+    queue = std::make_unique<AidlRequestMetadataQueue>(desc);
+    if (!queue->isValid() || queue->availableToWrite() <= 0) {
+        ALOGE("HAL returns empty result metadata fmq, not use it");
+        queue = nullptr;
+        // Don't use resQueue onwards.
+    }
+
+    std::unique_ptr<AidlResultMetadataQueue>& resQueue = mInjectionResultMetadataQueue;
+    ::aidl::android::hardware::common::fmq::MQDescriptor<
+        int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite> resDesc;
+    ::ndk::ScopedAStatus resultQueueRet = deviceSession->getCaptureResultMetadataQueue(&resDesc);
+    if (!resultQueueRet.isOk()) {
+        ALOGE("Transaction error when getting result metadata queue from camera session: %s",
+                resultQueueRet.getMessage());
+        return AidlProviderInfo::mapToStatusT(resultQueueRet);
+    }
+    resQueue = std::make_unique<AidlResultMetadataQueue>(resDesc);
+    if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
+        ALOGE("HAL returns empty result metadata fmq, not use it");
+        resQueue = nullptr;
+        // Don't use resQueue onwards.
+    }
+
+    ALOGV("%s: Injection camera interface = new HalInterface()", __FUNCTION__);
+
+    mInjectedCamHalInterface =
+            new AidlHalInterface(deviceSession, injectionSession, queue, parent->mUseHalBufManager,
+                       parent->mSupportOfflineProcessing);
+    if (mInjectedCamHalInterface == nullptr) {
+        ALOGE("%s: mInjectedCamHalInterface does not exist!", __FUNCTION__);
+        return DEAD_OBJECT;
+    }
+
+    return OK;
+}
+
+status_t AidlCamera3Device::AidlCamera3DeviceInjectionMethods::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 (parent->getTransportType() != IPCTransport::AIDL ||
+            newHalInterface->getTransportType() != IPCTransport::AIDL) {
+        ALOGE("%s Parent transport not AIDL for replacing hal interface", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    AidlCamera3Device *aidlParent = static_cast<AidlCamera3Device *>(parent.get());
+    if (keepBackup) {
+        if (mBackupHalInterface == nullptr) {
+            mBackupHalInterface = parent->mInterface;
+        }
+        if (mBackupResultMetadataQueue == nullptr) {
+            mBackupResultMetadataQueue = std::move(aidlParent->mResultMetadataQueue);
+            aidlParent->mResultMetadataQueue = std::move(mInjectionResultMetadataQueue);
+        }
+    } else {
+        mBackupHalInterface = nullptr;
+        aidlParent->mResultMetadataQueue = std::move(mBackupResultMetadataQueue);
+        mBackupResultMetadataQueue = nullptr;
+    }
+    parent->mInterface = newHalInterface;
+    return OK;
+}
+
+status_t AidlCamera3Device::injectionCameraInitialize(const String8 &injectedCamId,
+            sp<CameraProviderManager> manager) {
+        return (static_cast<AidlCamera3DeviceInjectionMethods *>
+                    (mInjectionMethods.get()))->injectionInitialize(injectedCamId, manager,
+                        std::shared_ptr<camera::device::ICameraDeviceCallback>(mCallbacks));
+};
+
+sp<Camera3Device::RequestThread> AidlCamera3Device::createNewRequestThread(
+                wp<Camera3Device> parent, sp<camera3::StatusTracker> statusTracker,
+                sp<Camera3Device::HalInterface> interface,
+                const Vector<int32_t>& sessionParamKeys,
+                bool useHalBufManager,
+                bool supportCameraMute) {
+    return new AidlRequestThread(parent, statusTracker, interface, sessionParamKeys,
+            useHalBufManager, supportCameraMute);
+};
+
+sp<Camera3Device::Camera3DeviceInjectionMethods>
+AidlCamera3Device::createCamera3DeviceInjectionMethods(wp<Camera3Device> parent) {
+    return new AidlCamera3DeviceInjectionMethods(parent);
+}
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h
new file mode 100644
index 0000000..e7998b9
--- /dev/null
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h
@@ -0,0 +1,273 @@
+/*
+ * 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_AIDLCAMERA3DEVICE_H
+#define ANDROID_SERVERS_AIDLCAMERA3DEVICE_H
+
+#include "../Camera3Device.h"
+#include "AidlCamera3OutputUtils.h"
+#include <fmq/AidlMessageQueue.h>
+
+#include <aidl/android/hardware/camera/device/BnCameraDeviceCallback.h>
+#include <aidl/android/hardware/camera/device/ICameraDevice.h>
+#include <aidl/android/hardware/camera/device/ICameraInjectionSession.h>
+namespace android {
+
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::android::AidlMessageQueue;
+
+/**
+ * CameraDevice for AIDL HAL devices.
+ */
+class AidlCamera3Device :
+            public Camera3Device {
+  public:
+
+    using AidlRequestMetadataQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
+    class AidlCameraDeviceCallbacks;
+    friend class AidlCameraDeviceCallbacks;
+    explicit AidlCamera3Device(const String8& id, bool overrideForPerfClass,
+            bool legacyClient = false);
+
+    virtual ~AidlCamera3Device() { }
+
+    static aidl::android::hardware::graphics::common::PixelFormat mapToAidlPixelFormat(
+            int frameworkFormat);
+    static aidl::android::hardware::graphics::common::Dataspace mapToAidlDataspace(
+            android_dataspace dataSpace);
+    static aidl::android::hardware::graphics::common::BufferUsage mapToAidlConsumerUsage(
+            uint64_t usage);
+    static aidl::android::hardware::camera::device::StreamRotation
+            mapToAidlStreamRotation(camera_stream_rotation_t rotation);
+
+    static status_t mapToAidlStreamConfigurationMode(
+            camera_stream_configuration_mode_t operationMode,
+            aidl::android::hardware::camera::device::StreamConfigurationMode *mode);
+
+    static int mapToFrameworkFormat(
+        aidl::android::hardware::graphics::common::PixelFormat pixelFormat);
+    static android_dataspace mapToFrameworkDataspace(
+            aidl::android::hardware::graphics::common::Dataspace);
+    static uint64_t mapConsumerToFrameworkUsage(
+            aidl::android::hardware::graphics::common::BufferUsage usage);
+    static uint64_t mapProducerToFrameworkUsage(
+            aidl::android::hardware::graphics::common::BufferUsage usage);
+
+    virtual status_t switchToOffline(const std::vector<int32_t>& /*streamsToKeep*/,
+            /*out*/ sp<CameraOfflineSessionBase>* /*session*/) override;
+
+    status_t initialize(sp<CameraProviderManager> manager, const String8& monitorTags) override;
+    class AidlHalInterface : public Camera3Device::HalInterface {
+     public:
+        AidlHalInterface(std::shared_ptr<
+                aidl::android::hardware::camera::device::ICameraDeviceSession> &session,
+                std::shared_ptr<AidlRequestMetadataQueue> queue,
+                bool useHalBufManager, bool supportOfflineProcessing);
+        AidlHalInterface(
+                std::shared_ptr<aidl::android::hardware::camera::device::ICameraDeviceSession>
+                    &injectionSession,
+                std::shared_ptr<
+                aidl::android::hardware::camera::device::ICameraInjectionSession> &session,
+                std::shared_ptr<AidlRequestMetadataQueue> queue,
+                bool useHalBufManager, bool supportOfflineProcessing);
+
+        virtual IPCTransport getTransportType() {return IPCTransport::AIDL; }
+
+
+        // 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;
+
+        // 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;
+
+        // Calls into the HAL interface
+        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 ,
+                const std::vector<int32_t> &) override;
+
+        status_t switchToOffline(
+        const std::vector<int32_t>& streamsToKeep,
+        /*out*/aidl::android::hardware::camera::device::CameraOfflineSessionInfo*
+                offlineSessionInfo,
+        /*out*/std::shared_ptr<aidl::android::hardware::camera::device::ICameraOfflineSession>*
+                offlineSession,
+        /*out*/camera3::BufferRecords* bufferRecords);
+
+     private:
+
+        // Always valid
+        std::shared_ptr<aidl::android::hardware::camera::device::ICameraDeviceSession>
+                mAidlSession = nullptr;
+        //Valid for injection sessions
+        std::shared_ptr<aidl::android::hardware::camera::device::ICameraInjectionSession>
+                mAidlInjectionSession = nullptr;
+
+        status_t wrapAsAidlRequest(camera_capture_request_t* request,
+                /*out*/aidl::android::hardware::camera::device::CaptureRequest* captureRequest,
+                /*out*/std::vector<native_handle_t*>* handlesCreated,
+                /*out*/std::vector<std::pair<int32_t, int32_t>>* inflightBuffers);
+
+        std::shared_ptr<AidlRequestMetadataQueue> mRequestMetadataQueue;
+    }; // class AidlHalInterface
+
+    /**
+     * Implementation of aidl::android::hardware::camera::device::ICameraDeviceCallback
+     */
+    ::ndk::ScopedAStatus processCaptureResult(
+            const std::vector<aidl::android::hardware::camera::device::CaptureResult>& results);
+    ::ndk::ScopedAStatus notify(
+            const std::vector<aidl::android::hardware::camera::device::NotifyMsg>& msgs);
+
+    ::ndk::ScopedAStatus requestStreamBuffers(
+            const std::vector<aidl::android::hardware::camera::device::BufferRequest>& bufReqs,
+            std::vector<aidl::android::hardware::camera::device::StreamBufferRet>* outBuffers,
+            aidl::android::hardware::camera::device::BufferRequestStatus* status);
+
+    ::ndk::ScopedAStatus returnStreamBuffers(
+            const std::vector<aidl::android::hardware::camera::device::StreamBuffer>& buffers);
+
+    class AidlRequestThread : public Camera3Device::RequestThread {
+      public:
+        AidlRequestThread(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*/aidl::android::hardware::camera::device::CameraOfflineSessionInfo*
+                        offlineSessionInfo,
+                /*out*/std::shared_ptr<
+                        aidl::android::hardware::camera::device::ICameraOfflineSession>*
+                                offlineSession,
+                /*out*/camera3::BufferRecords* bufferRecords);
+    }; // class AidlRequestThread
+
+    class AidlCamera3DeviceInjectionMethods : public Camera3DeviceInjectionMethods {
+     public:
+        // Initialize the injection camera and generate an hal interface.
+        status_t injectionInitialize(
+                const String8& injectedCamId, sp<CameraProviderManager> manager,
+                const std::shared_ptr<
+                    aidl::android::hardware::camera::device::ICameraDeviceCallback>&
+                    callback);
+        AidlCamera3DeviceInjectionMethods(wp<Camera3Device> parent) :
+                Camera3DeviceInjectionMethods(parent) { };
+        ~AidlCamera3DeviceInjectionMethods() {}
+     private:
+        // Backup of the original camera hal result FMQ.
+        std::unique_ptr<AidlResultMetadataQueue> mBackupResultMetadataQueue;
+
+        // FMQ writes the result for the injection camera. Must be guarded by
+        // mProcessCaptureResultLock.
+        std::unique_ptr<AidlResultMetadataQueue> mInjectionResultMetadataQueue;
+
+        // Use injection camera hal interface to replace and backup original
+        // camera hal interface.
+        virtual status_t replaceHalInterface(sp<HalInterface> newHalInterface,
+                bool keepBackup) override;
+    };
+
+    // We need a separate class which inherits from AIDL ICameraDeviceCallbacks
+    // since we use the ndk backend for AIDL HAL interfaces. The ndk backend of
+    // ICameraDeviceCallbacks doesn't support sp<> (since it doesn't inherit
+    // from RefBase).
+    // As a result we can't write sp<Camera3Device> = new AidlCamera3Device(...).
+    // It supports std::shared_ptr instead. Other references to
+    // Camera3Device in cameraserver use sp<> widely, so to keep supporting
+    // that, we create a new class which will be managed through std::shared_ptr
+    // internally by AidlCamera3Device.
+    class AidlCameraDeviceCallbacks :
+            public aidl::android::hardware::camera::device::BnCameraDeviceCallback {
+      public:
+
+        AidlCameraDeviceCallbacks(wp<AidlCamera3Device> parent) : mParent(parent)  { }
+        ~AidlCameraDeviceCallbacks() { }
+        ::ndk::ScopedAStatus processCaptureResult(
+                const std::vector<
+                        aidl::android::hardware::camera::device::CaptureResult>& results) override;
+        ::ndk::ScopedAStatus notify(
+                const std::vector<
+                        aidl::android::hardware::camera::device::NotifyMsg>& msgs) override;
+
+        ::ndk::ScopedAStatus requestStreamBuffers(
+                const std::vector<
+                        aidl::android::hardware::camera::device::BufferRequest>& bufReqs,
+                std::vector<aidl::android::hardware::camera::device::StreamBufferRet>* outBuffers,
+                aidl::android::hardware::camera::device::BufferRequestStatus* status) override;
+
+        ::ndk::ScopedAStatus returnStreamBuffers(
+                const std::vector<
+                        aidl::android::hardware::camera::device::StreamBuffer>& buffers) override;
+        private:
+            wp<AidlCamera3Device> mParent = nullptr;
+    };
+
+  private:
+    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<AidlResultMetadataQueue> mResultMetadataQueue = nullptr;
+
+    std::shared_ptr<AidlCameraDeviceCallbacks> mCallbacks = nullptr;
+
+
+}; // class AidlCamera3Device
+
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp
new file mode 100644
index 0000000..895ce56
--- /dev/null
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp
@@ -0,0 +1,247 @@
+/*
+ * 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 "AidlCamera3-OffLnSsn"
+#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
+
+#include <inttypes.h>
+
+#include <utils/Trace.h>
+
+#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
+
+#include "device3/aidl/AidlCamera3OfflineSession.h"
+#include "device3/Camera3OutputStream.h"
+#include "device3/aidl/AidlCamera3OutputUtils.h"
+#include "device3/Camera3InputStream.h"
+#include "device3/Camera3SharedOutputStream.h"
+#include "utils/CameraTraces.h"
+
+using namespace android::camera3;
+using namespace aidl::android::hardware;
+
+namespace android {
+
+
+AidlCamera3OfflineSession::~AidlCamera3OfflineSession() {
+    ATRACE_CALL();
+    ALOGV("%s: Tearing down aidl offline session for camera id %s", __FUNCTION__, mId.string());
+    AidlCamera3OfflineSession::disconnectSession();
+}
+
+status_t AidlCamera3OfflineSession::initialize(wp<NotificationListener> listener) {
+    ATRACE_CALL();
+
+    if (mSession == nullptr) {
+        ALOGE("%s: AIDL session is null!", __FUNCTION__);
+        return DEAD_OBJECT;
+    }
+
+    {
+        std::lock_guard<std::mutex> lock(mLock);
+
+        mListener = listener;
+
+        // setup result FMQ
+        std::unique_ptr<AidlResultMetadataQueue>& resQueue = mResultMetadataQueue;
+        ::aidl::android::hardware::common::fmq::MQDescriptor<
+            int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite> desc;
+        ::ndk::ScopedAStatus resultQueueRet = mSession->getCaptureResultMetadataQueue(&desc);
+        if (!resultQueueRet.isOk()) {
+            ALOGE("Transaction error when getting result metadata queue from camera session: %s",
+                    resultQueueRet.getMessage());
+            return DEAD_OBJECT;
+        }
+        resQueue = std::make_unique<AidlResultMetadataQueue>(desc);
+        if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
+            ALOGE("HAL returns empty result metadata fmq, not use it");
+            resQueue = nullptr;
+            // Don't use resQueue onwards.
+        }
+
+        mStatus = STATUS_ACTIVE;
+    }
+
+    mSession->setCallback(mCallbacks);
+
+    return OK;
+}
+
+::ndk::ScopedAStatus AidlCamera3OfflineSession::AidlCameraDeviceCallbacks::processCaptureResult(
+        const std::vector<camera::device::CaptureResult>& results) {
+    sp<AidlCamera3OfflineSession> p = mParent.promote();
+    if (p == nullptr) {
+        ALOGE("%s Parent AidlCameraDevice not alive, can't process callbacks", __FUNCTION__);
+        return ::ndk::ScopedAStatus::ok();
+    }
+    return p->processCaptureResult(results);
+}
+
+::ndk::ScopedAStatus AidlCamera3OfflineSession::processCaptureResult(
+        const std::vector<camera::device::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 ::ndk::ScopedAStatus::ok();
+        }
+        listener = mListener.promote();
+    }
+
+    AidlCaptureOutputStates 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, result.physicalCameraMetadata);
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus AidlCamera3OfflineSession::AidlCameraDeviceCallbacks::notify(
+        const std::vector<camera::device::NotifyMsg>& msgs) {
+    sp<AidlCamera3OfflineSession> p = mParent.promote();
+    if (p == nullptr) {
+        ALOGE("%s Parent AidlCameraDevice not alive, can't process callbacks", __FUNCTION__);
+        return ::ndk::ScopedAStatus::ok();
+    }
+    return p->notify(msgs);
+}
+
+::ndk::ScopedAStatus AidlCamera3OfflineSession::notify(
+        const std::vector<camera::device::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 ::ndk::ScopedAStatus::ok();
+        }
+        listener = mListener.promote();
+    }
+
+    AidlCaptureOutputStates 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 ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus AidlCamera3OfflineSession::AidlCameraDeviceCallbacks::requestStreamBuffers(
+        const std::vector<::aidl::android::hardware::camera::device::BufferRequest>& bufReqs,
+        std::vector<::aidl::android::hardware::camera::device::StreamBufferRet>* buffers,
+        ::aidl::android::hardware::camera::device::BufferRequestStatus* status) {
+    sp<AidlCamera3OfflineSession> p = mParent.promote();
+    if (p == nullptr) {
+        ALOGE("%s Parent AidlCameraDevice not alive, can't process callbacks", __FUNCTION__);
+        return ::ndk::ScopedAStatus::ok();
+    }
+    return p->requestStreamBuffers(bufReqs, buffers, status);
+}
+
+::ndk::ScopedAStatus AidlCamera3OfflineSession::requestStreamBuffers(
+        const std::vector<::aidl::android::hardware::camera::device::BufferRequest>& bufReqs,
+        std::vector<::aidl::android::hardware::camera::device::StreamBufferRet>* buffers,
+        ::aidl::android::hardware::camera::device::BufferRequestStatus* status) {
+
+    {
+        std::lock_guard<std::mutex> lock(mLock);
+        if (mStatus != STATUS_ACTIVE) {
+            ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+            return ::ndk::ScopedAStatus::ok();
+        }
+    }
+
+    RequestBufferStates states {
+        mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder,
+        *this, mBufferRecords, *this};
+    camera3::requestStreamBuffers(states, bufReqs, buffers, status);
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus AidlCamera3OfflineSession::AidlCameraDeviceCallbacks::returnStreamBuffers(
+        const std::vector<camera::device::StreamBuffer>& buffers) {
+    sp<AidlCamera3OfflineSession> p = mParent.promote();
+    if (p == nullptr) {
+        ALOGE("%s Parent AidlCameraDevice not alive, can't process callbacks", __FUNCTION__);
+        return ::ndk::ScopedAStatus::ok();
+    }
+    return p->returnStreamBuffers(buffers);
+}
+
+::ndk::ScopedAStatus AidlCamera3OfflineSession::returnStreamBuffers(
+        const std::vector<camera::device::StreamBuffer>& buffers) {
+    {
+        std::lock_guard<std::mutex> lock(mLock);
+        if (mStatus != STATUS_ACTIVE) {
+            ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+            return ::ndk::ScopedAStatus::ok();
+        }
+    }
+
+    ReturnBufferStates states {
+        mId, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder,
+        mBufferRecords};
+
+    camera3::returnStreamBuffers(states, buffers);
+    return ::ndk::ScopedAStatus::ok();
+}
+
+void AidlCamera3OfflineSession::disconnectSession() {
+  std::lock_guard<std::mutex> lock(mLock);
+  if (mSession != nullptr) {
+      mSession->close();
+  }
+  mSession.reset();
+}
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.h b/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.h
new file mode 100644
index 0000000..ad4a480
--- /dev/null
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.h
@@ -0,0 +1,134 @@
+/*
+ * 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_AIDL_CAMERA3OFFLINESESSION_H
+#define ANDROID_SERVERS_AIDL_CAMERA3OFFLINESESSION_H
+
+#include <memory>
+#include <mutex>
+
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+#include "AidlCamera3OutputUtils.h"
+#include <aidl/android/hardware/camera/device/BnCameraDeviceCallback.h>
+#include <aidl/android/hardware/camera/device/ICameraOfflineSession.h>
+
+#include <fmq/AidlMessageQueue.h>
+
+#include "common/CameraOfflineSessionBase.h"
+
+#include "device3/Camera3BufferManager.h"
+#include "device3/Camera3OfflineSession.h"
+#include "utils/TagMonitor.h"
+#include <camera_metadata_hidden.h>
+
+namespace android {
+
+namespace camera3 {
+
+class Camera3Stream;
+class Camera3OutputStreamInterface;
+class Camera3StreamInterface;
+
+} // namespace camera3
+
+/**
+ * AidlCamera3OfflineSession for offline session defined in AIDL ICameraOfflineSession
+ */
+class AidlCamera3OfflineSession :
+            public Camera3OfflineSession {
+  public:
+
+    virtual ~AidlCamera3OfflineSession();
+
+    virtual status_t initialize(wp<NotificationListener> listener) override;
+
+    /**
+     * Implementation of aidl::android::hardware::camera::device::ICameraDeviceCallback
+     */
+    ::ndk::ScopedAStatus processCaptureResult(
+            const std::vector<aidl::android::hardware::camera::device::CaptureResult>& results);
+    ::ndk::ScopedAStatus notify(
+            const std::vector<aidl::android::hardware::camera::device::NotifyMsg>& msgs);
+    ::ndk::ScopedAStatus requestStreamBuffers(
+            const std::vector<aidl::android::hardware::camera::device::BufferRequest>& bufReqs,
+            std::vector<aidl::android::hardware::camera::device::StreamBufferRet>* outBuffers,
+            aidl::android::hardware::camera::device::BufferRequestStatus* status);
+
+    ::ndk::ScopedAStatus returnStreamBuffers(
+            const std::vector<aidl::android::hardware::camera::device::StreamBuffer>& buffers);
+
+    // See explanation for why we need a separate class for this in
+    // AidlCamera3Device::AidlCameraDeviceCallbacks in AidlCamera3Device.h
+    class AidlCameraDeviceCallbacks :
+            virtual public aidl::android::hardware::camera::device::BnCameraDeviceCallback {
+      public:
+
+        AidlCameraDeviceCallbacks(wp<AidlCamera3OfflineSession> parent) : mParent(parent)  { }
+        ~AidlCameraDeviceCallbacks() {}
+        ::ndk::ScopedAStatus processCaptureResult(
+                const std::vector<
+                        aidl::android::hardware::camera::device::CaptureResult>& results) override;
+        ::ndk::ScopedAStatus notify(
+                const std::vector<
+                        aidl::android::hardware::camera::device::NotifyMsg>& msgs) override;
+
+        ::ndk::ScopedAStatus requestStreamBuffers(
+                const std::vector<
+                        aidl::android::hardware::camera::device::BufferRequest>& bufReqs,
+                std::vector<aidl::android::hardware::camera::device::StreamBufferRet>* out_buffers,
+                aidl::android::hardware::camera::device::BufferRequestStatus* _aidl_return
+                ) override;
+
+        ::ndk::ScopedAStatus returnStreamBuffers(
+                const std::vector<
+                        aidl::android::hardware::camera::device::StreamBuffer>& buffers) override;
+        private:
+            wp<AidlCamera3OfflineSession> mParent = nullptr;
+    };
+
+    // initialize by Camera3Device.
+    explicit AidlCamera3OfflineSession(const String8& id,
+            const sp<camera3::Camera3Stream>& inputStream,
+            const camera3::StreamSet& offlineStreamSet,
+            camera3::BufferRecords&& bufferRecords,
+            const camera3::InFlightRequestMap& offlineReqs,
+            const Camera3OfflineStates& offlineStates,
+            std::shared_ptr<aidl::android::hardware::camera::device::ICameraOfflineSession>
+                    offlineSession) :
+      Camera3OfflineSession(id, inputStream, offlineStreamSet, std::move(bufferRecords),
+              offlineReqs, offlineStates),
+      mSession(offlineSession) { mCallbacks = std::make_shared<AidlCameraDeviceCallbacks>(this);};
+
+    /**
+     * End of CameraOfflineSessionBase interface
+     */
+
+  private:
+    std::shared_ptr<aidl::android::hardware::camera::device::ICameraOfflineSession> mSession;
+    // FMQ to write result on. Must be guarded by mProcessCaptureResultLock.
+    std::unique_ptr<AidlResultMetadataQueue> mResultMetadataQueue;
+
+    std::shared_ptr<AidlCameraDeviceCallbacks> mCallbacks;
+
+    virtual void disconnectSession() override;
+
+}; // class AidlCamera3OfflineSession
+
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.cpp
new file mode 100644
index 0000000..3809f37
--- /dev/null
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.cpp
@@ -0,0 +1,341 @@
+/*
+ * 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 "AidlCamera3-OutputUtils"
+#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 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 <aidlcommonsupport/NativeHandle.h>
+
+#include <camera/CameraUtils.h>
+#include <camera_metadata_hidden.h>
+
+#include "device3/aidl/AidlCamera3OutputUtils.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(
+        AidlCaptureOutputStates& states,
+        const aidl::android::hardware::camera::device::CaptureResult& result,
+        const std::vector<aidl::android::hardware::camera::device::PhysicalCameraMetadata>
+                &physicalCameraMetadata) {
+    processOneCaptureResultLockedT<AidlCaptureOutputStates,
+        aidl::android::hardware::camera::device::CaptureResult,
+        std::vector<aidl::android::hardware::camera::device::PhysicalCameraMetadata>,
+        std::vector<uint8_t>, AidlResultMetadataQueue,
+        aidl::android::hardware::camera::device::BufferStatus, int8_t>(states, result,
+                physicalCameraMetadata);
+}
+
+void notify(CaptureOutputStates& states,
+        const aidl::android::hardware::camera::device::NotifyMsg& msg) {
+
+    using ErrorCode = aidl::android::hardware::camera::device::ErrorCode;
+    using Tag = aidl::android::hardware::camera::device::NotifyMsg::Tag;
+
+    ATRACE_CALL();
+    camera_notify_msg m;
+
+    switch (msg.getTag()) {
+        case Tag::error:
+            m.type = CAMERA_MSG_ERROR;
+            m.message.error.frame_number = msg.get<Tag::error>().frameNumber;
+            if (msg.get<Tag::error>().errorStreamId >= 0) {
+                sp<Camera3StreamInterface> stream =
+                        states.outputStreams.get(msg.get<Tag::error>().errorStreamId);
+                if (stream == nullptr) {
+                    ALOGE("%s: Frame %d: Invalid error stream id %d", __FUNCTION__,
+                            m.message.error.frame_number, msg.get<Tag::error>().errorStreamId);
+                    return;
+                }
+                m.message.error.error_stream = stream->asHalStream();
+            } else {
+                m.message.error.error_stream = nullptr;
+            }
+            switch (msg.get<Tag::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 Tag::shutter:
+            m.type = CAMERA_MSG_SHUTTER;
+            m.message.shutter.frame_number = msg.get<Tag::shutter>().frameNumber;
+            m.message.shutter.timestamp = msg.get<Tag::shutter>().timestamp;
+            m.message.shutter.readout_timestamp = msg.get<Tag::shutter>().readoutTimestamp;
+            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 std::vector<aidl::android::hardware::camera::device::BufferRequest>& bufReqs,
+        std::vector<::aidl::android::hardware::camera::device::StreamBufferRet>* outBuffers,
+        ::aidl::android::hardware::camera::device::BufferRequestStatus* status) {
+    using aidl::android::hardware::camera::device::BufferStatus;
+    using aidl::android::hardware::camera::device::StreamBuffer;
+    using aidl::android::hardware::camera::device::BufferRequestStatus;
+    using aidl::android::hardware::camera::device::StreamBufferRet;
+    using aidl::android::hardware::camera::device::StreamBufferRequestError;
+    using Tag = aidl::android::hardware::camera::device::StreamBuffersVal::Tag;
+    if (outBuffers == nullptr || status == nullptr) {
+        ALOGE("%s outBuffers / buffer status nullptr", __FUNCTION__);
+        return;
+    }
+    std::lock_guard<std::mutex> lock(states.reqBufferLock);
+    std::vector<StreamBufferRet> bufRets;
+    outBuffers->clear();
+    if (!states.useHalBufManager) {
+        ALOGE("%s: Camera %s does not support HAL buffer management",
+                __FUNCTION__, states.cameraId.string());
+        *status = BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS;
+        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());
+        *status = BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS;
+        return;
+    }
+
+    if (bufReqs.size() > states.outputStreams.size()) {
+        ALOGE("%s: too many buffer requests (%zu > # of output streams %zu)",
+                __FUNCTION__, bufReqs.size(), states.outputStreams.size());
+        *status = BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS;
+        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);
+            *status = BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS;
+            return;
+        }
+        streamIds.add(bufReq.streamId);
+    }
+
+    if (!states.reqBufferIntf.startRequestBuffer()) {
+        ALOGE("%s: request buffer disallowed while camera service is configuring",
+                __FUNCTION__);
+        *status = BufferRequestStatus::FAILED_CONFIGURING;
+        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);
+            std::vector<StreamBufferRet> emptyBufRets;
+            *status = BufferRequestStatus::FAILED_CONFIGURING;
+            states.reqBufferIntf.endRequestBuffer();
+            return;
+        }
+
+        bufRet.streamId = streamId;
+        if (outputStream->isAbandoned()) {
+            bufRet.val.set<Tag::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.set<Tag::error>(StreamBufferRequestError::MAX_BUFFER_EXCEEDED);
+            allReqsSucceeds = false;
+            continue;
+        }
+
+        std::vector<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.set<Tag::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.set<Tag::error>(StreamBufferRequestError::NO_BUFFER_AVAILABLE);
+                    } else {
+                        bufRet.val.set<Tag::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) ? camera3::dupToAidlIfNotNull(*buffer) :
+                    aidl::android::hardware::common::NativeHandle();
+            hBuf.status = BufferStatus::OK;
+            hBuf.releaseFence =  aidl::android::hardware::common::NativeHandle();
+            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;
+            }
+            //makeToAidl passes ownership to aidl NativeHandle made. Ownership
+            //is passed : see system/window.h : dequeueBuffer
+            hBuf.acquireFence = makeToAidlIfNotNull(acquireFence);
+            if (acquireFence != nullptr) {
+                native_handle_delete(acquireFence);
+            }
+            hBuf.releaseFence =  aidl::android::hardware::common::NativeHandle();
+
+            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.set<Tag::error>(StreamBufferRequestError::UNKNOWN_ERROR);
+                currentReqSucceeds = false;
+                break;
+            }
+            numPushedInflightBuffers++;
+        }
+        if (currentReqSucceeds) {
+            bufRet.val.set<Tag::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, nullptr,
+                    streamBuffers.data(), numAllocatedBuffers, 0,
+                    0, false,
+                    0, states.sessionStatsBuilder);
+            for (auto buf : newBuffers) {
+                states.bufferRecordsIntf.removeOneBufferCache(streamId, buf);
+            }
+        }
+    }
+
+    *status = allReqsSucceeds ? BufferRequestStatus::OK :
+            oneReqSucceeds ? BufferRequestStatus::FAILED_PARTIAL :
+                             BufferRequestStatus::FAILED_UNKNOWN,
+    // Transfer ownership of buffer fds to outBuffers
+    *outBuffers = std::move(bufRets);
+
+    states.reqBufferIntf.endRequestBuffer();
+}
+
+void returnStreamBuffers(ReturnBufferStates& states,
+        const std::vector<aidl::android::hardware::camera::device::StreamBuffer>& buffers) {
+    returnStreamBuffersT(states, buffers);
+}
+
+} // camera3
+} // namespace android
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.h b/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.h
new file mode 100644
index 0000000..e795624
--- /dev/null
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.h
@@ -0,0 +1,100 @@
+/*
+ * 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_AIDL_CAMERA3_OUTPUT_UTILS_H
+#define ANDROID_SERVERS_AIDL_CAMERA3_OUTPUT_UTILS_H
+
+#include <memory>
+#include <mutex>
+
+#include <cutils/native_handle.h>
+
+#include <aidlcommonsupport/NativeHandle.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include <common/CameraDeviceBase.h>
+
+#include <aidl/android/hardware/camera/device/ICameraDevice.h>
+#include <aidl/android/hardware/camera/device/ICameraDeviceCallback.h>
+#include "device3/BufferUtils.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 ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::android::AidlMessageQueue;
+
+using AidlResultMetadataQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
+namespace camera3 {
+    inline aidl::android::hardware::common::NativeHandle dupToAidlIfNotNull(
+            const native_handle_t *nh) {
+        if (nh == nullptr) {
+            return aidl::android::hardware::common::NativeHandle();
+        }
+        return dupToAidl(nh);
+    }
+
+    inline aidl::android::hardware::common::NativeHandle makeToAidlIfNotNull(
+            const native_handle_t *nh) {
+        if (nh == nullptr) {
+            return aidl::android::hardware::common::NativeHandle();
+        }
+        return makeToAidl(nh);
+    }
+
+    /**
+     * Helper methods shared between AidlCamera3Device/AidlCamera3OfflineSession for HAL callbacks
+     */
+
+    // Camera3Device/Camera3OfflineSession internal states used in notify/processCaptureResult
+    // callbacks
+    struct AidlCaptureOutputStates : public CaptureOutputStates {
+        std::unique_ptr<AidlResultMetadataQueue>& fmq;
+    };
+
+    // Handle one capture result. Assume callers hold the lock to serialize all
+    // processCaptureResult calls
+    void processOneCaptureResultLocked(
+            AidlCaptureOutputStates& states,
+            const aidl::android::hardware::camera::device::CaptureResult& result,
+            const std::vector<aidl::android::hardware::camera::device::PhysicalCameraMetadata>
+                    &physicalCameraMetadata);
+
+    void notify(CaptureOutputStates& states,
+        const aidl::android::hardware::camera::device::NotifyMsg& msg,
+        bool hasReadoutTime, uint64_t readoutTime);
+
+    void notify(CaptureOutputStates& states,
+        const aidl::android::hardware::camera::device::NotifyMsg& msg);
+
+    void requestStreamBuffers(RequestBufferStates& states,
+        const std::vector<aidl::android::hardware::camera::device::BufferRequest>& bufReqs,
+        std::vector<::aidl::android::hardware::camera::device::StreamBufferRet>* out_buffers,
+        ::aidl::android::hardware::camera::device::BufferRequestStatus* _aidl_return);
+
+    void returnStreamBuffers(ReturnBufferStates& states,
+        const std::vector<aidl::android::hardware::camera::device::StreamBuffer>& buffers);
+
+} // namespace camera3
+
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3OutputUtils.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3OutputUtils.cpp
index afe9d56..1563dcf 100644
--- a/services/camera/libcameraservice/device3/hidl/HidlCamera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3OutputUtils.cpp
@@ -38,6 +38,8 @@
 #include <camera_metadata_hidden.h>
 
 #include "device3/hidl/HidlCamera3OutputUtils.h"
+#include "device3/aidl/AidlCamera3OutputUtils.h"
+#include "device3/Camera3Device.h"
 #include "device3/Camera3OutputUtilsTemplated.h"
 
 #include "system/camera_metadata.h"
@@ -132,7 +134,116 @@
     notify(states, &m);
 }
 
+static void convertToAidl(
+        const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& hidlBufReqs,
+        std::vector<aidl::android::hardware::camera::device::BufferRequest> &aidlBufReqs) {
+    size_t i = 0;
+    aidlBufReqs.resize(hidlBufReqs.size());
+    for (const auto &hidlBufReq : hidlBufReqs) {
+        aidlBufReqs[i].streamId = hidlBufReq.streamId;
+        aidlBufReqs[i].numBuffersRequested = hidlBufReq.numBuffersRequested;
+        i++;
+    }
+}
 
+static hardware::camera::device::V3_5::StreamBufferRequestError
+convertToHidl(aidl::android::hardware::camera::device::StreamBufferRequestError aError) {
+    using AError = aidl::android::hardware::camera::device::StreamBufferRequestError;
+    using HError = hardware::camera::device::V3_5::StreamBufferRequestError;
+
+    switch(aError) {
+        case AError::NO_BUFFER_AVAILABLE:
+            return HError::NO_BUFFER_AVAILABLE;
+        case AError::MAX_BUFFER_EXCEEDED:
+            return HError::MAX_BUFFER_EXCEEDED;
+        case AError::STREAM_DISCONNECTED:
+            return HError::STREAM_DISCONNECTED;
+        default:
+            return HError::UNKNOWN_ERROR;
+    }
+}
+
+static hardware::camera::device::V3_5::BufferRequestStatus
+convertToHidl(const aidl::android::hardware::camera::device::BufferRequestStatus &aBufStatus) {
+    using AStatus = aidl::android::hardware::camera::device::BufferRequestStatus;
+    using HStatus = hardware::camera::device::V3_5::BufferRequestStatus;
+    switch (aBufStatus) {
+        case AStatus::OK:
+            return HStatus::OK;
+        case AStatus::FAILED_PARTIAL:
+            return HStatus::FAILED_PARTIAL;
+        case AStatus::FAILED_CONFIGURING:
+            return HStatus::FAILED_CONFIGURING;
+        case AStatus::FAILED_ILLEGAL_ARGUMENTS:
+            return HStatus::FAILED_ILLEGAL_ARGUMENTS;
+        case AStatus::FAILED_UNKNOWN:
+            return HStatus::FAILED_UNKNOWN;
+    }
+    return HStatus::FAILED_UNKNOWN;
+}
+
+static hardware::camera::device::V3_2::BufferStatus
+convertToHidl(const aidl::android::hardware::camera::device::BufferStatus &aBufStatus) {
+    using AStatus = aidl::android::hardware::camera::device::BufferStatus;
+    using HStatus = hardware::camera::device::V3_2::BufferStatus;
+    switch (aBufStatus) {
+        case AStatus::OK:
+            return HStatus::OK;
+        case AStatus::ERROR:
+            return HStatus::ERROR;
+    }
+    return HStatus::ERROR;
+}
+
+static native_handle_t *convertToHidl(const aidl::android::hardware::common::NativeHandle &ah,
+        std::vector<native_handle_t *> &handlesCreated) {
+    if (isHandleNull(ah)) {
+        return nullptr;
+    }
+    native_handle_t *nh = makeFromAidl(ah);
+    handlesCreated.emplace_back(nh);
+    return nh;
+}
+
+static void convertToHidl(
+        const std::vector<aidl::android::hardware::camera::device::StreamBuffer> &aBuffers,
+        hardware::camera::device::V3_5::StreamBuffersVal &hBuffersVal,
+        std::vector<native_handle_t *> &handlesCreated) {
+    using HStreamBuffer = hardware::camera::device::V3_2::StreamBuffer;
+    hardware::hidl_vec<HStreamBuffer> tmpBuffers(aBuffers.size());
+    size_t i = 0;
+    for (const auto &aBuf : aBuffers) {
+        tmpBuffers[i].status = convertToHidl(aBuf.status);
+        tmpBuffers[i].streamId = aBuf.streamId;
+        tmpBuffers[i].bufferId = aBuf.bufferId;
+        tmpBuffers[i].buffer = convertToHidl(aBuf.buffer, handlesCreated);
+        tmpBuffers[i].acquireFence = convertToHidl(aBuf.acquireFence, handlesCreated);
+        tmpBuffers[i].releaseFence = convertToHidl(aBuf.releaseFence, handlesCreated);
+    }
+    hBuffersVal.buffers(std::move(tmpBuffers));
+}
+
+static void convertToHidl(
+        const std::vector<aidl::android::hardware::camera::device::StreamBufferRet> &aidlBufRets,
+        hardware::hidl_vec<hardware::camera::device::V3_5::StreamBufferRet> &hidlBufRets,
+        std::vector<native_handle_t *> &handlesCreated) {
+    size_t i = 0;
+    using Tag = aidl::android::hardware::camera::device::StreamBuffersVal::Tag;
+    hidlBufRets.resize(aidlBufRets.size());
+    for (const auto &aidlBufRet : aidlBufRets) {
+        auto &hidlBufRet = hidlBufRets[i];
+        hidlBufRet.streamId = aidlBufRet.streamId;
+        switch(aidlBufRet.val.getTag()) {
+          case Tag::error:
+              hidlBufRet.val.error(convertToHidl(aidlBufRet.val.get<Tag::error>()));
+              break;
+          case Tag::buffers:
+              convertToHidl(aidlBufRet.val.get<Tag::buffers>(), hidlBufRet.val, handlesCreated);
+              break;
+        }
+        i++;
+    }
+}
 
 // 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
@@ -145,194 +256,22 @@
 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::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::vector<aidl::android::hardware::camera::device::BufferRequest> aidlBufReqs;
+    hardware::hidl_vec<hardware::camera::device::V3_5::StreamBufferRet> hidlBufRets;
+    convertToAidl(bufReqs, aidlBufReqs);
+    std::vector<::aidl::android::hardware::camera::device::StreamBufferRet> aidlBufRets;
+    ::aidl::android::hardware::camera::device::BufferRequestStatus aidlBufRetStatus;
 
-    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();
+    requestStreamBuffers(states, aidlBufReqs, &aidlBufRets, &aidlBufRetStatus);
+    std::vector<native_handle_t *> handlesCreated;
+    convertToHidl(aidlBufRets, hidlBufRets, handlesCreated);
+    _hidl_cb(convertToHidl(aidlBufRetStatus), hidlBufRets);
+    Camera3Device::cleanupNativeHandles(&handlesCreated);
 }
 
 void returnStreamBuffers(ReturnBufferStates& states,
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
index 557591f..84dbf6e 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
@@ -23,6 +23,7 @@
 #include "common/CameraDeviceBase.h"
 #include "common/HalConversionsTemplated.h"
 #include "../CameraService.h"
+#include "device3/aidl/AidlCamera3Device.h"
 #include "device3/hidl/HidlCamera3Device.h"
 #include "device3/Camera3OutputStream.h"
 #include "system/graphics-base-v1.1.h"
@@ -505,61 +506,6 @@
     return binder::Status::ok();
 }
 
-aidl::android::hardware::graphics::common::PixelFormat mapToAidlPixelFormat(
-        int frameworkFormat) {
-    return (aidl::android::hardware::graphics::common::PixelFormat) frameworkFormat;
-}
-
-aidl::android::hardware::graphics::common::Dataspace mapToAidlDataspace(
-        android_dataspace dataSpace) {
-    return (aidl::android::hardware::graphics::common::Dataspace)dataSpace;
-}
-
-aidl::android::hardware::graphics::common::BufferUsage mapToAidlConsumerUsage(
-        uint64_t usage) {
-    return (aidl::android::hardware::graphics::common::BufferUsage)usage;
-}
-
-aidl::android::hardware::camera::device::StreamRotation
-mapToAidlStreamRotation(camera_stream_rotation_t rotation) {
-    switch (rotation) {
-        case CAMERA_STREAM_ROTATION_0:
-            return aidl::android::hardware::camera::device::StreamRotation::ROTATION_0;
-        case CAMERA_STREAM_ROTATION_90:
-            return aidl::android::hardware::camera::device::StreamRotation::ROTATION_90;
-        case CAMERA_STREAM_ROTATION_180:
-            return aidl::android::hardware::camera::device::StreamRotation::ROTATION_180;
-        case CAMERA_STREAM_ROTATION_270:
-            return aidl::android::hardware::camera::device::StreamRotation::ROTATION_270;
-    }
-    ALOGE("%s: Unknown stream rotation %d", __FUNCTION__, rotation);
-    return aidl::android::hardware::camera::device::StreamRotation::ROTATION_0;
-}
-
-status_t mapToAidlStreamConfigurationMode(
-        camera_stream_configuration_mode_t operationMode,
-        aidl::android::hardware::camera::device::StreamConfigurationMode *mode) {
-    using StreamConfigurationMode =
-            aidl::android::hardware::camera::device::StreamConfigurationMode;
-    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;
-}
-
 void mapStreamInfo(const OutputStreamInfo &streamInfo,
             camera3::camera_stream_rotation_t rotation, String8 physicalId,
             int32_t groupId, aidl::android::hardware::camera::device::Stream *stream /*out*/) {
@@ -570,12 +516,12 @@
     stream->streamType = aidl::android::hardware::camera::device::StreamType::OUTPUT;
     stream->width = streamInfo.width;
     stream->height = streamInfo.height;
-    stream->format = mapToAidlPixelFormat(streamInfo.format);
+    stream->format = AidlCamera3Device::mapToAidlPixelFormat(streamInfo.format);
     auto u = streamInfo.consumerUsage;
     camera3::Camera3OutputStream::applyZSLUsageQuirk(streamInfo.format, &u);
-    stream->usage = mapToAidlConsumerUsage(u);
-    stream->dataSpace = mapToAidlDataspace(streamInfo.dataSpace);
-    stream->rotation = mapToAidlStreamRotation(rotation);
+    stream->usage = AidlCamera3Device::mapToAidlConsumerUsage(u);
+    stream->dataSpace = AidlCamera3Device::mapToAidlDataspace(streamInfo.dataSpace);
+    stream->rotation = AidlCamera3Device::mapToAidlStreamRotation(rotation);
     stream->id = -1; // Invalid stream id
     stream->physicalCameraId = std::string(physicalId.string());
     stream->bufferSize = 0;
@@ -668,8 +614,7 @@
         metadataGetter getMetadata, const std::vector<std::string> &physicalCameraIds,
         aidl::android::hardware::camera::device::StreamConfiguration &streamConfiguration,
         bool overrideForPerfClass, bool *earlyExit) {
-    using SensorPixelMode =
-            aidl::android::hardware::camera::metadata::SensorPixelMode;
+    using SensorPixelMode = aidl::android::hardware::camera::metadata::SensorPixelMode;
     auto operatingMode = sessionConfiguration.getOperatingMode();
     binder::Status res = checkOperatingMode(operatingMode, deviceInfo, logicalCameraId);
     if (!res.isOk()) {
@@ -682,7 +627,7 @@
         return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
     }
     *earlyExit = false;
-    auto ret = mapToAidlStreamConfigurationMode(
+    auto ret = AidlCamera3Device::mapToAidlStreamConfigurationMode(
             static_cast<camera_stream_configuration_mode_t> (operatingMode),
             /*out*/ &streamConfiguration.operationMode);
     if (ret != OK) {
@@ -712,7 +657,9 @@
         stream.streamType =  aidl::android::hardware::camera::device::StreamType::INPUT;
         stream.width = static_cast<uint32_t> (sessionConfiguration.getInputWidth());
         stream.height =  static_cast<uint32_t> (sessionConfiguration.getInputHeight());
-        stream.format = mapToAidlPixelFormat(sessionConfiguration.getInputFormat());
+        stream.format =
+                AidlCamera3Device::AidlCamera3Device::mapToAidlPixelFormat(
+                        sessionConfiguration.getInputFormat());
         stream.usage = static_cast<aidl::android::hardware::graphics::common::BufferUsage>(0);
         stream.dataSpace =
               static_cast<aidl::android::hardware::graphics::common::Dataspace>(