audio: Parametrize core VTS tests am: ccd484bb80
am: 51a1ee3c24

Change-Id: I9acd77cca413c95ceea6538ae04206999b2243d5
diff --git a/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h b/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h
index 0e416f3..2b240ce 100644
--- a/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h
+++ b/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h
@@ -20,9 +20,6 @@
 #include <functional>
 #include <list>
 
-#include <VtsHalHidlTargetTestEnvBase.h>
-#include <gtest/gtest.h>
-
 namespace android {
 namespace hardware {
 namespace audio {
@@ -34,18 +31,20 @@
  * Avoid destroying static objects after main return.
  * Post main return destruction leads to incorrect gtest timing measurements as
  * well as harder debuging if anything goes wrong during destruction. */
-class Environment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
+class EnvironmentTearDown {
+  public:
     using TearDownFunc = std::function<void()>;
     void registerTearDown(TearDownFunc&& tearDown) { tearDowns.push_front(std::move(tearDown)); }
 
-   private:
-    void HidlTearDown() override {
+  protected:
+    void executeAllTearDowns() {
         // Call the tear downs in reverse order of insertion
         for (auto& tearDown : tearDowns) {
             tearDown();
         }
     }
+
+  private:
     std::list<TearDownFunc> tearDowns;
 };
 
diff --git a/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp
index 7906bf1..c189464 100644
--- a/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp
@@ -60,19 +60,20 @@
                "deconnection",
                testConnectedState(stream.get()))
 
-TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", ASSERT_IS_OK(device->getHwAvSync()));
+TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail",
+               ASSERT_IS_OK(getDevice()->getHwAvSync()));
 
-TEST_F(AudioPrimaryHidlTest, setMode) {
+TEST_P(AudioPrimaryHidlTest, setMode) {
     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));
-        ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(mode));
+        ASSERT_RESULT(Result::INVALID_ARGUMENTS, getDevice()->setMode(mode));
     }
     // Test valid values
     for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE,
                            AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) {
         SCOPED_TRACE("mode=" + toString(mode));
-        ASSERT_OK(device->setMode(mode));
+        ASSERT_OK(getDevice()->setMode(mode));
     }
 }
diff --git a/audio/core/all-versions/vts/functional/2.0/EnvironmentTearDown.h b/audio/core/all-versions/vts/functional/2.0/EnvironmentTearDown.h
new file mode 100644
index 0000000..6373e39
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/2.0/EnvironmentTearDown.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_CORE_2_0_ENVIRONMENT_TEARDOWN_H
+#define ANDROID_HARDWARE_AUDIO_CORE_2_0_ENVIRONMENT_TEARDOWN_H
+
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+
+#include "utility/EnvironmentTearDown.h"
+
+class Environment : public ::android::hardware::audio::common::test::utility::EnvironmentTearDown,
+                    public ::testing::VtsHalHidlTargetTestEnvBase {
+  private:
+    void HidlTearDown() override {
+        executeAllTearDowns();
+        VtsHalHidlTargetTestEnvBase::HidlTearDown();
+    }
+};
+
+#endif  // ANDROID_HARDWARE_AUDIO_CORE_2_0_ENVIRONMENT_TEARDOWN_H
diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
index 15be3bf..b8defb6 100644
--- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
@@ -16,25 +16,14 @@
 
 #include "AudioPrimaryHidlHalTest.h"
 
