Audio HAL: Align V2 and V4 VTS

It was thought that the V2 VTS were not going to be supported after V4
VTS were created. Thus a large portion of the code was copy paste and
modified.

That assumption ended up wrong as a lot of OEM reported bugs that needed
to be fixed in both versions.

As a result align the code of both version VTS as much as possible.
The code will be merged in a follow up patch.

Bug: 118203066
Test: compile
Change-Id: I994232db237b5d7c52e7d796f199ab3c6eec21f4
Signed-off-by: Kevin Rocard <krocard@google.com>
diff --git a/audio/common/all-versions/default/include/common/all-versions/default/HidlUtils.impl.h b/audio/common/all-versions/default/include/common/all-versions/default/HidlUtils.impl.h
index 632e816..03b50b5 100644
--- a/audio/common/all-versions/default/include/common/all-versions/default/HidlUtils.impl.h
+++ b/audio/common/all-versions/default/include/common/all-versions/default/HidlUtils.impl.h
@@ -33,7 +33,7 @@
 using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioStreamType;
 using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioUsage;
 
-using ::android::hardware::audio::common::utils::mkEnumConverter;
+using ::android::hardware::audio::common::utils::EnumBitfield;
 
 namespace android {
 namespace hardware {
@@ -43,7 +43,7 @@
 
 void HidlUtils::audioConfigFromHal(const audio_config_t& halConfig, AudioConfig* config) {
     config->sampleRateHz = halConfig.sample_rate;
-    config->channelMask = mkEnumConverter<AudioChannelMask>(halConfig.channel_mask);
+    config->channelMask = EnumBitfield<AudioChannelMask>(halConfig.channel_mask);
     config->format = AudioFormat(halConfig.format);
     audioOffloadInfoFromHal(halConfig.offload_info, &config->offloadInfo);
     config->frameCount = halConfig.frame_count;
@@ -61,8 +61,8 @@
 void HidlUtils::audioGainConfigFromHal(const struct audio_gain_config& halConfig,
                                        AudioGainConfig* config) {
     config->index = halConfig.index;
-    config->mode = mkEnumConverter<AudioGainMode>(halConfig.mode);
-    config->channelMask = mkEnumConverter<AudioChannelMask>(halConfig.channel_mask);
+    config->mode = EnumBitfield<AudioGainMode>(halConfig.mode);
+    config->channelMask = EnumBitfield<AudioChannelMask>(halConfig.channel_mask);
     for (size_t i = 0; i < sizeof(audio_channel_mask_t) * 8; ++i) {
         config->values[i] = halConfig.values[i];
     }
@@ -82,8 +82,8 @@
 }
 
 void HidlUtils::audioGainFromHal(const struct audio_gain& halGain, AudioGain* gain) {
-    gain->mode = mkEnumConverter<AudioGainMode>(halGain.mode);
-    gain->channelMask = mkEnumConverter<AudioChannelMask>(halGain.channel_mask);
+    gain->mode = EnumBitfield<AudioGainMode>(halGain.mode);
+    gain->channelMask = EnumBitfield<AudioChannelMask>(halGain.channel_mask);
     gain->minValue = halGain.min_value;
     gain->maxValue = halGain.max_value;
     gain->defaultValue = halGain.default_value;
@@ -122,7 +122,7 @@
 void HidlUtils::audioOffloadInfoFromHal(const audio_offload_info_t& halOffload,
                                         AudioOffloadInfo* offload) {
     offload->sampleRateHz = halOffload.sample_rate;
-    offload->channelMask = mkEnumConverter<AudioChannelMask>(halOffload.channel_mask);
+    offload->channelMask = EnumBitfield<AudioChannelMask>(halOffload.channel_mask);
     offload->format = AudioFormat(halOffload.format);
     offload->streamType = AudioStreamType(halOffload.stream_type);
     offload->bitRatePerSecond = halOffload.bit_rate;
@@ -155,9 +155,9 @@
     config->id = halConfig.id;
     config->role = AudioPortRole(halConfig.role);
     config->type = AudioPortType(halConfig.type);
-    config->configMask = mkEnumConverter<AudioPortConfigMask>(halConfig.config_mask);
+    config->configMask = EnumBitfield<AudioPortConfigMask>(halConfig.config_mask);
     config->sampleRateHz = halConfig.sample_rate;
-    config->channelMask = mkEnumConverter<AudioChannelMask>(halConfig.channel_mask);
+    config->channelMask = EnumBitfield<AudioChannelMask>(halConfig.channel_mask);
     config->format = AudioFormat(halConfig.format);
     audioGainConfigFromHal(halConfig.gain, &config->gain);
     switch (halConfig.type) {
@@ -257,7 +257,7 @@
     }
     port->channelMasks.resize(halPort.num_channel_masks);
     for (size_t i = 0; i < halPort.num_channel_masks; ++i) {
-        port->channelMasks[i] = mkEnumConverter<AudioChannelMask>(halPort.channel_masks[i]);
+        port->channelMasks[i] = EnumBitfield<AudioChannelMask>(halPort.channel_masks[i]);
     }
     port->formats.resize(halPort.num_formats);
     for (size_t i = 0; i < halPort.num_formats; ++i) {
diff --git a/audio/common/all-versions/util/include/common/all-versions/VersionUtils.h b/audio/common/all-versions/util/include/common/all-versions/VersionUtils.h
index 70c3d56..3b5c0fb 100644
--- a/audio/common/all-versions/util/include/common/all-versions/VersionUtils.h
+++ b/audio/common/all-versions/util/include/common/all-versions/VersionUtils.h
@@ -26,36 +26,31 @@
 namespace common {
 namespace utils {
 
-/** Similar to static_cast but also casts to hidl_bitfield depending on
- * return type inference (emulated through user-define conversion).
- */
-template <class Source, class Destination = Source>
-class EnumConverter {
+/** Converting between a bitfield or itself. */
+template <class Enum>
+class EnumBitfield {
    public:
-    static_assert(std::is_enum<Source>::value || std::is_enum<Destination>::value,
-                  "Source or destination should be an enum");
+    using Bitfield = ::android::hardware::hidl_bitfield<Enum>;
 
-    explicit EnumConverter(Source source) : mSource(source) {}
+    EnumBitfield(const EnumBitfield&) = default;
+    explicit EnumBitfield(Enum value) : mValue(value) {}
+    explicit EnumBitfield(Bitfield value) : EnumBitfield(static_cast<Enum>(value)) {}
 
-    operator Destination() const { return static_cast<Destination>(mSource); }
+    EnumBitfield& operator=(const EnumBitfield&) = default;
+    EnumBitfield& operator=(Enum value) { return *this = EnumBitfield{value}; }
+    EnumBitfield& operator=(Bitfield value) { return *this = EnumBitfield{value}; }
 
-    template <class = std::enable_if_t<std::is_enum<Destination>::value>>
-    operator ::android::hardware::hidl_bitfield<Destination>() {
-        return static_cast<std::underlying_type_t<Destination>>(mSource);
-    }
+    operator Enum() const { return mValue; }
+    operator Bitfield() const { return static_cast<Bitfield>(mValue); }
 
    private:
-    const Source mSource;
+    Enum mValue;
 };
-template <class Destination, class Source>
-auto mkEnumConverter(Source source) {
-    return EnumConverter<Source, Destination>{source};
-}
 
-/** Allows converting an enum to its bitfield or itself. */
+/** ATD way to create a EnumBitfield. */
 template <class Enum>
-EnumConverter<Enum> mkBitfield(Enum value) {
-    return EnumConverter<Enum>{value};
+EnumBitfield<Enum> mkEnumBitfield(Enum value) {
+    return EnumBitfield<Enum>{value};
 }
 
 }  // namespace utils
diff --git a/audio/core/2.0/vts/functional/Android.bp b/audio/core/2.0/vts/functional/Android.bp
index cfa637b..ce6e8a2 100644
--- a/audio/core/2.0/vts/functional/Android.bp
+++ b/audio/core/2.0/vts/functional/Android.bp
@@ -29,5 +29,11 @@
         "libicuuc_stubdata",
         "libxml2",
     ],
+    shared_libs: [
+        "libfmq",
+    ],
+    header_libs: [
+        "android.hardware.audio.common.util@all-versions",
+    ],
     test_suites: ["general-tests"],
 }
diff --git a/audio/core/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp b/audio/core/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp
index 01544fe..2f4c34d 100644
--- a/audio/core/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp
@@ -22,12 +22,15 @@
 #include <cstdio>
 #include <initializer_list>
 #include <limits>
+#include <list>
 #include <string>
 #include <vector>
 
 #include <fcntl.h>
 #include <unistd.h>
 
+#include <hwbinder/IPCThreadState.h>
+
 #include <VtsHalHidlTargetTestBase.h>
 
 #include <android-base/logging.h>
@@ -37,6 +40,10 @@
 #include <android/hardware/audio/2.0/IPrimaryDevice.h>
 #include <android/hardware/audio/2.0/types.h>
 #include <android/hardware/audio/common/2.0/types.h>
+#include <fmq/EventFlag.h>
+#include <fmq/MessageQueue.h>
+
+#include <common/all-versions/VersionUtils.h>
 
 #include "utility/AssertOk.h"
 #include "utility/Documentation.h"
@@ -46,14 +53,21 @@
 #include "utility/ReturnIn.h"
 
 using std::initializer_list;
+using std::list;
 using std::string;
 using std::to_string;
 using std::vector;
 
 using ::android::sp;
+using ::android::hardware::EventFlag;
+using ::android::hardware::hidl_bitfield;
+using ::android::hardware::hidl_enum_range;
 using ::android::hardware::hidl_handle;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
+using ::android::hardware::IPCThreadState;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
 using ::android::hardware::MQDescriptorSync;
 using ::android::hardware::Return;
 using ::android::hardware::audio::V2_0::AudioDrain;
@@ -64,14 +78,17 @@
 using ::android::hardware::audio::V2_0::IDevicesFactory;
 using ::android::hardware::audio::V2_0::IStream;
 using ::android::hardware::audio::V2_0::IStreamIn;
+using ::android::hardware::audio::V2_0::MessageQueueFlagBits;
 using ::android::hardware::audio::V2_0::TimeSpec;
 using ReadParameters = ::android::hardware::audio::V2_0::IStreamIn::ReadParameters;
 using ReadStatus = ::android::hardware::audio::V2_0::IStreamIn::ReadStatus;
+using ::android::hardware::audio::common::utils::mkEnumBitfield;
 using ::android::hardware::audio::common::V2_0::AudioChannelMask;
 using ::android::hardware::audio::common::V2_0::AudioConfig;
 using ::android::hardware::audio::common::V2_0::AudioDevice;
 using ::android::hardware::audio::common::V2_0::AudioFormat;
 using ::android::hardware::audio::common::V2_0::AudioHandleConsts;
+using ::android::hardware::audio::common::V2_0::AudioHwSync;
 using ::android::hardware::audio::common::V2_0::AudioInputFlag;
 using ::android::hardware::audio::common::V2_0::AudioIoHandle;
 using ::android::hardware::audio::common::V2_0::AudioMode;
@@ -88,6 +105,15 @@
 
 using namespace ::android::hardware::audio::common::test::utility;
 
+// Typical accepted results from interface methods
+static auto okOrNotSupported = {Result::OK, Result::NOT_SUPPORTED};
+static auto okOrNotSupportedOrInvalidArgs = {Result::OK, Result::NOT_SUPPORTED,
+                                             Result::INVALID_ARGUMENTS};
+static auto okOrInvalidStateOrNotSupported = {Result::OK, Result::INVALID_STATE,
+                                              Result::NOT_SUPPORTED};
+static auto invalidArgsOrNotSupported = {Result::INVALID_ARGUMENTS, Result::NOT_SUPPORTED};
+static auto invalidStateOrNotSupported = {Result::INVALID_STATE, Result::NOT_SUPPORTED};
+
 class AudioHidlTestEnvironment : public ::Environment {
    public:
     virtual void registerTestServices() override { registerTestService<IDevicesFactory>(); }
@@ -127,15 +153,16 @@
 sp<IDevicesFactory> AudioHidlTest::devicesFactory;
 
 TEST_F(AudioHidlTest, GetAudioDevicesFactoryService) {
-    doc::test("test the getService (called in SetUp)");
+    doc::test("Test the getService (called in SetUp)");
 }
 
 TEST_F(AudioHidlTest, OpenDeviceInvalidParameter) {
-    doc::test("test passing an invalid parameter to openDevice");
-    IDevicesFactory::Result result;
+    doc::test("Test passing an invalid parameter to openDevice");
+    Result result;
     sp<IDevice> device;
-    ASSERT_OK(devicesFactory->openDevice(IDevicesFactory::Device(-1), returnIn(result, device)));
-    ASSERT_EQ(IDevicesFactory::Result::INVALID_ARGUMENTS, result);
+    auto invalidDevice = IDevicesFactory::Device(-1);
+    ASSERT_OK(devicesFactory->openDevice(invalidDevice, returnIn(result, device)));
+    ASSERT_EQ(Result::INVALID_ARGUMENTS, result);
     ASSERT_TRUE(device == nullptr);
 }
 
@@ -151,22 +178,27 @@
         ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp());  // setup base
 
         if (device == nullptr) {
-            IDevicesFactory::Result result;
-            sp<IDevice> baseDevice;
-            ASSERT_OK(devicesFactory->openDevice(IDevicesFactory::Device::PRIMARY,
-                                                 returnIn(result, baseDevice)));
-            ASSERT_OK(result);
-            ASSERT_TRUE(baseDevice != nullptr);
-
-            environment->registerTearDown([] { device.clear(); });
-            device = IPrimaryDevice::castFrom(baseDevice);
+            initPrimaryDevice();
             ASSERT_TRUE(device != nullptr);
+            environment->registerTearDown([] { device.clear(); });
         }
     }
 
    protected:
     // Cache the device opening to speed up each test by ~0.5s
     static sp<IPrimaryDevice> device;
+
+   private:
+    void initPrimaryDevice() {
+        Result result;
+        sp<IDevice> baseDevice;
+        ASSERT_OK(devicesFactory->openDevice(IDevicesFactory::Device::PRIMARY,
+                                             returnIn(result, baseDevice)));
+        ASSERT_OK(result);
+        ASSERT_TRUE(baseDevice != nullptr);
+
+        device = IPrimaryDevice::castFrom(baseDevice);
+    }
 };
 sp<IPrimaryDevice> AudioPrimaryHidlTest::device;
 
@@ -186,53 +218,59 @@
 template <class Property>
 class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest {
    protected:
-    /** Test a property getter and setter. */
-    template <class Getter, class Setter>
-    void testAccessors(const string& propertyName, const vector<Property>& valuesToTest,
-                       Setter setter, Getter getter, const vector<Property>& invalidValues = {}) {
-        Property initialValue;  // Save initial value to restore it at the end
-                                // of the test
-        ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue)));
-        ASSERT_OK(res);
+    enum Optionality { REQUIRED, OPTIONAL };
+    struct Initial {  // Initial property value
+        Initial(Property value, Optionality check = REQUIRED) : value(value), check(check) {}
+        Property value;
+        Optionality check;  // If this initial value should be checked
+    };
+    /** Test a property getter and setter.
+     *  The getter and/or the setter may return NOT_SUPPORTED if optionality == OPTIONAL.
+     */
+    template <Optionality optionality = REQUIRED, class Getter, class Setter>
+    void testAccessors(const string& propertyName, const Initial expectedInitial,
+                       list<Property> valuesToTest, Setter setter, Getter getter,
+                       const vector<Property>& invalidValues = {}) {
+        const auto expectedResults = {Result::OK,
+                                      optionality == OPTIONAL ? Result::NOT_SUPPORTED : Result::OK};
 
+        Property initialValue = expectedInitial.value;
+        ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue)));
+        ASSERT_RESULT(expectedResults, res);
+        if (res == Result::OK && expectedInitial.check == REQUIRED) {
+            EXPECT_EQ(expectedInitial.value, initialValue);
+        }
+
+        valuesToTest.push_front(expectedInitial.value);
+        valuesToTest.push_back(initialValue);
         for (Property setValue : valuesToTest) {
             SCOPED_TRACE("Test " + propertyName + " getter and setter for " +
                          testing::PrintToString(setValue));
-            ASSERT_OK((device.get()->*setter)(setValue));
+            auto ret = (device.get()->*setter)(setValue);
+            ASSERT_RESULT(expectedResults, ret);
+            if (ret == Result::NOT_SUPPORTED) {
+                doc::partialTest(propertyName + " setter is not supported");
+                break;
+            }
             Property getValue;
             // Make sure the getter returns the same value just set
             ASSERT_OK((device.get()->*getter)(returnIn(res, getValue)));
-            ASSERT_OK(res);
+            ASSERT_RESULT(expectedResults, res);
+            if (res == Result::NOT_SUPPORTED) {
+                doc::partialTest(propertyName + " getter is not supported");
+                continue;
+            }
             EXPECT_EQ(setValue, getValue);
         }
 
         for (Property invalidValue : invalidValues) {
             SCOPED_TRACE("Try to set " + propertyName + " with the invalid value " +
                          testing::PrintToString(invalidValue));
-            EXPECT_RESULT(Result::INVALID_ARGUMENTS, (device.get()->*setter)(invalidValue));
+            EXPECT_RESULT(invalidArgsOrNotSupported, (device.get()->*setter)(invalidValue));
         }
 
-        ASSERT_OK((device.get()->*setter)(initialValue));  // restore initial value
-    }
-
-    /** Test the getter and setter of an optional feature. */
-    template <class Getter, class Setter>
-    void testOptionalAccessors(const string& propertyName, const vector<Property>& valuesToTest,
-                               Setter setter, Getter getter,
-                               const vector<Property>& invalidValues = {}) {
-        doc::test("Test the optional " + propertyName + " getters and setter");
-        {
-            SCOPED_TRACE("Test feature support by calling the getter");
-            Property initialValue;
-            ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue)));
-            if (res == Result::NOT_SUPPORTED) {
-                doc::partialTest(propertyName + " getter is not supported");
-                return;
-            }
-            ASSERT_OK(res);  // If it is supported it must succeed
-        }
-        // The feature is supported, test it
-        testAccessors(propertyName, valuesToTest, setter, getter, invalidValues);
+        // Restore initial value
+        EXPECT_RESULT(expectedResults, (device.get()->*setter)(initialValue));
     }
 };
 
