Camera VTS: Add test validating stream configuration metadata

Vendor static metadata entries related to the stream configuration tags
like min frame duration, stall duration could include duplicate or
invalid data. Check that this is not the case.

Initially, this test only has impact for 10-bit HDR devices. More checks
will be added in the future.

Bug: 269165407
Test: Ran test on Pixel 7.
Change-Id: I2ad820c1ba4753508fa1f61b31b51739358099ea
diff --git a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
index 50fb052..398d201 100644
--- a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
+++ b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
@@ -3051,6 +3051,47 @@
     configureStreamUseCaseInternal(previewStreamThreshold);
 }
 
+// Validate the integrity of stream configuration metadata
+TEST_P(CameraAidlTest, validateStreamConfigurations) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    std::vector<AvailableStream> outputStreams;
+
+    const int32_t scalerSizesTag = ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
+    const int32_t scalerMinFrameDurationsTag = ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS;
+    const int32_t scalerStallDurationsTag = ANDROID_SCALER_AVAILABLE_STALL_DURATIONS;
+
+    for (const auto& name : cameraDeviceNames) {
+        CameraMetadata meta;
+        std::shared_ptr<ICameraDevice> cameraDevice;
+
+        openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
+                               &cameraDevice /*out*/);
+        camera_metadata_t* staticMeta = reinterpret_cast<camera_metadata_t*>(meta.metadata.data());
+
+        if (is10BitDynamicRangeCapable(staticMeta)) {
+            std::vector<std::tuple<size_t, size_t>> supportedP010Sizes, supportedBlobSizes;
+
+            getSupportedSizes(staticMeta, scalerSizesTag, HAL_PIXEL_FORMAT_BLOB,
+                              &supportedBlobSizes);
+            getSupportedSizes(staticMeta, scalerSizesTag, HAL_PIXEL_FORMAT_YCBCR_P010,
+                              &supportedP010Sizes);
+            ASSERT_FALSE(supportedP010Sizes.empty());
+
+            std::vector<int64_t> blobMinDurations, blobStallDurations;
+            getSupportedDurations(staticMeta, scalerMinFrameDurationsTag, HAL_PIXEL_FORMAT_BLOB,
+                                  supportedP010Sizes, &blobMinDurations);
+            getSupportedDurations(staticMeta, scalerStallDurationsTag, HAL_PIXEL_FORMAT_BLOB,
+                                  supportedP010Sizes, &blobStallDurations);
+            ASSERT_FALSE(blobStallDurations.empty());
+            ASSERT_FALSE(blobMinDurations.empty());
+            ASSERT_EQ(supportedP010Sizes.size(), blobMinDurations.size());
+            ASSERT_EQ(blobMinDurations.size(), blobStallDurations.size());
+        }
+
+        // Validate other aspects of stream configuration metadata...
+    }
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CameraAidlTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, CameraAidlTest,
diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp
index 64507fe..42b5b7d 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.cpp
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -3703,3 +3703,48 @@
         ASSERT_TRUE(ret.isOk());
     }
 }
+
+void CameraAidlTest::getSupportedSizes(const camera_metadata_t* ch, uint32_t tag, int32_t format,
+                                       std::vector<std::tuple<size_t, size_t>>* sizes /*out*/) {
+    if (sizes == nullptr) {
+        return;
+    }
+
+    camera_metadata_ro_entry entry;
+    int retcode = find_camera_metadata_ro_entry(ch, tag, &entry);
+    if ((0 == retcode) && (entry.count > 0)) {
+        // Scaler entry contains 4 elements (format, width, height, type)
+        for (size_t i = 0; i < entry.count; i += 4) {
+            if ((entry.data.i32[i] == format) &&
+                (entry.data.i32[i + 3] == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT)) {
+                sizes->push_back(std::make_tuple(entry.data.i32[i + 1], entry.data.i32[i + 2]));
+            }
+        }
+    }
+}
+
+void CameraAidlTest::getSupportedDurations(const camera_metadata_t* ch, uint32_t tag,
+                                           int32_t format,
+                                           const std::vector<std::tuple<size_t, size_t>>& sizes,
+                                           std::vector<int64_t>* durations /*out*/) {
+    if (durations == nullptr) {
+        return;
+    }
+
+    camera_metadata_ro_entry entry;
+    int retcode = find_camera_metadata_ro_entry(ch, tag, &entry);
+    if ((0 == retcode) && (entry.count > 0)) {
+        // Duration entry contains 4 elements (format, width, height, duration)
+        for (const auto& size : sizes) {
+            int64_t width = std::get<0>(size);
+            int64_t height = std::get<1>(size);
+            for (size_t i = 0; i < entry.count; i += 4) {
+                if ((entry.data.i64[i] == format) && (entry.data.i64[i + 1] == width) &&
+                    (entry.data.i64[i + 2] == height)) {
+                    durations->push_back(entry.data.i64[i + 3]);
+                    break;
+                }
+            }
+        }
+    }
+}
diff --git a/camera/provider/aidl/vts/camera_aidl_test.h b/camera/provider/aidl/vts/camera_aidl_test.h
index f13d6b2..bf409d9 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.h
+++ b/camera/provider/aidl/vts/camera_aidl_test.h
@@ -418,6 +418,13 @@
     bool supportsCroppedRawUseCase(const camera_metadata_t *staticMeta);
     bool isPerFrameControl(const camera_metadata_t* staticMeta);
 
+    void getSupportedSizes(const camera_metadata_t* ch, uint32_t tag, int32_t format,
+                           std::vector<std::tuple<size_t, size_t>>* sizes /*out*/);
+
+    void getSupportedDurations(const camera_metadata_t* ch, uint32_t tag, int32_t format,
+                               const std::vector<std::tuple<size_t, size_t>>& sizes,
+                               std::vector<int64_t>* durations /*out*/);
+
   protected:
     // In-flight queue for tracking completion of capture requests.
     struct InFlightRequest {