Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b75130b6 authored by Kevin Rocard's avatar Kevin Rocard Committed by Android (Google) Code Review
Browse files

Merge changes from topic "policy-xml-vts"

* changes:
  Audio VTS: Reset HAL after setConnectionState
  Audio HAL: do not test input stream if no Built-in mic on primary
parents 31cc9a38 681846f0
Loading
Loading
Loading
Loading
+19 −9
Original line number Diff line number Diff line
@@ -16,6 +16,17 @@

#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);
}

TEST_F(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) {
    doc::test("Calling openDevice(\"primary\") should return the primary device.");
    {
@@ -29,14 +40,7 @@ TEST_F(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) {
        ASSERT_TRUE(primaryDevice.isOk());
        ASSERT_TRUE(sp<IPrimaryDevice>(primaryDevice) != nullptr);
    }  // Destroy local IDevice proxy
    // 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);
    waitForDeviceDestruction();
}

//////////////////////////////////////////////////////////////////////////////
@@ -133,11 +137,17 @@ TEST_F(AudioPrimaryHidlTest, SetConnectedState) {
            ASSERT_TRUE(ret.isOk());
            if (ret == Result::NOT_SUPPORTED) {
                doc::partialTest("setConnectedState is not supported");
                return;
                break;  // other deviceType might be supported
            }
            ASSERT_OK(ret);
        }
    }

    // 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();
}