-static void waitForDeviceDestruction() {
-    // FIXME: there is no way to know when the remote IDevice is being destroyed
-    //        Binder does not support testing if an object is alive, thus
-    //        wait for 100ms to let the binder destruction propagates and
-    //        the remote device has the time to be destroyed.
-    //        flushCommand makes sure all local command are sent, thus should reduce
-    //        the latency between local and remote destruction.
-    IPCThreadState::self()->flushCommands();
-    usleep(100 * 1000);
-}
-
-TEST_F(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) {
+TEST_P(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) {
     doc::test("Calling openDevice(\"primary\") should return the primary device.");
     struct WaitExecutor {
-        ~WaitExecutor() { waitForDeviceDestruction(); }
+        ~WaitExecutor() { DeviceManager::waitForInstanceDestruction(); }
     } waitExecutor;  // Make sure we wait for the device destruction on exiting from the test.
     Result result;
     sp<IDevice> baseDevice;
-    ASSERT_OK(devicesFactory->openDevice("primary", returnIn(result, baseDevice)));
+    ASSERT_OK(getDevicesFactory()->openDevice("primary", returnIn(result, baseDevice)));
     if (result != Result::OK && isPrimaryDeviceOptional()) {
         GTEST_SKIP() << "No primary device on this factory";  // returns
     }
@@ -50,10 +39,10 @@
 /////////////////////////// get(Active)Microphones ///////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-TEST_F(AudioPrimaryHidlTest, GetMicrophonesTest) {
+TEST_P(AudioPrimaryHidlTest, GetMicrophonesTest) {
     doc::test("Make sure getMicrophones always succeeds");
     hidl_vec<MicrophoneInfo> microphones;
-    ASSERT_OK(device->getMicrophones(returnIn(res, microphones)));
+    ASSERT_OK(getDevice()->getMicrophones(returnIn(res, microphones)));
     ASSERT_OK(res);
     if (microphones.size() > 0) {
         // When there is microphone on the phone, try to open an input stream
@@ -75,15 +64,15 @@
             }
             sp<IStreamIn> stream;
             AudioConfig suggestedConfig{};
-            ASSERT_OK(device->openInputStream(ioHandle, microphone.deviceAddress, config, flags,
-                                              initMetadata,
-                                              returnIn(res, stream, suggestedConfig)));
+            ASSERT_OK(getDevice()->openInputStream(ioHandle, microphone.deviceAddress, config,
+                                                   flags, initMetadata,
+                                                   returnIn(res, stream, suggestedConfig)));
             if (res != Result::OK) {
                 ASSERT_TRUE(stream == nullptr);
                 AudioConfig suggestedConfigRetry{};
-                ASSERT_OK(device->openInputStream(ioHandle, microphone.deviceAddress,
-                                                  suggestedConfig, flags, initMetadata,
-                                                  returnIn(res, stream, suggestedConfigRetry)));
+                ASSERT_OK(getDevice()->openInputStream(
+                        ioHandle, microphone.deviceAddress, suggestedConfig, flags, initMetadata,
+                        returnIn(res, stream, suggestedConfigRetry)));
             }
             ASSERT_OK(res);
             hidl_vec<MicrophoneInfo> activeMicrophones;
@@ -131,7 +120,7 @@
     }
 }
 
-TEST_F(AudioPrimaryHidlTest, SetConnectedState) {
+TEST_P(AudioPrimaryHidlTest, SetConnectedState) {
     doc::test("Check that the HAL can be notified of device connection and deconnection");
     using AD = AudioDevice;
     for (auto deviceType : {AD::OUT_HDMI, AD::OUT_WIRED_HEADPHONE, AD::IN_USB_HEADSET}) {
@@ -140,7 +129,7 @@
             SCOPED_TRACE("state=" + ::testing::PrintToString(state));
             DeviceAddress address = {};
             address.device = deviceType;
-            auto ret = device->setConnectedState(address, state);
+            auto ret = getDevice()->setConnectedState(address, state);
             ASSERT_TRUE(ret.isOk());
             if (ret == Result::NOT_SUPPORTED) {
                 doc::partialTest("setConnectedState is not supported");
@@ -153,9 +142,7 @@
     // Because there is no way of knowing if the devices were connected before
     // calling setConnectedState, there is no way to restore the HAL to its
     // initial state. To workaround this, destroy the HAL at the end of this test.
-    device.clear();
-    waitForDeviceDestruction();
-    ASSERT_NO_FATAL_FAILURE(initPrimaryDevice());
+    ASSERT_TRUE(DeviceManager::getInstance().resetPrimary(getFactoryName()));
 }
 
 static void testGetDevices(IStream* stream, AudioDevice expectedDevice) {
@@ -199,7 +186,7 @@
     }
     ASSERT_OK(res);
 }
-TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", checkGetHwAVSync(device.get()));
+TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", checkGetHwAVSync(getDevice().get()));
 
 TEST_P(InputStreamTest, updateSinkMetadata) {
     doc::test("The HAL should not crash on metadata change");
@@ -259,58 +246,58 @@
     ASSERT_OK(stream->updateSourceMetadata(initMetadata));
 }
 
-TEST_F(AudioPrimaryHidlTest, setMode) {
+TEST_P(AudioPrimaryHidlTest, setMode) {
     doc::test("Make sure setMode always succeeds if mode is valid and fails otherwise");
     // Test Invalid values
     for (int mode : {-2, -1, int(AudioMode::IN_COMMUNICATION) + 1}) {
-        ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(AudioMode(mode)))
-            << "mode=" << mode;
+        ASSERT_RESULT(Result::INVALID_ARGUMENTS, getDevice()->setMode(AudioMode(mode)))
+                << "mode=" << mode;
     }
     // Test valid values
     for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE,
                            AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) {
-        ASSERT_OK(device->setMode(mode)) << "mode=" << toString(mode);
+        ASSERT_OK(getDevice()->setMode(mode)) << "mode=" << toString(mode);
     }
 }
 
-TEST_F(AudioPrimaryHidlTest, setBtHfpSampleRate) {
+TEST_P(AudioPrimaryHidlTest, setBtHfpSampleRate) {
     doc::test(
         "Make sure setBtHfpSampleRate either succeeds or "
         "indicates that it is not supported at all, or that the provided value is invalid");
     for (auto samplingRate : {8000, 16000, 22050, 24000}) {
-        ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, device->setBtHfpSampleRate(samplingRate));
+        ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, getDevice()->setBtHfpSampleRate(samplingRate));
     }
 }
 
-TEST_F(AudioPrimaryHidlTest, setBtHfpVolume) {
+TEST_P(AudioPrimaryHidlTest, setBtHfpVolume) {
     doc::test(
         "Make sure setBtHfpVolume is either not supported or "
         "only succeed if volume is in [0,1]");
-    auto ret = device->setBtHfpVolume(0.0);
+    auto ret = getDevice()->setBtHfpVolume(0.0);
     ASSERT_TRUE(ret.isOk());
     if (ret == Result::NOT_SUPPORTED) {
         doc::partialTest("setBtHfpVolume is not supported");
         return;
     }
-    testUnitaryGain([](float volume) { return device->setBtHfpVolume(volume); });
+    testUnitaryGain([this](float volume) { return getDevice()->setBtHfpVolume(volume); });
 }
 
-TEST_F(AudioPrimaryHidlTest, setBtScoHeadsetDebugName) {
+TEST_P(AudioPrimaryHidlTest, setBtScoHeadsetDebugName) {
     doc::test(
         "Make sure setBtScoHeadsetDebugName either succeeds or "
         "indicates that it is not supported");
-    ASSERT_RESULT(okOrNotSupported, device->setBtScoHeadsetDebugName("test"));
+    ASSERT_RESULT(okOrNotSupported, getDevice()->setBtScoHeadsetDebugName("test"));
 }
 
-TEST_F(AudioPrimaryHidlTest, updateRotation) {
+TEST_P(AudioPrimaryHidlTest, updateRotation) {
     doc::test("Check that the hal can receive the current rotation");
     for (Rotation rotation : {Rotation::DEG_0, Rotation::DEG_90, Rotation::DEG_180,
                               Rotation::DEG_270, Rotation::DEG_0}) {
-        ASSERT_RESULT(okOrNotSupported, device->updateRotation(rotation));
+        ASSERT_RESULT(okOrNotSupported, getDevice()->updateRotation(rotation));
     }
 }
 
-TEST_F(BoolAccessorPrimaryHidlTest, setGetBtHfpEnabled) {
+TEST_P(BoolAccessorPrimaryHidlTest, setGetBtHfpEnabled) {
     doc::test("Query and set the BT HFP state");
     testAccessors<OPTIONAL>("BtHfpEnabled", Initial{false, OPTIONAL}, {true},
                             &IPrimaryDevice::setBtHfpEnabled, &IPrimaryDevice::getBtHfpEnabled);
diff --git a/audio/core/all-versions/vts/functional/6.0/EnvironmentTearDown.h b/audio/core/all-versions/vts/functional/6.0/EnvironmentTearDown.h
new file mode 100644
index 0000000..593759f
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/6.0/EnvironmentTearDown.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_CORE_6_0_ENVIRONMENT_TEARDOWN_H
+#define ANDROID_HARDWARE_AUDIO_CORE_6_0_ENVIRONMENT_TEARDOWN_H
+
+#include <gtest/gtest.h>
+
+#include "utility/EnvironmentTearDown.h"
+
+class Environment : public ::android::hardware::audio::common::test::utility::EnvironmentTearDown,
+                    public ::testing::Environment {
+  public:
+    void init(int* /*argc*/, char** /*argv*/) {}  // emulate VtsHalHidlTargetTestEnvBase
+  private:
+    void TearDown() override { executeAllTearDowns(); }
+};
+
+// FIXME: Will be removed while making getDeviceParameters to use the config
+static constexpr const char* kDefaultServiceName = "default";
+
+#endif  // ANDROID_HARDWARE_AUDIO_CORE_6_0_ENVIRONMENT_TEARDOWN_H
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index 6c51c1b..e59ab98 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -23,6 +23,7 @@
 #include <initializer_list>
 #include <limits>
 #include <list>
+#include <map>
 #include <string>
 #include <vector>
 
@@ -31,7 +32,9 @@
 
 #include <hwbinder/IPCThreadState.h>
 
+#if MAJOR_VERSION <= 5
 #include <VtsHalHidlTargetTestBase.h>
+#endif
 
 #include <android-base/logging.h>
 
@@ -44,16 +47,25 @@
 #include <Serializer.h>
 #include <fmq/EventFlag.h>
 #include <fmq/MessageQueue.h>
+#if MAJOR_VERSION >= 6
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#endif
 
 #include <common/all-versions/VersionUtils.h>
 
 #include "utility/AssertOk.h"
 #include "utility/Documentation.h"
-#include "utility/EnvironmentTearDown.h"
 #include "utility/PrettyPrintAudioTypes.h"
 #include "utility/ReturnIn.h"
 #include "utility/ValidateXml.h"
 
+#if MAJOR_VERSION <= 5
+#include "2.0/EnvironmentTearDown.h"
+#elif MAJOR_VERSION >= 6
+#include "6.0/EnvironmentTearDown.h"
+#endif
+
 /** Provide version specific functions that are used in the generic tests */
 #if MAJOR_VERSION == 2
 #include "2.0/AudioPrimaryHidlHalUtils.h"
@@ -105,14 +117,23 @@
 
 class AudioHidlTestEnvironment : public ::Environment {
    public:
-    virtual void registerTestServices() override { registerTestService<IDevicesFactory>(); }
+#if MAJOR_VERSION <= 5
+     void registerTestServices() override { registerTestService<IDevicesFactory>(); }
+#endif
 };
 
 // Instance to register global tearDown
 static AudioHidlTestEnvironment* environment;
 
+#define AUDIO_PRIMARY_HIDL_HAL_TEST
+#include "DeviceManager.h"
+
+#if MAJOR_VERSION <= 5
 class HidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   protected:
+#elif MAJOR_VERSION >= 6
+class HidlTest : public ::testing::Test {
+#endif
+  protected:
     // Convenient member to store results
     Result res;
 };
@@ -201,6 +222,21 @@
         ASSERT_TRUE(mPrimaryConfig) << "Could not find primary module in configuration file: "
                                     << policyConfig.getFilePath();
     }
+
+  protected:
+    sp<IDevicesFactory> getDevicesFactory(const std::string& factoryName) const {
+        return DevicesFactoryManager::getInstance().get(factoryName);
+    }
+
+    sp<IPrimaryDevice> getPrimaryDevice(const std::string& factoryName) const {
+        return DeviceManager::getInstance().getPrimary(factoryName);
+    }
+
+    bool isPrimaryDeviceOptional(const std::string& factoryName) const {
+        // It's OK not to have "primary" device on non-default audio HAL service.
+        return factoryName != kDefaultServiceName;
+    }
+
     sp<const HwModule> mPrimaryConfig = nullptr;
 };
 
@@ -209,41 +245,85 @@
 }
 
 //////////////////////////////////////////////////////////////////////////////
+//////////////////// Test parameter types and definitions ////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+enum { PARAM_FACTORY_NAME, PARAM_DEVICE_NAME };
+using DeviceParameter = std::tuple<std::string, std::string>;
+
+static inline std::string DeviceParameterToString(
+        const ::testing::TestParamInfo<DeviceParameter>& info) {
+#if MAJOR_VERSION <= 5
+    return std::get<PARAM_DEVICE_NAME>(info.param);
+#elif MAJOR_VERSION >= 6
+    const auto factoryName =
+            ::android::hardware::PrintInstanceNameToString(::testing::TestParamInfo<std::string>{
+                    std::get<PARAM_FACTORY_NAME>(info.param), info.index});
+    const auto& deviceName = std::get<PARAM_DEVICE_NAME>(info.param);
+    return !deviceName.empty() ? factoryName + "_" + deviceName : factoryName;
+#endif
+}
+
+#if MAJOR_VERSION <= 5
+// For V2..5 the factory is looked up using the instance name passed
+// in the environment, only one factory is returned. This is because the VTS
+// framework will call the test for each instance. Only the primary device of
+// the factory specified in the environment is tested.
+const std::vector<DeviceParameter>& getDeviceParameters() {
+    static std::vector<DeviceParameter> parameters = {
+            {environment->getServiceName<IDevicesFactory>(), DeviceManager::kPrimaryDevice}};
+    return parameters;
+}
+#elif MAJOR_VERSION >= 6
+// FIXME: Will be replaced with code that analyzes the audio policy config file.
+const std::vector<DeviceParameter>& getDeviceParameters() {
+    static std::vector<DeviceParameter> parameters = [] {
+        const auto instances =
+                ::android::hardware::getAllHalInstanceNames(IDevicesFactory::descriptor);
+        std::vector<DeviceParameter> result;
+        result.reserve(instances.size());
+        for (const auto& instance : instances) {
+            result.emplace_back(instance, DeviceManager::kPrimaryDevice);
+        }
+        return result;
+    }();
+    return parameters;
+}
+#endif
+
+class AudioHidlTestWithDeviceParameter : public AudioPolicyConfigTest,
+                                         public ::testing::WithParamInterface<DeviceParameter> {
+  protected:
+    const std::string& getFactoryName() const { return std::get<PARAM_FACTORY_NAME>(GetParam()); }
+    bool isPrimaryDeviceOptional() const {
+        return AudioPolicyConfigTest::isPrimaryDeviceOptional(getFactoryName());
+    }
+    sp<IDevicesFactory> getDevicesFactory() const {
+        return AudioPolicyConfigTest::getDevicesFactory(getFactoryName());
+    }
+    sp<IPrimaryDevice> getPrimaryDevice() const {
+        return AudioPolicyConfigTest::getPrimaryDevice(getFactoryName());
+    }
+};
+
+//////////////////////////////////////////////////////////////////////////////
 ////////////////////// getService audio_devices_factory //////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
 // Test all audio devices
-class AudioHidlTest : public AudioPolicyConfigTest {
-   public:
-     static void SetUpTestSuite() {
-         devicesFactory = ::testing::VtsHalHidlTargetTestBase::getService<IDevicesFactory>(
-                 environment->getServiceName<IDevicesFactory>());
-     }
-
-     static void TearDownTestSuite() { devicesFactory.clear(); }
-
-     void SetUp() override {
-         ASSERT_NO_FATAL_FAILURE(AudioPolicyConfigTest::SetUp());  // setup base
-         // Failures during SetUpTestSuite do not cause test termination.
-         ASSERT_TRUE(devicesFactory != nullptr);
-     }
-
-   protected:
-    // Cache the devicesFactory retrieval to speed up each test by ~0.5s
-    static sp<IDevicesFactory> devicesFactory;
-
-    static bool isPrimaryDeviceOptional() {
-        // It's OK not to have "primary" device on non-default audio HAL service.
-        return environment->getServiceName<IDevicesFactory>() != kDefaultServiceName;
+class AudioHidlTest : public AudioHidlTestWithDeviceParameter {
+  public:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(AudioHidlTestWithDeviceParameter::SetUp());  // setup base
+        ASSERT_TRUE(getDevicesFactory() != nullptr);
     }
 };
-sp<IDevicesFactory> AudioHidlTest::devicesFactory;
 
-TEST_F(AudioHidlTest, GetAudioDevicesFactoryService) {
+TEST_P(AudioHidlTest, GetAudioDevicesFactoryService) {
     doc::test("Test the getService");
 }
 
-TEST_F(AudioHidlTest, OpenDeviceInvalidParameter) {
+TEST_P(AudioHidlTest, OpenDeviceInvalidParameter) {
     doc::test("Test passing an invalid parameter to openDevice");
     Result result;
     sp<IDevice> device;
@@ -252,11 +332,14 @@
 #elif MAJOR_VERSION >= 4
     auto invalidDevice = "Non existing device";
 #endif
-    ASSERT_OK(devicesFactory->openDevice(invalidDevice, returnIn(result, device)));
+    ASSERT_OK(getDevicesFactory()->openDevice(invalidDevice, returnIn(result, device)));
     ASSERT_EQ(Result::INVALID_ARGUMENTS, result);
     ASSERT_TRUE(device == nullptr);
 }
 
+INSTANTIATE_TEST_CASE_P(AudioHidl, AudioHidlTest, ::testing::ValuesIn(getDeviceParameters()),
+                        &DeviceParameterToString);
+
 //////////////////////////////////////////////////////////////////////////////
 /////////////////////////////// openDevice primary ///////////////////////////
 //////////////////////////////////////////////////////////////////////////////
@@ -264,57 +347,30 @@
 // Test the primary device
 class AudioPrimaryHidlTest : public AudioHidlTest {
    public:
-     static void SetUpTestSuite() {
-         ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUpTestSuite());
-         ASSERT_NO_FATAL_FAILURE(initPrimaryDevice());
-     }
-
-     static void TearDownTestSuite() {
-         device.clear();
-         AudioHidlTest::TearDownTestSuite();
-     }
-
     void SetUp() override {
         ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp());  // setup base
-        if (device == nullptr && isPrimaryDeviceOptional()) {
+        if (getDevice() == nullptr && isPrimaryDeviceOptional()) {
             GTEST_SKIP() << "No primary device on this factory";
         }
-        ASSERT_TRUE(device != nullptr);
+        ASSERT_TRUE(getDevice() != nullptr);
     }
 
    protected:
-    // Cache the device opening to speed up each test by ~0.5s
-    static sp<IPrimaryDevice> device;
-
-    static void initPrimaryDevice() {
-        // Failures during test suite set up do not cause test termination.
-        ASSERT_TRUE(devicesFactory != nullptr);
-        Result result;
-#if MAJOR_VERSION == 2
-        sp<IDevice> baseDevice;
-        ASSERT_OK(devicesFactory->openDevice(IDevicesFactory::Device::PRIMARY,
-                                             returnIn(result, baseDevice)));
-        ASSERT_OK(result);
-        ASSERT_TRUE(baseDevice != nullptr);
-
-        device = IPrimaryDevice::castFrom(baseDevice);
-#elif MAJOR_VERSION >= 4
-        ASSERT_OK(devicesFactory->openPrimaryDevice(returnIn(result, device)));
-        ASSERT_OK(result);
-#endif
-    }
+     sp<IPrimaryDevice> getDevice() const { return getPrimaryDevice(); }
 };
-sp<IPrimaryDevice> AudioPrimaryHidlTest::device;
 
-TEST_F(AudioPrimaryHidlTest, OpenPrimaryDevice) {
+TEST_P(AudioPrimaryHidlTest, OpenPrimaryDevice) {
     doc::test("Test the openDevice (called during setup)");
 }
 
-TEST_F(AudioPrimaryHidlTest, Init) {
+TEST_P(AudioPrimaryHidlTest, Init) {
     doc::test("Test that the audio primary hal initialized correctly");
-    ASSERT_OK(device->initCheck());
+    ASSERT_OK(getDevice()->initCheck());
 }
 
+INSTANTIATE_TEST_CASE_P(AudioPrimaryHidl, AudioPrimaryHidlTest,
+                        ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
+
 //////////////////////////////////////////////////////////////////////////////
 ///////////////////// {set,get}{Master,Mic}{Mute,Volume} /////////////////////
 //////////////////////////////////////////////////////////////////////////////
@@ -339,7 +395,7 @@
                                       optionality == OPTIONAL ? Result::NOT_SUPPORTED : Result::OK};
 
         Property initialValue = expectedInitial.value;
-        ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue)));
+        ASSERT_OK((getDevice().get()->*getter)(returnIn(res, initialValue)));
         ASSERT_RESULT(expectedResults, res);
         if (res == Result::OK && expectedInitial.check == REQUIRED) {
             EXPECT_EQ(expectedInitial.value, initialValue);
@@ -350,7 +406,7 @@
         for (Property setValue : valuesToTest) {
             SCOPED_TRACE("Test " + propertyName + " getter and setter for " +
                          testing::PrintToString(setValue));
-            auto ret = (device.get()->*setter)(setValue);
+            auto ret = (getDevice().get()->*setter)(setValue);
             ASSERT_RESULT(expectedResults, ret);
             if (ret == Result::NOT_SUPPORTED) {
                 doc::partialTest(propertyName + " setter is not supported");
@@ -358,7 +414,7 @@
             }
             Property getValue;
             // Make sure the getter returns the same value just set
-            ASSERT_OK((device.get()->*getter)(returnIn(res, getValue)));
+            ASSERT_OK((getDevice().get()->*getter)(returnIn(res, getValue)));
             ASSERT_RESULT(expectedResults, res);
             if (res == Result::NOT_SUPPORTED) {
                 doc::partialTest(propertyName + " getter is not supported");
@@ -370,31 +426,34 @@
         for (Property invalidValue : invalidValues) {
             SCOPED_TRACE("Try to set " + propertyName + " with the invalid value " +
                          testing::PrintToString(invalidValue));
-            EXPECT_RESULT(invalidArgsOrNotSupported, (device.get()->*setter)(invalidValue));
+            EXPECT_RESULT(invalidArgsOrNotSupported, (getDevice().get()->*setter)(invalidValue));
         }
 
         // Restore initial value
-        EXPECT_RESULT(expectedResults, (device.get()->*setter)(initialValue));
+        EXPECT_RESULT(expectedResults, (getDevice().get()->*setter)(initialValue));
     }
 };
 
 using BoolAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<bool>;
 
-TEST_F(BoolAccessorPrimaryHidlTest, MicMuteTest) {
+TEST_P(BoolAccessorPrimaryHidlTest, MicMuteTest) {
     doc::test("Check that the mic can be muted and unmuted");
     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) {
+TEST_P(BoolAccessorPrimaryHidlTest, MasterMuteTest) {
     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
 }
 
+INSTANTIATE_TEST_CASE_P(BoolAccessorPrimaryHidl, BoolAccessorPrimaryHidlTest,
+                        ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
+
 using FloatAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<float>;
-TEST_F(FloatAccessorPrimaryHidlTest, MasterVolumeTest) {
+TEST_P(FloatAccessorPrimaryHidlTest, MasterVolumeTest) {
     doc::test("Test the master volume if supported");
     testAccessors<OPTIONAL>(
         "master volume", Initial{1}, {0, 0.5}, &IDevice::setMasterVolume, &IDevice::getMasterVolume,
@@ -402,16 +461,19 @@
     // TODO: check that the master volume is really changed
 }
 
+INSTANTIATE_TEST_CASE_P(FloatAccessorPrimaryHidl, FloatAccessorPrimaryHidlTest,
+                        ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
+
 //////////////////////////////////////////////////////////////////////////////
 //////////////////////////////// AudioPatches ////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
 class AudioPatchPrimaryHidlTest : public AudioPrimaryHidlTest {
    protected:
-     bool areAudioPatchesSupported() { return extract(device->supportsAudioPatches()); }
+     bool areAudioPatchesSupported() { return extract(getDevice()->supportsAudioPatches()); }
 };
 
-TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) {
+TEST_P(AudioPatchPrimaryHidlTest, AudioPatches) {
     doc::test("Test if audio patches are supported");
     if (!areAudioPatchesSupported()) {
         doc::partialTest("Audio patches are not supported");
@@ -420,6 +482,9 @@
     // TODO: test audio patches
 }
 
+INSTANTIATE_TEST_CASE_P(AudioPatchPrimaryHidl, AudioPatchPrimaryHidlTest,
+                        ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
+
 //////////////////////////////////////////////////////////////////////////////
 //////////////// Required and recommended audio format support ///////////////
 // From:
@@ -429,8 +494,7 @@
 /////////// TODO: move to the beginning of the file for easier update ////////
 //////////////////////////////////////////////////////////////////////////////
 
-class AudioConfigPrimaryTest : public AudioPatchPrimaryHidlTest {
-   public:
+struct ConfigHelper {
     // for retro compatibility only test the primary device IN_BUILTIN_MIC
     // FIXME: in the next audio HAL version, test all available devices
     static bool primaryHasMic() {
@@ -502,21 +566,51 @@
     }
 };
 
+// Nesting a tuple in another tuple allows to use GTest Combine function to generate
+// all combinations of devices and configs.
+enum { PARAM_DEVICE, PARAM_CONFIG };
+using DeviceConfigParameter = std::tuple<DeviceParameter, AudioConfig>;
+
 /** Generate a test name based on an audio config.
  *
  * As the only parameter changing are channel mask and sample rate,
  * only print those ones in the test name.
  */
-static string generateTestName(const testing::TestParamInfo<AudioConfig>& info) {
-    const AudioConfig& config = info.param;
-    return to_string(info.index) + "__" + to_string(config.sampleRateHz) + "_" +
+static string DeviceConfigParameterToString(
+        const testing::TestParamInfo<DeviceConfigParameter>& info) {
+    const AudioConfig& config = std::get<PARAM_CONFIG>(info.param);
+    const auto deviceName = DeviceParameterToString(::testing::TestParamInfo<DeviceParameter>{
+            std::get<PARAM_DEVICE>(info.param), info.index});
+    return (deviceName.empty() ? "" : deviceName + "_") + to_string(info.index) + "__" +
+           to_string(config.sampleRateHz) + "_" +
            // "MONO" is more clear than "FRONT_LEFT"
            ((config.channelMask == mkEnumBitfield(AudioChannelMask::OUT_MONO) ||
              config.channelMask == mkEnumBitfield(AudioChannelMask::IN_MONO))
-                ? "MONO"
-                : ::testing::PrintToString(config.channelMask));
+                    ? "MONO"
+                    : ::testing::PrintToString(config.channelMask));
 }
 
+class AudioHidlTestWithDeviceConfigParameter
+    : public AudioPolicyConfigTest,
+      public ::testing::WithParamInterface<DeviceConfigParameter> {
+  protected:
+    const std::string& getFactoryName() const {
+        return std::get<PARAM_FACTORY_NAME>(std::get<PARAM_DEVICE>(GetParam()));
+    }
+    bool isPrimaryDeviceOptional() const {
+        return AudioPolicyConfigTest::isPrimaryDeviceOptional(getFactoryName());
+    }
+    sp<IDevicesFactory> getDevicesFactory() const {
+        return AudioPolicyConfigTest::getDevicesFactory(getFactoryName());
+    }
+    sp<IPrimaryDevice> getPrimaryDevice() const {
+        return AudioPolicyConfigTest::getPrimaryDevice(getFactoryName());
+    }
+    const AudioConfig& getConfig() const { return std::get<PARAM_CONFIG>(GetParam()); }
+    // FIXME: Split out tests that don't require primary device
+    sp<IPrimaryDevice> getDevice() const { return getPrimaryDevice(); }
+};
+
 //////////////////////////////////////////////////////////////////////////////
 ///////////////////////////// getInputBufferSize /////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
@@ -525,12 +619,21 @@
 // android.hardware.microphone
 //        how to get this value ? is it a property ???
 
-class AudioCaptureConfigPrimaryTest : public AudioConfigPrimaryTest,
-                                      public ::testing::WithParamInterface<AudioConfig> {
-   protected:
+class AudioCaptureConfigPrimaryTest : public AudioHidlTestWithDeviceConfigParameter {
+  public:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(AudioHidlTestWithDeviceConfigParameter::SetUp());  // setup base
+        ASSERT_TRUE(getDevicesFactory() != nullptr);
+        if (getDevice() == nullptr && isPrimaryDeviceOptional()) {
+            GTEST_SKIP() << "No primary device on this factory";
+        }
+        ASSERT_TRUE(getDevice() != nullptr);
+    }
+
+  protected:
     void inputBufferSizeTest(const AudioConfig& audioConfig, bool supportRequired) {
         uint64_t bufferSize;
-        ASSERT_OK(device->getInputBufferSize(audioConfig, returnIn(res, bufferSize)));
+        ASSERT_OK(getDevice()->getInputBufferSize(audioConfig, returnIn(res, bufferSize)));
 
         switch (res) {
             case Result::INVALID_ARGUMENTS:
@@ -554,16 +657,19 @@
     doc::test(
         "Input buffer size must be retrievable for a format with required "
         "support.");
-    inputBufferSizeTest(GetParam(), true);
+    inputBufferSizeTest(getConfig(), true);
 }
 INSTANTIATE_TEST_CASE_P(
-    RequiredInputBufferSize, RequiredInputBufferSizeTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()),
-    &generateTestName);
+        RequiredInputBufferSize, RequiredInputBufferSizeTest,
+        ::testing::Combine(
+                ::testing::ValuesIn(getDeviceParameters()),
+                ::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig())),
+        &DeviceConfigParameterToString);
 INSTANTIATE_TEST_CASE_P(
-    SupportedInputBufferSize, RequiredInputBufferSizeTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()),
-    &generateTestName);
+        SupportedInputBufferSize, RequiredInputBufferSizeTest,
+        ::testing::Combine(::testing::ValuesIn(getDeviceParameters()),
+                           ::testing::ValuesIn(ConfigHelper::getSupportedCaptureAudioConfig())),
+        &DeviceConfigParameterToString);
 
 // Test that the recommended capture config are supported or lead to a
 // INVALID_ARGUMENTS return
@@ -572,21 +678,23 @@
     doc::test(
         "Input buffer size should be retrievable for a format with recommended "
         "support.");
-    inputBufferSizeTest(GetParam(), false);
+    inputBufferSizeTest(getConfig(), false);
 }
 INSTANTIATE_TEST_CASE_P(
-    RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()),
-    &generateTestName);
+        RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest,
+        ::testing::Combine(
+                ::testing::ValuesIn(getDeviceParameters()),
+                ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig())),
+        &DeviceConfigParameterToString);
 
 //////////////////////////////////////////////////////////////////////////////
 /////////////////////////////// setScreenState ///////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-TEST_F(AudioPrimaryHidlTest, setScreenState) {
+TEST_P(AudioPrimaryHidlTest, setScreenState) {
     doc::test("Check that the hal can receive the screen state");
     for (bool turnedOn : {false, true, true, false, false}) {
-        ASSERT_RESULT(okOrNotSupported, device->setScreenState(turnedOn));
+        ASSERT_RESULT(okOrNotSupported, getDevice()->setScreenState(turnedOn));
     }
 }
 
@@ -594,15 +702,15 @@
 //////////////////////////// {get,set}Parameters /////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-TEST_F(AudioPrimaryHidlTest, getParameters) {
+TEST_P(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(Parameters::get(device, keys, returnIn(res, values)));
-    ASSERT_OK(Parameters::set(device, values));
+    ASSERT_OK(Parameters::get(getDevice(), keys, returnIn(res, values)));
+    ASSERT_OK(Parameters::set(getDevice(), values));
     values.resize(0);
-    ASSERT_OK(Parameters::set(device, values));
+    ASSERT_OK(Parameters::set(getDevice(), values));
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -643,14 +751,14 @@
     EXPECT_EQ(0, close(fds[1])) << errno;
 }
 
-TEST_F(AudioPrimaryHidlTest, DebugDump) {
+TEST_P(AudioPrimaryHidlTest, DebugDump) {
     doc::test("Check that the hal can dump its state without error");
-    testDebugDump([](const auto& handle) { return dump(device, handle); });
+    testDebugDump([this](const auto& handle) { return dump(getDevice(), handle); });
 }
 
-TEST_F(AudioPrimaryHidlTest, DebugDumpInvalidArguments) {
+TEST_P(AudioPrimaryHidlTest, DebugDumpInvalidArguments) {
     doc::test("Check that the hal dump doesn't crash on invalid arguments");
-    ASSERT_OK(dump(device, hidl_handle()));
+    ASSERT_OK(dump(getDevice(), hidl_handle()));
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -658,9 +766,17 @@
 //////////////////////////////////////////////////////////////////////////////
 
 template <class Stream>
-class OpenStreamTest : public AudioConfigPrimaryTest,
-                       public ::testing::WithParamInterface<AudioConfig> {
-   protected:
+class OpenStreamTest : public AudioHidlTestWithDeviceConfigParameter {
+  protected:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(AudioHidlTestWithDeviceConfigParameter::SetUp());  // setup base
+        ASSERT_TRUE(getDevicesFactory() != nullptr);
+        if (getDevice() == nullptr && isPrimaryDeviceOptional()) {
+            GTEST_SKIP() << "No primary device on this factory";
+        }
+        ASSERT_TRUE(getDevice() != nullptr);
+    }
+
     template <class Open>
     void testOpen(Open openStream, const AudioConfig& config) {
         // FIXME: Open a stream without an IOHandle
@@ -701,7 +817,7 @@
         return res;
     }
 
-    void waitForStreamDestruction() {
+    static void waitForStreamDestruction() {
         // FIXME: there is no way to know when the remote IStream is being destroyed
         //        Binder does not support testing if an object is alive, thus
         //        wait for 100ms to let the binder destruction propagates and
@@ -712,12 +828,14 @@
         usleep(100 * 1000);
     }
 
-   private:
+    bool areAudioPatchesSupported() { return extract(getDevice()->supportsAudioPatches()); }
+
+  private:
     void TearDown() override {
         if (open) {
             ASSERT_OK(closeStream());
         }
-        AudioConfigPrimaryTest::TearDown();
+        AudioPolicyConfigTest::TearDown();
     }
 
    protected:
@@ -734,18 +852,19 @@
         ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp());  // setup base
         if (IsSkipped()) return;                           // do not attempt to use 'device'
         address.device = AudioDevice::OUT_DEFAULT;
-        const AudioConfig& config = GetParam();
+        const AudioConfig& config = getConfig();
         // TODO: test all flag combination
         auto flags = mkEnumBitfield(AudioOutputFlag::NONE);
         testOpen(
-            [&](AudioIoHandle handle, AudioConfig config, auto cb) {
+                [&](AudioIoHandle handle, AudioConfig config, auto cb) {
 #if MAJOR_VERSION == 2
-                return device->openOutputStream(handle, address, config, flags, cb);
+                    return getDevice()->openOutputStream(handle, address, config, flags, cb);
 #elif MAJOR_VERSION >= 4
-                return device->openOutputStream(handle, address, config, flags, initMetadata, cb);
+                    return getDevice()->openOutputStream(handle, address, config, flags,
+                                                         initMetadata, cb);
 #endif
-            },
-            config);
+                },
+                config);
     }
 #if MAJOR_VERSION >= 4
 
@@ -763,18 +882,23 @@
     // Open done in SetUp
 }
 INSTANTIATE_TEST_CASE_P(
-    RequiredOutputStreamConfigSupport, OutputStreamTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportPlaybackAudioConfig()),
-    &generateTestName);
+        RequiredOutputStreamConfigSupport, OutputStreamTest,
+        ::testing::Combine(
+                ::testing::ValuesIn(getDeviceParameters()),
+                ::testing::ValuesIn(ConfigHelper::getRequiredSupportPlaybackAudioConfig())),
+        &DeviceConfigParameterToString);
 INSTANTIATE_TEST_CASE_P(
-    SupportedOutputStreamConfig, OutputStreamTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedPlaybackAudioConfig()),
-    &generateTestName);
+        SupportedOutputStreamConfig, OutputStreamTest,
+        ::testing::Combine(::testing::ValuesIn(getDeviceParameters()),
+                           ::testing::ValuesIn(ConfigHelper::getSupportedPlaybackAudioConfig())),
+        &DeviceConfigParameterToString);
 
 INSTANTIATE_TEST_CASE_P(
-    RecommendedOutputStreamConfigSupport, OutputStreamTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportPlaybackAudioConfig()),
-    &generateTestName);
+        RecommendedOutputStreamConfigSupport, OutputStreamTest,
+        ::testing::Combine(
+                ::testing::ValuesIn(getDeviceParameters()),
+                ::testing::ValuesIn(ConfigHelper::getRecommendedSupportPlaybackAudioConfig())),
+        &DeviceConfigParameterToString);
 
 ////////////////////////////// openInputStream //////////////////////////////
 
@@ -783,14 +907,15 @@
         ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp());  // setup base
         if (IsSkipped()) return;                           // do not attempt to use 'device'
         address.device = AudioDevice::IN_DEFAULT;
-        const AudioConfig& config = GetParam();
+        const AudioConfig& config = getConfig();
         // 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, initMetadata, cb);
-            },
-            config);
+                [&](AudioIoHandle handle, AudioConfig config, auto cb) {
+                    return getDevice()->openInputStream(handle, address, config, flags,
+                                                        initMetadata, cb);
+                },
+                config);
     }
 
    protected:
