Merge "Remove non-test ScopedWakelock dependency" into rvc-dev
diff --git a/automotive/audiocontrol/2.0/default/AudioControl.cpp b/automotive/audiocontrol/2.0/default/AudioControl.cpp
index 5bde839..b7c11cd 100644
--- a/automotive/audiocontrol/2.0/default/AudioControl.cpp
+++ b/automotive/audiocontrol/2.0/default/AudioControl.cpp
@@ -69,7 +69,7 @@
}
Return<void> AudioControl::setFadeTowardFront(float value) {
- if (!isValidValue(value)) {
+ if (isValidValue(value)) {
// Just log in this default mock implementation
LOG(INFO) << "Fader set to " << value;
} else {
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 05b8b47..bf5fbfe 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -18,12 +18,13 @@
#include <algorithm>
#include <chrono>
+#include <condition_variable>
+#include <list>
#include <mutex>
#include <regex>
#include <string>
#include <unordered_map>
#include <unordered_set>
-#include <condition_variable>
#include <inttypes.h>
@@ -165,6 +166,26 @@
YUV_REPROCESS,
};
+enum SystemCameraKind {
+ /**
+ * These camera devices are visible to all apps and system components alike
+ */
+ PUBLIC = 0,
+
+ /**
+ * These camera devices are visible only to processes having the
+ * android.permission.SYSTEM_CAMERA permission. They are not exposed to 3P
+ * apps.
+ */
+ SYSTEM_ONLY_CAMERA,
+
+ /**
+ * These camera devices are visible only to HAL clients (that try to connect
+ * on a hwbinder thread).
+ */
+ HIDDEN_SECURE_CAMERA
+};
+
namespace {
// "device@<version>/legacy/<id>"
const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/%s/(.+)";
@@ -851,6 +872,8 @@
static Status isAutoFocusModeAvailable(
CameraParameters &cameraParams, const char *mode) ;
static Status isMonochromeCamera(const camera_metadata_t *staticMeta);
+ static Status getSystemCameraKind(const camera_metadata_t* staticMeta,
+ SystemCameraKind* systemCameraKind);
// Used by switchToOffline where a new result queue is created for offline reqs
void updateInflightResultQueue(std::shared_ptr<ResultMetadataQueue> resultQueue);
@@ -2555,6 +2578,90 @@
}
}
+TEST_P(CameraHidlTest, systemCameraTest) {
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+ std::map<std::string, std::list<SystemCameraKind>> hiddenPhysicalIdToLogicalMap;
+ for (const auto& name : cameraDeviceNames) {
+ int deviceVersion = getCameraDeviceVersion(name, mProviderType);
+ switch (deviceVersion) {
+ 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, Status::OK);
+ const camera_metadata_t* staticMeta =
+ reinterpret_cast<const camera_metadata_t*>(chars.data());
+ ASSERT_NE(staticMeta, nullptr);
+ Status rc = isLogicalMultiCamera(staticMeta);
+ ASSERT_TRUE(Status::OK == rc || Status::METHOD_NOT_SUPPORTED == rc);
+ if (Status::METHOD_NOT_SUPPORTED == rc) {
+ return;
+ }
+ std::unordered_set<std::string> physicalIds;
+ ASSERT_EQ(Status::OK, getPhysicalCameraIds(staticMeta, &physicalIds));
+ SystemCameraKind systemCameraKind = SystemCameraKind::PUBLIC;
+ rc = getSystemCameraKind(staticMeta, &systemCameraKind);
+ ASSERT_EQ(rc, Status::OK);
+ for (auto physicalId : physicalIds) {
+ bool isPublicId = false;
+ for (auto& deviceName : cameraDeviceNames) {
+ std::string publicVersion, publicId;
+ ASSERT_TRUE(::matchDeviceName(deviceName, mProviderType, &publicVersion,
+ &publicId));
+ if (physicalId == publicId) {
+ isPublicId = true;
+ break;
+ }
+ }
+ // For hidden physical cameras, collect their associated logical cameras
+ // and store the system camera kind.
+ if (!isPublicId) {
+ auto it = hiddenPhysicalIdToLogicalMap.find(physicalId);
+ if (it == hiddenPhysicalIdToLogicalMap.end()) {
+ hiddenPhysicalIdToLogicalMap.insert(std::make_pair(
+ physicalId, std::list<SystemCameraKind>(systemCameraKind)));
+ } else {
+ it->second.push_back(systemCameraKind);
+ }
+ }
+ }
+ });
+ 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;
+ }
+ }
+
+ // Check that the system camera kind of the logical cameras associated with
+ // each hidden physical camera is the same.
+ for (const auto& it : hiddenPhysicalIdToLogicalMap) {
+ SystemCameraKind neededSystemCameraKind = it.second.front();
+ for (auto foundSystemCamera : it.second) {
+ ASSERT_EQ(neededSystemCameraKind, foundSystemCamera);
+ }
+ }
+}
+
// Verify that the static camera characteristics can be retrieved
// successfully.
TEST_P(CameraHidlTest, getCameraCharacteristics) {
@@ -5671,6 +5778,39 @@
return ret;
}
+Status CameraHidlTest::getSystemCameraKind(const camera_metadata_t* staticMeta,
+ SystemCameraKind* systemCameraKind) {
+ Status ret = Status::OK;
+ if (nullptr == staticMeta || nullptr == systemCameraKind) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ camera_metadata_ro_entry entry;
+ int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+ &entry);
+ if (0 != rc) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ if (entry.count == 1 &&
+ entry.data.u8[0] == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA) {
+ *systemCameraKind = SystemCameraKind::HIDDEN_SECURE_CAMERA;
+ return ret;
+ }
+
+ // Go through the capabilities and check if it has
+ // ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA
+ for (size_t i = 0; i < entry.count; ++i) {
+ uint8_t capability = entry.data.u8[i];
+ if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA) {
+ *systemCameraKind = SystemCameraKind::SYSTEM_ONLY_CAMERA;
+ return ret;
+ }
+ }
+ *systemCameraKind = SystemCameraKind::PUBLIC;
+ return ret;
+}
+
// Check whether this is a monochrome camera using the static camera characteristics.
Status CameraHidlTest::isMonochromeCamera(const camera_metadata_t *staticMeta) {
Status ret = Status::METHOD_NOT_SUPPORTED;
@@ -6391,8 +6531,10 @@
const hidl_vec<hidl_string>& deviceNames) {
const camera_metadata_t* metadata = (camera_metadata_t*)chars.data();
ASSERT_NE(nullptr, metadata);
-
- Status rc = isLogicalMultiCamera(metadata);
+ SystemCameraKind systemCameraKind = SystemCameraKind::PUBLIC;
+ Status rc = getSystemCameraKind(metadata, &systemCameraKind);
+ ASSERT_EQ(rc, Status::OK);
+ rc = isLogicalMultiCamera(metadata);
ASSERT_TRUE(Status::OK == rc || Status::METHOD_NOT_SUPPORTED == rc);
if (Status::METHOD_NOT_SUPPORTED == rc) {
return;
@@ -6411,6 +6553,7 @@
ASSERT_NE(physicalId, cameraId);
bool isPublicId = false;
std::string fullPublicId;
+ SystemCameraKind physSystemCameraKind = SystemCameraKind::PUBLIC;
for (auto& deviceName : deviceNames) {
std::string publicVersion, publicId;
ASSERT_TRUE(::matchDeviceName(deviceName, mProviderType, &publicVersion, &publicId));
@@ -6434,9 +6577,16 @@
ret = subDevice->getCameraCharacteristics(
[&](auto status, const auto& chars) {
ASSERT_EQ(Status::OK, status);
- retcode = find_camera_metadata_ro_entry(
- (const camera_metadata_t *)chars.data(),
- ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
+ const camera_metadata_t* staticMeta =
+ reinterpret_cast<const camera_metadata_t*>(chars.data());
+ rc = getSystemCameraKind(staticMeta, &physSystemCameraKind);
+ ASSERT_EQ(rc, Status::OK);
+ // Make sure that the system camera kind of a non-hidden
+ // physical cameras is the same as the logical camera associated
+ // with it.
+ ASSERT_EQ(physSystemCameraKind, systemCameraKind);
+ retcode = find_camera_metadata_ro_entry(staticMeta,
+ ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
bool subCameraHasZoomRatioRange = (0 == retcode && entry.count == 2);
ASSERT_EQ(hasZoomRatioRange, subCameraHasZoomRatioRange);
});
@@ -6452,17 +6602,16 @@
ASSERT_NE(device3_5, nullptr);
// Check camera characteristics for hidden camera id
- Return<void> ret = device3_5->getPhysicalCameraCharacteristics(physicalId,
- [&](auto status, const auto& chars) {
- verifyCameraCharacteristics(status, chars);
- verifyMonochromeCharacteristics(chars, deviceVersion);
-
- retcode = find_camera_metadata_ro_entry(
- (const camera_metadata_t *)chars.data(),
- ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
- bool subCameraHasZoomRatioRange = (0 == retcode && entry.count == 2);
- ASSERT_EQ(hasZoomRatioRange, subCameraHasZoomRatioRange);
- });
+ Return<void> ret = device3_5->getPhysicalCameraCharacteristics(
+ physicalId, [&](auto status, const auto& chars) {
+ verifyCameraCharacteristics(status, chars);
+ verifyMonochromeCharacteristics(chars, deviceVersion);
+ retcode =
+ find_camera_metadata_ro_entry((const camera_metadata_t*)chars.data(),
+ ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
+ bool subCameraHasZoomRatioRange = (0 == retcode && entry.count == 2);
+ ASSERT_EQ(hasZoomRatioRange, subCameraHasZoomRatioRange);
+ });
ASSERT_TRUE(ret.isOk());
// Check calling getCameraDeviceInterface_V3_x() on hidden camera id returns
diff --git a/media/omx/1.0/vts/functional/master/Android.bp b/media/omx/1.0/vts/functional/master/Android.bp
index 8e58821..5953eb5 100644
--- a/media/omx/1.0/vts/functional/master/Android.bp
+++ b/media/omx/1.0/vts/functional/master/Android.bp
@@ -19,6 +19,7 @@
defaults: ["VtsHalMediaOmxV1_0Defaults"],
srcs: ["VtsHalMediaOmxV1_0TargetMasterTest.cpp"],
test_suites: [
+ "general-tests",
"vts",
],
}
diff --git a/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp b/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp
index c14f1da..9b4722e 100644
--- a/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp
+++ b/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp
@@ -20,6 +20,7 @@
#endif
#include <android-base/logging.h>
+#include <android-base/strings.h>
#include <android/hardware/media/omx/1.0/IOmx.h>
#include <android/hardware/media/omx/1.0/IOmxNode.h>
@@ -33,21 +34,22 @@
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
-using ::android::hardware::media::omx::V1_0::IOmx;
-using ::android::hardware::media::omx::V1_0::IOmxObserver;
-using ::android::hardware::media::omx::V1_0::IOmxNode;
-using ::android::hardware::media::omx::V1_0::IOmxStore;
-using ::android::hardware::media::omx::V1_0::Message;
-using ::android::hardware::media::omx::V1_0::CodecBuffer;
-using ::android::hardware::media::omx::V1_0::PortMode;
-using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::android::hidl::memory::V1_0::IMapper;
+using ::android::sp;
+using ::android::base::Join;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
+using ::android::hardware::media::omx::V1_0::CodecBuffer;
+using ::android::hardware::media::omx::V1_0::IOmx;
+using ::android::hardware::media::omx::V1_0::IOmxNode;
+using ::android::hardware::media::omx::V1_0::IOmxObserver;
+using ::android::hardware::media::omx::V1_0::IOmxStore;
+using ::android::hardware::media::omx::V1_0::Message;
+using ::android::hardware::media::omx::V1_0::PortMode;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMapper;
+using ::android::hidl::memory::V1_0::IMemory;
#include <getopt.h>
#include <media_hidl_test_common.h>
@@ -70,6 +72,11 @@
}
};
+struct AttributePattern {
+ const testing::internal::RE key;
+ const testing::internal::RE value;
+};
+
void displayComponentInfo(hidl_vec<IOmx::ComponentInfo>& nodeList) {
for (size_t i = 0; i < nodeList.size(); i++) {
printf("%s | ", nodeList[i].mName.c_str());
@@ -80,6 +87,109 @@
}
}
+/*
+ * Returns the role based on is_encoder and mime.
+ *
+ * The mapping from a pair (is_encoder, mime) to a role string is
+ * defined in frameworks/av/media/libmedia/MediaDefs.cpp and
+ * frameworks/av/media/libstagefright/omx/OMXUtils.cpp. This function
+ * does essentially the same work as GetComponentRole() in
+ * OMXUtils.cpp.
+ *
+ * Args:
+ * is_encoder: A boolean indicating whether the role is for an
+ * encoder or a decoder.
+ * mime: A string of the desired mime type.
+ *
+ * Returns:
+ * A const string for the requested role name, empty if mime is not
+ * recognized.
+ */
+const std::string getComponentRole(bool isEncoder, const std::string mime) {
+ // Mapping from mime types to roles.
+ // These values come from MediaDefs.cpp and OMXUtils.cpp
+ const std::map<const std::string, const std::string> audioMimeToRole = {
+ {"3gpp", "amrnb"}, {"ac3", "ac3"}, {"amr-wb", "amrwb"},
+ {"eac3", "eac3"}, {"flac", "flac"}, {"g711-alaw", "g711alaw"},
+ {"g711-mlaw", "g711mlaw"}, {"gsm", "gsm"}, {"mp4a-latm", "aac"},
+ {"mpeg", "mp3"}, {"mpeg-L1", "mp1"}, {"mpeg-L2", "mp2"},
+ {"opus", "opus"}, {"raw", "raw"}, {"vorbis", "vorbis"},
+ };
+ const std::map<const std::string, const std::string> videoMimeToRole = {
+ {"3gpp", "h263"}, {"avc", "avc"}, {"dolby-vision", "dolby-vision"},
+ {"hevc", "hevc"}, {"mp4v-es", "mpeg4"}, {"mpeg2", "mpeg2"},
+ {"x-vnd.on2.vp8", "vp8"}, {"x-vnd.on2.vp9", "vp9"},
+ };
+ const std::map<const std::string, const std::string> imageMimeToRole = {
+ {"vnd.android.heic", "heic"},
+ };
+
+ // Suffix begins after the mime prefix.
+ const size_t prefixEnd = mime.find("/");
+ if (prefixEnd == std::string::npos || prefixEnd == mime.size()) return "";
+ const std::string mime_suffix = mime.substr(prefixEnd + 1, mime.size() - 1);
+ const std::string middle = isEncoder ? "encoder." : "decoder.";
+ std::string prefix;
+ std::string suffix;
+ if (mime.rfind("audio/", 0) != std::string::npos) {
+ const auto it = audioMimeToRole.find(mime_suffix);
+ if (it == audioMimeToRole.end()) return "";
+ prefix = "audio_";
+ suffix = it->second;
+ } else if (mime.rfind("video/", 0) != std::string::npos) {
+ const auto it = videoMimeToRole.find(mime_suffix);
+ if (it == videoMimeToRole.end()) return "";
+ prefix = "video_";
+ suffix = it->second;
+ } else if (mime.rfind("image/", 0) != std::string::npos) {
+ const auto it = imageMimeToRole.find(mime_suffix);
+ if (it == imageMimeToRole.end()) return "";
+ prefix = "image_";
+ suffix = it->second;
+ } else {
+ return "";
+ }
+ return prefix + middle + suffix;
+}
+
+void validateAttributes(
+ const std::map<const std::string, const testing::internal::RE>& knownPatterns,
+ const std::vector<const struct AttributePattern>& unknownPatterns,
+ hidl_vec<IOmxStore::Attribute> attributes) {
+ std::set<const std::string> attributeKeys;
+ for (const auto& attr : attributes) {
+ // Make sure there are no duplicates
+ const auto [nodeIter, inserted] = attributeKeys.insert(attr.key);
+ EXPECT_EQ(inserted, true) << "Attribute \"" << attr.key << "\" has duplicates.";
+
+ // Check the value against the corresponding regular
+ // expression.
+ const auto knownPattern = knownPatterns.find(attr.key);
+ if (knownPattern != knownPatterns.end()) {
+ EXPECT_EQ(testing::internal::RE::FullMatch(attr.value, knownPattern->second), true)
+ << "Attribute \"" << attr.key << "\" has invalid value \"" << attr.value << ".";
+ ;
+ } else {
+ // Failed to find exact attribute, check against
+ // possible patterns.
+ bool keyFound = false;
+ for (const auto& unknownPattern : unknownPatterns) {
+ if (testing::internal::RE::PartialMatch(attr.key, unknownPattern.key)) {
+ keyFound = true;
+ EXPECT_EQ(testing::internal::RE::FullMatch(attr.value, unknownPattern.value),
+ true)
+ << "Attribute \"" << attr.key << "\" has invalid value \"" << attr.value
+ << ".";
+ }
+ }
+ if (!keyFound) {
+ std::cout << "Warning, Unrecognized attribute \"" << attr.key << "\" with value \""
+ << attr.value << "\"." << std::endl;
+ }
+ }
+ }
+}
+
// Make sure IOmx and IOmxStore have the same set of instances.
TEST(MasterHidlTest, instanceMatchValidation) {
auto omxInstances = android::hardware::getAllHalInstanceNames(IOmx::descriptor);
@@ -91,7 +201,7 @@
}
}
-// list service attributes
+// list service attributes and verify expected formats
TEST_P(MasterHidlTest, ListServiceAttr) {
description("list service attributes");
android::hardware::media::omx::V1_0::Status status;
@@ -105,7 +215,36 @@
})
.isOk());
ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
- if (attributes.size() == 0) ALOGV("Warning, Attribute list empty");
+ if (attributes.size() == 0) {
+ std::cout << "Warning, Attribute list empty" << std::endl;
+ } else {
+ /*
+ * knownPatterns is a map whose keys are the known "key" for a service
+ * attribute pair (see IOmxStore::Attribute), and whose values are the
+ * corresponding regular expressions that will have to match with the
+ * "value" of the attribute pair. If listServiceAttributes() returns an
+ * attribute that has a matching key but an unmatched value, the test
+ * will fail.
+ */
+ const std::map<const std::string, const testing::internal::RE> knownPatterns = {
+ {"max-video-encoder-input-buffers", "0|[1-9][0-9]*"},
+ {"supports-multiple-secure-codecs", "0|1"},
+ {"supports-secure-with-non-secure-codec", "0|1"},
+ };
+ /*
+ * unknownPatterns is a vector of pairs of regular expressions.
+ * For each attribute whose key is not known (i.e., does not match any
+ * of the keys in the "knownPatterns" variable defined above), that key will be
+ * tried for a match with the first element of each pair of the variable
+ * "unknownPatterns". If a match occurs, the value of that same attribute will be
+ * tried for a match with the second element of the pair. If this second
+ * match fails, the test will fail.
+ */
+ const std::vector<const struct AttributePattern> unknownPatterns = {
+ {"supports-[a-z0-9-]*", "0|1"}};
+
+ validateAttributes(knownPatterns, unknownPatterns, attributes);
+ }
}
// get node prefix
@@ -114,17 +253,183 @@
hidl_string prefix;
omxStore->getNodePrefix(
[&prefix](hidl_string const& _nl) { prefix = _nl; });
- if (prefix.empty()) ALOGV("Warning, Node Prefix empty");
+ if (prefix.empty()) std::cout << "Warning, Node Prefix empty" << std::endl;
}
-// list roles
+// list roles and validate all RoleInfo objects
TEST_P(MasterHidlTest, ListRoles) {
description("list roles");
hidl_vec<IOmxStore::RoleInfo> roleList;
omxStore->listRoles([&roleList](hidl_vec<IOmxStore::RoleInfo> const& _nl) {
roleList = _nl;
});
- if (roleList.size() == 0) ALOGV("Warning, RoleInfo list empty");
+ if (roleList.size() == 0) {
+ GTEST_SKIP() << "Warning, RoleInfo list empty";
+ return;
+ }
+
+ // Basic patterns for matching
+ const std::string toggle = "(0|1)";
+ const std::string string = "(.*)";
+ const std::string num = "(0|([1-9][0-9]*))";
+ const std::string size = "(" + num + "x" + num + ")";
+ const std::string ratio = "(" + num + ":" + num + ")";
+ const std::string range_num = "((" + num + "-" + num + ")|" + num + ")";
+ const std::string range_size = "((" + size + "-" + size + ")|" + size + ")";
+ const std::string range_ratio = "((" + ratio + "-" + ratio + ")|" + ratio + ")";
+ const std::string list_range_num = "(" + range_num + "(," + range_num + ")*)";
+
+ // Matching rules for node attributes with fixed keys
+ const std::map<const std::string, const testing::internal::RE> knownPatterns = {
+ {"alignment", size},
+ {"bitrate-range", range_num},
+ {"block-aspect-ratio-range", range_ratio},
+ {"block-count-range", range_num},
+ {"block-size", size},
+ {"blocks-per-second-range", range_num},
+ {"complexity-default", num},
+ {"complexity-range", range_num},
+ {"feature-adaptive-playback", toggle},
+ {"feature-bitrate-control", "(VBR|CBR|CQ)[,(VBR|CBR|CQ)]*"},
+ {"feature-can-swap-width-height", toggle},
+ {"feature-intra-refresh", toggle},
+ {"feature-partial-frame", toggle},
+ {"feature-secure-playback", toggle},
+ {"feature-tunneled-playback", toggle},
+ {"frame-rate-range", range_num},
+ {"max-channel-count", num},
+ {"max-concurrent-instances", num},
+ {"max-supported-instances", num},
+ {"pixel-aspect-ratio-range", range_ratio},
+ {"quality-default", num},
+ {"quality-range", range_num},
+ {"quality-scale", string},
+ {"sample-rate-ranges", list_range_num},
+ {"size-range", range_size},
+ };
+
+ // Strings for matching rules for node attributes with key patterns
+ const std::vector<const struct AttributePattern> unknownPatterns = {
+ {"measured-frame-rate-" + size + "-range", range_num},
+ {"feature-[a-zA-Z0-9_-]+", string},
+ };
+
+ // Matching rules for node names and owners
+ const testing::internal::RE nodeNamePattern = "[a-zA-Z0-9.-]+";
+ const testing::internal::RE nodeOwnerPattern = "[a-zA-Z0-9._-]+";
+
+ std::set<const std::string> roleKeys;
+ std::map<const std::string, std::set<const std::string>> nodeToRoles;
+ std::map<const std::string, std::set<const std::string>> ownerToNodes;
+ for (const IOmxStore::RoleInfo& role : roleList) {
+ // Make sure there are no duplicates
+ const auto [roleIter, inserted] = roleKeys.insert(role.role);
+ EXPECT_EQ(inserted, true) << "Role \"" << role.role << "\" has duplicates.";
+
+ // Make sure role name follows expected format based on type and
+ // isEncoder
+ const std::string role_name = getComponentRole(role.isEncoder, role.type);
+ EXPECT_EQ(role_name, role.role) << "Role \"" << role.role << "\" does not match "
+ << (role.isEncoder ? "an encoder " : "a decoder ")
+ << "for mime type \"" << role.type << ".";
+
+ // Check the nodes for this role
+ std::set<const std::string> nodeKeys;
+ for (const IOmxStore::NodeInfo& node : role.nodes) {
+ // Make sure there are no duplicates
+ const auto [nodeIter, inserted] = nodeKeys.insert(node.name);
+ EXPECT_EQ(inserted, true) << "Node \"" << node.name << "\" has duplicates.";
+
+ // Check the format of node name
+ EXPECT_EQ(testing::internal::RE::FullMatch(node.name, nodeNamePattern), true)
+ << "Node name \"" << node.name << " is invalid.";
+ // Check the format of node owner
+ EXPECT_EQ(testing::internal::RE::FullMatch(node.owner, nodeOwnerPattern), true)
+ << "Node owner \"" << node.owner << " is invalid.";
+
+ validateAttributes(knownPatterns, unknownPatterns, node.attributes);
+
+ ownerToNodes[node.owner].insert(node.name);
+ nodeToRoles[node.name].insert(role.role);
+ }
+ }
+
+ // Verify the information with IOmx::listNodes().
+ // IOmxStore::listRoles() and IOmx::listNodes() should give consistent
+ // information about nodes and roles.
+ for (const auto& [owner, nodes] : ownerToNodes) {
+ // Obtain the IOmx instance for each "owner"
+ const sp<IOmx> omx = omxStore->getOmx(owner);
+ EXPECT_NE(nullptr, omx);
+
+ // Invoke IOmx::listNodes()
+ android::hardware::media::omx::V1_0::Status status;
+ hidl_vec<IOmx::ComponentInfo> nodeList;
+ EXPECT_TRUE(
+ omx->listNodes([&status, &nodeList](android::hardware::media::omx::V1_0::Status _s,
+ hidl_vec<IOmx::ComponentInfo> const& _nl) {
+ status = _s;
+ nodeList = _nl;
+ }).isOk());
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // Verify that roles for each node match with the information from
+ // IOmxStore::listRoles().
+ std::set<const std::string> nodeKeys;
+ for (IOmx::ComponentInfo node : nodeList) {
+ // Make sure there are no duplicates
+ const auto [nodeIter, inserted] = nodeKeys.insert(node.mName);
+ EXPECT_EQ(inserted, true)
+ << "IOmx::listNodes() lists duplicate nodes \"" << node.mName << "\".";
+
+ // Skip "hidden" nodes, i.e. those that are not advertised by
+ // IOmxStore::listRoles().
+ if (nodes.find(node.mName) == nodes.end()) {
+ std::cout << "Warning, IOmx::listNodes() lists unknown node \"" << node.mName
+ << "\" for IOmx instance \"" << owner << "\"." << std::endl;
+ continue;
+ }
+
+ // All the roles advertised by IOmxStore::listRoles() for this
+ // node must be included in roleKeys.
+ std::set<const std::string> difference;
+ std::set_difference(nodeToRoles[node.mName].begin(), nodeToRoles[node.mName].end(),
+ roleKeys.begin(), roleKeys.end(),
+ std::inserter(difference, difference.begin()));
+ EXPECT_EQ(difference.empty(), true) << "IOmx::listNodes() for IOmx "
+ "instance \""
+ << owner
+ << "\" does not report some "
+ "expected nodes: "
+ << android::base::Join(difference, ", ") << ".";
+ }
+ // Check that all nodes obtained from IOmxStore::listRoles() are
+ // supported by the their corresponding IOmx instances.
+ std::set<const std::string> difference;
+ std::set_difference(nodes.begin(), nodes.end(), nodeKeys.begin(), nodeKeys.end(),
+ std::inserter(difference, difference.begin()));
+ EXPECT_EQ(difference.empty(), true) << "IOmx::listNodes() for IOmx "
+ "instance \""
+ << owner
+ << "\" does not report some "
+ "expected nodes: "
+ << android::base::Join(difference, ", ") << ".";
+ }
+
+ if (!nodeToRoles.empty()) {
+ // Check that the prefix is a sensible string.
+ hidl_string prefix;
+ omxStore->getNodePrefix([&prefix](hidl_string const& _nl) { prefix = _nl; });
+ EXPECT_EQ(testing::internal::RE::PartialMatch(prefix, nodeNamePattern), true)
+ << "\"" << prefix << "\" is not a valid prefix for node names.";
+
+ // Check that all node names have the said prefix.
+ for (const auto& node : nodeToRoles) {
+ EXPECT_NE(node.first.rfind(prefix, 0), std::string::npos)
+ << "Node \"" << node.first << "\" does not start with prefix \"" << prefix
+ << "\".";
+ }
+ }
}
// list components and roles.
@@ -143,7 +448,7 @@
.isOk());
ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
if (nodeList.size() == 0)
- ALOGV("Warning, ComponentInfo list empty");
+ std::cout << "Warning, ComponentInfo list empty" << std::endl;
else {
// displayComponentInfo(nodeList);
for (size_t i = 0; i < nodeList.size(); i++) {