Camera: Update camera service to use new HIDL HALs, part 2

- Use string for device ID in Camera3Device
- Remove camera3_device_t parameter from Camera3Stream::finishConfiguration
  - Disables ability for the stream to register buffers
  - This means device HALv3.0 and v3.1 are no longer supported
- Add HIDL support to Camera3Device:
  - Add HalInterface class to abstract whether legacy or HIDL HAL is in use
- TODO
  - CameraHardwareInterface
  - Switch to using HIDL definitions instead of camera3.h definitions in
    main body of code

Test: Compiles
Bug: 30985004
Bug: 32991422
Change-Id: I9c3c0f7b7ea5d1d74e14b1d882779e3b9445da69
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index c4402f2..40b368e 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -48,7 +48,7 @@
     /**
      * The device's camera ID
      */
-    virtual int      getId() const = 0;
+    virtual const String8& getId() const = 0;
 
     virtual status_t initialize(CameraModule *module) = 0;
     virtual status_t initialize(sp<CameraProviderManager> manager) = 0;
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 8b08f2d..8b27c67 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -151,7 +151,7 @@
         CameraMetadata* characteristics) const {
     std::lock_guard<std::mutex> lock(mInterfaceMutex);
 
-    auto deviceInfo = findDeviceInfoLocked(id, /*minVersion*/ hardware::hidl_version{3,0});
+    auto deviceInfo = findDeviceInfoLocked(id, /*minVersion*/ {3,0}, /*maxVersion*/ {4,0});
     if (deviceInfo == nullptr) return NAME_NOT_FOUND;
 
     return deviceInfo->getCameraCharacteristics(characteristics);
@@ -180,7 +180,6 @@
     return OK;
 }
 
-
 status_t CameraProviderManager::setTorchMode(const std::string &id, bool enabled) {
     std::lock_guard<std::mutex> lock(mInterfaceMutex);
 
@@ -190,6 +189,51 @@
     return deviceInfo->setTorchMode(enabled);
 }
 
+status_t CameraProviderManager::openSession(const std::string &id,
+        const sp<hardware::camera::device::V3_2::ICameraDeviceCallback>& callback,
+        /*out*/
+        sp<hardware::camera::device::V3_2::ICameraDeviceSession> *session) {
+
+    std::lock_guard<std::mutex> lock(mInterfaceMutex);
+
+    auto deviceInfo = findDeviceInfoLocked(id,
+            /*minVersion*/ {3,0}, /*maxVersion*/ {4,0});
+    if (deviceInfo == nullptr) return NAME_NOT_FOUND;
+
+    auto *deviceInfo3 = static_cast<ProviderInfo::DeviceInfo3*>(deviceInfo);
+
+    Status status;
+    deviceInfo3->mInterface->open(callback, [&status, &session]
+            (Status s, const sp<device::V3_2::ICameraDeviceSession>& cameraSession) {
+                status = s;
+                if (status == Status::OK) {
+                    *session = cameraSession;
+                }
+            });
+    return mapToStatusT(status);
+}
+
+status_t CameraProviderManager::openSession(const std::string &id,
+        const sp<hardware::camera::device::V1_0::ICameraDeviceCallback>& callback,
+        /*out*/
+        sp<hardware::camera::device::V1_0::ICameraDevice> *session) {
+
+    std::lock_guard<std::mutex> lock(mInterfaceMutex);
+
+    auto deviceInfo = findDeviceInfoLocked(id,
+            /*minVersion*/ {1,0}, /*maxVersion*/ {2,0});
+    if (deviceInfo == nullptr) return NAME_NOT_FOUND;
+
+    auto *deviceInfo1 = static_cast<ProviderInfo::DeviceInfo1*>(deviceInfo);
+
+    Status status = deviceInfo1->mInterface->open(callback);
+    if (status == Status::OK) {
+        *session = deviceInfo1->mInterface;
+    }
+    return mapToStatusT(status);
+}
+
+
 hardware::Return<void> CameraProviderManager::onRegistration(
         const hardware::hidl_string& /*fqName*/,
         const hardware::hidl_string& name,
@@ -211,10 +255,12 @@
 }
 
 CameraProviderManager::ProviderInfo::DeviceInfo* CameraProviderManager::findDeviceInfoLocked(
-        const std::string& id, hardware::hidl_version minVersion) const {
+        const std::string& id,
+        hardware::hidl_version minVersion, hardware::hidl_version maxVersion) const {
     for (auto& provider : mProviders) {
         for (auto& deviceInfo : provider->mDevices) {
-            if (deviceInfo->mId == id && minVersion <= deviceInfo->mVersion) {
+            if (deviceInfo->mId == id &&
+                    minVersion <= deviceInfo->mVersion && maxVersion >= deviceInfo->mVersion) {
                 return deviceInfo.get();
             }
         }
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index b095ad7..345863c 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -156,6 +156,22 @@
     status_t setTorchMode(const std::string &id, bool enabled);
 
     /**
+     * Open an active session to a camera device.
+     *
+     * This fully powers on the camera device hardware, and returns a handle to a
+     * session to be used for hardware configuration and operation.
+     */
+    status_t openSession(const std::string &id,
+            const sp<hardware::camera::device::V3_2::ICameraDeviceCallback>& callback,
+            /*out*/
+            sp<hardware::camera::device::V3_2::ICameraDeviceSession> *session);
+
+    status_t openSession(const std::string &id,
+            const sp<hardware::camera::device::V1_0::ICameraDeviceCallback>& callback,
+            /*out*/
+            sp<hardware::camera::device::V1_0::ICameraDevice> *session);
+
+    /**
      * IServiceNotification::onRegistration
      * Invoked by the hardware service manager when a new camera provider is registered
      */
@@ -168,6 +184,12 @@
      */
     status_t dump(int fd, const Vector<String16>& args);
 
+    /**
+     * Conversion methods between HAL Status and status_t and strings
+     */
+    static status_t mapToStatusT(const hardware::camera::common::V1_0::Status& s);
+    static const char* statusToString(const hardware::camera::common::V1_0::Status& s);
+
 private:
     // All private members, unless otherwise noted, expect mInterfaceMutex to be locked before use
     mutable std::mutex mInterfaceMutex;
@@ -238,12 +260,6 @@
         };
         std::vector<std::unique_ptr<DeviceInfo>> mDevices;
 
-    private:
-        std::string mType;
-        uint32_t mId;
-
-        CameraProviderManager *mManager;
-
         // HALv1-specific camera fields, including the actual device interface
         struct DeviceInfo1 : public DeviceInfo {
             typedef hardware::camera::device::V1_0::ICameraDevice InterfaceT;
@@ -280,6 +296,12 @@
             CameraMetadata mCameraCharacteristics;
         };
 
+    private:
+        std::string mType;
+        uint32_t mId;
+
+        CameraProviderManager *mManager;
+
         // Templated method to instantiate the right kind of DeviceInfo and call the
         // right CameraProvider getCameraDeviceInterface_* method.
         template<class DeviceInfoT>
@@ -301,8 +323,12 @@
 
     // Utility to find a DeviceInfo by ID; pointer is only valid while mInterfaceMutex is held
     // and the calling code doesn't mutate the list of providers or their lists of devices.
+    // Finds the first device of the given ID that falls within the requested version range
+    //   minVersion <= deviceVersion < maxVersion
+    // No guarantees on the order of traversal
     ProviderInfo::DeviceInfo* findDeviceInfoLocked(const std::string& id,
-            hardware::hidl_version minVersion = hardware::hidl_version{0,0}) const;
+            hardware::hidl_version minVersion = hardware::hidl_version{0,0},
+            hardware::hidl_version maxVersion = hardware::hidl_version{1000,0}) const;
 
     status_t addProvider(const std::string& newProvider, bool expected = true);
     status_t removeProvider(const std::string& provider);
@@ -311,8 +337,6 @@
 
     std::vector<sp<ProviderInfo>> mProviders;
 
-    static status_t mapToStatusT(const hardware::camera::common::V1_0::Status& s);
-    static const char* statusToString(const hardware::camera::common::V1_0::Status&);
     static const char* deviceStatusToString(
         const hardware::camera::common::V1_0::CameraDeviceStatus&);
     static const char* torchStatusToString(
diff --git a/services/camera/libcameraservice/common/FrameProcessorBase.cpp b/services/camera/libcameraservice/common/FrameProcessorBase.cpp
index 2ef3057..9e78f88 100644
--- a/services/camera/libcameraservice/common/FrameProcessorBase.cpp
+++ b/services/camera/libcameraservice/common/FrameProcessorBase.cpp
@@ -123,7 +123,7 @@
     ATRACE_CALL();
     CaptureResult result;
 
-    ALOGV("%s: Camera %d: Process new frames", __FUNCTION__, device->getId());
+    ALOGV("%s: Camera %s: Process new frames", __FUNCTION__, device->getId().string());
 
     while ( (res = device->getNextResult(&result)) == OK) {
 
@@ -133,8 +133,8 @@
 
         entry = result.mMetadata.find(ANDROID_REQUEST_FRAME_COUNT);
         if (entry.count == 0) {
-            ALOGE("%s: Camera %d: Error reading frame number",
-                    __FUNCTION__, device->getId());
+            ALOGE("%s: Camera %s: Error reading frame number",
+                    __FUNCTION__, device->getId().string());
             break;
         }
         ATRACE_INT("cam2_frame", entry.data.i32[0]);
@@ -149,8 +149,8 @@
         }
     }
     if (res != NOT_ENOUGH_DATA) {
-        ALOGE("%s: Camera %d: Error getting next frame: %s (%d)",
-                __FUNCTION__, device->getId(), strerror(-res), res);
+        ALOGE("%s: Camera %s: Error getting next frame: %s (%d)",
+                __FUNCTION__, device->getId().string(), strerror(-res), res);
         return;
     }
 
@@ -159,8 +159,8 @@
 
 bool FrameProcessorBase::processSingleFrame(CaptureResult &result,
                                             const sp<CameraDeviceBase> &device) {
-    ALOGV("%s: Camera %d: Process single frame (is empty? %d)",
-          __FUNCTION__, device->getId(), result.mMetadata.isEmpty());
+    ALOGV("%s: Camera %s: Process single frame (is empty? %d)",
+            __FUNCTION__, device->getId().string(), result.mMetadata.isEmpty());
     return processListeners(result, device) == OK;
 }
 
@@ -178,8 +178,8 @@
         entry = result.mMetadata.find(ANDROID_QUIRKS_PARTIAL_RESULT);
         if (entry.count != 0 &&
                 entry.data.u8[0] == ANDROID_QUIRKS_PARTIAL_RESULT_PARTIAL) {
-            ALOGV("%s: Camera %d: This is a partial result",
-                    __FUNCTION__, device->getId());
+            ALOGV("%s: Camera %s: This is a partial result",
+                    __FUNCTION__, device->getId().string());
             isPartialResult = true;
         }
     }