@@ -808,18 +933,23 @@
     // Open done in setup
 }
 INSTANTIATE_TEST_CASE_P(
-    RequiredInputStreamConfigSupport, InputStreamTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()),
-    &generateTestName);
+        RequiredInputStreamConfigSupport, InputStreamTest,
+        ::testing::Combine(
+                ::testing::ValuesIn(getDeviceParameters()),
+                ::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig())),
+        &DeviceConfigParameterToString);
 INSTANTIATE_TEST_CASE_P(
-    SupportedInputStreamConfig, InputStreamTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()),
-    &generateTestName);
+        SupportedInputStreamConfig, InputStreamTest,
+        ::testing::Combine(::testing::ValuesIn(getDeviceParameters()),
+                           ::testing::ValuesIn(ConfigHelper::getSupportedCaptureAudioConfig())),
+        &DeviceConfigParameterToString);
 
 INSTANTIATE_TEST_CASE_P(
-    RecommendedInputStreamConfigSupport, InputStreamTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()),
-    &generateTestName);
+        RecommendedInputStreamConfigSupport, InputStreamTest,
+        ::testing::Combine(
+                ::testing::ValuesIn(getDeviceParameters()),
+                ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig())),
+        &DeviceConfigParameterToString);
 
 //////////////////////////////////////////////////////////////////////////////
 ////////////////////////////// IStream getters ///////////////////////////////
