camera: Add support for logical camera

- Add physical cameraId field in stream structure.
- Override processCaptureRequest due to physicalCameraId change.
- Update 3.3 metadata with logical camera characteristics.

Test: Camera CTS on Taimen, LogicalCamera CTS test on C1
Bug: 64691172
Change-Id: I65bd1ae38381ecb89fae439ae14b813c9bcc3248
diff --git a/camera/device/3.4/Android.bp b/camera/device/3.4/Android.bp
index 2523fa8..67b79b9 100644
--- a/camera/device/3.4/Android.bp
+++ b/camera/device/3.4/Android.bp
@@ -18,6 +18,9 @@
         "android.hidl.base@1.0",
     ],
     types: [
+        "HalStream",
+        "HalStreamConfiguration",
+        "Stream",
         "StreamConfiguration",
     ],
     gen_java: false,
diff --git a/camera/device/3.4/ICameraDeviceSession.hal b/camera/device/3.4/ICameraDeviceSession.hal
index e5693b2..71a4b34 100644
--- a/camera/device/3.4/ICameraDeviceSession.hal
+++ b/camera/device/3.4/ICameraDeviceSession.hal
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2017-2018 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.
@@ -19,6 +19,8 @@
 import android.hardware.camera.common@1.0::Status;
 import @3.3::ICameraDeviceSession;
 import @3.3::HalStreamConfiguration;
+import @3.2::BufferCache;
+import @3.2::CaptureRequest;
 
 /**
  * Camera device active session interface.
@@ -69,6 +71,5 @@
      */
     configureStreams_3_4(@3.4::StreamConfiguration requestedConfiguration)
             generates (Status status,
-                       @3.3::HalStreamConfiguration halConfiguration);
-
+                       @3.4::HalStreamConfiguration halConfiguration);
 };
