Merge "Adds float16 support for RANDOM_MULTINOMIAL."
diff --git a/camera/common/1.0/default/CameraModule.cpp b/camera/common/1.0/default/CameraModule.cpp
index 9c2b02b..08354b3 100644
--- a/camera/common/1.0/default/CameraModule.cpp
+++ b/camera/common/1.0/default/CameraModule.cpp
@@ -452,6 +452,16 @@
     return res;
 }
 
+int CameraModule::isStreamCombinationSupported(int cameraId, camera_stream_combination_t *streams) {
+    int res = INVALID_OPERATION;
+    if (mModule->is_stream_combination_supported != NULL) {
+        ATRACE_BEGIN("camera_module->is_stream_combination_supported");
+        res = mModule->is_stream_combination_supported(cameraId, streams);
+        ATRACE_END();
+    }
+    return res;
+}
+
 status_t CameraModule::filterOpenErrorCode(status_t err) {
     switch(err) {
         case NO_ERROR:
diff --git a/camera/common/1.0/default/include/CameraModule.h b/camera/common/1.0/default/include/CameraModule.h
index aee9654..ee75e72 100644
--- a/camera/common/1.0/default/include/CameraModule.h
+++ b/camera/common/1.0/default/include/CameraModule.h
@@ -66,6 +66,7 @@
     // Only used by CameraProvider
     void removeCamera(int cameraId);
     int getPhysicalCameraInfo(int physicalCameraId, camera_metadata_t **physicalInfo);
+    int isStreamCombinationSupported(int cameraId, camera_stream_combination_t *streams);
 
 private:
     // Derive camera characteristics keys defined after HAL device version
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index 4ef5fc9..66b17db 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -2163,7 +2163,8 @@
     }
 }
 