@@ -190,7 +190,7 @@
     // include CaptureResultExtras.
     entry = result.mMetadata.find(ANDROID_REQUEST_ID);
     if (entry.count == 0) {
-        ALOGE("%s: Camera %d: Error reading frame id", __FUNCTION__, device->getId());
+        ALOGE("%s: Camera %s: Error reading frame id", __FUNCTION__, device->getId().string());
         return BAD_VALUE;
     }
     int32_t requestId = entry.data.i32[0];
@@ -215,8 +215,8 @@
             item++;
         }
     }
-    ALOGV("%s: Camera %d: Got %zu range listeners out of %zu", __FUNCTION__,
-          device->getId(), listeners.size(), mRangeListeners.size());
+    ALOGV("%s: Camera %s: Got %zu range listeners out of %zu", __FUNCTION__,
+          device->getId().string(), listeners.size(), mRangeListeners.size());
 
     List<sp<FilteredListener> >::iterator item = listeners.begin();
     for (; item != listeners.end(); item++) {
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 5b3509f..a357be1 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -26,7 +26,7 @@
 #endif
 
 // Convenience macro for transient errors
-#define CLOGE(fmt, ...) ALOGE("Camera %d: %s: " fmt, mId, __FUNCTION__, \
+#define CLOGE(fmt, ...) ALOGE("Camera %s: %s: " fmt, mId.string(), __FUNCTION__, \
             ##__VA_ARGS__)
 
 // Convenience macros for transitioning to the error state
@@ -56,13 +56,14 @@
 #include "CameraService.h"
 
 using namespace android::camera3;
+using namespace android::hardware::camera;
+using namespace android::hardware::camera::device::V3_2;
 
 namespace android {
 
 Camera3Device::Camera3Device(const String8 &id):
-        mId(atoi(id.string())),
+        mId(id),
         mIsConstrainedHighSpeedConfiguration(false),
-        mHal3Device(NULL),
         mStatus(STATUS_UNINITIALIZED),
         mStatusWaiters(0),
         mUsePartialResult(false),
@@ -77,17 +78,17 @@
     ATRACE_CALL();
     camera3_callback_ops::notify = &sNotify;
     camera3_callback_ops::process_capture_result = &sProcessCaptureResult;
-    ALOGV("%s: Created device for camera %d", __FUNCTION__, mId);
+    ALOGV("%s: Created device for camera %s", __FUNCTION__, mId.string());
 }
 
 Camera3Device::~Camera3Device()
 {
     ATRACE_CALL();
-    ALOGV("%s: Tearing down for camera id %d", __FUNCTION__, mId);
+    ALOGV("%s: Tearing down for camera id %s", __FUNCTION__, mId.string());
     disconnect();
 }
 
-int Camera3Device::getId() const {
+const String8& Camera3Device::getId() const {
     return mId;
 }
 
@@ -101,7 +102,7 @@
     Mutex::Autolock il(mInterfaceLock);
     Mutex::Autolock l(mLock);
 
-    ALOGV("%s: Initializing device for camera %d", __FUNCTION__, mId);
+    ALOGV("%s: Initializing device for camera %s", __FUNCTION__, mId.string());
     if (mStatus != STATUS_UNINITIALIZED) {
         CLOGE("Already initialized!");
         return INVALID_OPERATION;
@@ -110,12 +111,11 @@
     /** Open HAL device */
 
     status_t res;
-    String8 deviceName = String8::format("%d", mId);
 
     camera3_device_t *device;
 
-    ATRACE_BEGIN("camera3->open");
-    res = module->open(deviceName.string(),
+    ATRACE_BEGIN("CameraHal::open");
+    res = module->open(mId.string(),
             reinterpret_cast<hw_device_t**>(&device));
     ATRACE_END();
 
@@ -125,17 +125,17 @@
     }
 
     /** Cross-check device version */
-    if (device->common.version < CAMERA_DEVICE_API_VERSION_3_0) {
+    if (device->common.version < CAMERA_DEVICE_API_VERSION_3_2) {
         SET_ERR_L("Could not open camera: "
                 "Camera device should be at least %x, reports %x instead",
-                CAMERA_DEVICE_API_VERSION_3_0,
+                CAMERA_DEVICE_API_VERSION_3_2,
                 device->common.version);
         device->common.close(&device->common);
         return BAD_VALUE;
     }
 
     camera_info info;
-    res = module->getCameraInfo(mId, &info);
+    res = module->getCameraInfo(atoi(mId), &info);
     if (res != OK) return res;
 
     if (info.device_version != device->common.version) {
@@ -148,7 +148,7 @@
 
     /** Initialize device with callback functions */
 
-    ATRACE_BEGIN("camera3->initialize");
+    ATRACE_BEGIN("CameraHal::initialize");
     res = device->ops->initialize(device, this);
     ATRACE_END();
 
@@ -156,16 +156,62 @@
         SET_ERR_L("Unable to initialize HAL device: %s (%d)",
                 strerror(-res), res);
         device->common.close(&device->common);
-        return BAD_VALUE;
+        return res;
     }
 
+    /** Everything is good to go */
+
+    mDeviceVersion = device->common.version;
+    mDeviceInfo = info.static_camera_characteristics;
+    mInterface = std::make_unique<HalInterface>(device);
+
+    return initializeCommonLocked();
+}
+
+status_t Camera3Device::initialize(sp<CameraProviderManager> manager) {
+    ATRACE_CALL();
+    Mutex::Autolock il(mInterfaceLock);
+    Mutex::Autolock l(mLock);
+
+    ALOGV("%s: Initializing HIDL device for camera %s", __FUNCTION__, mId.string());
+    if (mStatus != STATUS_UNINITIALIZED) {
+        CLOGE("Already initialized!");
+        return INVALID_OPERATION;
+    }
+    if (manager == nullptr) return INVALID_OPERATION;
+
+    sp<ICameraDeviceSession> session;
+    ATRACE_BEGIN("CameraHal::openSession");
+    status_t res = manager->openSession(String8::std_string(mId), this,
+            /*out*/ &session);
+    ATRACE_END();
+    if (res != OK) {
+        SET_ERR_L("Could not open camera session: %s (%d)", strerror(-res), res);
+        return res;
+    }
+
+    res = manager->getCameraCharacteristics(String8::std_string(mId), &mDeviceInfo);
+    if (res != OK) {
+        SET_ERR_L("Could not retrive camera characteristics: %s (%d)", strerror(-res), res);
+        session->close();
+        return res;
+    }
+    hardware::hidl_version version = session->getInterfaceVersion();
+    mDeviceVersion = HARDWARE_DEVICE_API_VERSION(version.get_major(), version.get_minor());
+    mInterface = std::make_unique<HalInterface>(session);
+
+    return initializeCommonLocked();
+}
+
+status_t Camera3Device::initializeCommonLocked() {
+
     /** Start up status tracker thread */
     mStatusTracker = new StatusTracker(this);
-    res = mStatusTracker->run(String8::format("C3Dev-%d-Status", mId).string());
+    status_t res = mStatusTracker->run(String8::format("C3Dev-%s-Status", mId.string()).string());
     if (res != OK) {
         SET_ERR_L("Unable to start status tracking thread: %s (%d)",
                 strerror(-res), res);
-        device->common.close(&device->common);
+        mInterface->close();
         mStatusTracker.clear();
         return res;
     }
@@ -177,33 +223,27 @@
     mBufferManager = new Camera3BufferManager();
 
     bool aeLockAvailable = false;
-    camera_metadata_ro_entry aeLockAvailableEntry;
-    res = find_camera_metadata_ro_entry(info.static_camera_characteristics,
-            ANDROID_CONTROL_AE_LOCK_AVAILABLE, &aeLockAvailableEntry);
-    if (res == OK && aeLockAvailableEntry.count > 0) {
+    camera_metadata_entry aeLockAvailableEntry = mDeviceInfo.find(
+            ANDROID_CONTROL_AE_LOCK_AVAILABLE);
+    if (aeLockAvailableEntry.count > 0) {
         aeLockAvailable = (aeLockAvailableEntry.data.u8[0] ==
                 ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE);
     }
 
     /** Start up request queue thread */
-    mRequestThread = new RequestThread(this, mStatusTracker, device, aeLockAvailable);
-    res = mRequestThread->run(String8::format("C3Dev-%d-ReqQueue", mId).string());
+    mRequestThread = new RequestThread(this, mStatusTracker, mInterface.get(), mDeviceVersion,
+            aeLockAvailable);
+    res = mRequestThread->run(String8::format("C3Dev-%s-ReqQueue", mId.string()).string());
     if (res != OK) {
         SET_ERR_L("Unable to start request queue thread: %s (%d)",
                 strerror(-res), res);
-        device->common.close(&device->common);
+        mInterface->close();
         mRequestThread.clear();
         return res;
     }
 
     mPreparerThread = new PreparerThread();
 
-    /** Everything is good to go */
-
-    mDeviceVersion = device->common.version;
-    mDeviceInfo = info.static_camera_characteristics;
-    mHal3Device = device;
-
     // Determine whether we need to derive sensitivity boost values for older devices.
     // If post-RAW sensitivity boost range is listed, so should post-raw sensitivity control
     // be listed (as the default value 100)
@@ -256,12 +296,6 @@
     return OK;
 }
 
-status_t Camera3Device::initialize(sp<CameraProviderManager> manager) {
-    (void) manager;
-    ALOGE("%s: Not supported yet", __FUNCTION__);
-    return INVALID_OPERATION;
-}
-
 status_t Camera3Device::disconnect() {
     ATRACE_CALL();
     Mutex::Autolock il(mInterfaceLock);
@@ -318,7 +352,7 @@
         mStatusTracker->join();
     }
 
-    camera3_device_t *hal3Device;
+    HalInterface* interface;
     {
         Mutex::Autolock l(mLock);
 
@@ -326,20 +360,16 @@
         mStatusTracker.clear();
         mBufferManager.clear();
 
-        hal3Device = mHal3Device;
+        interface = mInterface.get();
     }
 
     // Call close without internal mutex held, as the HAL close may need to
     // wait on assorted callbacks,etc, to complete before it can return.
-    if (hal3Device != NULL) {
-        ATRACE_BEGIN("camera3->close");
-        hal3Device->common.close(&hal3Device->common);
-        ATRACE_END();
-    }
+    interface->close();
 
     {
         Mutex::Autolock l(mLock);
-        mHal3Device = NULL;
+        mInterface->clear();
         internalUpdateStatusLocked(STATUS_UNINITIALIZED);
     }
 
@@ -453,12 +483,80 @@
     }
 }
 
+hardware::graphics::common::V1_0::PixelFormat Camera3Device::mapToPixelFormat(
+        int frameworkFormat) {
+    return (hardware::graphics::common::V1_0::PixelFormat) frameworkFormat;
+}
+
+DataspaceFlags Camera3Device::mapToHidlDataspace(
+        android_dataspace dataSpace) {
+    return dataSpace;
+}
+
+ConsumerUsageFlags Camera3Device::mapToConsumerUsage(
+        uint32_t usage) {
+    return usage;
+}
+
+StreamRotation Camera3Device::mapToStreamRotation(camera3_stream_rotation_t rotation) {
+    switch (rotation) {
+        case CAMERA3_STREAM_ROTATION_0:
+            return StreamRotation::ROTATION_0;
+        case CAMERA3_STREAM_ROTATION_90:
+            return StreamRotation::ROTATION_90;
+        case CAMERA3_STREAM_ROTATION_180:
+            return StreamRotation::ROTATION_180;
+        case CAMERA3_STREAM_ROTATION_270:
+            return StreamRotation::ROTATION_270;
+    }
+    ALOGE("%s: Unknown stream rotation %d", __FUNCTION__, rotation);
+    return StreamRotation::ROTATION_0;
+}
+
+StreamConfigurationMode Camera3Device::mapToStreamConfigurationMode(
+        camera3_stream_configuration_mode_t operationMode) {
+    switch(operationMode) {
+        case CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE:
+            return StreamConfigurationMode::NORMAL_MODE;
+        case CAMERA3_STREAM_CONFIGURATION_CONSTRAINED_HIGH_SPEED_MODE:
+            return StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE;
+        case CAMERA3_VENDOR_STREAM_CONFIGURATION_MODE_START:
+            // Needs to be mapped by vendor extensions
+            break;
+    }
+    ALOGE("%s: Unknown stream configuration mode %d", __FUNCTION__, operationMode);
+    return StreamConfigurationMode::NORMAL_MODE;
+}
+
+camera3_buffer_status_t Camera3Device::mapHidlBufferStatus(BufferStatus status) {
+    switch (status) {
+        case BufferStatus::OK: return CAMERA3_BUFFER_STATUS_OK;
+        case BufferStatus::ERROR: return CAMERA3_BUFFER_STATUS_ERROR;
+    }
+    return CAMERA3_BUFFER_STATUS_ERROR;
+}
+
+int Camera3Device::mapToFrameworkFormat(
+        hardware::graphics::common::V1_0::PixelFormat pixelFormat) {
+    return static_cast<uint32_t>(pixelFormat);
+}
+
+uint32_t Camera3Device::mapConsumerToFrameworkUsage(
+        ConsumerUsageFlags usage) {
+    return usage;
+}
+
+uint32_t Camera3Device::mapProducerToFrameworkUsage(
+        ProducerUsageFlags usage) {
+    return usage;
+}
+
 ssize_t Camera3Device::getJpegBufferSize(uint32_t width, uint32_t height) const {
     // Get max jpeg size (area-wise).
     Size maxJpegResolution = getMaxJpegResolution();
     if (maxJpegResolution.width == 0) {
-        ALOGE("%s: Camera %d: Can't find valid available jpeg sizes in static metadata!",
-                __FUNCTION__, mId);
+        ALOGE("%s: Camera %s: Can't find valid available jpeg sizes in static metadata!",
+                __FUNCTION__, mId.string());
         return BAD_VALUE;
     }
 
@@ -466,7 +564,8 @@
     ssize_t maxJpegBufferSize = 0;
     camera_metadata_ro_entry jpegBufMaxSize = mDeviceInfo.find(ANDROID_JPEG_MAX_SIZE);
     if (jpegBufMaxSize.count == 0) {
-        ALOGE("%s: Camera %d: Can't find maximum JPEG size in static metadata!", __FUNCTION__, mId);
+        ALOGE("%s: Camera %s: Can't find maximum JPEG size in static metadata!", __FUNCTION__,
+                mId.string());
         return BAD_VALUE;
     }
     maxJpegBufferSize = jpegBufMaxSize.data.i32[0];
@@ -488,8 +587,8 @@
     const int FLOATS_PER_POINT=4;
     camera_metadata_ro_entry maxPointCount = mDeviceInfo.find(ANDROID_DEPTH_MAX_DEPTH_SAMPLES);
     if (maxPointCount.count == 0) {
-        ALOGE("%s: Camera %d: Can't find maximum depth point cloud size in static metadata!",
-                __FUNCTION__, mId);
+        ALOGE("%s: Camera %s: Can't find maximum depth point cloud size in static metadata!",
+                __FUNCTION__, mId.string());
         return BAD_VALUE;
     }
     ssize_t maxBytesForPointCloud = sizeof(android_depth_points) +
@@ -506,8 +605,8 @@
         mDeviceInfo.find(ANDROID_SENSOR_OPAQUE_RAW_SIZE);
     size_t count = rawOpaqueSizes.count;
     if (count == 0 || (count % PER_CONFIGURATION_SIZE)) {
-        ALOGE("%s: Camera %d: bad opaque RAW size static metadata length(%zu)!",
-                __FUNCTION__, mId, count);
+        ALOGE("%s: Camera %s: bad opaque RAW size static metadata length(%zu)!",
+                __FUNCTION__, mId.string(), count);
         return BAD_VALUE;
     }
 
@@ -518,8 +617,8 @@
         }
     }
 
-    ALOGE("%s: Camera %d: cannot find size for %dx%d opaque RAW image!",
-            __FUNCTION__, mId, width, height);
+    ALOGE("%s: Camera %s: cannot find size for %dx%d opaque RAW image!",
+            __FUNCTION__, mId.string(), width, height);
     return BAD_VALUE;
 }
 