diff --git a/camera/device/3.4/default/Android.bp b/camera/device/3.4/default/Android.bp
index c0ce838..a0ab167 100644
--- a/camera/device/3.4/default/Android.bp
+++ b/camera/device/3.4/default/Android.bp
@@ -28,6 +28,7 @@
     srcs: [
         "CameraDevice.cpp",
         "CameraDeviceSession.cpp",
+        "convert.cpp",
     ],
     shared_libs: [
         "libhidlbase",
diff --git a/camera/device/3.4/default/CameraDeviceSession.cpp b/camera/device/3.4/default/CameraDeviceSession.cpp
index 0ae470f..b74fd57 100644
--- a/camera/device/3.4/default/CameraDeviceSession.cpp
+++ b/camera/device/3.4/default/CameraDeviceSession.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2017-2018 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.
@@ -41,8 +41,8 @@
 }
 
 Return<void> CameraDeviceSession::configureStreams_3_4(
-        const V3_4::StreamConfiguration& requestedConfiguration,
-        ICameraDeviceSession::configureStreams_3_3_cb _hidl_cb)  {
+        const StreamConfiguration& requestedConfiguration,
+        ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb)  {
     Status status = initStatus();
     HalStreamConfiguration outStreams;
 
@@ -86,7 +86,7 @@
     camera3_stream_configuration_t stream_list{};
     hidl_vec<camera3_stream_t*> streams;
     stream_list.session_parameters = paramBuffer;
-    if (!preProcessConfigurationLocked(requestedConfiguration.v3_2, &stream_list, &streams)) {
+    if (!preProcessConfigurationLocked_3_4(requestedConfiguration, &stream_list, &streams)) {
         _hidl_cb(Status::INTERNAL_ERROR, outStreams);
         return Void();
     }
@@ -98,7 +98,7 @@
     // In case Hal returns error most likely it was not able to release
     // the corresponding resources of the deleted streams.
     if (ret == OK) {
-        postProcessConfigurationLocked(requestedConfiguration.v3_2);
+        postProcessConfigurationLocked_3_4(requestedConfiguration);
     }
 
     if (ret == -EINVAL) {
@@ -106,7 +106,7 @@
     } else if (ret != OK) {
         status = Status::INTERNAL_ERROR;
     } else {
-        V3_3::implementation::convertToHidl(stream_list, &outStreams);
+        V3_4::implementation::convertToHidl(stream_list, &outStreams);
         mFirstRequest = true;
     }
 
@@ -114,6 +114,244 @@
     return Void();
 }
 
+bool CameraDeviceSession::preProcessConfigurationLocked_3_4(
+        const StreamConfiguration& requestedConfiguration,
+        camera3_stream_configuration_t *stream_list /*out*/,
+        hidl_vec<camera3_stream_t*> *streams /*out*/) {
+
+    if ((stream_list == nullptr) || (streams == nullptr)) {
+        return false;
+    }
+
+    stream_list->operation_mode = (uint32_t) requestedConfiguration.operationMode;
+    stream_list->num_streams = requestedConfiguration.streams.size();
+    streams->resize(stream_list->num_streams);
+    stream_list->streams = streams->data();
+
+    for (uint32_t i = 0; i < stream_list->num_streams; i++) {
+        int id = requestedConfiguration.streams[i].v3_2.id;
+
+        if (mStreamMap.count(id) == 0) {
+            Camera3Stream stream;
+            convertFromHidl(requestedConfiguration.streams[i], &stream);
+            mStreamMap[id] = stream;
+            mPhysicalCameraIdMap[id] = requestedConfiguration.streams[i].physicalCameraId;
+            mStreamMap[id].data_space = mapToLegacyDataspace(
+                    mStreamMap[id].data_space);
+            mStreamMap[id].physical_camera_id = mPhysicalCameraIdMap[id].c_str();
+            mCirculatingBuffers.emplace(stream.mId, CirculatingBuffers{});
+        } else {
+            // width/height/format must not change, but usage/rotation might need to change
+            if (mStreamMap[id].stream_type !=
+                    (int) requestedConfiguration.streams[i].v3_2.streamType ||
+                    mStreamMap[id].width != requestedConfiguration.streams[i].v3_2.width ||
+                    mStreamMap[id].height != requestedConfiguration.streams[i].v3_2.height ||
+                    mStreamMap[id].format != (int) requestedConfiguration.streams[i].v3_2.format ||
+                    mStreamMap[id].data_space !=
+                            mapToLegacyDataspace( static_cast<android_dataspace_t> (
+                                    requestedConfiguration.streams[i].v3_2.dataSpace)) ||
+                    mPhysicalCameraIdMap[id] != requestedConfiguration.streams[i].physicalCameraId) {
+                ALOGE("%s: stream %d configuration changed!", __FUNCTION__, id);
+                return false;
+            }
+            mStreamMap[id].rotation = (int) requestedConfiguration.streams[i].v3_2.rotation;
+            mStreamMap[id].usage = (uint32_t) requestedConfiguration.streams[i].v3_2.usage;
+        }
+        (*streams)[i] = &mStreamMap[id];
+    }
+
+    return true;
+}
+
+void CameraDeviceSession::postProcessConfigurationLocked_3_4(
+        const StreamConfiguration& requestedConfiguration) {
+    // delete unused streams, note we do this after adding new streams to ensure new stream
+    // will not have the same address as deleted stream, and HAL has a chance to reference
+    // the to be deleted stream in configure_streams call
+    for(auto it = mStreamMap.begin(); it != mStreamMap.end();) {
+        int id = it->first;
+        bool found = false;
+        for (const auto& stream : requestedConfiguration.streams) {
+            if (id == stream.v3_2.id) {
+                found = true;
+                break;
+            }
+        }
+        if (!found) {
+            // Unmap all buffers of deleted stream
+            // in case the configuration call succeeds and HAL
+            // is able to release the corresponding resources too.
+            cleanupBuffersLocked(id);
+            it = mStreamMap.erase(it);
+        } else {
+            ++it;
+        }
+    }
+
+    // Track video streams
+    mVideoStreamIds.clear();
+    for (const auto& stream : requestedConfiguration.streams) {
+        if (stream.v3_2.streamType == StreamType::OUTPUT &&
+            stream.v3_2.usage &
+                graphics::common::V1_0::BufferUsage::VIDEO_ENCODER) {
+            mVideoStreamIds.push_back(stream.v3_2.id);
+        }
+    }
+    mResultBatcher.setBatchedStreams(mVideoStreamIds);
+}
+
+Return<void> CameraDeviceSession::processCaptureRequest_3_4(
+        const hidl_vec<CaptureRequest>& requests,
+        const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+        ICameraDeviceSession::processCaptureRequest_cb _hidl_cb)  {
+    updateBufferCaches(cachesToRemove);
+
+    uint32_t numRequestProcessed = 0;
+    Status s = Status::OK;
+    for (size_t i = 0; i < requests.size(); i++, numRequestProcessed++) {
+        s = processOneCaptureRequest_3_4(requests[i]);
+        if (s != Status::OK) {
+            break;
+        }
+    }
+
+    if (s == Status::OK && requests.size() > 1) {
+        mResultBatcher.registerBatch(requests);
+    }
+
+    _hidl_cb(s, numRequestProcessed);
+    return Void();
+}
+
+Status CameraDeviceSession::processOneCaptureRequest_3_4(const CaptureRequest& request)  {
+    Status status = initStatus();
+    if (status != Status::OK) {
+        ALOGE("%s: camera init failed or disconnected", __FUNCTION__);
+        return status;
+    }
+
+    camera3_capture_request_t halRequest;
+    halRequest.frame_number = request.frameNumber;
+
+    bool converted = true;
+    V3_2::CameraMetadata settingsFmq;  // settings from FMQ
+    if (request.fmqSettingsSize > 0) {
+        // non-blocking read; client must write metadata before calling
+        // processOneCaptureRequest
+        settingsFmq.resize(request.fmqSettingsSize);
+        bool read = mRequestMetadataQueue->read(settingsFmq.data(), request.fmqSettingsSize);
+        if (read) {
+            converted = V3_2::implementation::convertFromHidl(settingsFmq, &halRequest.settings);
+        } else {
+            ALOGE("%s: capture request settings metadata couldn't be read from fmq!", __FUNCTION__);
+            converted = false;
+        }
+    } else {
+        converted = V3_2::implementation::convertFromHidl(request.settings, &halRequest.settings);
+    }
+
+    if (!converted) {
+        ALOGE("%s: capture request settings metadata is corrupt!", __FUNCTION__);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    if (mFirstRequest && halRequest.settings == nullptr) {
+        ALOGE("%s: capture request settings must not be null for first request!",
+                __FUNCTION__);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    hidl_vec<buffer_handle_t*> allBufPtrs;
+    hidl_vec<int> allFences;
+    bool hasInputBuf = (request.inputBuffer.streamId != -1 &&
+            request.inputBuffer.bufferId != 0);
+    size_t numOutputBufs = request.outputBuffers.size();
+    size_t numBufs = numOutputBufs + (hasInputBuf ? 1 : 0);
+
+    if (numOutputBufs == 0) {
+        ALOGE("%s: capture request must have at least one output buffer!", __FUNCTION__);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    status = importRequest(request, allBufPtrs, allFences);
+    if (status != Status::OK) {
+        return status;
+    }
+
+    hidl_vec<camera3_stream_buffer_t> outHalBufs;
+    outHalBufs.resize(numOutputBufs);
+    bool aeCancelTriggerNeeded = false;
+    ::android::hardware::camera::common::V1_0::helper::CameraMetadata settingsOverride;
+    {
+        Mutex::Autolock _l(mInflightLock);
+        if (hasInputBuf) {
+            auto streamId = request.inputBuffer.streamId;
+            auto key = std::make_pair(request.inputBuffer.streamId, request.frameNumber);
+            auto& bufCache = mInflightBuffers[key] = camera3_stream_buffer_t{};
+            convertFromHidl(
+                    allBufPtrs[numOutputBufs], request.inputBuffer.status,
+                    &mStreamMap[request.inputBuffer.streamId], allFences[numOutputBufs],
+                    &bufCache);
+            bufCache.stream->physical_camera_id = mPhysicalCameraIdMap[streamId].c_str();
+            halRequest.input_buffer = &bufCache;
+        } else {
+            halRequest.input_buffer = nullptr;
+        }
+
+        halRequest.num_output_buffers = numOutputBufs;
+        for (size_t i = 0; i < numOutputBufs; i++) {
+            auto streamId = request.outputBuffers[i].streamId;
+            auto key = std::make_pair(streamId, request.frameNumber);
+            auto& bufCache = mInflightBuffers[key] = camera3_stream_buffer_t{};
+            convertFromHidl(
+                    allBufPtrs[i], request.outputBuffers[i].status,
+                    &mStreamMap[streamId], allFences[i],
+                    &bufCache);
+            bufCache.stream->physical_camera_id = mPhysicalCameraIdMap[streamId].c_str();
+            outHalBufs[i] = bufCache;
+        }
+        halRequest.output_buffers = outHalBufs.data();
+
+        AETriggerCancelOverride triggerOverride;
+        aeCancelTriggerNeeded = handleAePrecaptureCancelRequestLocked(
+                halRequest, &settingsOverride /*out*/, &triggerOverride/*out*/);
+        if (aeCancelTriggerNeeded) {
+            mInflightAETriggerOverrides[halRequest.frame_number] =
+                    triggerOverride;
+            halRequest.settings = settingsOverride.getAndLock();
+        }
+    }
+
+    ATRACE_ASYNC_BEGIN("frame capture", request.frameNumber);
+    ATRACE_BEGIN("camera3->process_capture_request");
+    status_t ret = mDevice->ops->process_capture_request(mDevice, &halRequest);
+    ATRACE_END();
+    if (aeCancelTriggerNeeded) {
+        settingsOverride.unlock(halRequest.settings);
+    }
+    if (ret != OK) {
+        Mutex::Autolock _l(mInflightLock);
+        ALOGE("%s: HAL process_capture_request call failed!", __FUNCTION__);
+
+        cleanupInflightFences(allFences, numBufs);
+        if (hasInputBuf) {
+            auto key = std::make_pair(request.inputBuffer.streamId, request.frameNumber);
+            mInflightBuffers.erase(key);
+        }
+        for (size_t i = 0; i < numOutputBufs; i++) {
+            auto key = std::make_pair(request.outputBuffers[i].streamId, request.frameNumber);
+            mInflightBuffers.erase(key);
+        }
+        if (aeCancelTriggerNeeded) {
+            mInflightAETriggerOverrides.erase(request.frameNumber);
+        }
+        return Status::INTERNAL_ERROR;
+    }
+
+    mFirstRequest = false;
+    return Status::OK;
+}
+
 } // namespace implementation
 }  // namespace V3_4
 }  // namespace device
diff --git a/camera/device/3.4/default/convert.cpp b/camera/device/3.4/default/convert.cpp
new file mode 100644
index 0000000..f12230c
--- /dev/null
+++ b/camera/device/3.4/default/convert.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 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 "android.hardware.camera.device@3.4-convert-impl"
+#include <log/log.h>
+
+#include <cstring>
+#include "include/convert.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_4 {
+namespace implementation {
+
+using ::android::hardware::graphics::common::V1_0::Dataspace;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::camera::device::V3_2::BufferUsageFlags;
+
+void convertToHidl(const Camera3Stream* src, HalStream* dst) {
+    V3_3::implementation::convertToHidl(src, &dst->v3_3);
+    dst->physicalCameraId = src->physical_camera_id;
+}
+
+void convertToHidl(const camera3_stream_configuration_t& src, HalStreamConfiguration* dst) {
+    dst->streams.resize(src.num_streams);
+    for (uint32_t i = 0; i < src.num_streams; i++) {
+        convertToHidl(static_cast<Camera3Stream*>(src.streams[i]), &dst->streams[i]);
+    }
+    return;
+}
+
+void convertFromHidl(const Stream &src, Camera3Stream* dst) {
+    V3_2::implementation::convertFromHidl(src.v3_2, dst);
+    // Initialize physical_camera_id
+    dst->physical_camera_id = nullptr;
+    return;
+}
+
+}  // namespace implementation
+}  // namespace V3_4
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/device/3.4/default/include/convert.h b/camera/device/3.4/default/include/convert.h
new file mode 100644
index 0000000..e8e3951
--- /dev/null
+++ b/camera/device/3.4/default/include/convert.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 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 HARDWARE_INTERFACES_CAMERA_DEVICE_V3_4_DEFAULT_INCLUDE_CONVERT_H_
+#define HARDWARE_INTERFACES_CAMERA_DEVICE_V3_4_DEFAULT_INCLUDE_CONVERT_H_
+
+#include <android/hardware/camera/device/3.4/types.h>
+#include "hardware/camera3.h"
+#include "../../3.3/default/include/convert.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_4 {
+namespace implementation {
+
+using ::android::hardware::camera::device::V3_2::implementation::Camera3Stream;
+
+void convertToHidl(const Camera3Stream* src, HalStream* dst);
+
+void convertToHidl(const camera3_stream_configuration_t& src, HalStreamConfiguration* dst);
+
+void convertFromHidl(const Stream &src, Camera3Stream* dst);
+
+}  // namespace implementation
+}  // namespace V3_4
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_CAMERA_DEVICE_V3_4_DEFAULT_INCLUDE_CONVERT_H_
diff --git a/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h b/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
index bff1734..83b3afe 100644
--- a/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
+++ b/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2017-2018 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.
@@ -18,7 +18,6 @@
 #define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_CAMERADEVICE3SESSION_H
 
 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