-bool ExternalCameraDeviceSession::isSupported(const Stream& stream) {
+bool ExternalCameraDeviceSession::isSupported(const Stream& stream,
+        const std::vector<SupportedV4L2Format>& supportedFormats) {
     int32_t ds = static_cast<int32_t>(stream.dataSpace);
     PixelFormat fmt = stream.format;
     uint32_t width = stream.width;
@@ -2206,7 +2207,7 @@
     // Assume we can convert any V4L2 format to any of supported output format for now, i.e,
     // ignoring v4l2Fmt.fourcc for now. Might need more subtle check if we support more v4l format
     // in the futrue.
-    for (const auto& v4l2Fmt : mSupportedFormats) {
+    for (const auto& v4l2Fmt : supportedFormats) {
         if (width == v4l2Fmt.width && height == v4l2Fmt.height) {
             return true;
         }
@@ -2541,11 +2542,9 @@
     mV4L2BufferReturned.notify_one();
 }
 
-Status ExternalCameraDeviceSession::configureStreams(
+Status ExternalCameraDeviceSession::isStreamCombinationSupported(
         const V3_2::StreamConfiguration& config,
-        V3_3::HalStreamConfiguration* out,
-        uint32_t blobBufferSize) {
-    ATRACE_CALL();
+        const std::vector<SupportedV4L2Format>& supportedFormats) {
     if (config.operationMode != StreamConfigurationMode::NORMAL_MODE) {
         ALOGE("%s: unsupported operation mode: %d", __FUNCTION__, config.operationMode);
         return Status::ILLEGAL_ARGUMENT;
@@ -2560,7 +2559,7 @@
     int numStallStream = 0;
     for (const auto& stream : config.streams) {
         // Check if the format/width/height combo is supported
-        if (!isSupported(stream)) {
+        if (!isSupported(stream, supportedFormats)) {
             return Status::ILLEGAL_ARGUMENT;
         }
         if (stream.format == PixelFormat::BLOB) {
@@ -2582,7 +2581,21 @@
         return Status::ILLEGAL_ARGUMENT;
     }
 
-    Status status = initStatus();
+    return Status::OK;
+}
+
+Status ExternalCameraDeviceSession::configureStreams(
+        const V3_2::StreamConfiguration& config,
+        V3_3::HalStreamConfiguration* out,
+        uint32_t blobBufferSize) {
+    ATRACE_CALL();
+
+    Status status = isStreamCombinationSupported(config, mSupportedFormats);
+    if (status != Status::OK) {
+        return status;
+    }
+
+    status = initStatus();
     if (status != Status::OK) {
         return status;
     }
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
index cabeaa4..9cc55cb 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
@@ -193,13 +193,16 @@
     int configureV4l2StreamLocked(const SupportedV4L2Format& fmt, double fps = 0.0);
     int v4l2StreamOffLocked();
     int setV4l2FpsLocked(double fps);
+    static Status isStreamCombinationSupported(const V3_2::StreamConfiguration& config,
+            const std::vector<SupportedV4L2Format>& supportedFormats);
 
     // TODO: change to unique_ptr for better tracking
     sp<V4L2Frame> dequeueV4l2FrameLocked(/*out*/nsecs_t* shutterTs); // Called with mLock hold
     void enqueueV4l2Frame(const sp<V4L2Frame>&);
 
     // Check if input Stream is one of supported stream setting on this device
-    bool isSupported(const Stream&);
+    static bool isSupported(const Stream& stream,
+            const std::vector<SupportedV4L2Format>& supportedFormats);
 
     // Validate and import request's output buffers and acquire fence
     virtual Status importRequestLocked(
diff --git a/camera/device/3.5/ICameraDevice.hal b/camera/device/3.5/ICameraDevice.hal
index a77380f..d9f2837 100644
--- a/camera/device/3.5/ICameraDevice.hal
+++ b/camera/device/3.5/ICameraDevice.hal
@@ -19,6 +19,7 @@
 import android.hardware.camera.common@1.0::Status;
 import @3.2::CameraMetadata;
 import @3.2::ICameraDevice;
+import @3.4::StreamConfiguration;
 
 /**
  * Camera device interface
@@ -75,4 +76,41 @@
     getPhysicalCameraCharacteristics(string physicalCameraId)
             generates (Status status, CameraMetadata cameraCharacteristics);
 
+
+    /**
+     * isStreamCombinationSupported:
+     *
+     * Check for device support of specific camera stream combination.
+     *
+     * The streamList must contain at least one output-capable stream, and may
+     * not contain more than one input-capable stream.
+     *
+     * ------------------------------------------------------------------------
+     *
+     * Preconditions:
+     *
+     * The framework can call this method at any time before, during and
+     * after active session configuration. This means that calls must not
+     * impact the performance of pending camera requests in any way. In
+     * particular there must not be any glitches or delays during normal
+     * camera streaming.
+     *
+     * Performance requirements:
+     * This call is expected to be significantly faster than stream
+     * configuration. In general HW and SW camera settings must not be
+     * changed and there must not be a user-visible impact on camera performance.
+     *
+     * @return Status Status code for the operation, one of:
+     *     OK:
+     *          On successful stream combination query.
+     *     METHOD_NOT_SUPPORTED:
+     *          The camera device does not support stream combination query.
+     *     INTERNAL_ERROR:
+     *          The stream combination query cannot complete due to internal
+     *          error.
+     * @return true in case the stream combination is supported, false otherwise.
+     *
+     */
+    isStreamCombinationSupported(@3.4::StreamConfiguration streams)
+            generates (Status status, bool queryStatus);
 };
diff --git a/camera/device/3.5/default/CameraDevice.cpp b/camera/device/3.5/default/CameraDevice.cpp
index a6969af..cffda4e 100644
--- a/camera/device/3.5/default/CameraDevice.cpp
+++ b/camera/device/3.5/default/CameraDevice.cpp
@@ -95,6 +95,57 @@
     return Void();
 }
 
+Return<void> CameraDevice::isStreamCombinationSupported(const V3_4::StreamConfiguration& streams,
+        V3_5::ICameraDevice::isStreamCombinationSupported_cb _hidl_cb) {
+    Status status;
+    bool streamsSupported = false;
+
+    // Require module 2.5+ version.
+    if (mModule->getModuleApiVersion() < CAMERA_MODULE_API_VERSION_2_5) {
+        ALOGE("%s: is_stream_combination_supported must be called on camera module 2.5 or "\
+                "newer", __FUNCTION__);
+        status = Status::INTERNAL_ERROR;
+    } else {
+        camera_stream_combination_t streamComb{};
+        streamComb.operation_mode = static_cast<uint32_t> (streams.operationMode);
+        streamComb.num_streams = streams.streams.size();
+        camera_stream_t *streamBuffer  = new camera_stream_t[streamComb.num_streams];
+
+        size_t i = 0;
+        for (const auto &it : streams.streams) {
+            streamBuffer[i].stream_type = static_cast<int> (it.v3_2.streamType);
+            streamBuffer[i].width = it.v3_2.width;
+            streamBuffer[i].height = it.v3_2.height;
+            streamBuffer[i].format = static_cast<int> (it.v3_2.format);
+            streamBuffer[i].data_space = static_cast<android_dataspace_t> (it.v3_2.dataSpace);
+            streamBuffer[i].usage = static_cast<uint32_t> (it.v3_2.usage);
+            streamBuffer[i].physical_camera_id = it.physicalCameraId.c_str();
+            streamBuffer[i++].rotation = static_cast<int> (it.v3_2.rotation);
+        }
+        streamComb.streams = streamBuffer;
+        auto res = mModule->isStreamCombinationSupported(mCameraIdInt, &streamComb);
+        switch (res) {
+            case NO_ERROR:
+                streamsSupported = true;
+                status = Status::OK;
+                break;
+            case BAD_VALUE:
+                status = Status::OK;
+                break;
+            case INVALID_OPERATION:
+                status = Status::METHOD_NOT_SUPPORTED;
+                break;
+            default:
+                ALOGE("%s: Unexpected error: %d", __FUNCTION__, res);
+                status = Status::INTERNAL_ERROR;
+        };
+        delete [] streamBuffer;
+    }
+
+    _hidl_cb(status, streamsSupported);
+    return Void();
+}
+
 // End of methods from ::android::hardware::camera::device::V3_2::ICameraDevice.
 
 } // namespace implementation
diff --git a/camera/device/3.5/default/ExternalCameraDevice.cpp b/camera/device/3.5/default/ExternalCameraDevice.cpp
index e8d14b5..6a0b51e 100644
--- a/camera/device/3.5/default/ExternalCameraDevice.cpp
+++ b/camera/device/3.5/default/ExternalCameraDevice.cpp
@@ -86,6 +86,27 @@
     return OK;
 }
 
+Return<void> ExternalCameraDevice::isStreamCombinationSupported(
+        const V3_4::StreamConfiguration& streams,
+        V3_5::ICameraDevice::isStreamCombinationSupported_cb _hidl_cb) {
+
+    if (isInitFailed()) {
+        ALOGE("%s: camera %s. camera init failed!", __FUNCTION__, mCameraId.c_str());
+        _hidl_cb(Status::INTERNAL_ERROR, false);
+        return Void();
+    }
+
+    hidl_vec<V3_2::Stream> streamsV3_2(streams.streams.size());
+    size_t i = 0;
+    for (const auto& it : streams.streams) {
+        streamsV3_2[i++] = it.v3_2;
+    }
+    V3_2::StreamConfiguration streamConfig = {streamsV3_2, streams.operationMode};
+    auto status = ExternalCameraDeviceSession::isStreamCombinationSupported(streamConfig,
+            mSupportedFormats);
+    _hidl_cb(Status::OK, Status::OK == status);
+    return Void();
+}
 #undef UPDATE
 
 }  // namespace implementation
diff --git a/camera/device/3.5/default/include/device_v3_5_impl/CameraDevice_3_5.h b/camera/device/3.5/default/include/device_v3_5_impl/CameraDevice_3_5.h
index 6bdc60f..76c8cf8 100644
--- a/camera/device/3.5/default/include/device_v3_5_impl/CameraDevice_3_5.h
+++ b/camera/device/3.5/default/include/device_v3_5_impl/CameraDevice_3_5.h
@@ -64,6 +64,10 @@
     Return<void> getPhysicalCameraCharacteristics(const hidl_string& physicalCameraId,
             V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb);
 
+    Return<void> isStreamCombinationSupported(
+            const V3_4::StreamConfiguration& streams,
+            V3_5::ICameraDevice::isStreamCombinationSupported_cb _hidl_cb);
+
 private:
     struct TrampolineDeviceInterface_3_5 : public ICameraDevice {
         TrampolineDeviceInterface_3_5(sp<CameraDevice> parent) :
@@ -96,6 +100,13 @@
                 V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb) override {
             return mParent->getPhysicalCameraCharacteristics(physicalCameraId, _hidl_cb);
         }
+
+        virtual Return<void> isStreamCombinationSupported(
+                const V3_4::StreamConfiguration& streams,
+                V3_5::ICameraDevice::isStreamCombinationSupported_cb _hidl_cb) override {
+            return mParent->isStreamCombinationSupported(streams, _hidl_cb);
+        }
+
     private:
         sp<CameraDevice> mParent;
     };
diff --git a/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h
index 4d2d6b7..aa119fc 100644
--- a/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h
+++ b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h
@@ -90,6 +90,12 @@
         return new TrampolineSessionInterface_3_5(this);
     }
 
+    static Status isStreamCombinationSupported(const V3_2::StreamConfiguration& config,
+            const std::vector<SupportedV4L2Format>& supportedFormats) {
+        return V3_4::implementation::ExternalCameraDeviceSession::isStreamCombinationSupported(
+                config, supportedFormats);
+    }
+
 protected:
     // Methods from v3.4 and earlier will trampoline to inherited implementation
     Return<void> configureStreams_3_5(
diff --git a/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDevice_3_5.h b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDevice_3_5.h
index 7db86dc..b73490c 100644
--- a/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDevice_3_5.h
+++ b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDevice_3_5.h
@@ -67,6 +67,10 @@
     Return<void> getPhysicalCameraCharacteristics(const hidl_string& physicalCameraId,
             V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb);
 
+    Return<void> isStreamCombinationSupported(
+            const V3_4::StreamConfiguration& streams,
+            V3_5::ICameraDevice::isStreamCombinationSupported_cb _hidl_cb);
+
 protected:
     virtual sp<V3_4::implementation::ExternalCameraDeviceSession> createSession(
             const sp<V3_2::ICameraDeviceCallback>&,
@@ -116,6 +120,13 @@
                 V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb) override {
             return mParent->getPhysicalCameraCharacteristics(physicalCameraId, _hidl_cb);
         }
+
+        virtual Return<void> isStreamCombinationSupported(
+                const V3_4::StreamConfiguration& streams,
+                V3_5::ICameraDevice::isStreamCombinationSupported_cb _hidl_cb) override {
+            return mParent->isStreamCombinationSupported(streams, _hidl_cb);
+        }
+
     private:
         sp<ExternalCameraDevice> mParent;
     };
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index bb03d91..e376551 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -703,11 +703,14 @@
     void openEmptyDeviceSession(const std::string &name,
             sp<ICameraProvider> provider,
             sp<ICameraDeviceSession> *session /*out*/,
-            camera_metadata_t **staticMeta /*out*/);
+            camera_metadata_t **staticMeta /*out*/,
+            ::android::sp<ICameraDevice> *device = nullptr/*out*/);
     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*/,
             sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/);