@@ -533,11 +632,11 @@
     bool gotLock = tryLockSpinRightRound(mLock);
 
     ALOGW_IF(!gotInterfaceLock,
-            "Camera %d: %s: Unable to lock interface lock, proceeding anyway",
-            mId, __FUNCTION__);
+            "Camera %s: %s: Unable to lock interface lock, proceeding anyway",
+            mId.string(), __FUNCTION__);
     ALOGW_IF(!gotLock,
-            "Camera %d: %s: Unable to lock main lock, proceeding anyway",
-            mId, __FUNCTION__);
+            "Camera %s: %s: Unable to lock main lock, proceeding anyway",
+            mId.string(), __FUNCTION__);
 
     bool dumpTemplates = false;
 
@@ -630,12 +729,11 @@
         };
 
         for (int i = 1; i < CAMERA3_TEMPLATE_COUNT; i++) {
-            const camera_metadata_t *templateRequest;
-            templateRequest =
-                mHal3Device->ops->construct_default_request_settings(
-                    mHal3Device, i);
+            camera_metadata_t *templateRequest = nullptr;
+            mInterface->constructDefaultRequestSettings(
+                    (camera3_request_template_t) i, &templateRequest);
             lines = String8::format("    HAL Request %s:\n", templateNames[i-1]);
-            if (templateRequest == NULL) {
+            if (templateRequest == nullptr) {
                 lines.append("       Not supported\n");
                 write(fd, lines.string(), lines.size());
             } else {
@@ -643,15 +741,16 @@
                 dump_indented_camera_metadata(templateRequest,
                         fd, /*verbosity*/2, /*indentation*/8);
             }
+            free_camera_metadata(templateRequest);
         }
     }
 
     mTagMonitor.dumpMonitoredMetadata(fd);
 
-    if (mHal3Device != NULL) {
+    if (mInterface->valid()) {
         lines = String8("    HAL device dump:\n");
         write(fd, lines.string(), lines.size());
-        mHal3Device->ops->dump(mHal3Device, fd);
+        mInterface->dump(fd);
     }
 
     if (gotLock) mLock.unlock();
@@ -785,7 +884,7 @@
             SET_ERR_L("Can't transition to active in %f seconds!",
                     kActiveTimeout/1e9);
         }
-        ALOGV("Camera %d: Capture request %" PRId32 " enqueued", mId,
+        ALOGV("Camera %s: Capture request %" PRId32 " enqueued", mId.string(),
               (*(requestList.begin()))->mResultExtras.requestId);
     } else {
         CLOGE("Cannot queue request. Impossible.");
@@ -795,6 +894,141 @@
     return res;
 }
 
