Audio: Add VTS tests for invalid enum-strings, Part 3
Add checks for rejection of invalid port configs.
Fix the default implementation to pass the tests.
Clarified that patch-related operations in IDevice
are optional.
Bug: 142480271
Test: atest VtsHalAudioV6_0TargetTest
Test: atest VtsHalAudioV7_0TargetTest
with side-loaded V7 default wrapper
Change-Id: I08e85d4883938b4d8f3c411be9fb1bd597eea0c2
diff --git a/audio/7.0/IDevice.hal b/audio/7.0/IDevice.hal
index d9e0ad2..e423f29 100644
--- a/audio/7.0/IDevice.hal
+++ b/audio/7.0/IDevice.hal
@@ -174,6 +174,9 @@
* Creates an audio patch between several source and sink ports. The handle
* is allocated by the HAL and must be unique for this audio HAL module.
*
+ * Optional method. HAL must support it if 'supportsAudioPatches' returns
+ * 'true'.
+ *
* @param sources patch sources.
* @param sinks patch sinks.
* @return retval operation completion status.
@@ -189,6 +192,9 @@
* as the HAL module can figure out a way of switching the route without
* causing audio disruption.
*
+ * Optional method. HAL must support it if 'supportsAudioPatches' returns
+ * 'true'.
+ *
* @param previousPatch handle of the previous patch to update.
* @param sources new patch sources.
* @param sinks new patch sinks.
@@ -204,6 +210,9 @@
/**
* Release an audio patch.
*
+ * Optional method. HAL must support it if 'supportsAudioPatches' returns
+ * 'true'.
+ *
* @param patch patch handle.
* @return retval operation completion status.
*/
diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp
index 05c1066..7caed44 100644
--- a/audio/core/all-versions/default/Device.cpp
+++ b/audio/core/all-versions/default/Device.cpp
@@ -325,11 +325,17 @@
const hidl_vec<AudioPortConfig>& sinks) {
Result retval(Result::NOT_SUPPORTED);
if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
- std::unique_ptr<audio_port_config[]> halSources;
- HidlUtils::audioPortConfigsToHal(sources, &halSources);
- std::unique_ptr<audio_port_config[]> halSinks;
- HidlUtils::audioPortConfigsToHal(sinks, &halSinks);
audio_patch_handle_t halPatch = static_cast<audio_patch_handle_t>(patch);
+ std::unique_ptr<audio_port_config[]> halSources;
+ if (status_t status = HidlUtils::audioPortConfigsToHal(sources, &halSources);
+ status != NO_ERROR) {
+ return {analyzeStatus("audioPortConfigsToHal;sources", status), patch};
+ }
+ std::unique_ptr<audio_port_config[]> halSinks;
+ if (status_t status = HidlUtils::audioPortConfigsToHal(sinks, &halSinks);
+ status != NO_ERROR) {
+ return {analyzeStatus("audioPortConfigsToHal;sinks", status), patch};
+ }
retval = analyzeStatus("create_audio_patch",
mDevice->create_audio_patch(mDevice, sources.size(), &halSources[0],
sinks.size(), &halSinks[0], &halPatch));
@@ -364,7 +370,10 @@
Return<Result> Device::setAudioPortConfig(const AudioPortConfig& config) {
if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
struct audio_port_config halPortConfig;
- HidlUtils::audioPortConfigToHal(config, &halPortConfig);
+ if (status_t status = HidlUtils::audioPortConfigToHal(config, &halPortConfig);
+ status != NO_ERROR) {
+ return analyzeStatus("audioPortConfigToHal", status);
+ }
return analyzeStatus("set_audio_port_config",
mDevice->set_audio_port_config(mDevice, &halPortConfig));
}
diff --git a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
index 0f52a90..ef4daba 100644
--- a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
@@ -298,6 +298,18 @@
&DeviceConfigParameterToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InputBufferSizeInvalidConfig);
+static const DeviceAddress& getValidInputDeviceAddress() {
+ static const DeviceAddress valid = {
+ .deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT)};
+ return valid;
+}
+
+static const DeviceAddress& getValidOutputDeviceAddress() {
+ static const DeviceAddress valid = {
+ .deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT)};
+ return valid;
+}
+
static const DeviceAddress& getInvalidDeviceAddress() {
static const DeviceAddress valid = {.deviceType = "random_string"};
return valid;
@@ -311,6 +323,141 @@
getDevice()->setConnectedState(getInvalidDeviceAddress(), false));
}
+static std::vector<AudioPortConfig>& generatePortConfigs(bool valid) {
+ enum { // Note: This is for convenience when deriving "invalid" configs from "valid".
+ PORT_CONF_MINIMAL,
+ PORT_CONF_WITH_GAIN,
+ PORT_CONF_EXT_DEVICE,
+ PORT_CONF_EXT_MIX_SOURCE,
+ PORT_CONF_EXT_MIX_SINK,
+ PORT_CONF_EXT_SESSION
+ };
+ static std::vector<AudioPortConfig> valids = [] {
+ std::vector<AudioPortConfig> result;
+ result.reserve(PORT_CONF_EXT_SESSION + 1);
+ result.push_back(AudioPortConfig{});
+ AudioPortConfig configWithGain{};
+ configWithGain.gain.config(AudioGainConfig{
+ .index = 0,
+ .mode = {toString(xsd::AudioGainMode::AUDIO_GAIN_MODE_JOINT)},
+ .channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_MONO),
+ .rampDurationMs = 1});
+ configWithGain.gain.config().values.resize(1);
+ configWithGain.gain.config().values[0] = 1000;
+ result.push_back(std::move(configWithGain));
+ AudioPortConfig configWithPortExtDevice{};
+ configWithPortExtDevice.ext.device(getValidOutputDeviceAddress());
+ result.push_back(std::move(configWithPortExtDevice));
+ AudioPortConfig configWithPortExtMixSource{};
+ configWithPortExtMixSource.ext.mix({});
+ configWithPortExtMixSource.ext.mix().useCase.stream(
+ toString(xsd::AudioStreamType::AUDIO_STREAM_VOICE_CALL));
+ result.push_back(std::move(configWithPortExtMixSource));
+ AudioPortConfig configWithPortExtMixSink{};
+ configWithPortExtMixSink.ext.mix({});
+ configWithPortExtMixSink.ext.mix().useCase.source(
+ toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT));
+ result.push_back(std::move(configWithPortExtMixSink));
+ AudioPortConfig configWithPortExtSession{};
+ configWithPortExtSession.ext.session(
+ static_cast<AudioSession>(AudioSessionConsts::OUTPUT_MIX));
+ result.push_back(std::move(configWithPortExtSession));
+ return result;
+ }();
+ static std::vector<AudioPortConfig> invalids = [&] {
+ std::vector<AudioPortConfig> result;
+ AudioPortConfig invalidBaseChannelMask = valids[PORT_CONF_MINIMAL];
+ invalidBaseChannelMask.base.channelMask = "random_string";
+ result.push_back(std::move(invalidBaseChannelMask));
+ AudioPortConfig invalidBaseFormat = valids[PORT_CONF_MINIMAL];
+ invalidBaseFormat.base.format = "random_string";
+ result.push_back(std::move(invalidBaseFormat));
+ AudioPortConfig invalidGainMode = valids[PORT_CONF_WITH_GAIN];
+ invalidGainMode.gain.config().mode = {{"random_string"}};
+ result.push_back(std::move(invalidGainMode));
+ AudioPortConfig invalidGainChannelMask = valids[PORT_CONF_WITH_GAIN];
+ invalidGainChannelMask.gain.config().channelMask = "random_string";
+ result.push_back(std::move(invalidGainChannelMask));
+ AudioPortConfig invalidDeviceType = valids[PORT_CONF_EXT_DEVICE];
+ invalidDeviceType.ext.device().deviceType = "random_string";
+ result.push_back(std::move(invalidDeviceType));
+ AudioPortConfig invalidStreamType = valids[PORT_CONF_EXT_MIX_SOURCE];
+ invalidStreamType.ext.mix().useCase.stream() = "random_string";
+ result.push_back(std::move(invalidStreamType));
+ AudioPortConfig invalidSource = valids[PORT_CONF_EXT_MIX_SINK];
+ invalidSource.ext.mix().useCase.source() = "random_string";
+ result.push_back(std::move(invalidSource));
+ return result;
+ }();
+ return valid ? valids : invalids;
+}
+
+TEST_P(AudioHidlDeviceTest, SetAudioPortConfigInvalidArguments) {
+ doc::test("Check that invalid port configs are rejected by IDevice::setAudioPortConfig");
+ for (const auto& invalidConfig : generatePortConfigs(false /*valid*/)) {
+ EXPECT_RESULT(invalidArgsOrNotSupported, getDevice()->setAudioPortConfig(invalidConfig))
+ << ::testing::PrintToString(invalidConfig);
+ }
+}
+
+TEST_P(AudioPatchHidlTest, CreatePatchInvalidArguments) {
+ doc::test("Check that invalid port configs are rejected by IDevice::createAudioPatch");
+ // Note that HAL actually might reject the proposed source / sink combo
+ // due to other reasons than presence of invalid enum-strings.
+ // TODO: Come up with a way to guarantee validity of a source / sink combo.
+ for (const auto& validSource : generatePortConfigs(true /*valid*/)) {
+ for (const auto& invalidSink : generatePortConfigs(false /*valid*/)) {
+ AudioPatchHandle handle;
+ EXPECT_OK(getDevice()->createAudioPatch(hidl_vec<AudioPortConfig>{validSource},
+ hidl_vec<AudioPortConfig>{invalidSink},
+ returnIn(res, handle)));
+ EXPECT_EQ(Result::INVALID_ARGUMENTS, res)
+ << "Source: " << ::testing::PrintToString(validSource)
+ << "; Sink: " << ::testing::PrintToString(invalidSink);
+ }
+ }
+ for (const auto& validSink : generatePortConfigs(true /*valid*/)) {
+ for (const auto& invalidSource : generatePortConfigs(false /*valid*/)) {
+ AudioPatchHandle handle;
+ EXPECT_OK(getDevice()->createAudioPatch(hidl_vec<AudioPortConfig>{invalidSource},
+ hidl_vec<AudioPortConfig>{validSink},
+ returnIn(res, handle)));
+ EXPECT_EQ(Result::INVALID_ARGUMENTS, res)
+ << "Source: " << ::testing::PrintToString(invalidSource)
+ << "; Sink: " << ::testing::PrintToString(validSink);
+ }
+ }
+}
+
+TEST_P(AudioPatchHidlTest, UpdatePatchInvalidArguments) {
+ doc::test("Check that invalid port configs are rejected by IDevice::updateAudioPatch");
+ // Note that HAL actually might reject the proposed source / sink combo
+ // due to other reasons than presence of invalid enum-strings.
+ // TODO: Come up with a way to guarantee validity of a source / sink combo.
+ for (const auto& validSource : generatePortConfigs(true /*valid*/)) {
+ for (const auto& invalidSink : generatePortConfigs(false /*valid*/)) {
+ AudioPatchHandle handle{};
+ EXPECT_OK(getDevice()->updateAudioPatch(handle, hidl_vec<AudioPortConfig>{validSource},
+ hidl_vec<AudioPortConfig>{invalidSink},
+ returnIn(res, handle)));
+ EXPECT_EQ(Result::INVALID_ARGUMENTS, res)
+ << "Source: " << ::testing::PrintToString(validSource)
+ << "; Sink: " << ::testing::PrintToString(invalidSink);
+ }
+ }
+ for (const auto& validSink : generatePortConfigs(true /*valid*/)) {
+ for (const auto& invalidSource : generatePortConfigs(false /*valid*/)) {
+ AudioPatchHandle handle{};
+ EXPECT_OK(getDevice()->updateAudioPatch(
+ handle, hidl_vec<AudioPortConfig>{invalidSource},
+ hidl_vec<AudioPortConfig>{validSink}, returnIn(res, handle)));
+ EXPECT_EQ(Result::INVALID_ARGUMENTS, res)
+ << "Source: " << ::testing::PrintToString(invalidSource)
+ << "; Sink: " << ::testing::PrintToString(validSink);
+ }
+ }
+}
+
enum { PARAM_DEVICE_CONFIG, PARAM_ADDRESS, PARAM_METADATA };
enum { INDEX_SINK, INDEX_SOURCE };
using SinkOrSourceMetadata = std::variant<SinkMetadata, SourceMetadata>;
@@ -362,18 +509,6 @@
}
};
-static const DeviceAddress& getValidInputDeviceAddress() {
- static const DeviceAddress valid = {
- .deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT)};
- return valid;
-}
-
-static const DeviceAddress& getValidOutputDeviceAddress() {
- static const DeviceAddress valid = {
- .deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT)};
- return valid;
-}
-
static const RecordTrackMetadata& getValidRecordTrackMetadata() {
static const RecordTrackMetadata valid = {
.source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT), .gain = 1};