static void testGetDevices(IStream* stream, AudioDevice expectedDevice) {
+2 −3
Original line number Diff line number Diff line
@@ -17,13 +17,12 @@
cc_defaults {
    name: "VtsHalAudioTargetTest_defaults",
    defaults: ["VtsHalTargetTestDefaults"],
    srcs: [
        "ValidateAudioConfiguration.cpp"
    ],
    static_libs: [
        "android.hardware.audio.common.test.utility",
        "libaudiopolicycomponents",
        "libicuuc",
        "libicuuc_stubdata",
        "libmedia_helper",
        "libxml2",
    ],
    shared_libs: [
+121 −1
Original line number Diff line number Diff line
@@ -40,6 +40,8 @@
#include PATH(android/hardware/audio/FILE_VERSION/IPrimaryDevice.h)
#include PATH(android/hardware/audio/FILE_VERSION/types.h)
#include PATH(android/hardware/audio/common/FILE_VERSION/types.h)

#include <Serializer.h>
#include <fmq/EventFlag.h>
#include <fmq/MessageQueue.h>

@@ -50,6 +52,7 @@
#include "utility/EnvironmentTearDown.h"
#include "utility/PrettyPrintAudioTypes.h"
#include "utility/ReturnIn.h"
#include "utility/ValidateXml.h"

/** Provide version specific functions that are used in the generic tests */
#if MAJOR_VERSION == 2
@@ -64,7 +67,12 @@ using std::string;
using std::to_string;
using std::vector;

using ::android::AudioPolicyConfig;
using ::android::HwModule;
using ::android::NO_INIT;
using ::android::OK;
using ::android::sp;
using ::android::status_t;
using ::android::hardware::EventFlag;
using ::android::hardware::hidl_bitfield;
using ::android::hardware::hidl_enum_range;
@@ -120,6 +128,10 @@ static auto okOrInvalidStateOrNotSupported = {Result::OK, Result::INVALID_STATE,
static auto invalidArgsOrNotSupported = {Result::INVALID_ARGUMENTS, Result::NOT_SUPPORTED};
static auto invalidStateOrNotSupported = {Result::INVALID_STATE, Result::NOT_SUPPORTED};

//////////////////////////////////////////////////////////////////////////////
//////////////////////////////// Environment /////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

class AudioHidlTestEnvironment : public ::Environment {
   public:
    virtual void registerTestServices() override { registerTestService<IDevicesFactory>(); }
@@ -134,12 +146,104 @@ class HidlTest : public ::testing::VtsHalHidlTargetTestBase {
    Result res;
};

//////////////////////////////////////////////////////////////////////////////
////////////////////////// Audio policy configuration ////////////////////////
//////////////////////////////////////////////////////////////////////////////

static const std::vector<const char*> kConfigLocations = {"/odm/etc", "/vendor/etc", "/system/etc"};
static constexpr char kConfigFileName[] = "audio_policy_configuration.xml";

// Stringify the argument.
#define QUOTE(x) #x
#define STRINGIFY(x) QUOTE(x)

TEST(CheckConfig, audioPolicyConfigurationValidation) {
    RecordProperty("description",
                   "Verify that the audio policy configuration file "
                   "is valid according to the schema");

    const char* xsd = "/data/local/tmp/audio_policy_configuration_" STRINGIFY(CPP_VERSION) ".xsd";
    EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS(kConfigFileName, kConfigLocations, xsd);
}

struct PolicyConfigData {
    android::HwModuleCollection hwModules;
    android::DeviceVector availableOutputDevices;
    android::DeviceVector availableInputDevices;
    sp<android::DeviceDescriptor> defaultOutputDevice;
    android::VolumeCurvesCollection volumes;
};

class PolicyConfig : private PolicyConfigData, public AudioPolicyConfig {
   public:
    PolicyConfig()
        : AudioPolicyConfig(hwModules, availableOutputDevices, availableInputDevices,
                            defaultOutputDevice, &volumes) {
        for (const char* location : kConfigLocations) {
            std::string path = std::string(location) + '/' + kConfigFileName;
            if (access(path.c_str(), F_OK) == 0) {
                mFilePath = path;
                break;
            }
        }
        mStatus = android::deserializeAudioPolicyFile(mFilePath.c_str(), this);
        if (mStatus == OK) {
            mPrimaryModule = getHwModules().getModuleFromName("primary");
        }
    }
    status_t getStatus() const { return mStatus; }
    std::string getError() const {
        if (mFilePath.empty()) {
            return std::string{"Could not find "} + kConfigFileName +
                   " file in: " + testing::PrintToString(kConfigLocations);
        } else {
            return "Invalid config file: " + mFilePath;
        }
    }
    const std::string& getFilePath() const { return mFilePath; }
    sp<const HwModule> getPrimaryModule() const { return mPrimaryModule; }

   private:
    status_t mStatus = NO_INIT;
    std::string mFilePath;
    sp<HwModule> mPrimaryModule = nullptr;
};

// Cached policy config after parsing for faster test startup
const PolicyConfig& getCachedPolicyConfig() {
    static std::unique_ptr<PolicyConfig> policyConfig = [] {
        auto config = std::make_unique<PolicyConfig>();
        environment->registerTearDown([] { policyConfig.reset(); });
        return config;
    }();
    return *policyConfig;
}

class AudioPolicyConfigTest : public HidlTest {
   public:
    void SetUp() override {
        ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp());  // setup base

        auto& policyConfig = getCachedPolicyConfig();
        ASSERT_EQ(0, policyConfig.getStatus()) << policyConfig.getError();

        mPrimaryConfig = policyConfig.getPrimaryModule();
        ASSERT_TRUE(mPrimaryConfig) << "Could not find primary module in configuration file: "
                                    << policyConfig.getFilePath();
    }
    sp<const HwModule> mPrimaryConfig = nullptr;
};

TEST_F(AudioPolicyConfigTest, LoadAudioPolicyXMLConfiguration) {
    doc::test("Test parsing audio_policy_configuration.xml (called in SetUp)");
}

//////////////////////////////////////////////////////////////////////////////
////////////////////// getService audio_devices_factory //////////////////////
//////////////////////////////////////////////////////////////////////////////

// Test all audio devices
class AudioHidlTest : public HidlTest {
class AudioHidlTest : public AudioPolicyConfigTest {
   public:
    void SetUp() override {
        ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp());  // setup base
@@ -346,6 +450,20 @@ TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) {

class AudioConfigPrimaryTest : public AudioPatchPrimaryHidlTest {
   public:
    // 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() {
        auto& policyConfig = getCachedPolicyConfig();
        if (policyConfig.getStatus() != OK || policyConfig.getPrimaryModule() == nullptr) {
            return true;  // Could not get the information, run all tests
        }
        auto getMic = [](auto& devs) { return devs.getDevice(AUDIO_DEVICE_IN_BUILTIN_MIC, {}); };
        auto primaryMic = getMic(policyConfig.getPrimaryModule()->getDeclaredDevices());
        auto availableMic = getMic(policyConfig.getAvailableInputDevices());

        return primaryMic != nullptr && primaryMic->equals(availableMic);
    }

    // Cache result ?
    static const vector<AudioConfig> getRequiredSupportPlaybackAudioConfig() {
        return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO},
@@ -365,10 +483,12 @@ class AudioConfigPrimaryTest : public AudioPatchPrimaryHidlTest {
    }

    static const vector<AudioConfig> getRequiredSupportCaptureAudioConfig() {
        if (!primaryHasMic()) return {};
        return combineAudioConfig({AudioChannelMask::IN_MONO}, {8000, 11025, 16000, 44100},
                                  {AudioFormat::PCM_16_BIT});
    }
    static const vector<AudioConfig> getRecommendedSupportCaptureAudioConfig() {
        if (!primaryHasMic()) return {};
        return combineAudioConfig({AudioChannelMask::IN_STEREO}, {22050, 48000},
                                  {AudioFormat::PCM_16_BIT});
    }
+0 −34
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.
 */

#include <unistd.h>
#include <string>

#include "utility/ValidateXml.h"

// Stringify the argument.
#define QUOTE(x) #x
#define STRINGIFY(x) QUOTE(x)

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"};
    const char* xsd = "/data/local/tmp/audio_policy_configuration_" STRINGIFY(CPP_VERSION) ".xsd";
    EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS("audio_policy_configuration.xml", locations, xsd);
}