+    void castDevice(const sp<device::V3_2::ICameraDevice> &device, int32_t deviceVersion,
+            sp<device::V3_5::ICameraDevice> *device3_5/*out*/);
     void createStreamConfiguration(const ::android::hardware::hidl_vec<V3_2::Stream>& streams3_2,
             StreamConfigurationMode configMode,
             ::android::hardware::camera::device::V3_2::StreamConfiguration *config3_2,
@@ -748,6 +751,9 @@
     void verifyMonochromeCharacteristics(const CameraMetadata& chars, int deviceVersion);
     void verifyMonochromeCameraResult(
             const ::android::hardware::camera::common::V1_0::helper::CameraMetadata& metadata);
+    void verifyStreamCombination(sp<device::V3_5::ICameraDevice> cameraDevice3_5,
+            const ::android::hardware::camera::device::V3_4::StreamConfiguration &config3_4,
+            bool expectedStatus);
 
     void verifyBuffersReturned(sp<device::V3_2::ICameraDeviceSession> session,
             int deviceVerison, int32_t streamId, sp<DeviceCb> cb,
@@ -2769,9 +2775,12 @@
         sp<device::V3_3::ICameraDeviceSession> session3_3;
         sp<device::V3_4::ICameraDeviceSession> session3_4;
         sp<device::V3_5::ICameraDeviceSession> session3_5;
+        sp<device::V3_2::ICameraDevice> cameraDevice;
+        sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         openEmptyDeviceSession(name, mProvider,
-                &session /*out*/, &staticMeta /*out*/);
+                &session /*out*/, &staticMeta /*out*/, &cameraDevice /*out*/);
         castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5);
 
         outputStreams.clear();
         ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