-#include <android/hardware/camera/device/3.3/ICameraDeviceSession.h>
 #include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
 #include <../../3.3/default/CameraDeviceSession.h>
 #include <../../3.3/default/include/convert.h>
@@ -43,8 +42,9 @@
 
 using namespace ::android::hardware::camera::device;
 using ::android::hardware::camera::device::V3_2::CaptureRequest;
-using ::android::hardware::camera::device::V3_2::StreamConfiguration;
-using ::android::hardware::camera::device::V3_3::HalStreamConfiguration;
+using ::android::hardware::camera::device::V3_2::StreamType;
+using ::android::hardware::camera::device::V3_4::StreamConfiguration;
+using ::android::hardware::camera::device::V3_4::HalStreamConfiguration;
 using ::android::hardware::camera::device::V3_4::ICameraDeviceSession;
 using ::android::hardware::camera::common::V1_0::Status;
 using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
@@ -75,8 +75,22 @@
     // New methods for v3.4
 
     Return<void> configureStreams_3_4(
-            const V3_4::StreamConfiguration& requestedConfiguration,
-            ICameraDeviceSession::configureStreams_3_3_cb _hidl_cb);
+            const StreamConfiguration& requestedConfiguration,
+            ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb);
+
+    bool preProcessConfigurationLocked_3_4(
+            const StreamConfiguration& requestedConfiguration,
+            camera3_stream_configuration_t *stream_list /*out*/,
+            hidl_vec<camera3_stream_t*> *streams /*out*/);
+    void postProcessConfigurationLocked_3_4(const StreamConfiguration& requestedConfiguration);
+
+    Return<void> processCaptureRequest_3_4(
+            const hidl_vec<CaptureRequest>& requests,
+            const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+            ICameraDeviceSession::processCaptureRequest_cb _hidl_cb);
+    Status processOneCaptureRequest_3_4(const CaptureRequest& request);
+
+    std::map<int, std::string> mPhysicalCameraIdMap;
 private:
 
     struct TrampolineSessionInterface_3_4 : public ICameraDeviceSession {
@@ -90,7 +104,7 @@
         }
 
         virtual Return<void> configureStreams(
-                const StreamConfiguration& requestedConfiguration,
+                const V3_2::StreamConfiguration& requestedConfiguration,
                 V3_3::ICameraDeviceSession::configureStreams_cb _hidl_cb) override {
             return mParent->configureStreams(requestedConfiguration, _hidl_cb);
         }
@@ -98,7 +112,7 @@
         virtual Return<void> processCaptureRequest(const hidl_vec<V3_2::CaptureRequest>& requests,
                 const hidl_vec<V3_2::BufferCache>& cachesToRemove,
                 V3_3::ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) override {
-            return mParent->processCaptureRequest(requests, cachesToRemove, _hidl_cb);
+            return mParent->processCaptureRequest_3_4(requests, cachesToRemove, _hidl_cb);
         }
 
         virtual Return<void> getCaptureRequestMetadataQueue(
@@ -120,14 +134,14 @@
         }
 
         virtual Return<void> configureStreams_3_3(
-                const StreamConfiguration& requestedConfiguration,
+                const V3_2::StreamConfiguration& requestedConfiguration,
                 configureStreams_3_3_cb _hidl_cb) override {
             return mParent->configureStreams_3_3(requestedConfiguration, _hidl_cb);
         }
 
         virtual Return<void> configureStreams_3_4(
-                const V3_4::StreamConfiguration& requestedConfiguration,
-                configureStreams_3_3_cb _hidl_cb) override {
+                const StreamConfiguration& requestedConfiguration,
+                configureStreams_3_4_cb _hidl_cb) override {
             return mParent->configureStreams_3_4(requestedConfiguration, _hidl_cb);
         }
 
diff --git a/camera/device/3.4/types.hal b/camera/device/3.4/types.hal
index c822717..acad093 100644
--- a/camera/device/3.4/types.hal
+++ b/camera/device/3.4/types.hal
@@ -16,19 +16,68 @@
 
 package android.hardware.camera.device@3.4;
 
-import @3.2::StreamConfiguration;
 import @3.2::types;