+hardware::Return<void> Camera3Device::processCaptureResult(
+        const device::V3_2::CaptureResult& result) {
+    camera3_capture_result r;
+    status_t res;
+    r.frame_number = result.frameNumber;
+    r.result = reinterpret_cast<const camera_metadata_t*>(result.result.data());
+    size_t expected_metadata_size = result.result.size();
+    if ((res = validate_camera_metadata_structure(r.result, &expected_metadata_size)) != OK) {
+        ALOGE("%s: Frame %d: Invalid camera metadata received by camera service from HAL: %s (%d)",
+                __FUNCTION__, result.frameNumber, strerror(-res), res);
+        return hardware::Void();
+    }
+
+    std::vector<camera3_stream_buffer_t> outputBuffers(result.outputBuffers.size());
+    std::vector<buffer_handle_t> outputBufferHandles(result.outputBuffers.size());
+    for (size_t i = 0; i < result.outputBuffers.size(); i++) {
+        auto& bDst = outputBuffers[i];
+        const StreamBuffer &bSrc = result.outputBuffers[i];
+
+        ssize_t idx = mOutputStreams.indexOfKey(bSrc.streamId);
+        if (idx == -1) {
+            ALOGE("%s: Frame %d: Buffer %zu: Invalid output stream id %d",
+                    __FUNCTION__, result.frameNumber, i, bSrc.streamId);
+            return hardware::Void();
+        }
+        bDst.stream = mOutputStreams.valueAt(idx)->asHalStream();
+
+        buffer_handle_t *buffer;
+        res = mInterface->popInflightBuffer(result.frameNumber, bSrc.streamId,
+                &buffer);
+        if (res != OK) {
+            ALOGE("%s: Frame %d: Buffer %zu: No in-flight buffer for stream %d",
+                    __FUNCTION__, result.frameNumber, i, bSrc.streamId);
+            return hardware::Void();
+        }
+        bDst.buffer = buffer;
+        bDst.status = mapHidlBufferStatus(bSrc.status);
+        bDst.acquire_fence = -1;
+        if (bSrc.releaseFence == nullptr) {
+            bDst.release_fence = -1;
+        } else if (bSrc.releaseFence->numFds == 1) {
+            bDst.release_fence = dup(bSrc.releaseFence->data[0]);
+        } else {
+            ALOGE("%s: Frame %d: Invalid release fence for buffer %zu, fd count is %d, not 1",
+                    __FUNCTION__, result.frameNumber, i, bSrc.releaseFence->numFds);
+            return hardware::Void();
+        }
+    }
+    r.num_output_buffers = outputBuffers.size();
+    r.output_buffers = outputBuffers.data();
+
+    camera3_stream_buffer_t inputBuffer;
+    if (result.inputBuffer.buffer == nullptr) {
+        r.input_buffer = nullptr;
+    } else {
+        if (mInputStream->getId() != result.inputBuffer.streamId) {
+            ALOGE("%s: Frame %d: Invalid input stream id %d", __FUNCTION__,
+                    result.frameNumber, result.inputBuffer.streamId);
+            return hardware::Void();
+        }
+        inputBuffer.stream = mInputStream->asHalStream();
+        buffer_handle_t *buffer;
+        res = mInterface->popInflightBuffer(result.frameNumber, result.inputBuffer.streamId,
+                &buffer);
+        if (res != OK) {
+            ALOGE("%s: Frame %d: Input buffer: No in-flight buffer for stream %d",
+                    __FUNCTION__, result.frameNumber, result.inputBuffer.streamId);
+            return hardware::Void();
+        }
+        inputBuffer.buffer = buffer;
+        inputBuffer.status = mapHidlBufferStatus(result.inputBuffer.status);
+        inputBuffer.acquire_fence = -1;
+        if (result.inputBuffer.releaseFence == nullptr) {
+            inputBuffer.release_fence = -1;
+        } else if (result.inputBuffer.releaseFence->numFds == 1) {
+            inputBuffer.release_fence = dup(result.inputBuffer.releaseFence->data[0]);
+        } else {
+            ALOGE("%s: Frame %d: Invalid release fence for input buffer, fd count is %d, not 1",
+                    __FUNCTION__, result.frameNumber, result.inputBuffer.releaseFence->numFds);
+            return hardware::Void();
+        }
+        r.input_buffer = &inputBuffer;
+    }
+
+    r.partial_result = result.partialResult;
+
+    processCaptureResult(&r);
+
+    return hardware::Void();
+}
+
+hardware::Return<void> Camera3Device::notify(
+        const NotifyMsg& msg) {
+    camera3_notify_msg m;
+    switch (msg.type) {
+        case MsgType::ERROR:
+            m.type = CAMERA3_MSG_ERROR;
+            m.message.error.frame_number = msg.msg.error.frameNumber;
+            if (msg.msg.error.errorStreamId >= 0) {
+                ssize_t idx = mOutputStreams.indexOfKey(msg.msg.error.errorStreamId);
+                if (idx == -1) {
+                    ALOGE("%s: Frame %d: Invalid error stream id %d",
+                            __FUNCTION__, m.message.error.frame_number, msg.msg.error.errorStreamId);
+                    return hardware::Void();
+                }
+                m.message.error.error_stream = mOutputStreams.valueAt(idx)->asHalStream();
+            } else {
+                m.message.error.error_stream = nullptr;
+            }
+            switch (msg.msg.error.errorCode) {
+                case ErrorCode::ERROR_DEVICE:
+                    m.message.error.error_code = CAMERA3_MSG_ERROR_DEVICE;
+                    break;
+                case ErrorCode::ERROR_REQUEST:
+                    m.message.error.error_code = CAMERA3_MSG_ERROR_REQUEST;
+                    break;
+                case ErrorCode::ERROR_RESULT:
+                    m.message.error.error_code = CAMERA3_MSG_ERROR_RESULT;
+                    break;
+                case ErrorCode::ERROR_BUFFER:
+                    m.message.error.error_code = CAMERA3_MSG_ERROR_BUFFER;
+                    break;
+            }
+            break;
+        case MsgType::SHUTTER:
+            m.type = CAMERA3_MSG_SHUTTER;
+            m.message.shutter.frame_number = msg.msg.shutter.frameNumber;
+            m.message.shutter.timestamp = msg.msg.shutter.timestamp;
+            break;
+    }
+    notify(&m);
+
+    return hardware::Void();
+}
+
 status_t Camera3Device::captureList(const List<const CameraMetadata> &requests,
                                     int64_t *lastFrameNumber) {
     ATRACE_CALL();
@@ -860,7 +1094,7 @@
             SET_ERR_L("Unexpected status: %d", mStatus);
             return INVALID_OPERATION;
     }
-    ALOGV("Camera %d: Clearing repeating request", mId);
+    ALOGV("Camera %s: Clearing repeating request", mId.string());
 
     return mRequestThread->clearRepeatingRequests(lastFrameNumber);
 }
@@ -877,8 +1111,8 @@
     ATRACE_CALL();
     Mutex::Autolock il(mInterfaceLock);
     Mutex::Autolock l(mLock);
-    ALOGV("Camera %d: Creating new input stream %d: %d x %d, format %d",
-            mId, mNextStreamId, width, height, format);
+    ALOGV("Camera %s: Creating new input stream %d: %d x %d, format %d",
+            mId.string(), mNextStreamId, width, height, format);
 
     status_t res;
     bool wasActive = false;
@@ -934,7 +1168,7 @@
         internalResumeLocked();
     }
 
-    ALOGV("Camera %d: Created input stream", mId);
+    ALOGV("Camera %s: Created input stream", mId.string());
     return OK;
 }
 
@@ -948,8 +1182,8 @@
     ATRACE_CALL();
     Mutex::Autolock il(mInterfaceLock);
     Mutex::Autolock l(mLock);
-    ALOGV("Camera %d: Creating ZSL stream %d: %d x %d, depth %d",
-            mId, mNextStreamId, width, height, depth);
+    ALOGV("Camera %s: Creating ZSL stream %d: %d x %d, depth %d",
+            mId.string(), mNextStreamId, width, height, depth);
 
     status_t res;
     bool wasActive = false;
@@ -1014,7 +1248,7 @@
         internalResumeLocked();
     }
 
-    ALOGV("Camera %d: Created ZSL stream", mId);
+    ALOGV("Camera %s: Created ZSL stream", mId.string());
     return OK;
 }
 
@@ -1024,8 +1258,8 @@
     ATRACE_CALL();
     Mutex::Autolock il(mInterfaceLock);
     Mutex::Autolock l(mLock);
-    ALOGV("Camera %d: Creating new stream %d: %d x %d, format %d, dataspace %d rotation %d"
-            " consumer usage 0x%x", mId, mNextStreamId, width, height, format, dataSpace, rotation,
+    ALOGV("Camera %s: Creating new stream %d: %d x %d, format %d, dataspace %d rotation %d"
+            " consumer usage 0x%x", mId.string(), mNextStreamId, width, height, format, dataSpace, rotation,
             consumerUsage);
 
     status_t res;
@@ -1148,7 +1382,7 @@
         }
         internalResumeLocked();
     }
-    ALOGV("Camera %d: Created new stream", mId);
+    ALOGV("Camera %s: Created new stream", mId.string());
     return OK;
 }
 
@@ -1237,12 +1471,12 @@
     Mutex::Autolock l(mLock);
     status_t res;
 
-    ALOGV("%s: Camera %d: Deleting stream %d", __FUNCTION__, mId, id);
+    ALOGV("%s: Camera %s: Deleting stream %d", __FUNCTION__, mId.string(), id);
 
     // CameraDevice semantics require device to already be idle before
     // deleteStream is called, unlike for createStream.
     if (mStatus == STATUS_ACTIVE) {
-        ALOGV("%s: Camera %d: Device not idle", __FUNCTION__, mId);
+        ALOGV("%s: Camera %s: Device not idle", __FUNCTION__, mId.string());
         return -EBUSY;
     }
 
@@ -1349,18 +1583,20 @@
         return OK;
     }
 