@@ -2797,6 +2806,8 @@
             createStreamConfiguration(streams3_2, StreamConfigurationMode::NORMAL_MODE,
                                       &config3_2, &config3_4, &config3_5);
             if (session3_5 != nullptr) {
+                verifyStreamCombination(cameraDevice3_5, config3_4,
+                        /*expectedStatus*/ true);
                 config3_5.streamConfigCounter = streamConfigCounter++;
                 ret = session3_5->configureStreams_3_5(config3_5,
                         [streamId](Status s, device::V3_4::HalStreamConfiguration halConfig) {
@@ -2857,8 +2868,12 @@
         sp<device::V3_3::ICameraDeviceSession> session3_3;
         sp<device::V3_4::ICameraDeviceSession> session3_4;
         sp<device::V3_5::ICameraDeviceSession> session3_5;
-        openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/);
+        sp<device::V3_2::ICameraDevice> cameraDevice;
+        sp<device::V3_5::ICameraDevice> cameraDevice3_5;
+        openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
+                &cameraDevice /*out*/);
         castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5);
 
         outputStreams.clear();
         ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
@@ -2881,6 +2896,7 @@
         createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
                                   &config3_2, &config3_4, &config3_5);
         if (session3_5 != nullptr) {
+            verifyStreamCombination(cameraDevice3_5, config3_4, /*expectedStatus*/ false);
             config3_5.streamConfigCounter = streamConfigCounter++;
             ret = session3_5->configureStreams_3_5(config3_5,
                     [](Status s, device::V3_4::HalStreamConfiguration) {
@@ -3044,8 +3060,12 @@
         sp<device::V3_3::ICameraDeviceSession> session3_3;
         sp<device::V3_4::ICameraDeviceSession> session3_4;
         sp<device::V3_5::ICameraDeviceSession> session3_5;
-        openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/);
+        sp<device::V3_2::ICameraDevice> cameraDevice;
+        sp<device::V3_5::ICameraDevice> cameraDevice3_5;
+        openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
+                &cameraDevice /*out*/);
         castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5);
 
         Status rc = isZSLModeAvailable(staticMeta);
         if (Status::METHOD_NOT_SUPPORTED == rc) {
@@ -3132,6 +3152,8 @@
                 createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
                                           &config3_2, &config3_4, &config3_5);
                 if (session3_5 != nullptr) {
+                    verifyStreamCombination(cameraDevice3_5, config3_4,
+                            /*expectedStatus*/ true);
                     config3_5.streamConfigCounter = streamConfigCounter++;
                     ret = session3_5->configureStreams_3_5(config3_5,
                             [](Status s, device::V3_4::HalStreamConfiguration halConfig) {
@@ -3304,8 +3326,12 @@
         sp<device::V3_3::ICameraDeviceSession> session3_3;
         sp<device::V3_4::ICameraDeviceSession> session3_4;
         sp<device::V3_5::ICameraDeviceSession> session3_5;
-        openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/);
+        sp<device::V3_2::ICameraDevice> cameraDevice;
+        sp<device::V3_5::ICameraDevice> cameraDevice3_5;
+        openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
+                &cameraDevice /*out*/);
         castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5);
 
         outputBlobStreams.clear();
         ASSERT_EQ(Status::OK,
@@ -3346,6 +3372,8 @@
                 createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
                                           &config3_2, &config3_4, &config3_5);
                 if (session3_5 != nullptr) {
+                    verifyStreamCombination(cameraDevice3_5, config3_4,
+                            /*expectedStatus*/ true);
                     config3_5.streamConfigCounter = streamConfigCounter++;
                     ret = session3_5->configureStreams_3_5(config3_5,
                             [](Status s, device::V3_4::HalStreamConfiguration halConfig) {
@@ -3403,8 +3431,12 @@
         sp<device::V3_3::ICameraDeviceSession> session3_3;
         sp<device::V3_4::ICameraDeviceSession> session3_4;
         sp<device::V3_5::ICameraDeviceSession> session3_5;
-        openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/);
+        sp<device::V3_2::ICameraDevice> cameraDevice;
+        sp<device::V3_5::ICameraDevice> cameraDevice3_5;
+        openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
+                &cameraDevice /*out*/);
         castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5);
 
         Status rc = isConstrainedModeAvailable(staticMeta);
         if (Status::METHOD_NOT_SUPPORTED == rc) {
@@ -3435,6 +3467,8 @@
         createStreamConfiguration(streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE,
                                   &config3_2, &config3_4, &config3_5);
         if (session3_5 != nullptr) {
+            verifyStreamCombination(cameraDevice3_5, config3_4,
+                    /*expectedStatus*/ true);
             config3_5.streamConfigCounter = streamConfigCounter++;
             ret = session3_5->configureStreams_3_5(config3_5,
                     [streamId](Status s, device::V3_4::HalStreamConfiguration halConfig) {
@@ -3608,8 +3642,12 @@
         sp<device::V3_3::ICameraDeviceSession> session3_3;
         sp<device::V3_4::ICameraDeviceSession> session3_4;
         sp<device::V3_5::ICameraDeviceSession> session3_5;
-        openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/);
+        sp<device::V3_2::ICameraDevice> cameraDevice;
+        sp<device::V3_5::ICameraDevice> cameraDevice3_5;
+        openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
+                &cameraDevice /*out*/);
         castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5);
 
         outputBlobStreams.clear();
         ASSERT_EQ(Status::OK,
@@ -3650,6 +3688,8 @@
                 createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
                                           &config3_2, &config3_4, &config3_5);
                 if (session3_5 != nullptr) {
+                    verifyStreamCombination(cameraDevice3_5, config3_4,
+                            /*expectedStatus*/ true);
                     config3_5.streamConfigCounter = streamConfigCounter++;
                     ret = session3_5->configureStreams_3_5(config3_5,
                             [](Status s, device::V3_4::HalStreamConfiguration halConfig) {
@@ -5228,6 +5268,16 @@
     ASSERT_TRUE(ret.isOk());
 }
 
+void CameraHidlTest::castDevice(const sp<device::V3_2::ICameraDevice> &device,
+        int32_t deviceVersion, sp<device::V3_5::ICameraDevice> *device3_5/*out*/) {
+    ASSERT_NE(nullptr, device3_5);
+    if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_5) {
+        auto castResult = device::V3_5::ICameraDevice::castFrom(device);
+        ASSERT_TRUE(castResult.isOk());
+        *device3_5 = castResult;
+    }
+}
+
 //Cast camera device session to corresponding version
 void CameraHidlTest::castSession(const sp<ICameraDeviceSession> &session, int32_t deviceVersion,
         sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/,
@@ -5262,6 +5312,21 @@
     }
 }
 
+void CameraHidlTest::verifyStreamCombination(sp<device::V3_5::ICameraDevice> cameraDevice3_5,
+        const ::android::hardware::camera::device::V3_4::StreamConfiguration &config3_4,
+        bool expectedStatus) {
+    if (cameraDevice3_5.get() != nullptr) {
+        auto ret = cameraDevice3_5->isStreamCombinationSupported(config3_4,
+                [expectedStatus] (Status s, bool combStatus) {
+                    ASSERT_TRUE((Status::OK == s) || (Status::METHOD_NOT_SUPPORTED == s));
+                    if (Status::OK == s) {
+                        ASSERT_TRUE(combStatus == expectedStatus);
+                    }
+                });
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
 // Verify logical camera static metadata
 void CameraHidlTest::verifyLogicalCameraMetadata(const std::string& cameraName,
         const ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice>& device,
@@ -5531,10 +5596,9 @@
 }
 
 // Open a device session with empty callbacks and return static metadata.
-void CameraHidlTest::openEmptyDeviceSession(const std::string &name,
-        sp<ICameraProvider> provider,
-        sp<ICameraDeviceSession> *session /*out*/,
-        camera_metadata_t **staticMeta /*out*/) {
+void CameraHidlTest::openEmptyDeviceSession(const std::string &name, sp<ICameraProvider> provider,
+        sp<ICameraDeviceSession> *session /*out*/, camera_metadata_t **staticMeta /*out*/,
+        ::android::sp<ICameraDevice> *cameraDevice /*out*/) {
     ASSERT_NE(nullptr, session);
     ASSERT_NE(nullptr, staticMeta);
 
@@ -5551,6 +5615,9 @@
             device3_x = device;
         });
     ASSERT_TRUE(ret.isOk());
+    if (cameraDevice != nullptr) {
+        *cameraDevice = device3_x;
+    }
 
     sp<EmptyDeviceCb> cb = new EmptyDeviceCb();
     ret = device3_x->open(cb, [&](auto status, const auto& newSession) {
diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal
index f196792..45476ee 100644
--- a/neuralnetworks/1.2/types.hal
+++ b/neuralnetworks/1.2/types.hal
@@ -126,6 +126,8 @@
     ROTATED_BBOX_TRANSFORM = 87,
     ABS = 88,
     ROI_POOLING = 89,
+    EQUAL = 90,
+    NOT_EQUAL = 91,
     /* ADDING A NEW FUNDAMENTAL OPERATION REQUIRES UPDATING THE VALUE OF
      * OperationTypeRange::OPERATION_FUNDAMENTAL_MAX.
      */
@@ -139,7 +141,7 @@
  */
 enum OperationTypeRange : uint32_t {
     OPERATION_FUNDAMENTAL_MIN = 0,
-    OPERATION_FUNDAMENTAL_MAX = 89,
+    OPERATION_FUNDAMENTAL_MAX = 91,
     OPERATION_OEM_MIN = 10000,
     OPERATION_OEM_MAX = 10000,
 };