@@ -1332,19 +1462,19 @@
 /////////////////////////////// PrimaryDevice ////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-TEST_F(AudioPrimaryHidlTest, setVoiceVolume) {
+TEST_P(AudioPrimaryHidlTest, setVoiceVolume) {
     doc::test("Make sure setVoiceVolume only succeed if volume is in [0,1]");
-    testUnitaryGain([](float volume) { return device->setVoiceVolume(volume); });
+    testUnitaryGain([this](float volume) { return getDevice()->setVoiceVolume(volume); });
 }
 
-TEST_F(BoolAccessorPrimaryHidlTest, BtScoNrecEnabled) {
+TEST_P(BoolAccessorPrimaryHidlTest, BtScoNrecEnabled) {
     doc::test("Query and set the BT SCO NR&EC state");
     testAccessors<OPTIONAL>("BtScoNrecEnabled", Initial{false, OPTIONAL}, {true},
                             &IPrimaryDevice::setBtScoNrecEnabled,
                             &IPrimaryDevice::getBtScoNrecEnabled);
 }
 
-TEST_F(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) {
+TEST_P(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) {
     doc::test("Query and set the SCO whideband state");
     testAccessors<OPTIONAL>("BtScoWideband", Initial{false, OPTIONAL}, {true},
                             &IPrimaryDevice::setBtScoWidebandEnabled,
@@ -1352,15 +1482,17 @@
 }
 
 using TtyModeAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<IPrimaryDevice::TtyMode>;
-TEST_F(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) {
+TEST_P(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) {
     doc::test("Query and set the TTY mode state");
     testAccessors<OPTIONAL>(
         "TTY mode", Initial{IPrimaryDevice::TtyMode::OFF},
         {IPrimaryDevice::TtyMode::HCO, IPrimaryDevice::TtyMode::VCO, IPrimaryDevice::TtyMode::FULL},
         &IPrimaryDevice::setTtyMode, &IPrimaryDevice::getTtyMode);
 }
+INSTANTIATE_TEST_CASE_P(TtyModeAccessorPrimaryHidl, TtyModeAccessorPrimaryHidlTest,
+                        ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
 
-TEST_F(BoolAccessorPrimaryHidlTest, setGetHac) {
+TEST_P(BoolAccessorPrimaryHidlTest, setGetHac) {
     doc::test("Query and set the HAC state");
     testAccessors<OPTIONAL>("HAC", Initial{false}, {true}, &IPrimaryDevice::setHacEnabled,
                             &IPrimaryDevice::getHacEnabled);
@@ -1372,9 +1504,13 @@
 
 int main(int argc, char** argv) {
     environment = new AudioHidlTestEnvironment;
+    // For V2..5 it's critical to initialize environment before GTest.
+    // The environment parses the service name from the command line,
+    // then it can be used in GTest parameter generators which are
+    // initialized during the call to InitGoogleTest.
+    environment->init(&argc, argv);
     ::testing::AddGlobalTestEnvironment(environment);
     ::testing::InitGoogleTest(&argc, argv);
-    environment->init(&argc, argv);
     int status = RUN_ALL_TESTS();
     return status;
 }
diff --git a/audio/core/all-versions/vts/functional/DeviceManager.h b/audio/core/all-versions/vts/functional/DeviceManager.h
new file mode 100644
index 0000000..b6e2db0
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/DeviceManager.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Code in this file uses 'environment'
+#ifndef AUDIO_PRIMARY_HIDL_HAL_TEST
+#error Must be included from AudioPrimaryHidlTest.h
+#endif
+
+template <class Derived, class Key, class Interface>
+class InterfaceManager {
+  public:
+    sp<Interface> get(const Key& name) {
+        auto existing = instances.find(name);
+        if (existing != instances.end()) return existing->second;
+        auto [inserted, _] = instances.emplace(name, Derived::createInterfaceInstance(name));
+        if (inserted->second) {
+            environment->registerTearDown([name]() { (void)Derived::getInstance().reset(name); });
+        }
+        return inserted->second;
+    }
+
+    // The test must check that reset was successful. Reset failure means that the test code
+    // is holding a strong reference to the device.
+    bool reset(const Key& name) __attribute__((warn_unused_result)) {
+        auto iter = instances.find(name);
+        if (iter == instances.end()) return true;
+        ::android::wp<Interface> weak = iter->second;
+        instances.erase(iter);
+        if (weak.promote() != nullptr) return false;
+        waitForInstanceDestruction();
+        return true;
+    }
+
+    static void waitForInstanceDestruction() {
+        // FIXME: there is no way to know when the remote IDevice is being destroyed
+        //        Binder does not support testing if an object is alive, thus
+        //        wait for 100ms to let the binder destruction propagates and
+        //        the remote device has the time to be destroyed.
+        //        flushCommand makes sure all local command are sent, thus should reduce
+        //        the latency between local and remote destruction.
+        IPCThreadState::self()->flushCommands();
+        usleep(100 * 1000);
+    }
+
+  protected:
+    std::map<Key, sp<Interface>> instances;
+};
+
+class DevicesFactoryManager
+    : public InterfaceManager<DevicesFactoryManager, std::string, IDevicesFactory> {
+  public:
+    static DevicesFactoryManager& getInstance() {
+        static DevicesFactoryManager instance;
+        return instance;
+    }
+    static sp<IDevicesFactory> createInterfaceInstance(const std::string& name) {
+#if MAJOR_VERSION <= 5
+        return ::testing::VtsHalHidlTargetTestBase::getService<IDevicesFactory>(name);
+#elif MAJOR_VERSION >= 6
+        return IDevicesFactory::getService(name);
+#endif
+    }
+};
+
+using FactoryAndDevice = std::tuple<std::string, std::string>;
+class DeviceManager : public InterfaceManager<DeviceManager, FactoryAndDevice, IDevice> {
+  public:
+    static DeviceManager& getInstance() {
+        static DeviceManager instance;
+        return instance;
+    }
+    static sp<IDevice> createInterfaceInstance(const FactoryAndDevice& factoryAndDevice) {
+        auto [factoryName, name] = factoryAndDevice;
+        sp<IDevicesFactory> factory = DevicesFactoryManager::getInstance().get(factoryName);
+        return name == kPrimaryDevice ? openPrimaryDevice(factory) : openDevice(factory, name);
+    }
+    using InterfaceManager::reset;
+
+    static constexpr const char* kPrimaryDevice = "primary";
+
+    sp<IDevice> get(const std::string& factoryName, const std::string& name) {
+        return InterfaceManager::get(std::make_tuple(factoryName, name));
+    }
+    sp<IPrimaryDevice> getPrimary(const std::string& factoryName) {
+        sp<IDevice> device = get(factoryName, kPrimaryDevice);
+        return device != nullptr ? IPrimaryDevice::castFrom(device) : nullptr;
+    }
+    bool reset(const std::string& factoryName, const std::string& name)
+            __attribute__((warn_unused_result)) {
+        return InterfaceManager::reset(std::make_tuple(factoryName, name));
+    }
+    bool resetPrimary(const std::string& factoryName) __attribute__((warn_unused_result)) {
+        return reset(factoryName, kPrimaryDevice);
+    }
+
+  private:
+    static sp<IDevice> openDevice(const sp<IDevicesFactory>& factory, const std::string& name) {
+        if (factory == nullptr) return nullptr;
+        sp<IDevice> device;
+#if MAJOR_VERSION >= 4
+        Result result;
+        auto ret = factory->openDevice(name, returnIn(result, device));
+        if (!ret.isOk() || result != Result::OK || device == nullptr) {
+            ALOGW("Device %s can not be opened, transaction: %s, result %d, device %p",
+                  name.c_str(), ret.description().c_str(), result, device.get());
+            return nullptr;
+        }
+#else
+        (void)name;
+#endif
+        return device;
+    }
+
+    static sp<IDevice> openPrimaryDevice(const sp<IDevicesFactory>& factory) {
+        if (factory == nullptr) return nullptr;
+        Result result;
+        sp<IDevice> device;
+#if MAJOR_VERSION == 2
+        auto ret = factory->openDevice(IDevicesFactory::Device::PRIMARY, returnIn(result, device));
+#elif MAJOR_VERSION >= 4
+        auto ret = factory->openPrimaryDevice(returnIn(result, device));
+#endif
+        if (!ret.isOk() || result != Result::OK || device == nullptr) {
+            ALOGW("Primary device can not be opened, transaction: %s, result %d, device %p",
+                  ret.description().c_str(), result, device.get());
+            return nullptr;
+        }
+        return device;
+    }
+};