-    const camera_metadata_t *rawRequest;
-    ATRACE_BEGIN("camera3->construct_default_request_settings");
-    rawRequest = mHal3Device->ops->construct_default_request_settings(
-        mHal3Device, templateId);
-    ATRACE_END();
-    if (rawRequest == NULL) {
+    camera_metadata_t *rawRequest;
+    status_t res = mInterface->constructDefaultRequestSettings(
+            (camera3_request_template_t) templateId, &rawRequest);
+    if (res == BAD_VALUE) {
         ALOGI("%s: template %d is not supported on this camera device",
               __FUNCTION__, templateId);
-        return BAD_VALUE;
+        return res;
+    } else if (res != OK) {
+        CLOGE("Unable to construct request template %d: %s (%d)",
+                templateId, strerror(-res), res);
+        return res;
     }
 
-    mRequestTemplateCache[templateId] = rawRequest;
+    mRequestTemplateCache[templateId].acquire(rawRequest);
 
     // Derive some new keys for backward compatibility
     if (mDerivePostRawSensKey && !mRequestTemplateCache[templateId].exists(
@@ -1400,7 +1636,7 @@
             return INVALID_OPERATION;
     }
 
-    ALOGV("%s: Camera %d: Waiting until idle", __FUNCTION__, mId);
+    ALOGV("%s: Camera %s: Waiting until idle", __FUNCTION__, mId.string());
     status_t res = waitUntilStateThenRelock(/*active*/ false, kShutdownTimeout);
     if (res != OK) {
         SET_ERR_L("Error waiting for HAL to drain: %s (%d)", strerror(-res),
@@ -1421,7 +1657,7 @@
     mRequestThread->setPaused(true);
     mPauseStateNotify = true;
 
-    ALOGV("%s: Camera %d: Internal wait until idle", __FUNCTION__, mId);
+    ALOGV("%s: Camera %s: Internal wait until idle", __FUNCTION__, mId.string());
     status_t res = waitUntilStateThenRelock(/*active*/ false, kShutdownTimeout);
     if (res != OK) {
         SET_ERR_L("Can't idle device in %f seconds!",
@@ -1520,8 +1756,8 @@
         if (res == TIMED_OUT) {
             return res;
         } else if (res != OK) {
-            ALOGW("%s: Camera %d: No frame in %" PRId64 " ns: %s (%d)",
-                    __FUNCTION__, mId, timeout, strerror(-res), res);
+            ALOGW("%s: Camera %s: No frame in %" PRId64 " ns: %s (%d)",
+                    __FUNCTION__, mId.string(), timeout, strerror(-res), res);
             return res;
         }
     }
@@ -1623,7 +1859,7 @@
 
 status_t Camera3Device::flush(int64_t *frameNumber) {
     ATRACE_CALL();
-    ALOGV("%s: Camera %d: Flushing all requests", __FUNCTION__, mId);
+    ALOGV("%s: Camera %s: Flushing all requests", __FUNCTION__, mId.string());
     Mutex::Autolock il(mInterfaceLock);
 
     {
@@ -1632,7 +1868,7 @@
     }
 
     status_t res;
-    if (mHal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_1) {
+    if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_1) {
         res = mRequestThread->flush();
     } else {
         Mutex::Autolock l(mLock);
@@ -1648,7 +1884,7 @@
 
 status_t Camera3Device::prepare(int maxCount, int streamId) {
     ATRACE_CALL();
-    ALOGV("%s: Camera %d: Preparing stream %d", __FUNCTION__, mId, streamId);
+    ALOGV("%s: Camera %s: Preparing stream %d", __FUNCTION__, mId.string(), streamId);
     Mutex::Autolock il(mInterfaceLock);
     Mutex::Autolock l(mLock);
 
@@ -1676,15 +1912,15 @@
 
 status_t Camera3Device::tearDown(int streamId) {
     ATRACE_CALL();
-    ALOGV("%s: Camera %d: Tearing down stream %d", __FUNCTION__, mId, streamId);
+    ALOGV("%s: Camera %s: Tearing down stream %d", __FUNCTION__, mId.string(), streamId);
     Mutex::Autolock il(mInterfaceLock);
     Mutex::Autolock l(mLock);
 
     // Teardown can only be accomplished on devices that don't require register_stream_buffers,
     // since we cannot call register_stream_buffers except right after configure_streams.
-    if (mHal3Device->common.version < CAMERA_DEVICE_API_VERSION_3_2) {
+    if (mDeviceVersion < CAMERA_DEVICE_API_VERSION_3_2) {
         ALOGE("%s: Unable to tear down streams on device HAL v%x",
-                __FUNCTION__, mHal3Device->common.version);
+                __FUNCTION__, mDeviceVersion);
         return NO_INIT;
     }
 
@@ -1708,7 +1944,7 @@
 status_t Camera3Device::addBufferListenerForStream(int streamId,
         wp<Camera3StreamBufferListener> listener) {
     ATRACE_CALL();
-    ALOGV("%s: Camera %d: Adding buffer listener for stream %d", __FUNCTION__, mId, streamId);
+    ALOGV("%s: Camera %s: Adding buffer listener for stream %d", __FUNCTION__, mId.string(), streamId);
     Mutex::Autolock il(mInterfaceLock);
     Mutex::Autolock l(mLock);
 
@@ -1746,7 +1982,7 @@
         if (mStatus != STATUS_ACTIVE && mStatus != STATUS_CONFIGURED) {
             return;
         }
-        ALOGV("%s: Camera %d: Now %s", __FUNCTION__, mId,
+        ALOGV("%s: Camera %s: Now %s", __FUNCTION__, mId.string(),
                 idle ? "idle" : "active");
         internalUpdateStatusLocked(idle ? STATUS_CONFIGURED : STATUS_ACTIVE);
 
@@ -1767,7 +2003,7 @@
 
 status_t Camera3Device::setConsumerSurface(int streamId, sp<Surface> consumer) {
     ATRACE_CALL();
-    ALOGV("%s: Camera %d: set consumer surface for stream %d", __FUNCTION__, mId, streamId);
+    ALOGV("%s: Camera %s: set consumer surface for stream %d", __FUNCTION__, mId.string(), streamId);
     Mutex::Autolock il(mInterfaceLock);
     Mutex::Autolock l(mLock);
 
@@ -1793,7 +2029,7 @@
         return INVALID_OPERATION;
     }
 
-    res = stream->finishConfiguration(mHal3Device);
+    res = stream->finishConfiguration();
     if (res != OK) {
         SET_ERR_L("Can't finish configuring output stream %d: %s (%d)",
                 stream->getId(), strerror(-res), res);
@@ -1827,7 +2063,7 @@
         // Lazy completion of stream configuration (allocation/registration)
         // on first use
         if (mInputStream->isConfiguring()) {
-            res = mInputStream->finishConfiguration(mHal3Device);
+            res = mInputStream->finishConfiguration();
             if (res != OK) {
                 SET_ERR_L("Unable to finish configuring input stream %d:"
                         " %s (%d)",
@@ -1872,7 +2108,7 @@
         // Lazy completion of stream configuration (allocation/registration)
         // on first use
         if (stream->isConfiguring()) {
-            res = stream->finishConfiguration(mHal3Device);
+            res = stream->finishConfiguration();
             if (res != OK) {
                 SET_ERR_L("Unable to finish configuring stream %d: %s (%d)",
                         stream->getId(), strerror(-res), res);
@@ -1955,7 +2191,7 @@
     }
 
     // Start configuring the streams
-    ALOGV("%s: Camera %d: Starting stream configuration", __FUNCTION__, mId);
+    ALOGV("%s: Camera %s: Starting stream configuration", __FUNCTION__, mId.string());
 
     camera3_stream_configuration config;
     config.operation_mode = mIsConstrainedHighSpeedConfiguration ?
@@ -2001,9 +2237,8 @@
 
     // Do the HAL configuration; will potentially touch stream
     // max_buffers, usage, priv fields.
-    ATRACE_BEGIN("camera3->configure_streams");
-    res = mHal3Device->ops->configure_streams(mHal3Device, &config);
-    ATRACE_END();
+
+    res = mInterface->configureStreams(&config);
 
     if (res == BAD_VALUE) {
         // HAL rejected this set of streams as unsupported, clean up config
@@ -2024,7 +2259,7 @@
     // faster
 
     if (mInputStream != NULL && mInputStream->isConfiguring()) {
-        res = mInputStream->finishConfiguration(mHal3Device);
+        res = mInputStream->finishConfiguration();
         if (res != OK) {
             CLOGE("Can't finish configuring input stream %d: %s (%d)",
                     mInputStream->getId(), strerror(-res), res);
@@ -2037,7 +2272,7 @@
         sp<Camera3OutputStreamInterface> outputStream =
             mOutputStreams.editValueAt(i);
         if (outputStream->isConfiguring() && !outputStream->isConsumerConfigurationDeferred()) {
-            res = outputStream->finishConfiguration(mHal3Device);
+            res = outputStream->finishConfiguration();
             if (res != OK) {
                 CLOGE("Can't finish configuring output stream %d: %s (%d)",
                         outputStream->getId(), strerror(-res), res);
@@ -2074,7 +2309,7 @@
     internalUpdateStatusLocked((mDummyStreamId == NO_STREAM) ?
             STATUS_CONFIGURED : STATUS_UNCONFIGURED);
 
-    ALOGV("%s: Camera %d: Stream configuration complete", __FUNCTION__, mId);
+    ALOGV("%s: Camera %s: Stream configuration complete", __FUNCTION__, mId.string());
 
     // tear down the deleted streams after configure streams.
     mDeletedStreams.clear();
@@ -2089,12 +2324,12 @@
     if (mDummyStreamId != NO_STREAM) {
         // Should never be adding a second dummy stream when one is already
         // active
-        SET_ERR_L("%s: Camera %d: A dummy stream already exists!",
-                __FUNCTION__, mId);
+        SET_ERR_L("%s: Camera %s: A dummy stream already exists!",
+                __FUNCTION__, mId.string());
         return INVALID_OPERATION;
     }
 
-    ALOGV("%s: Camera %d: Adding a dummy stream", __FUNCTION__, mId);
+    ALOGV("%s: Camera %s: Adding a dummy stream", __FUNCTION__, mId.string());
 
     sp<Camera3OutputStreamInterface> dummyStream =
             new Camera3DummyStream(mNextStreamId);
@@ -2118,7 +2353,7 @@
     if (mDummyStreamId == NO_STREAM) return OK;
     if (mOutputStreams.size() == 1) return OK;
 
-    ALOGV("%s: Camera %d: Removing the dummy stream", __FUNCTION__, mId);
+    ALOGV("%s: Camera %s: Removing the dummy stream", __FUNCTION__, mId.string());
 
     // Ok, have a dummy stream and there's at least one other output stream,
     // so remove the dummy
@@ -2172,7 +2407,7 @@
 void Camera3Device::setErrorStateLockedV(const char *fmt, va_list args) {
     // Print out all error messages to log
     String8 errorCause = String8::formatV(fmt, args);
-    ALOGE("Camera %d: %s", mId, errorCause.string());
+    ALOGE("Camera %s: %s", mId.string(), errorCause.string());
 
     // But only do error state transition steps for the first error
     if (mStatus == STATUS_ERROR || mStatus == STATUS_UNINITIALIZED) return;
@@ -2645,8 +2880,8 @@
                 Camera3Stream::cast(msg.error_stream);
         streamId = stream->getId();
     }
-    ALOGV("Camera %d: %s: HAL error, frame %d, stream %d: %d",
-            mId, __FUNCTION__, msg.frame_number,
+    ALOGV("Camera %s: %s: HAL error, frame %d, stream %d: %d",
+            mId.string(), __FUNCTION__, msg.frame_number,
             streamId, msg.error_code);
 
     CaptureResultExtras resultExtras;
@@ -2667,8 +2902,8 @@
                     resultExtras = r.resultExtras;
                 } else {
                     resultExtras.frameNumber = msg.frame_number;
-                    ALOGE("Camera %d: %s: cannot find in-flight request on "
-                            "frame %" PRId64 " error", mId, __FUNCTION__,
+                    ALOGE("Camera %s: %s: cannot find in-flight request on "
+                            "frame %" PRId64 " error", mId.string(), __FUNCTION__,
                             resultExtras.frameNumber);
                 }
             }
@@ -2676,7 +2911,7 @@
             if (listener != NULL) {
                 listener->notifyError(errorCode, resultExtras);
             } else {
-                ALOGE("Camera %d: %s: no listener available", mId, __FUNCTION__);
+                ALOGE("Camera %s: %s: no listener available", mId.string(), __FUNCTION__);
             }
             break;
         default:
@@ -2721,8 +2956,8 @@
                 }
             }
 
-            ALOGVV("Camera %d: %s: Shutter fired for frame %d (id %d) at %" PRId64,
-                    mId, __FUNCTION__,
+            ALOGVV("Camera %s: %s: Shutter fired for frame %d (id %d) at %" PRId64,
+                    mId.string(), __FUNCTION__,
                     msg.frame_number, r.resultExtras.requestId, msg.timestamp);
             // Call listener, if any
             if (listener != NULL) {
@@ -2768,17 +3003,355 @@
 }
 
 /**
+ * HalInterface inner class methods
+ */
+
+Camera3Device::HalInterface::HalInterface(camera3_device_t *device) :
+        mHal3Device(device) {}
+
+Camera3Device::HalInterface::HalInterface(sp<ICameraDeviceSession> &session) :
+        mHal3Device(nullptr),
+        mHidlSession(session) {}
+
+Camera3Device::HalInterface::HalInterface() :
+        mHal3Device(nullptr) {}
+
+Camera3Device::HalInterface::HalInterface(const HalInterface& other) :
+        mHal3Device(other.mHal3Device), mHidlSession(other.mHidlSession) {}
+
+bool Camera3Device::HalInterface::valid() {
+    return (mHal3Device != nullptr) || (mHidlSession != nullptr);
+}
+
+void Camera3Device::HalInterface::clear() {
+    mHal3Device = nullptr;
+    mHidlSession.clear();
+}
+
+status_t Camera3Device::HalInterface::constructDefaultRequestSettings(
+        camera3_request_template_t templateId,
+        /*out*/ camera_metadata_t **requestTemplate) {
+    ATRACE_NAME("CameraHal::constructDefaultRequestSettings");
+    if (!valid()) return INVALID_OPERATION;
+    status_t res = OK;
+
+    if (mHal3Device != nullptr) {
+        const camera_metadata *r;
+        r = mHal3Device->ops->construct_default_request_settings(
+                mHal3Device, templateId);
+        if (r == nullptr) return BAD_VALUE;
+        *requestTemplate = clone_camera_metadata(r);
+        if (requestTemplate == nullptr) {
+            ALOGE("%s: Unable to clone camera metadata received from HAL",
+                    __FUNCTION__);
+            return INVALID_OPERATION;
+        }
+    } else {
+        common::V1_0::Status status;
+        RequestTemplate id;
+        switch (templateId) {
+            case CAMERA3_TEMPLATE_PREVIEW:
+                id = RequestTemplate::PREVIEW;
+                break;
+            case CAMERA3_TEMPLATE_STILL_CAPTURE:
+                id = RequestTemplate::STILL_CAPTURE;
+                break;
+            case CAMERA3_TEMPLATE_VIDEO_RECORD:
+                id = RequestTemplate::VIDEO_RECORD;
+                break;
+            case CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:
+                id = RequestTemplate::VIDEO_SNAPSHOT;
+                break;
+            case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:
+                id = RequestTemplate::ZERO_SHUTTER_LAG;
+                break;
+            case CAMERA3_TEMPLATE_MANUAL:
+                id = RequestTemplate::MANUAL;
+                break;
+            default:
+                // Unknown template ID
+                return BAD_VALUE;
+        }
+        mHidlSession->constructDefaultRequestSettings(id,
+                [&status, &requestTemplate]
+                (common::V1_0::Status s, const device::V3_2::CameraMetadata& request) {
+                    status = s;
+                    if (status == common::V1_0::Status::OK) {
+                        const camera_metadata *r =
+                                reinterpret_cast<const camera_metadata_t*>(request.data());
+                        size_t expectedSize = request.size();
+                        int ret = validate_camera_metadata_structure(r, &expectedSize);
+                        if (ret == OK) {
+                            *requestTemplate = clone_camera_metadata(r);
+                            if (*requestTemplate == nullptr) {
+                                ALOGE("%s: Unable to clone camera metadata received from HAL",
+                                        __FUNCTION__);
+                                status = common::V1_0::Status::INTERNAL_ERROR;
+                            }
+                        } else {
+                            ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
+                            status = common::V1_0::Status::INTERNAL_ERROR;
+                        }
+                    }
+                });
+        res = CameraProviderManager::mapToStatusT(status);
+    }
+    return res;
+}
+
+status_t Camera3Device::HalInterface::configureStreams(camera3_stream_configuration *config) {
+    ATRACE_NAME("CameraHal::configureStreams");
+    if (!valid()) return INVALID_OPERATION;
+    status_t res = OK;
+
+    if (mHal3Device != nullptr) {
+        res = mHal3Device->ops->configure_streams(mHal3Device, config);
+    } else {
+        // Convert stream config to HIDL
+
+        StreamConfiguration requestedConfiguration;
+        requestedConfiguration.streams.resize(config->num_streams);
+        for (size_t i = 0; i < config->num_streams; i++) {
+            Stream &dst = requestedConfiguration.streams[i];
+            camera3_stream_t *src = config->streams[i];
+
+            int streamId = Camera3Stream::cast(src)->getId();
+            StreamType streamType;
+            switch (src->stream_type) {
+                case CAMERA3_STREAM_OUTPUT:
+                    streamType = StreamType::OUTPUT;
+                    break;
+                case CAMERA3_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.format = mapToPixelFormat(src->format);
+            dst.usage = mapToConsumerUsage(src->usage);
+            dst.dataSpace = mapToHidlDataspace(src->data_space);
+            dst.rotation = mapToStreamRotation((camera3_stream_rotation_t) src->rotation);
+        }
+        requestedConfiguration.operationMode = mapToStreamConfigurationMode(
+                (camera3_stream_configuration_mode_t) config->operation_mode);
+
+        // Invoke configureStreams
+
+        HalStreamConfiguration finalConfiguration;
+        common::V1_0::Status status;
+        mHidlSession->configureStreams(requestedConfiguration,
+                [&status, &finalConfiguration]
+                (common::V1_0::Status s, const HalStreamConfiguration& halConfiguration) {
+                    finalConfiguration = halConfiguration;
+                    status = s;
+                });
+        if (status != common::V1_0::Status::OK ) {
+            return CameraProviderManager::mapToStatusT(status);
+        }
+
+        // And convert output stream configuration from HIDL
+
+        for (size_t i = 0; i < config->num_streams; i++) {
+            camera3_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;
+            for (size_t idx = 0; idx < finalConfiguration.streams.size(); idx++) {
+                if (finalConfiguration.streams[realIdx].id == streamId) {
+                    found = true;
+                    break;
+                }
+                realIdx = (realIdx >= finalConfiguration.streams.size()) ? 0 : realIdx + 1;
+            }
+            if (!found) {
+                ALOGE("%s: Stream %d not found in stream configuration response from HAL",
+                        __FUNCTION__, streamId);
+                return INVALID_OPERATION;
+            }
+            HalStream &src = finalConfiguration.streams[realIdx];
+
+            int overrideFormat = mapToFrameworkFormat(src.overrideFormat);
+            if (dst->format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+                if (dst->format != overrideFormat) {
+                    ALOGE("%s: Stream %d: Format override not allowed for format 0x%x", __FUNCTION__,
+                            streamId, dst->format);
+                }
+            } else {
+                // Override allowed with IMPLEMENTATION_DEFINED
+                dst->format = overrideFormat;
+            }
+
+            if (dst->stream_type == CAMERA3_STREAM_INPUT) {
+                if (src.producerUsage != 0) {
+                    ALOGE("%s: Stream %d: INPUT streams must have 0 for producer usage",
+                            __FUNCTION__, streamId);
+                    return INVALID_OPERATION;
+                }
+                dst->usage = mapConsumerToFrameworkUsage(src.consumerUsage);
+            } else {
+                // OUTPUT
+                if (src.consumerUsage != 0) {
+                    ALOGE("%s: Stream %d: OUTPUT streams must have 0 for consumer usage",
+                            __FUNCTION__, streamId);
+                    return INVALID_OPERATION;
+                }
+                dst->usage = mapProducerToFrameworkUsage(src.producerUsage);
+            }
+            dst->max_buffers = src.maxBuffers;
+        }
+    }
+    return res;
+}
+
+status_t Camera3Device::HalInterface::processCaptureRequest(
+        camera3_capture_request_t *request) {
+    ATRACE_NAME("CameraHal::processCaptureRequest");
+    (void) request;
+    if (!valid()) return INVALID_OPERATION;
+    status_t res = OK;
+
+    if (mHal3Device != nullptr) {
+        res = mHal3Device->ops->process_capture_request(mHal3Device, request);
+    } else {
+        device::V3_2::CaptureRequest captureRequest;
+        captureRequest.frameNumber = request->frame_number;
+        std::vector<native_handle_t*> handlesCreated;
+        // A null request settings maps to a size-0 CameraMetadata
+        if (request->settings != nullptr) {
+            captureRequest.settings.setToExternal(
+                    reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(request->settings)),
+                    get_camera_metadata_size(request->settings));
+        }
+        std::lock_guard<std::mutex> lock(mInflightLock);
+        if (request->input_buffer != nullptr) {
+            int32_t streamId = Camera3Stream::cast(request->input_buffer->stream)->getId();
+            captureRequest.inputBuffer.streamId = streamId;
+            captureRequest.inputBuffer.buffer = *(request->input_buffer->buffer);
+            captureRequest.inputBuffer.status = BufferStatus::OK;
+            native_handle_t *acquireFence = nullptr;
+            if (request->input_buffer->acquire_fence != -1) {
+                acquireFence = native_handle_create(1,0);
+                acquireFence->data[0] = request->input_buffer->acquire_fence;
+                handlesCreated.push_back(acquireFence);
+            }
+            captureRequest.inputBuffer.acquireFence = acquireFence;
+            captureRequest.inputBuffer.releaseFence = nullptr;
+
+            pushInflightBufferLocked(captureRequest.frameNumber, streamId,
+                    request->input_buffer->buffer);
+        }
+        captureRequest.outputBuffers.resize(request->num_output_buffers);
+        for (size_t i = 0; i < request->num_output_buffers; i++) {
+            const camera3_stream_buffer_t *src = request->output_buffers + i;
+            StreamBuffer &dst = captureRequest.outputBuffers[i];
+            int32_t streamId = Camera3Stream::cast(src->stream)->getId();
+            dst.streamId = streamId;
+            dst.buffer = *(src->buffer);
+            dst.status = BufferStatus::OK;
+            native_handle_t *acquireFence = nullptr;
+            if (src->acquire_fence != -1) {
+                acquireFence = native_handle_create(1,0);
+                acquireFence->data[0] = src->acquire_fence;
+                handlesCreated.push_back(acquireFence);
+            }
+            dst.acquireFence = acquireFence;
+            dst.releaseFence = nullptr;
+
+            pushInflightBufferLocked(captureRequest.frameNumber, streamId,
+                    src->buffer);
+        }
+
+        common::V1_0::Status status = mHidlSession->processCaptureRequest(captureRequest);
+
+        for (auto& handle : handlesCreated) {
+            native_handle_delete(handle);
+        }
+
+        res = CameraProviderManager::mapToStatusT(status);
+    }
+    return res;
+}
+
+status_t Camera3Device::HalInterface::flush() {
+    ATRACE_NAME("CameraHal::flush");
+    if (!valid()) return INVALID_OPERATION;
+    status_t res = OK;
+
+    if (mHal3Device != nullptr) {
+        res = mHal3Device->ops->flush(mHal3Device);
+    } else {
+        res = CameraProviderManager::mapToStatusT(mHidlSession->flush());
+    }
+    return res;
+}
+
+status_t Camera3Device::HalInterface::dump(int fd) {
+    ATRACE_NAME("CameraHal::dump");
+    if (!valid()) return INVALID_OPERATION;
+    status_t res = OK;
+
+    if (mHal3Device != nullptr) {
+        mHal3Device->ops->dump(mHal3Device, fd);
+    } else {
+        // Handled by CameraProviderManager::dump
+    }
+    return res;
+}
+
+status_t Camera3Device::HalInterface::close() {
+    ATRACE_NAME("CameraHal::close()");
+    if (!valid()) return INVALID_OPERATION;
+    status_t res = OK;
+
+    if (mHal3Device != nullptr) {
+        mHal3Device->common.close(&mHal3Device->common);
+    } else {
+        mHidlSession->close();
+    }
+    return res;
+}
+
+status_t Camera3Device::HalInterface::pushInflightBufferLocked(
+        int32_t frameNumber, int32_t streamId, buffer_handle_t *buffer) {
+    uint64_t key = static_cast<uint64_t>(frameNumber) << 32 | static_cast<uint64_t>(streamId);
+    mInflightBufferMap[key] = buffer;
+    return OK;
+}
+
+status_t Camera3Device::HalInterface::popInflightBuffer(
+        int32_t frameNumber, int32_t streamId, /*out*/ buffer_handle_t **buffer) {
+    std::lock_guard<std::mutex> lock(mInflightLock);
+
+    uint64_t key = static_cast<uint64_t>(frameNumber) << 32 | static_cast<uint64_t>(streamId);
+    auto it = mInflightBufferMap.find(key);
+    if (it == mInflightBufferMap.end()) return NAME_NOT_FOUND;
+    *buffer = it->second;
+    mInflightBufferMap.erase(it);
+    return OK;
+}
+
+/**
  * RequestThread inner class methods
  */
 
 Camera3Device::RequestThread::RequestThread(wp<Camera3Device> parent,
         sp<StatusTracker> statusTracker,
-        camera3_device_t *hal3Device,
+        HalInterface* interface,
+        uint32_t deviceVersion,
         bool aeLockAvailable) :
         Thread(/*canCallJava*/false),
         mParent(parent),
         mStatusTracker(statusTracker),
-        mHal3Device(hal3Device),
+        mInterface(interface),
+        mDeviceVersion(deviceVersion),
         mListener(nullptr),
         mId(getId(parent)),
         mReconfigured(false),
@@ -2795,6 +3368,8 @@
     mStatusId = statusTracker->addComponent();
 }
 
+Camera3Device::RequestThread::~RequestThread() {}
+
 void Camera3Device::RequestThread::setNotificationListener(
         wp<NotificationListener> listener) {
     Mutex::Autolock l(mRequestLock);
@@ -2849,10 +3424,11 @@
     return OK;
 }
 
-int Camera3Device::RequestThread::getId(const wp<Camera3Device> &device) {
+const String8& Camera3Device::RequestThread::getId(const wp<Camera3Device> &device) {
+    static String8 deadId("<DeadDevice>");
     sp<Camera3Device> d = device.promote();
-    if (d != NULL) return d->mId;
-    return 0;
+    if (d != nullptr) return d->mId;
+    return deadId;
 }
 
 status_t Camera3Device::RequestThread::queueTriggerLocked(
@@ -2982,8 +3558,8 @@
     ATRACE_CALL();
     Mutex::Autolock l(mFlushLock);
 
-    if (mHal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_1) {
-        return mHal3Device->ops->flush(mHal3Device);
+    if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_1) {
+        return mInterface->flush();
     }
 
     return -ENOTSUP;
@@ -3031,7 +3607,7 @@
     request->mAeTriggerCancelOverride.applyAeLock = false;
     request->mAeTriggerCancelOverride.applyAePrecaptureTrigger = false;
 
-    if (mHal3Device->common.version > CAMERA_DEVICE_API_VERSION_3_2) {
+    if (mDeviceVersion > CAMERA_DEVICE_API_VERSION_3_2) {
         return;
     }
 
@@ -3171,9 +3747,7 @@
     for (auto& nextRequest : mNextRequests) {
         // Submit request and block until ready for next one
         ATRACE_ASYNC_BEGIN("frame capture", nextRequest.halRequest.frame_number);
-        ATRACE_BEGIN("camera3->process_capture_request");
-        res = mHal3Device->ops->process_capture_request(mHal3Device, &nextRequest.halRequest);
-        ATRACE_END();
+        res = mInterface->processCaptureRequest(&nextRequest.halRequest);
 
         if (res != OK) {
             // Should only get a failure here for malformed requests or device-level
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 3eb566a..217c8b7 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -17,6 +17,9 @@
 #ifndef ANDROID_SERVERS_CAMERA3DEVICE_H
 #define ANDROID_SERVERS_CAMERA3DEVICE_H
 
+#include <utility>
+#include <unordered_map>
+
 #include <utils/Condition.h>
 #include <utils/Errors.h>
 #include <utils/List.h>
@@ -24,7 +27,12 @@
 #include <utils/Thread.h>
 #include <utils/KeyedVector.h>
 #include <utils/Timers.h>
+
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <android/hardware/camera/device/3.2/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.2/ICameraDeviceCallback.h>
 #include <hardware/camera3.h>
+
 #include <camera/CaptureResult.h>
 
 #include "common/CameraDeviceBase.h"
@@ -55,13 +63,14 @@
 class Camera3OutputStreamInterface;
 class Camera3StreamInterface;
 
-}
+} // namespace camera3
 
 /**
  * CameraDevice for HAL devices with version CAMERA_DEVICE_API_VERSION_3_0 or higher.
  */
 class Camera3Device :
             public CameraDeviceBase,
+            virtual public hardware::camera::device::V3_2::ICameraDeviceCallback,
             private camera3_callback_ops {
   public:
 
@@ -73,92 +82,92 @@
      * CameraDeviceBase interface
      */
 
-    virtual int      getId() const;
+    const String8& getId() const override;
 
     // Transitions to idle state on success.
-    virtual status_t initialize(CameraModule *module);
-    virtual status_t initialize(sp<CameraProviderManager> manager);
-    virtual status_t disconnect();
-    virtual status_t dump(int fd, const Vector<String16> &args);
-    virtual const CameraMetadata& info() const;
+    status_t initialize(CameraModule *module) override;
+    status_t initialize(sp<CameraProviderManager> manager) override;
+    status_t disconnect() override;
+    status_t dump(int fd, const Vector<String16> &args) override;
+    const CameraMetadata& info() const override;
 
     // Capture and setStreamingRequest will configure streams if currently in
     // idle state
-    virtual status_t capture(CameraMetadata &request, int64_t *lastFrameNumber = NULL);
-    virtual status_t captureList(const List<const CameraMetadata> &requests,
-                                 int64_t *lastFrameNumber = NULL);
-    virtual status_t setStreamingRequest(const CameraMetadata &request,
-                                         int64_t *lastFrameNumber = NULL);
-    virtual status_t setStreamingRequestList(const List<const CameraMetadata> &requests,
-                                             int64_t *lastFrameNumber = NULL);
-    virtual status_t clearStreamingRequest(int64_t *lastFrameNumber = NULL);
+    status_t capture(CameraMetadata &request, int64_t *lastFrameNumber = NULL) override;
+    status_t captureList(const List<const CameraMetadata> &requests,
+            int64_t *lastFrameNumber = NULL) override;
+    status_t setStreamingRequest(const CameraMetadata &request,
+            int64_t *lastFrameNumber = NULL) override;
+    status_t setStreamingRequestList(const List<const CameraMetadata> &requests,
+            int64_t *lastFrameNumber = NULL) override;
+    status_t clearStreamingRequest(int64_t *lastFrameNumber = NULL) override;
 
-    virtual status_t waitUntilRequestReceived(int32_t requestId, nsecs_t timeout);
+    status_t waitUntilRequestReceived(int32_t requestId, nsecs_t timeout) override;
 
     // Actual stream creation/deletion is delayed until first request is submitted
     // If adding streams while actively capturing, will pause device before adding
     // stream, reconfiguring device, and unpausing. If the client create a stream
     // with nullptr consumer surface, the client must then call setConsumer()
     // and finish the stream configuration before starting output streaming.
-    virtual status_t createStream(sp<Surface> consumer,
+    status_t createStream(sp<Surface> consumer,
             uint32_t width, uint32_t height, int format,
             android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
             int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
-            uint32_t consumerUsage = 0);
-    virtual status_t createInputStream(
+            uint32_t consumerUsage = 0) override;
+    status_t createInputStream(
             uint32_t width, uint32_t height, int format,
-            int *id);
-    virtual status_t createZslStream(
+            int *id) override;
+    status_t createZslStream(
             uint32_t width, uint32_t height,
             int depth,
             /*out*/
             int *id,
             sp<camera3::Camera3ZslStream>* zslStream);
-    virtual status_t createReprocessStreamFromStream(int outputId, int *id);
+    status_t createReprocessStreamFromStream(int outputId, int *id) override;
 
-    virtual status_t getStreamInfo(int id,
+    status_t getStreamInfo(int id,
             uint32_t *width, uint32_t *height,
-            uint32_t *format, android_dataspace *dataSpace);
-    virtual status_t setStreamTransform(int id, int transform);
+            uint32_t *format, android_dataspace *dataSpace) override;
+    status_t setStreamTransform(int id, int transform) override;
 
-    virtual status_t deleteStream(int id);
-    virtual status_t deleteReprocessStream(int id);
+    status_t deleteStream(int id) override;
+    status_t deleteReprocessStream(int id) override;
 
-    virtual status_t configureStreams(bool isConstraiedHighSpeed = false);
-    virtual status_t getInputBufferProducer(
-            sp<IGraphicBufferProducer> *producer);
+    status_t configureStreams(bool isConstraiedHighSpeed = false) override;
+    status_t getInputBufferProducer(
+            sp<IGraphicBufferProducer> *producer) override;
 
-    virtual status_t createDefaultRequest(int templateId, CameraMetadata *request);
+    status_t createDefaultRequest(int templateId, CameraMetadata *request) override;
 
     // Transitions to the idle state on success
-    virtual status_t waitUntilDrained();
+    status_t waitUntilDrained() override;
 
-    virtual status_t setNotifyCallback(wp<NotificationListener> listener);
-    virtual bool     willNotify3A();
-    virtual status_t waitForNextFrame(nsecs_t timeout);
-    virtual status_t getNextResult(CaptureResult *frame);
+    status_t setNotifyCallback(wp<NotificationListener> listener) override;
+    bool     willNotify3A() override;
+    status_t waitForNextFrame(nsecs_t timeout) override;
+    status_t getNextResult(CaptureResult *frame) override;
 
-    virtual status_t triggerAutofocus(uint32_t id);
-    virtual status_t triggerCancelAutofocus(uint32_t id);
-    virtual status_t triggerPrecaptureMetering(uint32_t id);
+    status_t triggerAutofocus(uint32_t id) override;
+    status_t triggerCancelAutofocus(uint32_t id) override;
+    status_t triggerPrecaptureMetering(uint32_t id) override;
 
-    virtual status_t pushReprocessBuffer(int reprocessStreamId,
-            buffer_handle_t *buffer, wp<BufferReleasedListener> listener);
+    status_t pushReprocessBuffer(int reprocessStreamId,
+            buffer_handle_t *buffer, wp<BufferReleasedListener> listener) override;
 
-    virtual status_t flush(int64_t *lastFrameNumber = NULL);
+    status_t flush(int64_t *lastFrameNumber = NULL) override;
 
-    virtual status_t prepare(int streamId);
+    status_t prepare(int streamId) override;
 
-    virtual status_t tearDown(int streamId);
+    status_t tearDown(int streamId) override;
 
-    virtual status_t addBufferListenerForStream(int streamId,
-            wp<camera3::Camera3StreamBufferListener> listener);
+    status_t addBufferListenerForStream(int streamId,
+            wp<camera3::Camera3StreamBufferListener> listener) override;
 
-    virtual status_t prepare(int maxCount, int streamId);
+    status_t prepare(int maxCount, int streamId) override;
 
-    virtual uint32_t getDeviceVersion();
+    uint32_t getDeviceVersion() override;
 
-    virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const;
+    ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const override;
     ssize_t getPointCloudBufferSize() const;
     ssize_t getRawOpaqueBufferSize(int32_t width, int32_t height) const;
 
@@ -169,7 +178,7 @@
      * Set the deferred consumer surface to the output stream and finish the deferred
      * consumer configuration.
      */
-    virtual status_t setConsumerSurface(int streamId, sp<Surface> consumer);
+    status_t setConsumerSurface(int streamId, sp<Surface> consumer) override;
 
   private:
     static const size_t        kDumpLockAttempts  = 10;
@@ -199,14 +208,58 @@
     Mutex                      mLock;
 
     // Camera device ID
-    const int                  mId;
+    const String8              mId;
 
     // Flag indicating is the current active stream configuration is constrained high speed.
     bool                       mIsConstrainedHighSpeedConfiguration;
 
     /**** Scope for mLock ****/
 
-    camera3_device_t          *mHal3Device;
+    /**
+     * Adapter for legacy HAL / HIDL HAL interface calls; calls either into legacy HALv3 or the
+     * HIDL HALv3 interfaces.
+     */
+    class HalInterface {
+      public:
+        HalInterface(camera3_device_t *device);
+        HalInterface(sp<hardware::camera::device::V3_2::ICameraDeviceSession> &session);
+        HalInterface(const HalInterface &other);
+        HalInterface();
+
+        // Returns true if constructed with a valid device or session, and not yet cleared
+        bool valid();
+
+        // Reset this HalInterface object (does not call close())
+        void clear();
+
+        // Calls into the HAL interface
+
+        // Caller takes ownership of requestTemplate
+        status_t constructDefaultRequestSettings(camera3_request_template_t templateId,
+                /*out*/ camera_metadata_t **requestTemplate);
+        status_t configureStreams(/*inout*/ camera3_stream_configuration *config);
+        status_t processCaptureRequest(camera3_capture_request_t *request);
+        status_t flush();
+        status_t dump(int fd);
+        status_t close();
+
+        // Find a buffer_handle_t based on frame number and stream ID
+        status_t popInflightBuffer(int32_t frameNumber, int32_t streamId,
+                /*out*/ buffer_handle_t **buffer);
+
+      private:
+        camera3_device_t *mHal3Device;
+        sp<hardware::camera::device::V3_2::ICameraDeviceSession> mHidlSession;
+
+        std::mutex mInflightLock;
+
+        status_t pushInflightBufferLocked(int32_t frameNumber, int32_t streamId,
+                buffer_handle_t *buffer);
+        // Cache of buffer handles keyed off (frameNumber << 32 | streamId)
+        std::unordered_map<uint64_t, buffer_handle_t*> mInflightBufferMap;
+    };
+
+    std::unique_ptr<HalInterface> mInterface;
 
     CameraMetadata             mDeviceInfo;
 
@@ -314,10 +367,27 @@
     status_t submitRequestsHelper(const List<const CameraMetadata> &requests, bool repeating,
                                   int64_t *lastFrameNumber = NULL);
 
+
+    /**
+     * Implementation of android::hardware::camera::device::V3_2::ICameraDeviceCallback
+     */
+
+    hardware::Return<void> processCaptureResult(
+            const hardware::camera::device::V3_2::CaptureResult& result) override;
+    hardware::Return<void> notify(
+            const hardware::camera::device::V3_2::NotifyMsg& msg) override;
+
+    /**
+     * Common initialization code shared by both HAL paths
+     *
+     * Must be called with mLock and mInterfaceLock held.
+     */
+    status_t initializeCommonLocked();
+
     /**
      * Get the last request submitted to the hal by the request thread.
      *
-     * Takes mLock.
+     * Must be called with mLock held.
      */
     virtual CameraMetadata getLatestRequestLocked();
 
@@ -435,6 +505,24 @@
      */
     static android_dataspace mapToLegacyDataspace(android_dataspace dataSpace);
 
+    /**
+     * Helper functions to map between framework and HIDL values
+     */
+    static hardware::graphics::common::V1_0::PixelFormat mapToPixelFormat(int frameworkFormat);
+    static hardware::camera::device::V3_2::DataspaceFlags mapToHidlDataspace(
+            android_dataspace dataSpace);
+    static hardware::camera::device::V3_2::ConsumerUsageFlags mapToConsumerUsage(uint32_t usage);
+    static hardware::camera::device::V3_2::StreamRotation mapToStreamRotation(
+            camera3_stream_rotation_t rotation);
+    static hardware::camera::device::V3_2::StreamConfigurationMode mapToStreamConfigurationMode(
+            camera3_stream_configuration_mode_t operationMode);
+    static camera3_buffer_status_t mapHidlBufferStatus(hardware::camera::device::V3_2::BufferStatus status);
+    static int mapToFrameworkFormat(hardware::graphics::common::V1_0::PixelFormat pixelFormat);
+    static uint32_t mapConsumerToFrameworkUsage(
+            hardware::camera::device::V3_2::ConsumerUsageFlags usage);
+    static uint32_t mapProducerToFrameworkUsage(
+            hardware::camera::device::V3_2::ProducerUsageFlags usage);
+
     struct RequestTrigger {
         // Metadata tag number, e.g. android.control.aePrecaptureTrigger
         uint32_t metadataTag;
@@ -461,8 +549,10 @@
 
         RequestThread(wp<Camera3Device> parent,
                 sp<camera3::StatusTracker> statusTracker,
-                camera3_device_t *hal3Device,
+                HalInterface* interface,
+                uint32_t deviceVersion,
                 bool aeLockAvailable);
+        ~RequestThread();
 
         void     setNotificationListener(wp<NotificationListener> listener);
 
@@ -542,7 +632,7 @@
         virtual bool threadLoop();
 
       private:
-        static int         getId(const wp<Camera3Device> &device);
+        static const String8& getId(const wp<Camera3Device> &device);
 
         status_t           queueTriggerLocked(RequestTrigger trigger);
         // Mix-in queued triggers into this request
@@ -603,11 +693,12 @@
 
         wp<Camera3Device>  mParent;
         wp<camera3::StatusTracker>  mStatusTracker;
-        camera3_device_t  *mHal3Device;
+        HalInterface*      mInterface;
+        uint32_t           mDeviceVersion;
 
         wp<NotificationListener> mListener;
 
-        const int          mId;       // The camera ID
+        const String8&     mId;       // The camera ID
         int                mStatusId; // The RequestThread's component ID for
                                       // status tracking
 
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 3ffd9d1..c3b7565 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -166,7 +166,7 @@
     return (mState == STATE_IN_CONFIG) || (mState == STATE_IN_RECONFIG);
 }
 
-status_t Camera3Stream::finishConfiguration(camera3_device *hal3Device) {
+status_t Camera3Stream::finishConfiguration() {
     ATRACE_CALL();
     Mutex::Autolock l(mLock);
     switch (mState) {
@@ -216,14 +216,6 @@
         return res;
     }
 
-    res = registerBuffersLocked(hal3Device);
-    if (res != OK) {
-        ALOGE("%s: Unable to register stream buffers with HAL: %s (%d)",
-                __FUNCTION__, strerror(-res), res);
-        mState = STATE_ERROR;
-        return res;
-    }
-
     mState = STATE_CONFIGURED;
 
     return res;
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 1ff215d..471b393 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -144,6 +144,10 @@
     int               getFormat() const;
     android_dataspace getDataSpace() const;
 
+    camera3_stream*   asHalStream() override {
+        return this;
+    }
+
     /**
      * Start the stream configuration process. Returns a handle to the stream's
      * information to be passed into the HAL device's configure_streams call.
@@ -165,11 +169,10 @@
     bool             isConfiguring() const;
 
     /**
-     * Completes the stream configuration process. During this call, the stream
-     * may call the device's register_stream_buffers() method. The stream
-     * information structure returned by startConfiguration() may no longer be
-     * modified after this call, but can still be read until the destruction of
-     * the stream.
+     * Completes the stream configuration process. The stream information
+     * structure returned by startConfiguration() may no longer be modified
+     * after this call, but can still be read until the destruction of the
+     * stream.
      *
      * Returns:
      *   OK on a successful configuration
@@ -178,7 +181,7 @@
      *   INVALID_OPERATION in case connecting to the consumer failed or consumer
      *       doesn't exist yet.
      */
-    status_t         finishConfiguration(camera3_device *hal3Device);
+    status_t         finishConfiguration();
 
     /**
      * Cancels the stream configuration process. This returns the stream to the
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 6cb7a54..ceea08a 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -72,6 +72,11 @@
     virtual android_dataspace getDataSpace() const = 0;
 
     /**
+     * Get a HAL3 handle for the stream, without starting stream configuration.
+     */
+    virtual camera3_stream* asHalStream() = 0;
+
+    /**
      * Start the stream configuration process. Returns a handle to the stream's
      * information to be passed into the HAL device's configure_streams call.
      *
@@ -104,7 +109,7 @@
      *   NO_MEMORY in case of an error registering buffers
      *   INVALID_OPERATION in case connecting to the consumer failed
      */
-    virtual status_t finishConfiguration(camera3_device *hal3Device) = 0;
+    virtual status_t finishConfiguration() = 0;
 
     /**
      * Cancels the stream configuration process. This returns the stream to the