+import @3.2::StreamConfigurationMode;
+import @3.2::Stream;
+import @3.3::HalStream;
+import @3.2::CameraMetadata;
+
+/**
+ * Stream:
+ *
+ * A descriptor for a single camera input or output stream. A stream is defined
+ * by the framework by its buffer resolution and format, and additionally by the
+ * HAL with the gralloc usage flags and the maximum in-flight buffer count.
+ *
+ * This version extends the @3.2 Stream with the physicalCameraId field.
+ */
+struct Stream {
+    /**
+     * The definition of Stream from the prior version
+     */
+    @3.2::Stream v3_2;
+
+    /**
+     * The physical camera id this stream belongs to.
+     *
+     * If the camera device is not a logical multi camera, or if the camera is a logical
+     * multi camera but the stream is not a physical output stream, this field will point to a
+     * 0-length string.
+     *
+     * A logical multi camera is a camera device backed by multiple physical cameras that
+     * are also exposed to the application. And for a logical multi camera, a physical output
+     * stream is an output stream specifically requested on an underlying physical camera.
+     *
+     * A logical camera is a camera device backed by multiple physical camera
+     * devices. And a physical stream is a stream specifically requested on a
+     * underlying physical camera device.
+     *
+     * For an input stream, this field is guaranteed to be a 0-length string.
+     *
+     * When not empty, this field is the <id> field of one of the full-qualified device
+     * instance names returned by getCameraIdList().
+     */
+    string physicalCameraId;
+};
 
 /**
  * StreamConfiguration:
  *
- * Identical to @3.2::StreamConfiguration, except that it contains session parameters.
+ * Identical to @3.2::StreamConfiguration, except that it contains session
+ * parameters, and the streams vector contains @3.4::Stream.
  */
 struct StreamConfiguration {
     /**
-     * The definition of StreamConfiguration from the prior version.
+     * An array of camera stream pointers, defining the input/output
+     * configuration for the camera HAL device.
      */
-    @3.2::StreamConfiguration v3_2;
+    vec<Stream> streams;
+
+    /**
+     * The definition of operation mode from prior version.
+     *
+     */
+    StreamConfigurationMode operationMode;
 
     /**
      * Session wide camera parameters.
@@ -44,3 +93,43 @@
      */
     CameraMetadata sessionParams;
 };
+
+/**
+ * HalStream:
+ *
+ * The camera HAL's response to each requested stream configuration.
+ *
+ * This version extends the @3.3 HalStream with the physicalCameraId
+ * field
+ */
+struct HalStream {
+    /**
+     * The definition of HalStream from the prior version.
+     */
+    @3.3::HalStream v3_3;
+
+    /**
+     * The physical camera id the current Hal stream belongs to.
+     *
+     * If current camera device isn't a logical camera, or the Hal stream isn't
+     * from a physical camera of the logical camera, this must be an empty
+     * string.
+     *
+     * A logical camera is a camera device backed by multiple physical camera
+     * devices.
+     *
+     * When not empty, this field is the <id> field of one of the full-qualified device
+     * instance names returned by getCameraIdList().
+     */
+    string physicalCameraId;
+};
+
+/**
+ * HalStreamConfiguration:
+ *
+ * Identical to @3.3::HalStreamConfiguration, except that it contains @3.4::HalStream entries.
+ *
+ */
+struct HalStreamConfiguration {
+    vec<HalStream> streams;
+};
diff --git a/camera/metadata/3.3/Android.bp b/camera/metadata/3.3/Android.bp
index 3f1dabc..23c1036 100644
--- a/camera/metadata/3.3/Android.bp
+++ b/camera/metadata/3.3/Android.bp
@@ -17,6 +17,9 @@
         "CameraMetadataEnumAndroidControlCaptureIntent",
         "CameraMetadataEnumAndroidLensPoseReference",
         "CameraMetadataEnumAndroidRequestAvailableCapabilities",
+        "CameraMetadataEnumAndroidLogicalMultiCameraSensorSyncType",
+        "CameraMetadataSection",
+        "CameraMetadataSectionStart",
         "CameraMetadataTag",
     ],
     gen_java: true,
diff --git a/camera/metadata/3.3/types.hal b/camera/metadata/3.3/types.hal
index 5c01e35..1a6e7a9 100644
--- a/camera/metadata/3.3/types.hal
+++ b/camera/metadata/3.3/types.hal
@@ -25,7 +25,30 @@
 /* Include definitions from all prior minor HAL metadata revisions */
 import android.hardware.camera.metadata@3.2;
 
-// No new metadata sections added in this revision
+/**
+ * Top level hierarchy definitions for camera metadata. *_INFO sections are for
+ * the static metadata that can be retrived without opening the camera device.
+ */
+enum CameraMetadataSection : @3.2::CameraMetadataSection {
+    ANDROID_LOGICAL_MULTI_CAMERA =
+        android.hardware.camera.metadata@3.2::CameraMetadataSection:ANDROID_SECTION_COUNT,
+
+    ANDROID_SECTION_COUNT_3_3,
+
+    VENDOR_SECTION_3_3 = 0x8000,
+
+};
+
+/**
+ * Hierarchy positions in enum space. All vendor extension sections must be
+ * defined with tag >= VENDOR_SECTION_START
+ */
+enum CameraMetadataSectionStart : android.hardware.camera.metadata@3.2::CameraMetadataSectionStart {
+    ANDROID_LOGICAL_MULTI_CAMERA_START = CameraMetadataSection:ANDROID_LOGICAL_MULTI_CAMERA << 16,
+
+    VENDOR_SECTION_START_3_3 = CameraMetadataSection:VENDOR_SECTION_3_3 << 16,
+
+};
 
 /**
  * Main enumeration for defining camera metadata tags added in this revision
@@ -71,6 +94,20 @@
 
     ANDROID_INFO_END_3_3,
 
+    /** android.logicalMultiCamera.physicalIds [static, byte[], hidden]
+     *
+     * <p>String containing the ids of the underlying physical cameras.</p>
+     */
+    ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS = CameraMetadataSectionStart:ANDROID_LOGICAL_MULTI_CAMERA_START,
+
+    /** android.logicalMultiCamera.sensorSyncType [static, enum, public]
+     *
+     * <p>The accuracy of frame timestamp synchronization between physical cameras</p>
+     */
+    ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE,
+
+    ANDROID_LOGICAL_MULTI_CAMERA_END_3_3,
+
 };
 
 /*
@@ -115,4 +152,13 @@
 enum CameraMetadataEnumAndroidRequestAvailableCapabilities :
         @3.2::CameraMetadataEnumAndroidRequestAvailableCapabilities {
     ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING,
+    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA,
+};
+
+/** android.logicalMultiCamera.sensorSyncType enumeration values
+ * @see ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE
+ */
+enum CameraMetadataEnumAndroidLogicalMultiCameraSensorSyncType : uint32_t {
+    ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE,
+    ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED,
 };
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 1bc9e7f..eb15766 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2016-2018 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.
@@ -47,6 +47,7 @@
 #include <VtsHalHidlTargetTestBase.h>
 #include <VtsHalHidlTargetTestEnvBase.h>
 
+using namespace ::android::hardware::camera::device;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
 using ::android::hardware::hidl_handle;
@@ -78,7 +79,6 @@
 using ::android::hardware::camera::device::V3_2::ICameraDeviceSession;
 using ::android::hardware::camera::device::V3_2::NotifyMsg;
 using ::android::hardware::camera::device::V3_2::RequestTemplate;
-using ::android::hardware::camera::device::V3_2::Stream;
 using ::android::hardware::camera::device::V3_2::StreamType;
 using ::android::hardware::camera::device::V3_2::StreamRotation;
 using ::android::hardware::camera::device::V3_2::StreamConfiguration;
@@ -620,11 +620,16 @@
     void castSession(const sp<ICameraDeviceSession> &session, int32_t deviceVersion,
             sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/,
             sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/);
+    void createStreamConfiguration(const ::android::hardware::hidl_vec<V3_2::Stream>& streams3_2,
+            StreamConfigurationMode configMode,
+            ::android::hardware::camera::device::V3_2::StreamConfiguration *config3_2,
+            ::android::hardware::camera::device::V3_4::StreamConfiguration *config3_4);
+
     void configurePreviewStream(const std::string &name, int32_t deviceVersion,
             sp<ICameraProvider> provider,
             const AvailableStream *previewThreshold,
             sp<ICameraDeviceSession> *session /*out*/,
-            Stream *previewStream /*out*/,
+            V3_2::Stream *previewStream /*out*/,
             HalStreamConfiguration *halStreamConfig /*out*/,
             bool *supportsPartialResults /*out*/,
             uint32_t *partialResultCount /*out*/);