@@ -240,24 +278,22 @@
 
 TEST_F(BoolAccessorPrimaryHidlTest, MicMuteTest) {
     doc::test("Check that the mic can be muted and unmuted");
-    testAccessors("mic mute", {true, false, true}, &IDevice::setMicMute, &IDevice::getMicMute);
+    testAccessors("mic mute", Initial{false}, {true}, &IDevice::setMicMute, &IDevice::getMicMute);
     // TODO: check that the mic is really muted (all sample are 0)
 }
 
 TEST_F(BoolAccessorPrimaryHidlTest, MasterMuteTest) {
-    doc::test(
-        "If master mute is supported, try to mute and unmute the master "
-        "output");
-    testOptionalAccessors("master mute", {true, false, true}, &IDevice::setMasterMute,
-                          &IDevice::getMasterMute);
+    doc::test("If master mute is supported, try to mute and unmute the master output");
+    testAccessors<OPTIONAL>("master mute", Initial{false}, {true}, &IDevice::setMasterMute,
+                            &IDevice::getMasterMute);
     // TODO: check that the master volume is really muted
 }
 
 using FloatAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<float>;
 TEST_F(FloatAccessorPrimaryHidlTest, MasterVolumeTest) {
     doc::test("Test the master volume if supported");
-    testOptionalAccessors(
-        "master volume", {0, 0.5, 1}, &IDevice::setMasterVolume, &IDevice::getMasterVolume,
+    testAccessors<OPTIONAL>(
+        "master volume", Initial{1}, {0, 0.5}, &IDevice::setMasterVolume, &IDevice::getMasterVolume,
         {-0.1, 1.1, NAN, INFINITY, -INFINITY, 1 + std::numeric_limits<float>::epsilon()});
     // TODO: check that the master volume is really changed
 }
@@ -337,7 +373,7 @@
                 for (auto format : formats) {
                     AudioConfig config{};
                     // leave offloadInfo to 0
-                    config.channelMask = channelMask;
+                    config.channelMask = mkEnumBitfield(channelMask);
                     config.sampleRateHz = sampleRate;
                     config.format = format;
                     // FIXME: leave frameCount to 0 ?
@@ -358,10 +394,10 @@
     const AudioConfig& config = info.param;
     return to_string(info.index) + "__" + to_string(config.sampleRateHz) + "_" +
            // "MONO" is more clear than "FRONT_LEFT"
-           ((config.channelMask == AudioChannelMask::OUT_MONO ||
-             config.channelMask == AudioChannelMask::IN_MONO)
+           ((config.channelMask == mkEnumBitfield(AudioChannelMask::OUT_MONO) ||
+             config.channelMask == mkEnumBitfield(AudioChannelMask::IN_MONO))
                 ? "MONO"
-                : toString(config.channelMask));
+                : ::testing::PrintToString(config.channelMask));
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -433,11 +469,7 @@
 TEST_F(AudioPrimaryHidlTest, setScreenState) {
     doc::test("Check that the hal can receive the screen state");
     for (bool turnedOn : {false, true, true, false, false}) {
-        auto ret = device->setScreenState(turnedOn);
-        ASSERT_IS_OK(ret);
-        Result result = ret;
-        auto okOrNotSupported = {Result::OK, Result::NOT_SUPPORTED};
-        ASSERT_RESULT(okOrNotSupported, result);
+        ASSERT_RESULT(okOrNotSupported, device->setScreenState(turnedOn));
     }
 }
 
@@ -445,14 +477,26 @@
 //////////////////////////// {get,set}Parameters /////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
+struct Parameters {
+    template <class T, class ReturnIn>
+    static auto get(T t, hidl_vec<hidl_string> keys, ReturnIn returnIn) {
+        return t->getParameters(keys, returnIn);
+    }
+    template <class T>
+    static auto set(T t, hidl_vec<ParameterValue> values) {
+        return t->setParameters(values);
+    }
+};
+
 TEST_F(AudioPrimaryHidlTest, getParameters) {
     doc::test("Check that the hal can set and get parameters");
+    hidl_vec<ParameterValue> context;
     hidl_vec<hidl_string> keys;
     hidl_vec<ParameterValue> values;
-    ASSERT_OK(device->getParameters(keys, returnIn(res, values)));
-    ASSERT_OK(device->setParameters(values));
+    ASSERT_OK(Parameters::get(device, keys, returnIn(res, values)));
+    ASSERT_OK(Parameters::set(device, values));
     values.resize(0);
-    ASSERT_OK(device->setParameters(values));
+    ASSERT_OK(Parameters::set(device, values));
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -493,14 +537,19 @@
     EXPECT_EQ(0, close(fds[1])) << errno;
 }
 
+template <class T>
+auto dump(T t, hidl_handle handle) {
+    return t->debugDump(handle);
+}
+
 TEST_F(AudioPrimaryHidlTest, DebugDump) {
     doc::test("Check that the hal can dump its state without error");
-    testDebugDump([](const auto& handle) { return device->debugDump(handle); });
+    testDebugDump([](const auto& handle) { return dump(device, handle); });
 }
 
 TEST_F(AudioPrimaryHidlTest, DebugDumpInvalidArguments) {
     doc::test("Check that the hal dump doesn't crash on invalid arguments");
-    ASSERT_OK(device->debugDump(hidl_handle()));
+    ASSERT_OK(dump(device, hidl_handle()));
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -569,7 +618,8 @@
         ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp());  // setup base
         address.device = AudioDevice::OUT_DEFAULT;
         const AudioConfig& config = GetParam();
-        AudioOutputFlag flags = AudioOutputFlag::NONE;  // TODO: test all flag combination
+        // TODO: test all flag combination
+        auto flags = mkEnumBitfield(AudioOutputFlag::NONE);
         testOpen(
             [&](AudioIoHandle handle, AudioConfig config, auto cb) {
                 return device->openOutputStream(handle, address, config, flags, cb);
@@ -604,14 +654,17 @@
         ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp());  // setup base
         address.device = AudioDevice::IN_DEFAULT;
         const AudioConfig& config = GetParam();
-        AudioInputFlag flags = AudioInputFlag::NONE;  // TODO: test all flag combination
-        AudioSource source = AudioSource::DEFAULT;    // TODO: test all flag combination
+        // TODO: test all supported flags and source
+        auto flags = mkEnumBitfield(AudioInputFlag::NONE);
         testOpen(
             [&](AudioIoHandle handle, AudioConfig config, auto cb) {
-                return device->openInputStream(handle, address, config, flags, source, cb);
+                return device->openInputStream(handle, address, config, flags, initMetadata, cb);
             },
             config);
     }
+
+   protected:
+    const AudioSource initMetadata = AudioSource::DEFAULT;
 };
 
 TEST_P(InputStreamTest, OpenInputStreamTest) {
@@ -682,27 +735,26 @@
 
 template <class Property, class CapabilityGetter>
 static void testCapabilityGetter(const string& name, IStream* stream,
-                                 CapabilityGetter capablityGetter,
+                                 CapabilityGetter capabilityGetter,
                                  Return<Property> (IStream::*getter)(),
                                  Return<Result> (IStream::*setter)(Property),
                                  bool currentMustBeSupported = true) {
     hidl_vec<Property> capabilities;
-    ASSERT_OK((stream->*capablityGetter)(returnIn(capabilities)));
-    if (capabilities.size() == 0) {
-        // The default hal should probably return a NOT_SUPPORTED if the hal
-        // does not expose
-        // capability retrieval. For now it returns an empty list if not
-        // implemented
+    auto ret = capabilityGetter(stream, capabilities);
+    ASSERT_RESULT(okOrNotSupported, ret);
+    bool notSupported = ret == Result::NOT_SUPPORTED;
+    if (notSupported) {
         doc::partialTest(name + " is not supported");
         return;
     };
 
     if (currentMustBeSupported) {
+        ASSERT_NE(0U, capabilities.size()) << name << " must not return an empty list";
         Property currentValue = extract((stream->*getter)());
-        EXPECT_NE(std::find(capabilities.begin(), capabilities.end(), currentValue),
-                  capabilities.end())
-            << "current " << name << " is not in the list of the supported ones "
-            << toString(capabilities);
+        EXPECT_TRUE(std::find(capabilities.begin(), capabilities.end(), currentValue) !=
+                    capabilities.end())
+            << "value returned by " << name << "() = " << testing::PrintToString(currentValue)
+            << " is not in the list of the supported ones " << toString(capabilities);
     }
 
     // Check that all declared supported values are indeed supported
@@ -718,9 +770,36 @@
     }
 }
 
+// The default hal should probably return a NOT_SUPPORTED if the hal
+// does not expose
+// capability retrieval. For now it returns an empty list if not
+// implemented
+struct GetSupported {
+    template <class Vec>
+    static Result convertToResult(const Vec& vec) {
+        return vec.size() == 0 ? Result::NOT_SUPPORTED : Result::OK;
+    }
+
+    static Result sampleRates(IStream* stream, hidl_vec<uint32_t>& rates) {
+        EXPECT_OK(stream->getSupportedSampleRates(returnIn(rates)));
+        return convertToResult(rates);
+    }
+
+    static Result channelMasks(IStream* stream, hidl_vec<AudioChannelMask>& channels) {
+        EXPECT_OK(stream->getSupportedChannelMasks(returnIn(channels)));
+        return convertToResult(channels);
+    }
+
+    static Result formats(IStream* stream, hidl_vec<AudioFormat>& capabilities) {
+        EXPECT_OK(stream->getSupportedFormats(returnIn(capabilities)));
+        // TODO: this should be an optional function
+        return Result::OK;
+    }
+};
+
 TEST_IO_STREAM(SupportedSampleRate, "Check that the stream sample rate is declared as supported",
                testCapabilityGetter("getSupportedSampleRate", stream.get(),
-                                    &IStream::getSupportedSampleRates, &IStream::getSampleRate,
+                                    &GetSupported::sampleRates, &IStream::getSampleRate,
                                     &IStream::setSampleRate,
                                     // getSupportedSampleRate returns the native sampling rates,
                                     // (the sampling rates that can be played without resampling)
@@ -729,13 +808,12 @@
 
 TEST_IO_STREAM(SupportedChannelMask, "Check that the stream channel mask is declared as supported",
                testCapabilityGetter("getSupportedChannelMask", stream.get(),
-                                    &IStream::getSupportedChannelMasks, &IStream::getChannelMask,
+                                    &GetSupported::channelMasks, &IStream::getChannelMask,
                                     &IStream::setChannelMask))
 
 TEST_IO_STREAM(SupportedFormat, "Check that the stream format is declared as supported",
-               testCapabilityGetter("getSupportedFormat", stream.get(),
-                                    &IStream::getSupportedFormats, &IStream::getFormat,
-                                    &IStream::setFormat))
+               testCapabilityGetter("getSupportedFormat", stream.get(), &GetSupported::formats,
+                                    &IStream::getFormat, &IStream::setFormat))
 
 static void testGetDevice(IStream* stream, AudioDevice expectedDevice) {
     // Unfortunately the interface does not allow the implementation to return
@@ -768,7 +846,7 @@
 
 static void testGetAudioProperties(IStream* stream, AudioConfig expectedConfig) {
     uint32_t sampleRateHz;
-    AudioChannelMask mask;
+    auto mask = mkEnumBitfield<AudioChannelMask>({});
     AudioFormat format;
 
     stream->getAudioProperties(returnIn(sampleRateHz, mask, format));
@@ -784,6 +862,9 @@
                "Check that the stream audio properties == the ones it was opened with",
                testGetAudioProperties(stream.get(), audioConfig))
 
+TEST_IO_STREAM(SetHwAvSync, "Try to set hardware sync to an invalid value",
+               ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, stream->setHwAvSync(666)))
+
 static void testConnectedState(IStream* stream) {
     DeviceAddress address = {};
     using AD = AudioDevice;
@@ -799,18 +880,13 @@
                "deconnection",
                testConnectedState(stream.get()))
 
-static auto invalidArgsOrNotSupportedOrOK = {Result::INVALID_ARGUMENTS, Result::NOT_SUPPORTED,
-                                             Result::OK};
-TEST_IO_STREAM(SetHwAvSync, "Try to set hardware sync to an invalid value",
-               ASSERT_RESULT(invalidArgsOrNotSupportedOrOK, stream->setHwAvSync(666)))
-
 TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", ASSERT_IS_OK(device->getHwAvSync()));
 
 static void checkGetNoParameter(IStream* stream, hidl_vec<hidl_string> keys,
                                 initializer_list<Result> expectedResults) {
     hidl_vec<ParameterValue> parameters;
     Result res;
-    ASSERT_OK(stream->getParameters(keys, returnIn(res, parameters)));
+    ASSERT_OK(Parameters::get(stream, keys, returnIn(res, parameters)));
     ASSERT_RESULT(expectedResults, res);
     if (res == Result::OK) {
         for (auto& parameter : parameters) {
@@ -831,22 +907,22 @@
                                    {Result::NOT_SUPPORTED}))
 
 TEST_IO_STREAM(setEmptySetParameter, "Set the values of an empty set of parameters",
-               ASSERT_RESULT(Result::OK, stream->setParameters({})))
+               ASSERT_RESULT(Result::OK, Parameters::set(stream, {})))
 
 TEST_IO_STREAM(setNonExistingParameter, "Set the values of an non existing parameter",
                // Unfortunately, the set_parameter legacy interface did not return any
                // error code when a key is not supported.
                // To allow implementation to just wrapped the legacy one, consider OK as a
                // valid result for setting a non existing parameter.
-               ASSERT_RESULT(invalidArgsOrNotSupportedOrOK,
-                             stream->setParameters({{"non existing key", "0"}})))
+               ASSERT_RESULT(okOrNotSupportedOrInvalidArgs,
+                             Parameters::set(stream, {{"non existing key", "0"}})))
 
 TEST_IO_STREAM(DebugDump, "Check that a stream can dump its state without error",
-               testDebugDump([this](const auto& handle) { return stream->debugDump(handle); }))
+               testDebugDump([this](const auto& handle) { return dump(stream, handle); }))
 
 TEST_IO_STREAM(DebugDumpInvalidArguments,
                "Check that the stream dump doesn't crash on invalid arguments",
-               ASSERT_OK(stream->debugDump(hidl_handle())))
+               ASSERT_OK(dump(stream, hidl_handle())))
 
 //////////////////////////////////////////////////////////////////////////////
 ////////////////////////////// addRemoveEffect ///////////////////////////////
