Camera: Add logical camera requirement test for GVF
The test verifies that if more than one color camera is available for a
particular facing, a logical mulit-camera must be supported consisting
all color cameras facing that direction.
Test: Run VTS test on Pixel4 and cuttlefish emulator
Bug: 178633246
Change-Id: I7b02a4057064a7f4a236c1bbc49f768ac80232cf
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 41a08f9..49e00f4 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -230,10 +230,10 @@
return false;
}
- int getCameraDeviceVersion(const hidl_string& deviceName,
- const hidl_string &providerType) {
+ int getCameraDeviceVersionAndId(const hidl_string& deviceName,
+ const hidl_string &providerType, std::string* id) {
std::string version;
- bool match = matchDeviceName(deviceName, providerType, &version, nullptr);
+ bool match = matchDeviceName(deviceName, providerType, &version, id);
if (!match) {
return -1;
}
@@ -256,6 +256,11 @@
return 0;
}
+ int getCameraDeviceVersion(const hidl_string& deviceName,
+ const hidl_string &providerType) {
+ return getCameraDeviceVersionAndId(deviceName, providerType, nullptr);
+ }
+
bool parseProviderName(const std::string& name, std::string *type /*out*/,
uint32_t *id /*out*/) {
if (!type || !id) {
@@ -930,6 +935,7 @@
camera_metadata_ro_entry* streamConfigs,
camera_metadata_ro_entry* maxResolutionStreamConfigs,
const camera_metadata_t* staticMetadata);
+ static bool isColorCamera(const camera_metadata_t *metadata);
static V3_2::DataspaceFlags getDataspace(PixelFormat format);
@@ -6179,6 +6185,167 @@
}
}
+// Test the multi-camera API requirement for Google Requirement Freeze S
+// Note that this requirement can only be partially tested. If a vendor
+// device doesn't expose a physical camera in any shape or form, there is no way
+// the test can catch it.
+TEST_P(CameraHidlTest, grfSMultiCameraTest) {
+ const int socGrfApi = property_get_int32("ro.board.first_api_level", /*default*/ -1);
+ if (socGrfApi < 31 /*S*/) {
+ // Non-GRF devices, or version < 31 Skip
+ ALOGI("%s: socGrfApi level is %d. Skipping", __FUNCTION__, socGrfApi);
+ return;
+ }
+
+ // Test that if more than one color cameras facing the same direction are
+ // supported, there must be at least one logical camera facing that
+ // direction.
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+ // Front and back facing non-logical color cameras
+ std::set<std::string> frontColorCameras, rearColorCameras;
+ // Front and back facing logical cameras' physical camera Id sets
+ std::set<std::set<std::string>> frontPhysicalIds, rearPhysicalIds;
+ for (const auto& name : cameraDeviceNames) {
+ std::string cameraId;
+ int deviceVersion = getCameraDeviceVersionAndId(name, mProviderType, &cameraId);
+ switch (deviceVersion) {
+ case CAMERA_DEVICE_API_VERSION_3_7:
+ case CAMERA_DEVICE_API_VERSION_3_6:
+ case CAMERA_DEVICE_API_VERSION_3_5:
+ case CAMERA_DEVICE_API_VERSION_3_4:
+ case CAMERA_DEVICE_API_VERSION_3_3:
+ case CAMERA_DEVICE_API_VERSION_3_2: {
+ ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_x;
+ ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str());
+ Return<void> ret;
+ ret = mProvider->getCameraDeviceInterface_V3_x(
+ name, [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device3_x = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ ret = device3_x->getCameraCharacteristics([&](auto status, const auto& chars) {
+ ASSERT_EQ(Status::OK, status);
+ const camera_metadata_t* metadata = (camera_metadata_t*)chars.data();
+
+ // Skip if this is not a color camera.
+ if (!CameraHidlTest::isColorCamera(metadata)) {
+ return;
+ }
+
+ // Check camera facing. Skip if facing is neither FRONT
+ // nor BACK. If this is not a logical camera, only note down
+ // the camera ID, and skip.
+ camera_metadata_ro_entry entry;
+ int retcode = find_camera_metadata_ro_entry(
+ metadata, ANDROID_LENS_FACING, &entry);
+ ASSERT_EQ(retcode, 0);
+ ASSERT_GT(entry.count, 0);
+ uint8_t facing = entry.data.u8[0];
+ bool isLogicalCamera = (isLogicalMultiCamera(metadata) == Status::OK);
+ if (facing == ANDROID_LENS_FACING_FRONT) {
+ if (!isLogicalCamera) {
+ frontColorCameras.insert(cameraId);
+ return;
+ }
+ } else if (facing == ANDROID_LENS_FACING_BACK) {
+ if (!isLogicalCamera) {
+ rearColorCameras.insert(cameraId);
+ return;
+ }
+ } else {
+ // Not FRONT or BACK facing. Skip.
+ return;
+ }
+
+ // Check logical camera's physical camera IDs for color
+ // cameras.
+ std::unordered_set<std::string> physicalCameraIds;
+ Status s = getPhysicalCameraIds(metadata, &physicalCameraIds);
+ ASSERT_EQ(Status::OK, s);
+ if (facing == ANDROID_LENS_FACING_FRONT) {
+ frontPhysicalIds.emplace(physicalCameraIds.begin(), physicalCameraIds.end());
+ } else {
+ rearPhysicalIds.emplace(physicalCameraIds.begin(), physicalCameraIds.end());
+ }
+ for (const auto& physicalId : physicalCameraIds) {
+ // Skip if the physicalId is publicly available
+ for (auto& deviceName : cameraDeviceNames) {
+ std::string publicVersion, publicId;
+ ASSERT_TRUE(::matchDeviceName(deviceName, mProviderType,
+ &publicVersion, &publicId));
+ if (physicalId == publicId) {
+ // Skip because public Ids will be iterated in outer loop.
+ return;
+ }
+ }
+
+ auto castResult = device::V3_5::ICameraDevice::castFrom(device3_x);
+ ASSERT_TRUE(castResult.isOk());
+ ::android::sp<::android::hardware::camera::device::V3_5::ICameraDevice>
+ device3_5 = castResult;
+ ASSERT_NE(device3_5, nullptr);
+
+ // Check camera characteristics for hidden camera id
+ Return<void> ret = device3_5->getPhysicalCameraCharacteristics(
+ physicalId, [&](auto status, const auto& chars) {
+ ASSERT_EQ(Status::OK, status);
+ const camera_metadata_t* physicalMetadata =
+ (camera_metadata_t*)chars.data();
+
+ if (CameraHidlTest::isColorCamera(physicalMetadata)) {
+ if (facing == ANDROID_LENS_FACING_FRONT) {
+ frontColorCameras.insert(physicalId);
+ } else if (facing == ANDROID_LENS_FACING_BACK) {
+ rearColorCameras.insert(physicalId);
+ }
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ } break;
+ case CAMERA_DEVICE_API_VERSION_1_0: {
+ // Not applicable
+ } break;
+ default: {
+ ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+ ADD_FAILURE();
+ } break;
+ }
+ }
+
+ // If there are more than one color cameras facing one direction, a logical
+ // multi-camera must be defined consisting of all color cameras facing that
+ // direction.
+ if (frontColorCameras.size() > 1) {
+ bool hasFrontLogical = false;
+ for (const auto& physicalIds : frontPhysicalIds) {
+ if (std::includes(physicalIds.begin(), physicalIds.end(),
+ frontColorCameras.begin(), frontColorCameras.end())) {
+ hasFrontLogical = true;
+ break;
+ }
+ }
+ ASSERT_TRUE(hasFrontLogical);
+ }
+ if (rearColorCameras.size() > 1) {
+ bool hasRearLogical = false;
+ for (const auto& physicalIds : rearPhysicalIds) {
+ if (std::includes(physicalIds.begin(), physicalIds.end(),
+ rearColorCameras.begin(), rearColorCameras.end())) {
+ hasRearLogical = true;
+ break;
+ }
+ }
+ ASSERT_TRUE(hasRearLogical);
+ }
+}
+
// Retrieve all valid output stream resolutions from the camera
// static characteristics.
Status CameraHidlTest::getAvailableOutputStreams(const camera_metadata_t* staticMeta,
@@ -6651,6 +6818,23 @@
return ret;
}
+bool CameraHidlTest::isColorCamera(const camera_metadata_t *metadata) {
+ camera_metadata_ro_entry entry;
+ int retcode = find_camera_metadata_ro_entry(
+ metadata, ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
+ if ((0 == retcode) && (entry.count > 0)) {
+ bool isBackwardCompatible = (std::find(entry.data.u8, entry.data.u8 + entry.count,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) !=
+ entry.data.u8 + entry.count);
+ bool isMonochrome = (std::find(entry.data.u8, entry.data.u8 + entry.count,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) !=
+ entry.data.u8 + entry.count);
+ bool isColor = isBackwardCompatible && !isMonochrome;
+ return isColor;
+ }
+ return false;
+}
+
// Retrieve the reprocess input-output format map from the static
// camera characteristics.
Status CameraHidlTest::getZSLInputOutputMap(camera_metadata_t *staticMeta,