@@ -2353,7 +2358,8 @@
 
         int32_t streamId = 0;
         for (auto& it : outputStreams) {
-            Stream stream = {streamId,
+            V3_2::Stream stream3_2;
+            stream3_2 = {streamId,
                              StreamType::OUTPUT,
                              static_cast<uint32_t>(it.width),
                              static_cast<uint32_t>(it.height),
@@ -2361,25 +2367,27 @@
                              GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
                              0,
                              StreamRotation::ROTATION_0};
-            ::android::hardware::hidl_vec<Stream> streams = {stream};
-            ::android::hardware::camera::device::V3_4::StreamConfiguration config;
-            config.v3_2 = {streams, StreamConfigurationMode::NORMAL_MODE};
+            ::android::hardware::hidl_vec<V3_2::Stream> streams3_2 = {stream3_2};
+            ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
+            ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2;
+            createStreamConfiguration(streams3_2, StreamConfigurationMode::NORMAL_MODE,
+                                      &config3_2, &config3_4);
             if (session3_4 != nullptr) {
-                ret = session3_4->configureStreams_3_4(config,
-                        [streamId](Status s, device::V3_3::HalStreamConfiguration halConfig) {
+                ret = session3_4->configureStreams_3_4(config3_4,
+                        [streamId](Status s, device::V3_4::HalStreamConfiguration halConfig) {
                             ASSERT_EQ(Status::OK, s);
                             ASSERT_EQ(1u, halConfig.streams.size());
-                            ASSERT_EQ(halConfig.streams[0].v3_2.id, streamId);
+                            ASSERT_EQ(halConfig.streams[0].v3_3.v3_2.id, streamId);
                         });
             } else if (session3_3 != nullptr) {
-                ret = session3_3->configureStreams_3_3(config.v3_2,
+                ret = session3_3->configureStreams_3_3(config3_2,
                         [streamId](Status s, device::V3_3::HalStreamConfiguration halConfig) {
                             ASSERT_EQ(Status::OK, s);
                             ASSERT_EQ(1u, halConfig.streams.size());
                             ASSERT_EQ(halConfig.streams[0].v3_2.id, streamId);
                         });
             } else {
-                ret = session->configureStreams(config.v3_2,
+                ret = session->configureStreams(config3_2,
                         [streamId](Status s, HalStreamConfiguration halConfig) {
                             ASSERT_EQ(Status::OK, s);
                             ASSERT_EQ(1u, halConfig.streams.size());
@@ -2424,7 +2432,7 @@
         ASSERT_NE(0u, outputStreams.size());
 
         int32_t streamId = 0;
-        Stream stream = {streamId++,
+        V3_2::Stream stream3_2 = {streamId++,
                          StreamType::OUTPUT,
                          static_cast<uint32_t>(0),
                          static_cast<uint32_t>(0),
@@ -2432,23 +2440,25 @@
                          GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
                          0,
                          StreamRotation::ROTATION_0};
-        ::android::hardware::hidl_vec<Stream> streams = {stream};
-        ::android::hardware::camera::device::V3_4::StreamConfiguration config;
-        config.v3_2 = {streams, StreamConfigurationMode::NORMAL_MODE};
+        ::android::hardware::hidl_vec<V3_2::Stream> streams = {stream3_2};
+        ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
+        ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2;
+        createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
+                                  &config3_2, &config3_4);
         if(session3_4 != nullptr) {
-            ret = session3_4->configureStreams_3_4(config,
-                [](Status s, device::V3_3::HalStreamConfiguration) {
+            ret = session3_4->configureStreams_3_4(config3_4,
+                [](Status s, device::V3_4::HalStreamConfiguration) {
                     ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
                             (Status::INTERNAL_ERROR == s));
                 });
         } else if(session3_3 != nullptr) {
-            ret = session3_3->configureStreams_3_3(config.v3_2,
+            ret = session3_3->configureStreams_3_3(config3_2,
                 [](Status s, device::V3_3::HalStreamConfiguration) {
                     ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
                             (Status::INTERNAL_ERROR == s));
                 });
         } else {
-            ret = session->configureStreams(config.v3_2,
+            ret = session->configureStreams(config3_2,
                 [](Status s, HalStreamConfiguration) {
                     ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
                             (Status::INTERNAL_ERROR == s));
@@ -2456,7 +2466,7 @@
         }
         ASSERT_TRUE(ret.isOk());
 
-        stream = {streamId++,
+        stream3_2 = {streamId++,
                   StreamType::OUTPUT,
                   static_cast<uint32_t>(UINT32_MAX),
                   static_cast<uint32_t>(UINT32_MAX),
@@ -2464,20 +2474,21 @@
                   GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
                   0,
                   StreamRotation::ROTATION_0};
-        streams[0] = stream;
-        config.v3_2 = {streams, StreamConfigurationMode::NORMAL_MODE};
+        streams[0] = stream3_2;
+        createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
+                &config3_2, &config3_4);
         if(session3_4 != nullptr) {
-            ret = session3_4->configureStreams_3_4(config, [](Status s,
-                        device::V3_3::HalStreamConfiguration) {
+            ret = session3_4->configureStreams_3_4(config3_4, [](Status s,
+                        device::V3_4::HalStreamConfiguration) {
                     ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
                 });
         } else if(session3_3 != nullptr) {
-            ret = session3_3->configureStreams_3_3(config.v3_2, [](Status s,
+            ret = session3_3->configureStreams_3_3(config3_2, [](Status s,
                         device::V3_3::HalStreamConfiguration) {
                     ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
                 });
         } else {
-            ret = session->configureStreams(config.v3_2, [](Status s,
+            ret = session->configureStreams(config3_2, [](Status s,
                         HalStreamConfiguration) {
                     ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
                 });
@@ -2485,7 +2496,7 @@
         ASSERT_TRUE(ret.isOk());
 
         for (auto& it : outputStreams) {
-            stream = {streamId++,
+            stream3_2 = {streamId++,
                       StreamType::OUTPUT,
                       static_cast<uint32_t>(it.width),
                       static_cast<uint32_t>(it.height),
@@ -2493,27 +2504,28 @@
                       GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
                       0,
                       StreamRotation::ROTATION_0};
-            streams[0] = stream;
-            config.v3_2 = {streams, StreamConfigurationMode::NORMAL_MODE};
+            streams[0] = stream3_2;
+            createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
+                    &config3_2, &config3_4);
             if(session3_4 != nullptr) {
-                ret = session3_4->configureStreams_3_4(config,
-                        [](Status s, device::V3_3::HalStreamConfiguration) {
+                ret = session3_4->configureStreams_3_4(config3_4,
+                        [](Status s, device::V3_4::HalStreamConfiguration) {
                             ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
                         });
             } else if(session3_3 != nullptr) {
-                ret = session3_3->configureStreams_3_3(config.v3_2,
+                ret = session3_3->configureStreams_3_3(config3_2,
                         [](Status s, device::V3_3::HalStreamConfiguration) {
                             ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
                         });
             } else {
-                ret = session->configureStreams(config.v3_2,
+                ret = session->configureStreams(config3_2,
                         [](Status s, HalStreamConfiguration) {
                             ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
                         });
             }
             ASSERT_TRUE(ret.isOk());
 
-            stream = {streamId++,
+            stream3_2 = {streamId++,
                       StreamType::OUTPUT,
                       static_cast<uint32_t>(it.width),
                       static_cast<uint32_t>(it.height),
@@ -2521,20 +2533,21 @@
                       GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
                       0,
                       static_cast<StreamRotation>(UINT32_MAX)};
-            streams[0] = stream;
-            config.v3_2 = {streams, StreamConfigurationMode::NORMAL_MODE};
+            streams[0] = stream3_2;
+            createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
+                    &config3_2, &config3_4);
             if(session3_4 != nullptr) {
-                ret = session3_4->configureStreams_3_4(config,
-                        [](Status s, device::V3_3::HalStreamConfiguration) {
+                ret = session3_4->configureStreams_3_4(config3_4,
+                        [](Status s, device::V3_4::HalStreamConfiguration) {
                             ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
                         });
             } else if(session3_3 != nullptr) {
-                ret = session3_3->configureStreams_3_3(config.v3_2,
+                ret = session3_3->configureStreams_3_3(config3_2,
                         [](Status s, device::V3_3::HalStreamConfiguration) {
                             ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
                         });
             } else {
-                ret = session->configureStreams(config.v3_2,
+                ret = session->configureStreams(config3_2,
                         [](Status s, HalStreamConfiguration) {
                             ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
                         });
@@ -2603,7 +2616,7 @@
                       getAvailableOutputStreams(staticMeta, outputStreams,
                               &outputThreshold));
             for (auto& outputIter : outputStreams) {
-                Stream zslStream = {streamId++,
+                V3_2::Stream zslStream = {streamId++,
                                     StreamType::OUTPUT,
                                     static_cast<uint32_t>(input.width),
                                     static_cast<uint32_t>(input.height),
@@ -2611,7 +2624,7 @@
                                     GRALLOC_USAGE_HW_CAMERA_ZSL,
                                     0,
                                     StreamRotation::ROTATION_0};
-                Stream inputStream = {streamId++,
+                V3_2::Stream inputStream = {streamId++,
                                       StreamType::INPUT,
                                       static_cast<uint32_t>(input.width),
                                       static_cast<uint32_t>(input.height),
@@ -2619,7 +2632,7 @@
                                       0,
                                       0,
                                       StreamRotation::ROTATION_0};
-                Stream outputStream = {streamId++,
+                V3_2::Stream outputStream = {streamId++,
                                        StreamType::OUTPUT,
                                        static_cast<uint32_t>(outputIter.width),
                                        static_cast<uint32_t>(outputIter.height),
@@ -2628,24 +2641,26 @@
                                        0,
                                        StreamRotation::ROTATION_0};
 
-                ::android::hardware::hidl_vec<Stream> streams = {inputStream, zslStream,
+                ::android::hardware::hidl_vec<V3_2::Stream> streams = {inputStream, zslStream,
                                                                  outputStream};
-                ::android::hardware::camera::device::V3_4::StreamConfiguration config;
-                config.v3_2 = {streams, StreamConfigurationMode::NORMAL_MODE};
+                ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
+                ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2;
+                createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
+                                          &config3_2, &config3_4);
                 if (session3_4 != nullptr) {
-                    ret = session3_4->configureStreams_3_4(config,
-                            [](Status s, device::V3_3::HalStreamConfiguration halConfig) {
+                    ret = session3_4->configureStreams_3_4(config3_4,
+                            [](Status s, device::V3_4::HalStreamConfiguration halConfig) {
                                 ASSERT_EQ(Status::OK, s);
                                 ASSERT_EQ(3u, halConfig.streams.size());
                             });
                 } else if (session3_3 != nullptr) {
-                    ret = session3_3->configureStreams_3_3(config.v3_2,
+                    ret = session3_3->configureStreams_3_3(config3_2,
                             [](Status s, device::V3_3::HalStreamConfiguration halConfig) {
                                 ASSERT_EQ(Status::OK, s);
                                 ASSERT_EQ(3u, halConfig.streams.size());
                             });
                 } else {
-                    ret = session->configureStreams(config.v3_2,
+                    ret = session->configureStreams(config3_2,
                             [](Status s, HalStreamConfiguration halConfig) {
                                 ASSERT_EQ(Status::OK, s);
                                 ASSERT_EQ(3u, halConfig.streams.size());
@@ -2733,7 +2748,8 @@
                 &previewThreshold));
         ASSERT_NE(0u, outputPreviewStreams.size());
 
-        Stream previewStream = {0,
+        V3_4::Stream previewStream;
+        previewStream.v3_2 = {0,
                                 StreamType::OUTPUT,
                                 static_cast<uint32_t>(outputPreviewStreams[0].width),
                                 static_cast<uint32_t>(outputPreviewStreams[0].height),
@@ -2741,15 +2757,16 @@
                                 GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
                                 0,
                                 StreamRotation::ROTATION_0};
-        ::android::hardware::hidl_vec<Stream> streams = {previewStream};
+        ::android::hardware::hidl_vec<V3_4::Stream> streams = {previewStream};
         ::android::hardware::camera::device::V3_4::StreamConfiguration config;
-        config.v3_2 = {streams, StreamConfigurationMode::NORMAL_MODE};
+        config.streams = streams;
+        config.operationMode = StreamConfigurationMode::NORMAL_MODE;
         const camera_metadata_t *sessionParamsBuffer = sessionParams.getAndLock();
         config.sessionParams.setToExternal(
                 reinterpret_cast<uint8_t *> (const_cast<camera_metadata_t *> (sessionParamsBuffer)),
                 get_camera_metadata_size(sessionParamsBuffer));
         ret = session3_4->configureStreams_3_4(config,
-                [](Status s, device::V3_3::HalStreamConfiguration halConfig) {
+                [](Status s, device::V3_4::HalStreamConfiguration halConfig) {
                     ASSERT_EQ(Status::OK, s);
                     ASSERT_EQ(1u, halConfig.streams.size());
                 });
@@ -2804,7 +2821,7 @@
         int32_t streamId = 0;
         for (auto& blobIter : outputBlobStreams) {
             for (auto& previewIter : outputPreviewStreams) {
-                Stream previewStream = {streamId++,
+                V3_2::Stream previewStream = {streamId++,
                                         StreamType::OUTPUT,
                                         static_cast<uint32_t>(previewIter.width),
                                         static_cast<uint32_t>(previewIter.height),
@@ -2812,7 +2829,7 @@
                                         GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
                                         0,
                                         StreamRotation::ROTATION_0};
-                Stream blobStream = {streamId++,
+                V3_2::Stream blobStream = {streamId++,
                                      StreamType::OUTPUT,
                                      static_cast<uint32_t>(blobIter.width),
                                      static_cast<uint32_t>(blobIter.height),
@@ -2820,24 +2837,26 @@
                                      GRALLOC1_CONSUMER_USAGE_CPU_READ,
                                      0,
                                      StreamRotation::ROTATION_0};
-                ::android::hardware::hidl_vec<Stream> streams = {previewStream,
+                ::android::hardware::hidl_vec<V3_2::Stream> streams = {previewStream,
                                                                  blobStream};
-                ::android::hardware::camera::device::V3_4::StreamConfiguration config;
-                config.v3_2 = {streams, StreamConfigurationMode::NORMAL_MODE};
+                ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
+                ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2;
+                createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
+                                          &config3_2, &config3_4);
                 if (session3_4 != nullptr) {
-                    ret = session3_4->configureStreams_3_4(config,
-                            [](Status s, device::V3_3::HalStreamConfiguration halConfig) {
+                    ret = session3_4->configureStreams_3_4(config3_4,
+                            [](Status s, device::V3_4::HalStreamConfiguration halConfig) {
                                 ASSERT_EQ(Status::OK, s);
                                 ASSERT_EQ(2u, halConfig.streams.size());
                             });
                 } else if (session3_3 != nullptr) {
-                    ret = session3_3->configureStreams_3_3(config.v3_2,
+                    ret = session3_3->configureStreams_3_3(config3_2,
                             [](Status s, device::V3_3::HalStreamConfiguration halConfig) {
                                 ASSERT_EQ(Status::OK, s);
                                 ASSERT_EQ(2u, halConfig.streams.size());
                             });
                 } else {
-                    ret = session->configureStreams(config.v3_2,
+                    ret = session->configureStreams(config3_2,
                             [](Status s, HalStreamConfiguration halConfig) {
                                 ASSERT_EQ(Status::OK, s);
                                 ASSERT_EQ(2u, halConfig.streams.size());
@@ -2890,7 +2909,7 @@
         ASSERT_EQ(Status::OK, rc);
 
         int32_t streamId = 0;
-        Stream stream = {streamId,
+        V3_2::Stream stream = {streamId,
                          StreamType::OUTPUT,
                          static_cast<uint32_t>(hfrStream.width),
                          static_cast<uint32_t>(hfrStream.height),
@@ -2898,25 +2917,27 @@
                          GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER,
                          0,
                          StreamRotation::ROTATION_0};
-        ::android::hardware::hidl_vec<Stream> streams = {stream};
-        ::android::hardware::camera::device::V3_4::StreamConfiguration config;
-        config.v3_2 = {streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
+        ::android::hardware::hidl_vec<V3_2::Stream> streams = {stream};
+        ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
+        ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2;
+        createStreamConfiguration(streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE,
+                                  &config3_2, &config3_4);
         if (session3_4 != nullptr) {
-            ret = session3_4->configureStreams_3_4(config,
-                    [streamId](Status s, device::V3_3::HalStreamConfiguration halConfig) {
+            ret = session3_4->configureStreams_3_4(config3_4,
+                    [streamId](Status s, device::V3_4::HalStreamConfiguration halConfig) {
                         ASSERT_EQ(Status::OK, s);
                         ASSERT_EQ(1u, halConfig.streams.size());
-                        ASSERT_EQ(halConfig.streams[0].v3_2.id, streamId);
+                        ASSERT_EQ(halConfig.streams[0].v3_3.v3_2.id, streamId);
                     });
         } else if (session3_3 != nullptr) {
-            ret = session3_3->configureStreams_3_3(config.v3_2,
+            ret = session3_3->configureStreams_3_3(config3_2,
                     [streamId](Status s, device::V3_3::HalStreamConfiguration halConfig) {
                         ASSERT_EQ(Status::OK, s);
                         ASSERT_EQ(1u, halConfig.streams.size());
                         ASSERT_EQ(halConfig.streams[0].v3_2.id, streamId);
                     });
         } else {
-            ret = session->configureStreams(config.v3_2,
+            ret = session->configureStreams(config3_2,
                     [streamId](Status s, HalStreamConfiguration halConfig) {
                         ASSERT_EQ(Status::OK, s);
                         ASSERT_EQ(1u, halConfig.streams.size());
@@ -2934,21 +2955,22 @@
                   0,
                   StreamRotation::ROTATION_0};
         streams[0] = stream;
-        config.v3_2 = {streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
+        createStreamConfiguration(streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE,
+                                  &config3_2, &config3_4);
         if (session3_4 != nullptr) {
-            ret = session3_4->configureStreams_3_4(config,
-                    [](Status s, device::V3_3::HalStreamConfiguration) {
+            ret = session3_4->configureStreams_3_4(config3_4,
+                    [](Status s, device::V3_4::HalStreamConfiguration) {
                         ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
                                 (Status::INTERNAL_ERROR == s));
                     });
         } else if (session3_3 != nullptr) {
-            ret = session3_3->configureStreams_3_3(config.v3_2,
+            ret = session3_3->configureStreams_3_3(config3_2,
                     [](Status s, device::V3_3::HalStreamConfiguration) {
                         ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
                                 (Status::INTERNAL_ERROR == s));
                     });
         } else {
-            ret = session->configureStreams(config.v3_2,
+            ret = session->configureStreams(config3_2,
                     [](Status s, HalStreamConfiguration) {
                         ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
                                 (Status::INTERNAL_ERROR == s));
@@ -2965,19 +2987,20 @@
                   0,
                   StreamRotation::ROTATION_0};
         streams[0] = stream;
-        config.v3_2 = {streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
+        createStreamConfiguration(streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE,
+                                  &config3_2, &config3_4);
         if (session3_4 != nullptr) {
-            ret = session3_4->configureStreams_3_4(config,
-                    [](Status s, device::V3_3::HalStreamConfiguration) {
+            ret = session3_4->configureStreams_3_4(config3_4,
+                    [](Status s, device::V3_4::HalStreamConfiguration) {
                         ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
                     });
         } else if (session3_3 != nullptr) {
-            ret = session3_3->configureStreams_3_3(config.v3_2,
+            ret = session3_3->configureStreams_3_3(config3_2,
                     [](Status s, device::V3_3::HalStreamConfiguration) {
                         ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
                     });
         } else {
-            ret = session->configureStreams(config.v3_2,
+            ret = session->configureStreams(config3_2,
                     [](Status s, HalStreamConfiguration) {
                         ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
                     });
@@ -2993,19 +3016,20 @@
                   0,
                   StreamRotation::ROTATION_0};
         streams[0] = stream;
-        config.v3_2 = {streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
+        createStreamConfiguration(streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE,
+                                  &config3_2, &config3_4);
         if (session3_4 != nullptr) {
-            ret = session3_4->configureStreams_3_4(config,
-                    [](Status s, device::V3_3::HalStreamConfiguration) {
+            ret = session3_4->configureStreams_3_4(config3_4,
+                    [](Status s, device::V3_4::HalStreamConfiguration) {
                         ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
                     });
         } else if (session3_3 != nullptr) {
-            ret = session3_3->configureStreams_3_3(config.v3_2,
+            ret = session3_3->configureStreams_3_3(config3_2,
                     [](Status s, device::V3_3::HalStreamConfiguration) {
                         ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
                     });
         } else {
-            ret = session->configureStreams(config.v3_2,
+            ret = session->configureStreams(config3_2,
                     [](Status s, HalStreamConfiguration) {
                         ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
                     });
@@ -3062,7 +3086,7 @@
         int32_t streamId = 0;
         for (auto& blobIter : outputBlobStreams) {
             for (auto& videoIter : outputVideoStreams) {
-                Stream videoStream = {streamId++,
+                V3_2::Stream videoStream = {streamId++,
                                       StreamType::OUTPUT,
                                       static_cast<uint32_t>(videoIter.width),
                                       static_cast<uint32_t>(videoIter.height),
@@ -3070,7 +3094,7 @@
                                       GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER,
                                       0,
                                       StreamRotation::ROTATION_0};
-                Stream blobStream = {streamId++,
+                V3_2::Stream blobStream = {streamId++,
                                      StreamType::OUTPUT,
                                      static_cast<uint32_t>(blobIter.width),
                                      static_cast<uint32_t>(blobIter.height),
@@ -3078,23 +3102,25 @@
                                      GRALLOC1_CONSUMER_USAGE_CPU_READ,
                                      0,
                                      StreamRotation::ROTATION_0};
-                ::android::hardware::hidl_vec<Stream> streams = {videoStream, blobStream};
-                ::android::hardware::camera::device::V3_4::StreamConfiguration config;
-                config.v3_2 = {streams, StreamConfigurationMode::NORMAL_MODE};
+                ::android::hardware::hidl_vec<V3_2::Stream> streams = {videoStream, blobStream};
+                ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
+                ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2;
+                createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
+                                          &config3_2, &config3_4);
                 if (session3_4 != nullptr) {
-                    ret = session3_4->configureStreams_3_4(config,
-                            [](Status s, device::V3_3::HalStreamConfiguration halConfig) {
+                    ret = session3_4->configureStreams_3_4(config3_4,
+                            [](Status s, device::V3_4::HalStreamConfiguration halConfig) {
                                 ASSERT_EQ(Status::OK, s);
                                 ASSERT_EQ(2u, halConfig.streams.size());
                             });
                 } else if (session3_3 != nullptr) {
-                    ret = session3_3->configureStreams_3_3(config.v3_2,
+                    ret = session3_3->configureStreams_3_3(config3_2,
                             [](Status s, device::V3_3::HalStreamConfiguration halConfig) {
                                 ASSERT_EQ(Status::OK, s);
                                 ASSERT_EQ(2u, halConfig.streams.size());
                             });
                 } else {
-                    ret = session->configureStreams(config.v3_2,
+                    ret = session->configureStreams(config3_2,
                             [](Status s, HalStreamConfiguration halConfig) {
                                 ASSERT_EQ(Status::OK, s);
                                 ASSERT_EQ(2u, halConfig.streams.size());
@@ -3129,7 +3155,7 @@
             return;
         }
 
-        Stream previewStream;
+        V3_2::Stream previewStream;
         HalStreamConfiguration halStreamConfig;
         sp<ICameraDeviceSession> session;
         bool supportsPartialResults = false;
@@ -3284,7 +3310,7 @@
             return;
         }
 
-        Stream previewStream;
+        V3_2::Stream previewStream;
         HalStreamConfiguration halStreamConfig;
         sp<ICameraDeviceSession> session;
         bool supportsPartialResults = false;
@@ -3351,7 +3377,7 @@
             return;
         }
 
-        Stream previewStream;
+        V3_2::Stream previewStream;
         HalStreamConfiguration halStreamConfig;
         sp<ICameraDeviceSession> session;
         bool supportsPartialResults = false;
@@ -3415,7 +3441,7 @@
             return;
         }
 
-        Stream previewStream;
+        V3_2::Stream previewStream;
         HalStreamConfiguration halStreamConfig;
         sp<ICameraDeviceSession> session;
         bool supportsPartialResults = false;
@@ -3545,7 +3571,7 @@
             return;
         }
 
-        Stream previewStream;
+        V3_2::Stream previewStream;
         HalStreamConfiguration halStreamConfig;
         sp<ICameraDeviceSession> session;
         bool supportsPartialResults = false;
@@ -3754,12 +3780,31 @@
     return Status::METHOD_NOT_SUPPORTED;
 }
 
+void CameraHidlTest::createStreamConfiguration(
+        const ::android::hardware::hidl_vec<V3_2::Stream>& streams3_2,
+        StreamConfigurationMode configMode,
+        ::android::hardware::camera::device::V3_2::StreamConfiguration *config3_2 /*out*/,
+        ::android::hardware::camera::device::V3_4::StreamConfiguration *config3_4 /*out*/) {
+    ASSERT_NE(nullptr, config3_2);
+    ASSERT_NE(nullptr, config3_4);
+
+    ::android::hardware::hidl_vec<V3_4::Stream> streams3_4(streams3_2.size());
+    size_t idx = 0;
+    for (auto& stream3_2 : streams3_2) {
+        V3_4::Stream stream;
+        stream.v3_2 = stream3_2;
+        streams3_4[idx++] = stream;
+    }
+    *config3_4 = {streams3_4, configMode, {}};
+    *config3_2 = {streams3_2, configMode};
+}
+
 // Open a device session and configure a preview stream.
 void CameraHidlTest::configurePreviewStream(const std::string &name, int32_t deviceVersion,
         sp<ICameraProvider> provider,
         const AvailableStream *previewThreshold,
         sp<ICameraDeviceSession> *session /*out*/,
-        Stream *previewStream /*out*/,
+        V3_2::Stream *previewStream /*out*/,
         HalStreamConfiguration *halStreamConfig /*out*/,
         bool *supportsPartialResults /*out*/,
         uint32_t *partialResultCount /*out*/) {
@@ -3824,33 +3869,35 @@
     ASSERT_EQ(Status::OK, rc);
     ASSERT_FALSE(outputPreviewStreams.empty());
 
-    *previewStream = {0, StreamType::OUTPUT,
+    V3_2::Stream stream3_2 = {0, StreamType::OUTPUT,
             static_cast<uint32_t> (outputPreviewStreams[0].width),
             static_cast<uint32_t> (outputPreviewStreams[0].height),
             static_cast<PixelFormat> (outputPreviewStreams[0].format),
             GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, 0, StreamRotation::ROTATION_0};
-    ::android::hardware::hidl_vec<Stream> streams = {*previewStream};
-    ::android::hardware::camera::device::V3_4::StreamConfiguration config;
-    config.v3_2 = {streams, StreamConfigurationMode::NORMAL_MODE};
+    ::android::hardware::hidl_vec<V3_2::Stream> streams3_2 = {stream3_2};
+    ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2;
+    ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
+    createStreamConfiguration(streams3_2, StreamConfigurationMode::NORMAL_MODE,
+                              &config3_2, &config3_4);
     if (session3_4 != nullptr) {
         RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
         ret = session3_4->constructDefaultRequestSettings(reqTemplate,
-                                                       [&config](auto status, const auto& req) {
+                                                       [&config3_4](auto status, const auto& req) {
                                                            ASSERT_EQ(Status::OK, status);
-                                                           config.sessionParams = req;
+                                                           config3_4.sessionParams = req;
                                                        });
         ASSERT_TRUE(ret.isOk());
-        ret = session3_4->configureStreams_3_4(config,
-                [&] (Status s, device::V3_3::HalStreamConfiguration halConfig) {
+        ret = session3_4->configureStreams_3_4(config3_4,
+                [&] (Status s, device::V3_4::HalStreamConfiguration halConfig) {
                     ASSERT_EQ(Status::OK, s);
                     ASSERT_EQ(1u, halConfig.streams.size());
                     halStreamConfig->streams.resize(halConfig.streams.size());
                     for (size_t i = 0; i < halConfig.streams.size(); i++) {
-                        halStreamConfig->streams[i] = halConfig.streams[i].v3_2;
+                        halStreamConfig->streams[i] = halConfig.streams[i].v3_3.v3_2;
                     }
                 });
     } else if (session3_3 != nullptr) {
-        ret = session3_3->configureStreams_3_3(config.v3_2,
+        ret = session3_3->configureStreams_3_3(config3_2,
                 [&] (Status s, device::V3_3::HalStreamConfiguration halConfig) {
                     ASSERT_EQ(Status::OK, s);
                     ASSERT_EQ(1u, halConfig.streams.size());
@@ -3860,13 +3907,14 @@
                     }
                 });
     } else {
-        ret = (*session)->configureStreams(config.v3_2,
+        ret = (*session)->configureStreams(config3_2,
                 [&] (Status s, HalStreamConfiguration halConfig) {
                     ASSERT_EQ(Status::OK, s);
                     ASSERT_EQ(1u, halConfig.streams.size());
                     *halStreamConfig = halConfig;
                 });
     }
+    *previewStream = stream3_2;
     ASSERT_TRUE(ret.isOk());
 }