@@ -866,8 +942,6 @@
 TEST_IO_STREAM(standby, "Make sure the stream can be put in stanby",
                ASSERT_OK(stream->standby()))  // can not fail
 
-static constexpr auto invalidStateOrNotSupported = {Result::INVALID_STATE, Result::NOT_SUPPORTED};
-
 TEST_IO_STREAM(startNoMmap, "Starting a mmaped stream before mapping it should fail",
                ASSERT_RESULT(invalidStateOrNotSupported, stream->start()))
 
@@ -881,7 +955,6 @@
 TEST_IO_STREAM(closeTwice, "Make sure a stream can not be closed twice", ASSERT_OK(closeStream());
                ASSERT_RESULT(Result::INVALID_STATE, closeStream()))
 
-static auto invalidArgsOrNotSupported = {Result::INVALID_ARGUMENTS, Result::NOT_SUPPORTED};
 static void testCreateTooBigMmapBuffer(IStream* stream) {
     MmapBufferInfo info;
     Result res;
@@ -988,15 +1061,19 @@
 TEST_P(InputStreamTest, getCapturePosition) {
     doc::test(
         "The capture position of a non prepared stream should not be "
-        "retrievable");
+        "retrievable or 0");
     uint64_t frames;
     uint64_t time;
     ASSERT_OK(stream->getCapturePosition(returnIn(res, frames, time)));
-    ASSERT_RESULT(invalidStateOrNotSupported, res);
+    ASSERT_RESULT(okOrInvalidStateOrNotSupported, res);
+    if (res == Result::OK) {
+        ASSERT_EQ(0U, frames);
+        ASSERT_LE(0U, time);
+    }
 }
 
 //////////////////////////////////////////////////////////////////////////////
-///////////////////////////////// StreamIn ///////////////////////////////////
+///////////////////////////////// StreamOut //////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
 TEST_P(OutputStreamTest, getLatency) {
@@ -1103,7 +1180,6 @@
     auto res = stream->setCallback(new MockOutCallbacks);
     stream->clearCallback();  // try to restore the no callback state, ignore
                               // any error
-    auto okOrNotSupported = {Result::OK, Result::NOT_SUPPORTED};
     EXPECT_RESULT(okOrNotSupported, res);
     return res.isOk() ? res == Result::OK : false;
 }
@@ -1152,7 +1228,7 @@
         doc::partialTest("The output stream does not support pause");
         return;
     }
-    ASSERT_RESULT(Result::INVALID_STATE, stream->resume());
+    ASSERT_RESULT(Result::INVALID_STATE, stream->pause());
 }
 
 static void testDrain(IStreamOut* stream, AudioDrain type) {
@@ -1223,9 +1299,7 @@
 }
 
 TEST_F(AudioPrimaryHidlTest, setMode) {
-    doc::test(
-        "Make sure setMode always succeeds if mode is valid "
-        "and fails otherwise");
+    doc::test("Make sure setMode always succeeds if mode is valid and fails otherwise");
     // Test Invalid values
     for (AudioMode mode : {AudioMode::INVALID, AudioMode::CURRENT, AudioMode::CNT}) {
         SCOPED_TRACE("mode=" + toString(mode));
@@ -1241,29 +1315,30 @@
 
 TEST_F(BoolAccessorPrimaryHidlTest, BtScoNrecEnabled) {
     doc::test("Query and set the BT SCO NR&EC state");
-    testOptionalAccessors("BtScoNrecEnabled", {true, false, true},
-                          &IPrimaryDevice::setBtScoNrecEnabled,
-                          &IPrimaryDevice::getBtScoNrecEnabled);
+    testAccessors<OPTIONAL>("BtScoNrecEnabled", Initial{false, OPTIONAL}, {true},
+                            &IPrimaryDevice::setBtScoNrecEnabled,
+                            &IPrimaryDevice::getBtScoNrecEnabled);
 }
 
 TEST_F(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) {
     doc::test("Query and set the SCO whideband state");
-    testOptionalAccessors("BtScoWideband", {true, false, true},
-                          &IPrimaryDevice::setBtScoWidebandEnabled,
-                          &IPrimaryDevice::getBtScoWidebandEnabled);
+    testAccessors<OPTIONAL>("BtScoWideband", Initial{false, OPTIONAL}, {true},
+                            &IPrimaryDevice::setBtScoWidebandEnabled,
+                            &IPrimaryDevice::getBtScoWidebandEnabled);
 }
 
 using TtyModeAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<TtyMode>;
 TEST_F(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) {
     doc::test("Query and set the TTY mode state");
-    testOptionalAccessors("TTY mode", {TtyMode::OFF, TtyMode::HCO, TtyMode::VCO, TtyMode::FULL},
-                          &IPrimaryDevice::setTtyMode, &IPrimaryDevice::getTtyMode);
+    testAccessors<OPTIONAL>("TTY mode", Initial{TtyMode::OFF},
+                            {TtyMode::HCO, TtyMode::VCO, TtyMode::FULL},
+                            &IPrimaryDevice::setTtyMode, &IPrimaryDevice::getTtyMode);
 }
 
 TEST_F(BoolAccessorPrimaryHidlTest, setGetHac) {
     doc::test("Query and set the HAC state");
-    testOptionalAccessors("HAC", {true, false, true}, &IPrimaryDevice::setHacEnabled,
-                          &IPrimaryDevice::getHacEnabled);
+    testAccessors<OPTIONAL>("HAC", Initial{false}, {true}, &IPrimaryDevice::setHacEnabled,
+                            &IPrimaryDevice::getHacEnabled);
 }
 
 //////////////////////////////////////////////////////////////////////////////
diff --git a/audio/core/2.0/vts/functional/ValidateAudioConfiguration.cpp b/audio/core/2.0/vts/functional/ValidateAudioConfiguration.cpp
index bef0e82..50c5333 100644
--- a/audio/core/2.0/vts/functional/ValidateAudioConfiguration.cpp
+++ b/audio/core/2.0/vts/functional/ValidateAudioConfiguration.cpp
@@ -19,12 +19,19 @@
 
 #include "utility/ValidateXml.h"
 
+// Stringify the argument.
+#define QUOTE(x) #x
+#define STRINGIFY(x) QUOTE(x)
+
+#define AUDIO_HAL_VERSION V2_0
+
 TEST(CheckConfig, audioPolicyConfigurationValidation) {
     RecordProperty("description",
                    "Verify that the audio policy configuration file "
                    "is valid according to the schema");
 
     std::vector<const char*> locations = {"/odm/etc", "/vendor/etc", "/system/etc"};
-    EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS("audio_policy_configuration.xml", locations,
-                                            "/data/local/tmp/audio_policy_configuration.xsd");
+    const char* xsd =
+        "/data/local/tmp/audio_policy_configuration_" STRINGIFY(AUDIO_HAL_VERSION) ".xsd";
+    EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS("audio_policy_configuration.xml", locations, xsd);
 }
diff --git a/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp b/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp
index d4a5daa..ebf6777 100644
--- a/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp
@@ -74,7 +74,6 @@
 using ::android::hardware::audio::V4_0::DeviceAddress;
 using ::android::hardware::audio::V4_0::IDevice;
 using ::android::hardware::audio::V4_0::IPrimaryDevice;
-using Rotation = ::android::hardware::audio::V4_0::IPrimaryDevice::Rotation;
 using TtyMode = ::android::hardware::audio::V4_0::IPrimaryDevice::TtyMode;
 using ::android::hardware::audio::V4_0::IDevicesFactory;
 using ::android::hardware::audio::V4_0::IStream;
@@ -83,10 +82,9 @@
 using ::android::hardware::audio::V4_0::TimeSpec;
 using ReadParameters = ::android::hardware::audio::V4_0::IStreamIn::ReadParameters;
 using ReadStatus = ::android::hardware::audio::V4_0::IStreamIn::ReadStatus;
-using ::android::hardware::audio::common::utils::mkBitfield;
+using ::android::hardware::audio::common::utils::mkEnumBitfield;
 using ::android::hardware::audio::common::V4_0::AudioChannelMask;
 using ::android::hardware::audio::common::V4_0::AudioConfig;
-using ::android::hardware::audio::common::V4_0::AudioContentType;
 using ::android::hardware::audio::common::V4_0::AudioDevice;
 using ::android::hardware::audio::common::V4_0::AudioFormat;
 using ::android::hardware::audio::common::V4_0::AudioHandleConsts;
@@ -97,15 +95,18 @@
 using ::android::hardware::audio::common::V4_0::AudioOffloadInfo;
 using ::android::hardware::audio::common::V4_0::AudioOutputFlag;
 using ::android::hardware::audio::common::V4_0::AudioSource;
-using ::android::hardware::audio::common::V4_0::AudioUsage;
 using ::android::hardware::audio::common::V4_0::ThreadInfo;
 using ::android::hardware::audio::V4_0::IStreamOut;
 using ::android::hardware::audio::V4_0::IStreamOutCallback;
-using ::android::hardware::audio::V4_0::MicrophoneInfo;
 using ::android::hardware::audio::V4_0::MmapBufferInfo;
 using ::android::hardware::audio::V4_0::MmapPosition;
 using ::android::hardware::audio::V4_0::ParameterValue;
 using ::android::hardware::audio::V4_0::Result;
+
+using Rotation = ::android::hardware::audio::V4_0::IPrimaryDevice::Rotation;
+using ::android::hardware::audio::common::V4_0::AudioContentType;
+using ::android::hardware::audio::common::V4_0::AudioUsage;
+using ::android::hardware::audio::V4_0::MicrophoneInfo;
 using ::android::hardware::audio::V4_0::SinkMetadata;
 using ::android::hardware::audio::V4_0::SourceMetadata;
 
@@ -166,7 +167,8 @@
     doc::test("Test passing an invalid parameter to openDevice");
     Result result;
     sp<IDevice> device;
-    ASSERT_OK(devicesFactory->openDevice("Non existing device", returnIn(result, device)));
+    auto invalidDevice = "Non existing device";
+    ASSERT_OK(devicesFactory->openDevice(invalidDevice, returnIn(result, device)));
     ASSERT_EQ(Result::INVALID_ARGUMENTS, result);
     ASSERT_TRUE(device == nullptr);
 }
@@ -206,11 +208,8 @@
         ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp());  // setup base
 
         if (device == nullptr) {
-            Result result;
-            ASSERT_OK(devicesFactory->openPrimaryDevice(returnIn(result, device)));
-            ASSERT_OK(result);
+            initPrimaryDevice();
             ASSERT_TRUE(device != nullptr);
-
             environment->registerTearDown([] { device.clear(); });
         }
     }
@@ -218,6 +217,13 @@
    protected:
     // Cache the device opening to speed up each test by ~0.5s
     static sp<IPrimaryDevice> device;
+
+   private:
+    void initPrimaryDevice() {
+        Result result;
+        ASSERT_OK(devicesFactory->openPrimaryDevice(returnIn(result, device)));
+        ASSERT_OK(result);
+    }
 };
 sp<IPrimaryDevice> AudioPrimaryHidlTest::device;
 
@@ -392,7 +398,7 @@
                 for (auto format : formats) {
                     AudioConfig config{};
                     // leave offloadInfo to 0
-                    config.channelMask = mkBitfield(channelMask);
+                    config.channelMask = mkEnumBitfield(channelMask);
                     config.sampleRateHz = sampleRate;
                     config.format = format;
                     // FIXME: leave frameCount to 0 ?
@@ -413,8 +419,8 @@
     const AudioConfig& config = info.param;
     return to_string(info.index) + "__" + to_string(config.sampleRateHz) + "_" +
            // "MONO" is more clear than "FRONT_LEFT"
-           ((config.channelMask == mkBitfield(AudioChannelMask::OUT_MONO) ||
-             config.channelMask == mkBitfield(AudioChannelMask::IN_MONO))
+           ((config.channelMask == mkEnumBitfield(AudioChannelMask::OUT_MONO) ||
+             config.channelMask == mkEnumBitfield(AudioChannelMask::IN_MONO))
                 ? "MONO"
                 : ::testing::PrintToString(config.channelMask));
 }
@@ -496,15 +502,28 @@
 //////////////////////////// {get,set}Parameters /////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
+struct Parameters {
+    template <class T, class ReturnIn>
+    static auto get(T t, hidl_vec<hidl_string> keys, ReturnIn returnIn) {
+        hidl_vec<ParameterValue> context;
+        return t->getParameters(context, keys, returnIn);
+    }
+    template <class T>
+    static auto set(T t, hidl_vec<ParameterValue> values) {
+        hidl_vec<ParameterValue> context;
+        return t->setParameters(context, values);
+    }
+};
+
 TEST_F(AudioPrimaryHidlTest, getParameters) {
     doc::test("Check that the hal can set and get parameters");
     hidl_vec<ParameterValue> context;
     hidl_vec<hidl_string> keys;
     hidl_vec<ParameterValue> values;
-    ASSERT_OK(device->getParameters(context, keys, returnIn(res, values)));
-    ASSERT_OK(device->setParameters(context, values));
+    ASSERT_OK(Parameters::get(device, keys, returnIn(res, values)));
+    ASSERT_OK(Parameters::set(device, values));
     values.resize(0);
-    ASSERT_OK(device->setParameters(context, values));
+    ASSERT_OK(Parameters::set(device, values));
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -524,11 +543,11 @@
             "and getActiveMicrophones always succeeds when recording from these microphones.");
         AudioIoHandle ioHandle = (AudioIoHandle)AudioHandleConsts::AUDIO_IO_HANDLE_NONE;
         AudioConfig config{};
-        config.channelMask = mkBitfield(AudioChannelMask::IN_MONO);
+        config.channelMask = mkEnumBitfield(AudioChannelMask::IN_MONO);
         config.sampleRateHz = 8000;
         config.format = AudioFormat::PCM_16_BIT;
         auto flags = hidl_bitfield<AudioInputFlag>(AudioInputFlag::NONE);
-        const SinkMetadata initialMetadata = {{{AudioSource::MIC, 1 /* gain */}}};
+        const SinkMetadata initMetadata = {{{AudioSource::MIC, 1 /* gain */}}};
         EventFlag* efGroup;
         for (auto microphone : microphones) {
             if (microphone.deviceAddress.device != AudioDevice::IN_BUILTIN_MIC) {
@@ -537,13 +556,13 @@
             sp<IStreamIn> stream;
             AudioConfig suggestedConfig{};
             ASSERT_OK(device->openInputStream(ioHandle, microphone.deviceAddress, config, flags,
-                                              initialMetadata,
+                                              initMetadata,
                                               returnIn(res, stream, suggestedConfig)));
             if (res != Result::OK) {
                 ASSERT_TRUE(stream == nullptr);
                 AudioConfig suggestedConfigRetry{};
                 ASSERT_OK(device->openInputStream(ioHandle, microphone.deviceAddress,
-                                                  suggestedConfig, flags, initialMetadata,
+                                                  suggestedConfig, flags, initMetadata,
                                                   returnIn(res, stream, suggestedConfigRetry)));
             }
             ASSERT_OK(res);
@@ -626,14 +645,19 @@
     EXPECT_EQ(0, close(fds[1])) << errno;
 }
 
+template <class T>
+auto dump(T t, hidl_handle handle) {
+    return t->debug(handle, {/* options */});
+}
+
 TEST_F(AudioPrimaryHidlTest, DebugDump) {
     doc::test("Check that the hal can dump its state without error");
-    testDebugDump([](const auto& handle) { return device->debug(handle, {/* options */}); });
+    testDebugDump([](const auto& handle) { return dump(device, handle); });
 }
 
 TEST_F(AudioPrimaryHidlTest, DebugDumpInvalidArguments) {
     doc::test("Check that the hal dump doesn't crash on invalid arguments");
-    ASSERT_OK(device->debug(hidl_handle(), {/* options */}));
+    ASSERT_OK(dump(device, hidl_handle()));
 }
 
 TEST_F(AudioPrimaryHidlTest, SetConnectedState) {
@@ -723,17 +747,16 @@
         address.device = AudioDevice::OUT_DEFAULT;
         const AudioConfig& config = GetParam();
         // TODO: test all flag combination
-        auto flags = hidl_bitfield<AudioOutputFlag>(AudioOutputFlag::NONE);
+        auto flags = mkEnumBitfield(AudioOutputFlag::NONE);
         testOpen(
             [&](AudioIoHandle handle, AudioConfig config, auto cb) {
-                return device->openOutputStream(handle, address, config, flags, initialMetadata,
-                                                cb);
+                return device->openOutputStream(handle, address, config, flags, initMetadata, cb);
             },
             config);
     }
 
    protected:
-    const SourceMetadata initialMetadata = {
+    const SourceMetadata initMetadata = {
         {{AudioUsage::MEDIA, AudioContentType::MUSIC, 1 /* gain */}}};
 };
 TEST_P(OutputStreamTest, OpenOutputStreamTest) {
@@ -764,16 +787,16 @@
         address.device = AudioDevice::IN_DEFAULT;
         const AudioConfig& config = GetParam();
         // TODO: test all supported flags and source
-        auto flags = hidl_bitfield<AudioInputFlag>(AudioInputFlag::NONE);
+        auto flags = mkEnumBitfield(AudioInputFlag::NONE);
         testOpen(
             [&](AudioIoHandle handle, AudioConfig config, auto cb) {
-                return device->openInputStream(handle, address, config, flags, initialMetadata, cb);
+                return device->openInputStream(handle, address, config, flags, initMetadata, cb);
             },
             config);
     }
 
    protected:
-    const SinkMetadata initialMetadata = {{{AudioSource::DEFAULT, 1 /* gain */}}};
+    const SinkMetadata initMetadata = {{{AudioSource::DEFAULT, 1 /* gain */}}};
 };
 
 TEST_P(InputStreamTest, OpenInputStreamTest) {
@@ -842,19 +865,20 @@
 TEST_IO_STREAM(GetBufferSize, "Check that the stream buffer size== the one it was opened with",
                ASSERT_GE(extract(stream->getBufferSize()), extract(stream->getFrameSize())));
 
-template <class Property, class CapablityGetter>
+template <class Property, class CapabilityGetter>
 static void testCapabilityGetter(const string& name, IStream* stream,
-                                 CapablityGetter capablityGetter,
+                                 CapabilityGetter capabilityGetter,
                                  Return<Property> (IStream::*getter)(),
                                  Return<Result> (IStream::*setter)(Property),
                                  bool currentMustBeSupported = true) {
     hidl_vec<Property> capabilities;
-    auto ret = capablityGetter(stream, capabilities);
-    if (ret == Result::NOT_SUPPORTED) {
+    auto ret = capabilityGetter(stream, capabilities);
+    ASSERT_RESULT(okOrNotSupported, ret);
+    bool notSupported = ret == Result::NOT_SUPPORTED;
+    if (notSupported) {
         doc::partialTest(name + " is not supported");
         return;
     };
-    ASSERT_OK(ret);
 
     if (currentMustBeSupported) {
         ASSERT_NE(0U, capabilities.size()) << name << " must not return an empty list";
@@ -878,29 +902,32 @@
     }
 }
 
-Result getSupportedSampleRates(IStream* stream, hidl_vec<uint32_t>& rates) {
-    Result res;
-    EXPECT_OK(stream->getSupportedSampleRates(extract(stream->getFormat()), returnIn(res, rates)));
-    return res;
-}
+struct GetSupported {
+    static Result sampleRates(IStream* stream, hidl_vec<uint32_t>& rates) {
+        Result res;
+        EXPECT_OK(
+            stream->getSupportedSampleRates(extract(stream->getFormat()), returnIn(res, rates)));
+        return res;
+    }
 
-Result getSupportedChannelMasks(IStream* stream,
-                                hidl_vec<hidl_bitfield<AudioChannelMask>>& channels) {
-    Result res;
-    EXPECT_OK(
-        stream->getSupportedChannelMasks(extract(stream->getFormat()), returnIn(res, channels)));
-    return res;
-}
+    static Result channelMasks(IStream* stream,
+                               hidl_vec<hidl_bitfield<AudioChannelMask>>& channels) {
+        Result res;
+        EXPECT_OK(stream->getSupportedChannelMasks(extract(stream->getFormat()),
+                                                   returnIn(res, channels)));
+        return res;
+    }
 
-Result getSupportedFormats(IStream* stream, hidl_vec<AudioFormat>& capabilities) {
-    EXPECT_OK(stream->getSupportedFormats(returnIn(capabilities)));
-    // TODO: this should be an optional function
-    return Result::OK;
-}
+    static Result formats(IStream* stream, hidl_vec<AudioFormat>& capabilities) {
+        EXPECT_OK(stream->getSupportedFormats(returnIn(capabilities)));
+        // TODO: this should be an optional function
+        return Result::OK;
+    }
+};
 
 TEST_IO_STREAM(SupportedSampleRate, "Check that the stream sample rate is declared as supported",
                testCapabilityGetter("getSupportedSampleRate", stream.get(),
-                                    &getSupportedSampleRates, &IStream::getSampleRate,
+                                    &GetSupported::sampleRates, &IStream::getSampleRate,
                                     &IStream::setSampleRate,
                                     // getSupportedSampleRate returns the native sampling rates,
                                     // (the sampling rates that can be played without resampling)
@@ -909,11 +936,11 @@
 
 TEST_IO_STREAM(SupportedChannelMask, "Check that the stream channel mask is declared as supported",
                testCapabilityGetter("getSupportedChannelMask", stream.get(),
-                                    &getSupportedChannelMasks, &IStream::getChannelMask,
+                                    &GetSupported::channelMasks, &IStream::getChannelMask,
                                     &IStream::setChannelMask))
 
 TEST_IO_STREAM(SupportedFormat, "Check that the stream format is declared as supported",
-               testCapabilityGetter("getSupportedFormat", stream.get(), &getSupportedFormats,
+               testCapabilityGetter("getSupportedFormat", stream.get(), &GetSupported::formats,
                                     &IStream::getFormat, &IStream::setFormat))
 
 static void testGetDevices(IStream* stream, AudioDevice expectedDevice) {
@@ -950,7 +977,7 @@
 
 static void testGetAudioProperties(IStream* stream, AudioConfig expectedConfig) {
     uint32_t sampleRateHz;
-    hidl_bitfield<AudioChannelMask> mask;
+    auto mask = mkEnumBitfield<AudioChannelMask>({});
     AudioFormat format;
 
     stream->getAudioProperties(returnIn(sampleRateHz, mask, format));
@@ -982,10 +1009,9 @@
 
 static void checkGetNoParameter(IStream* stream, hidl_vec<hidl_string> keys,
                                 initializer_list<Result> expectedResults) {
-    hidl_vec<ParameterValue> context;
     hidl_vec<ParameterValue> parameters;
     Result res;
-    ASSERT_OK(stream->getParameters(context, keys, returnIn(res, parameters)));
+    ASSERT_OK(Parameters::get(stream, keys, returnIn(res, parameters)));
     ASSERT_RESULT(expectedResults, res);
     if (res == Result::OK) {
         for (auto& parameter : parameters) {
@@ -1006,7 +1032,7 @@
                                    {Result::NOT_SUPPORTED}))
 
 TEST_IO_STREAM(setEmptySetParameter, "Set the values of an empty set of parameters",
-               ASSERT_RESULT(Result::OK, stream->setParameters({}, {})))
+               ASSERT_RESULT(Result::OK, Parameters::set(stream, {})))
 
 TEST_IO_STREAM(setNonExistingParameter, "Set the values of an non existing parameter",
                // Unfortunately, the set_parameter legacy interface did not return any
@@ -1014,14 +1040,14 @@
                // To allow implementation to just wrapped the legacy one, consider OK as a
                // valid result for setting a non existing parameter.
                ASSERT_RESULT(okOrNotSupportedOrInvalidArgs,
-                             stream->setParameters({}, {{"non existing key", "0"}})))
+                             Parameters::set(stream, {{"non existing key", "0"}})))
 
 TEST_IO_STREAM(DebugDump, "Check that a stream can dump its state without error",
-               testDebugDump([this](const auto& handle) { return stream->debug(handle, {}); }))
+               testDebugDump([this](const auto& handle) { return dump(stream, handle); }))
 
 TEST_IO_STREAM(DebugDumpInvalidArguments,
                "Check that the stream dump doesn't crash on invalid arguments",
-               ASSERT_OK(stream->debug(hidl_handle(), {})))
+               ASSERT_OK(dump(stream, hidl_handle())))
 
 //////////////////////////////////////////////////////////////////////////////
 ////////////////////////////// addRemoveEffect ///////////////////////////////
@@ -1190,7 +1216,7 @@
     ASSERT_OK(stream->updateSinkMetadata({}));
 
     // Restore initial
-    ASSERT_OK(stream->updateSinkMetadata(initialMetadata));
+    ASSERT_OK(stream->updateSinkMetadata(initMetadata));
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -1443,7 +1469,7 @@
     ASSERT_OK(stream->updateSourceMetadata({}));
 
     // Restore initial
-    ASSERT_OK(stream->updateSourceMetadata(initialMetadata));
+    ASSERT_OK(stream->updateSourceMetadata(initMetadata));
 }
 
 //////////////////////////////////////////////////////////////////////////////
diff --git a/audio/core/4.0/vts/functional/ValidateAudioConfiguration.cpp b/audio/core/4.0/vts/functional/ValidateAudioConfiguration.cpp
index a64513f..237ef47 100644
--- a/audio/core/4.0/vts/functional/ValidateAudioConfiguration.cpp
+++ b/audio/core/4.0/vts/functional/ValidateAudioConfiguration.cpp
@@ -19,12 +19,19 @@
 
 #include "utility/ValidateXml.h"
 
+// Stringify the argument.
+#define QUOTE(x) #x
+#define STRINGIFY(x) QUOTE(x)
+
+#define AUDIO_HAL_VERSION V4_0
+
 TEST(CheckConfig, audioPolicyConfigurationValidation) {
     RecordProperty("description",
                    "Verify that the audio policy configuration file "
                    "is valid according to the schema");
 
     std::vector<const char*> locations = {"/odm/etc", "/vendor/etc", "/system/etc"};
-    EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS("audio_policy_configuration.xml", locations,
-                                            "/data/local/tmp/audio_policy_configuration_V4_0.xsd");
+    const char* xsd =
+        "/data/local/tmp/audio_policy_configuration_" STRINGIFY(AUDIO_HAL_VERSION) ".xsd";
+    EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS("audio_policy_configuration.xml", locations, xsd);
 }
diff --git a/audio/effect/2.0/vts/functional/Android.bp b/audio/effect/2.0/vts/functional/Android.bp
index f3fefc3..38ca315 100644
--- a/audio/effect/2.0/vts/functional/Android.bp
+++ b/audio/effect/2.0/vts/functional/Android.bp
@@ -32,5 +32,8 @@
         "libicuuc_stubdata",
         "libxml2",
     ],
+    header_libs: [
+        "android.hardware.audio.common.util@all-versions",
+    ],
     test_suites: ["general-tests"],
 }
diff --git a/audio/effect/2.0/vts/functional/ValidateAudioEffectsConfiguration.cpp b/audio/effect/2.0/vts/functional/ValidateAudioEffectsConfiguration.cpp
index bf080d3..040c93f 100644
--- a/audio/effect/2.0/vts/functional/ValidateAudioEffectsConfiguration.cpp
+++ b/audio/effect/2.0/vts/functional/ValidateAudioEffectsConfiguration.cpp
@@ -21,12 +21,19 @@
 
 #include "utility/ValidateXml.h"
 
+// Stringify the argument.
+#define QUOTE(x) #x
+#define STRINGIFY(x) QUOTE(x)
+
+#define AUDIO_HAL_VERSION V2_0
+
 TEST(CheckConfig, audioEffectsConfigurationValidation) {
     RecordProperty("description",
                    "Verify that the effects configuration file is valid according to the schema");
     using namespace android::effectsConfig;
 
     std::vector<const char*> locations(std::begin(DEFAULT_LOCATIONS), std::end(DEFAULT_LOCATIONS));
-    EXPECT_VALID_XML_MULTIPLE_LOCATIONS(DEFAULT_NAME, locations,
-                                        "/data/local/tmp/audio_effects_conf_V2_0.xsd");
+    const char* xsd = "/data/local/tmp/audio_effects_conf_" STRINGIFY(AUDIO_HAL_VERSION) ".xsd";
+    // In V2, audio effect XML is not required. .conf is still allowed though deprecated
+    EXPECT_VALID_XML_MULTIPLE_LOCATIONS(DEFAULT_NAME, locations, xsd);
 }
diff --git a/audio/effect/2.0/vts/functional/VtsHalAudioEffectTargetTest.cpp b/audio/effect/2.0/vts/functional/VtsHalAudioEffectTargetTest.cpp
index ea755ae..078e420 100644
--- a/audio/effect/2.0/vts/functional/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/effect/2.0/vts/functional/VtsHalAudioEffectTargetTest.cpp
@@ -26,6 +26,8 @@
 #include <android/hidl/allocator/1.0/IAllocator.h>
 #include <android/hidl/memory/1.0/IMemory.h>
 
+#include <common/all-versions/VersionUtils.h>
+
 #include <VtsHalHidlTargetTestBase.h>
 #include <VtsHalHidlTargetTestEnvBase.h>
 
@@ -37,6 +39,7 @@
 using android::hardware::MQDescriptorSync;
 using android::hardware::Return;
 using android::hardware::Void;
+using android::hardware::audio::common::utils::mkEnumBitfield;
 using android::hardware::audio::common::V2_0::AudioDevice;
 using android::hardware::audio::common::V2_0::AudioHandleConsts;
 using android::hardware::audio::common::V2_0::AudioMode;
@@ -396,7 +399,7 @@
 
 TEST_F(AudioEffectHidlTest, SetDevice) {
     description("Verify that SetDevice works for an output chain effect");
-    Return<Result> ret = effect->setDevice(AudioDevice::OUT_SPEAKER);
+    Return<Result> ret = effect->setDevice(mkEnumBitfield(AudioDevice::OUT_SPEAKER));
     EXPECT_TRUE(ret.isOk());
     EXPECT_EQ(Result::OK, ret);
 }
@@ -446,7 +449,7 @@
 
 TEST_F(AudioEffectHidlTest, SetInputDevice) {
     description("Verify that SetInputDevice does not crash");
-    Return<Result> ret = effect->setInputDevice(AudioDevice::IN_BUILTIN_MIC);
+    Return<Result> ret = effect->setInputDevice(mkEnumBitfield(AudioDevice::IN_BUILTIN_MIC));
     EXPECT_TRUE(ret.isOk());
 }
 
diff --git a/audio/effect/4.0/vts/functional/ValidateAudioEffectsConfiguration.cpp b/audio/effect/4.0/vts/functional/ValidateAudioEffectsConfiguration.cpp
index 6338563..2e94143 100644
--- a/audio/effect/4.0/vts/functional/ValidateAudioEffectsConfiguration.cpp
+++ b/audio/effect/4.0/vts/functional/ValidateAudioEffectsConfiguration.cpp
@@ -21,12 +21,19 @@
 
 #include "utility/ValidateXml.h"
 
+// Stringify the argument.
+#define QUOTE(x) #x
+#define STRINGIFY(x) QUOTE(x)
+
+#define AUDIO_HAL_VERSION V4_0
+
 TEST(CheckConfig, audioEffectsConfigurationValidation) {
     RecordProperty("description",
                    "Verify that the effects configuration file is valid according to the schema");
     using namespace android::effectsConfig;
 
     std::vector<const char*> locations(std::begin(DEFAULT_LOCATIONS), std::end(DEFAULT_LOCATIONS));
-    EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS(DEFAULT_NAME, locations,
-                                            "/data/local/tmp/audio_effects_conf_V4_0.xsd");
+    const char* xsd = "/data/local/tmp/audio_effects_conf_" STRINGIFY(AUDIO_HAL_VERSION) ".xsd";
+    // Starting with V4, audio effect XML is required
+    EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS(DEFAULT_NAME, locations, xsd);
 }
diff --git a/audio/effect/4.0/vts/functional/VtsHalAudioEffectTargetTest.cpp b/audio/effect/4.0/vts/functional/VtsHalAudioEffectTargetTest.cpp
index 5c10c69..96b8602 100644
--- a/audio/effect/4.0/vts/functional/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/effect/4.0/vts/functional/VtsHalAudioEffectTargetTest.cpp
@@ -39,7 +39,7 @@
 using android::hardware::MQDescriptorSync;
 using android::hardware::Return;
 using android::hardware::Void;
-using android::hardware::audio::common::utils::mkBitfield;
+using android::hardware::audio::common::utils::mkEnumBitfield;
 using android::hardware::audio::common::V4_0::AudioDevice;
 using android::hardware::audio::common::V4_0::AudioHandleConsts;
 using android::hardware::audio::common::V4_0::AudioMode;
@@ -399,7 +399,7 @@
 
 TEST_F(AudioEffectHidlTest, SetDevice) {
     description("Verify that SetDevice works for an output chain effect");
-    Return<Result> ret = effect->setDevice(mkBitfield(AudioDevice::OUT_SPEAKER));
+    Return<Result> ret = effect->setDevice(mkEnumBitfield(AudioDevice::OUT_SPEAKER));
     EXPECT_TRUE(ret.isOk());
     EXPECT_EQ(Result::OK, ret);
 }
@@ -449,7 +449,7 @@
 
 TEST_F(AudioEffectHidlTest, SetInputDevice) {
     description("Verify that SetInputDevice does not crash");
-    Return<Result> ret = effect->setInputDevice(mkBitfield(AudioDevice::IN_BUILTIN_MIC));
+    Return<Result> ret = effect->setInputDevice(mkEnumBitfield(AudioDevice::IN_BUILTIN_MIC));
     EXPECT_TRUE(ret.isOk());
 }
 
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/Conversions.impl.h b/audio/effect/all-versions/default/include/effect/all-versions/default/Conversions.impl.h
index de67d89..0884d8f 100644
--- a/audio/effect/all-versions/default/include/effect/all-versions/default/Conversions.impl.h
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/Conversions.impl.h
@@ -22,7 +22,7 @@
 #include <common/all-versions/VersionUtils.h>
 
 using ::android::hardware::audio::common::AUDIO_HAL_VERSION::HidlUtils;
-using ::android::hardware::audio::common::utils::mkEnumConverter;
+using ::android::hardware::audio::common::utils::EnumBitfield;
 
 namespace android {
 namespace hardware {
@@ -35,7 +35,7 @@
                              EffectDescriptor* descriptor) {
     HidlUtils::uuidFromHal(halDescriptor.type, &descriptor->type);
     HidlUtils::uuidFromHal(halDescriptor.uuid, &descriptor->uuid);
-    descriptor->flags = mkEnumConverter<EffectFlags>(halDescriptor.flags);
+    descriptor->flags = EnumBitfield<EffectFlags>(halDescriptor.flags);
     descriptor->cpuLoad = halDescriptor.cpuLoad;
     descriptor->memoryUsage = halDescriptor.memoryUsage;
     memcpy(descriptor->name.data(), halDescriptor.name, descriptor->name.size());