audiopolicy: Add unit tests build target
This change adds audiopolicy_tests target for running
unit tests of AudioPolicyManager class.
AudioPolicyManager class is modified to allow
finer control over the configuration loading.
Test: audiopolicy_tests
Change-Id: Icf0cd7ff5b3b8b827b4f6909ff2c138ac2a2b82e
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index 92d98a8..43f6ed6 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -39,14 +39,13 @@
DeviceVector &availableOutputDevices,
DeviceVector &availableInputDevices,
sp<DeviceDescriptor> &defaultOutputDevices,
- bool &isSpeakerDrcEnabled,
VolumeCurvesCollection *volumes = nullptr)
: mHwModules(hwModules),
mAvailableOutputDevices(availableOutputDevices),
mAvailableInputDevices(availableInputDevices),
mDefaultOutputDevices(defaultOutputDevices),
mVolumeCurves(volumes),
- mIsSpeakerDrcEnabled(isSpeakerDrcEnabled)
+ mIsSpeakerDrcEnabled(false)
{}
void setVolumes(const VolumeCurvesCollection &volumes)
@@ -80,6 +79,8 @@
mAvailableOutputDevices.add(availableOutputDevices);
}
+ bool isSpeakerDrcEnabled() const { return mIsSpeakerDrcEnabled; }
+
void setSpeakerDrcEnabled(bool isSpeakerDrcEnabled)
{
mIsSpeakerDrcEnabled = isSpeakerDrcEnabled;
@@ -140,7 +141,10 @@
DeviceVector &mAvailableInputDevices;
sp<DeviceDescriptor> &mDefaultOutputDevices;
VolumeCurvesCollection *mVolumeCurves;
- bool &mIsSpeakerDrcEnabled;
+ // TODO: remove when legacy conf file is removed. true on devices that use DRC on the
+ // DEVICE_CATEGORY_SPEAKER path to boost soft sounds, used to adjust volume curves accordingly.
+ // Note: remove also speaker_drc_enabled from global configuration of XML config file.
+ bool mIsSpeakerDrcEnabled;
};
} // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 0e11c5c..25c5e7a 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -3474,10 +3474,22 @@
}
#endif
-AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
+AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface,
+ bool /*forTesting*/)
:
+ mUidCached(getuid()),
+ mpClientInterface(clientInterface),
mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
mA2dpSuspended(false),
+#ifdef USE_XML_AUDIO_POLICY_CONF
+ mVolumeCurves(new VolumeCurvesCollection()),
+ mConfig(mHwModulesAll, mAvailableOutputDevices, mAvailableInputDevices,
+ mDefaultOutputDevice, static_cast<VolumeCurvesCollection*>(mVolumeCurves)),
+#else
+ mVolumeCurves(new StreamDescriptorCollection()),
+ mConfig(mHwModulesAll, mAvailableOutputDevices, mAvailableInputDevices,
+ mDefaultOutputDevice),
+#endif
mAudioPortGeneration(1),
mBeaconMuteRefCount(0),
mBeaconPlayingRefCount(0),
@@ -3487,49 +3499,48 @@
mMusicEffectOutput(AUDIO_IO_HANDLE_NONE),
mHasComputedSoundTriggerSupportsConcurrentCapture(false)
{
- mUidCached = getuid();
- mpClientInterface = clientInterface;
+}
- // TODO: remove when legacy conf file is removed. true on devices that use DRC on the
- // DEVICE_CATEGORY_SPEAKER path to boost soft sounds, used to adjust volume curves accordingly.
- // Note: remove also speaker_drc_enabled from global configuration of XML config file.
- bool speakerDrcEnabled = false;
+AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
+ : AudioPolicyManager(clientInterface, false /*forTesting*/)
+{
+ loadConfig();
+ initialize();
+}
+void AudioPolicyManager::loadConfig() {
#ifdef USE_XML_AUDIO_POLICY_CONF
- mVolumeCurves = new VolumeCurvesCollection();
- AudioPolicyConfig config(mHwModulesAll, mAvailableOutputDevices, mAvailableInputDevices,
- mDefaultOutputDevice, speakerDrcEnabled,
- static_cast<VolumeCurvesCollection *>(mVolumeCurves));
- if (deserializeAudioPolicyXmlConfig(config) != NO_ERROR) {
+ if (deserializeAudioPolicyXmlConfig(getConfig()) != NO_ERROR) {
#else
- mVolumeCurves = new StreamDescriptorCollection();
- AudioPolicyConfig config(mHwModulesAll, mAvailableOutputDevices, mAvailableInputDevices,
- mDefaultOutputDevice, speakerDrcEnabled);
- if ((ConfigParsingUtils::loadConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE, config) != NO_ERROR) &&
- (ConfigParsingUtils::loadConfig(AUDIO_POLICY_CONFIG_FILE, config) != NO_ERROR)) {
+ if ((ConfigParsingUtils::loadConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE, getConfig()) != NO_ERROR)
+ && (ConfigParsingUtils::loadConfig(AUDIO_POLICY_CONFIG_FILE, getConfig()) != NO_ERROR)) {
#endif
ALOGE("could not load audio policy configuration file, setting defaults");
- config.setDefault();
+ getConfig().setDefault();
}
- // must be done after reading the policy (since conditionned by Speaker Drc Enabling)
- mVolumeCurves->initializeVolumeCurves(speakerDrcEnabled);
+}
+
+status_t AudioPolicyManager::initialize() {
+ mVolumeCurves->initializeVolumeCurves(getConfig().isSpeakerDrcEnabled());
// Once policy config has been parsed, retrieve an instance of the engine and initialize it.
audio_policy::EngineInstance *engineInstance = audio_policy::EngineInstance::getInstance();
if (!engineInstance) {
ALOGE("%s: Could not get an instance of policy engine", __FUNCTION__);
- return;
+ return NO_INIT;
}
// Retrieve the Policy Manager Interface
mEngine = engineInstance->queryInterface<AudioPolicyManagerInterface>();
if (mEngine == NULL) {
ALOGE("%s: Failed to get Policy Engine Interface", __FUNCTION__);
- return;
+ return NO_INIT;
}
mEngine->setObserver(this);
status_t status = mEngine->initCheck();
- (void) status;
- ALOG_ASSERT(status == NO_ERROR, "Policy engine not initialized(err=%d)", status);
+ if (status != NO_ERROR) {
+ LOG_FATAL("Policy engine not initialized(err=%d)", status);
+ return status;
+ }
// mAvailableOutputDevices and mAvailableInputDevices now contain all attached devices
// open all output streams needed to access attached devices
@@ -3692,11 +3703,16 @@
// make sure default device is reachable
if (mDefaultOutputDevice == 0 || mAvailableOutputDevices.indexOf(mDefaultOutputDevice) < 0) {
ALOGE("Default device %08x is unreachable", mDefaultOutputDevice->type());
+ status = NO_INIT;
}
- ALOGE_IF((mPrimaryOutput == 0), "Failed to open primary output");
+ if (mPrimaryOutput == 0) {
+ ALOGE("Failed to open primary output");
+ status = NO_INIT;
+ }
updateDevicesAndOutputs();
+ return status;
}
AudioPolicyManager::~AudioPolicyManager()
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 6038e33..3659e34 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -33,6 +33,7 @@
#include <AudioPolicyManagerInterface.h>
#include <AudioPolicyManagerObserver.h>
#include <AudioGain.h>
+#include <AudioPolicyConfig.h>
#include <AudioPort.h>
#include <AudioPatch.h>
#include <DeviceDescriptor.h>
@@ -234,6 +235,21 @@
routing_strategy getStrategy(audio_stream_type_t stream) const;
protected:
+ // A constructor that allows more fine-grained control over initialization process,
+ // used in automatic tests.
+ AudioPolicyManager(AudioPolicyClientInterface *clientInterface, bool forTesting);
+
+ // These methods should be used when finer control over APM initialization
+ // is needed, e.g. in tests. Must be used in conjunction with the constructor
+ // that only performs fields initialization. The public constructor comprises
+ // these steps in the following sequence:
+ // - field initializing constructor;
+ // - loadConfig;
+ // - initialize.
+ AudioPolicyConfig& getConfig() { return mConfig; }
+ void loadConfig();
+ status_t initialize();
+
// From AudioPolicyManagerObserver
virtual const AudioPatchCollection &getAudioPatches() const
{
@@ -526,18 +542,18 @@
SessionRouteMap mOutputRoutes = SessionRouteMap(SessionRouteMap::MAPTYPE_OUTPUT);
SessionRouteMap mInputRoutes = SessionRouteMap(SessionRouteMap::MAPTYPE_INPUT);
- IVolumeCurvesCollection *mVolumeCurves; // Volume Curves per use case and device category
-
bool mLimitRingtoneVolume; // limit ringtone volume to music volume if headset connected
audio_devices_t mDeviceForStrategy[NUM_STRATEGIES];
float mLastVoiceVolume; // last voice volume value sent to audio HAL
-
- EffectDescriptorCollection mEffects; // list of registered audio effects
bool mA2dpSuspended; // true if A2DP output is suspended
+
+ IVolumeCurvesCollection *mVolumeCurves; // Volume Curves per use case and device category
+ EffectDescriptorCollection mEffects; // list of registered audio effects
sp<DeviceDescriptor> mDefaultOutputDevice; // output device selected by default at boot time
HwModuleCollection mHwModules; // contains only modules that have been loaded successfully
HwModuleCollection mHwModulesAll; // normally not needed, used during construction and for
// dumps
+ AudioPolicyConfig mConfig;
std::atomic<uint32_t> mAudioPortGeneration;
diff --git a/services/audiopolicy/tests/Android.mk b/services/audiopolicy/tests/Android.mk
new file mode 100644
index 0000000..62869a4
--- /dev/null
+++ b/services/audiopolicy/tests/Android.mk
@@ -0,0 +1,30 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_C_INCLUDES := \
+ frameworks/av/services/audiopolicy \
+ frameworks/av/services/audiopolicy/common/include \
+ frameworks/av/services/audiopolicy/engine/interface \
+ frameworks/av/services/audiopolicy/utilities
+
+LOCAL_SHARED_LIBRARIES := \
+ libaudiopolicymanagerdefault \
+ libbase \
+ liblog \
+ libmedia_helper \
+ libutils \
+
+LOCAL_STATIC_LIBRARIES := \
+ libaudiopolicycomponents \
+
+LOCAL_SRC_FILES := \
+ audiopolicymanager_tests.cpp \
+
+LOCAL_MODULE := audiopolicy_tests
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_CFLAGS := -Werror -Wall
+
+include $(BUILD_NATIVE_TEST)
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
new file mode 100644
index 0000000..c4da98a
--- /dev/null
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+#pragma once
+
+#include "AudioPolicyInterface.h"
+
+namespace android {
+
+class AudioPolicyTestClient : public AudioPolicyClientInterface
+{
+public:
+ virtual ~AudioPolicyTestClient() {}
+
+ // AudioPolicyClientInterface Implementation
+ audio_module_handle_t loadHwModule(const char* /*name*/) override { return 0; }
+ status_t openOutput(audio_module_handle_t /*module*/,
+ audio_io_handle_t* /*output*/,
+ audio_config_t* /*config*/,
+ audio_devices_t* /*devices*/,
+ const String8& /*address*/,
+ uint32_t* /*latencyMs*/,
+ audio_output_flags_t /*flags*/) override { return 0; }
+ audio_io_handle_t openDuplicateOutput(audio_io_handle_t /*output1*/,
+ audio_io_handle_t /*output2*/) override { return 0; }
+ status_t closeOutput(audio_io_handle_t /*output*/) override { return 0; }
+ status_t suspendOutput(audio_io_handle_t /*output*/) override { return 0; }
+ status_t restoreOutput(audio_io_handle_t /*output*/) override { return 0; }
+ status_t openInput(audio_module_handle_t /*module*/,
+ audio_io_handle_t* /*input*/,
+ audio_config_t* /*config*/,
+ audio_devices_t* /*device*/,
+ const String8& /*address*/,
+ audio_source_t /*source*/,
+ audio_input_flags_t /*flags*/) override { return 0; }
+ status_t closeInput(audio_io_handle_t /*input*/) override { return 0; }
+ status_t setStreamVolume(audio_stream_type_t /*stream*/,
+ float /*volume*/,
+ audio_io_handle_t /*output*/,
+ int /*delayMs*/) override { return 0; }
+ status_t invalidateStream(audio_stream_type_t /*stream*/) override { return 0; }
+ void setParameters(audio_io_handle_t /*ioHandle*/,
+ const String8& /*keyValuePairs*/,
+ int /*delayMs*/) override { }
+ String8 getParameters(audio_io_handle_t /*ioHandle*/,
+ const String8& /*keys*/) override { return String8(); }
+ status_t startTone(audio_policy_tone_t /*tone*/,
+ audio_stream_type_t /*stream*/) override { return 0; }
+ status_t stopTone() override { return 0; }
+ status_t setVoiceVolume(float /*volume*/, int /*delayMs*/) override { return 0; }
+ status_t moveEffects(audio_session_t /*session*/,
+ audio_io_handle_t /*srcOutput*/,
+ audio_io_handle_t /*dstOutput*/) override { return 0; }
+ status_t createAudioPatch(const struct audio_patch* /*patch*/,
+ audio_patch_handle_t* /*handle*/,
+ int /*delayMs*/) override { return 0; }
+ status_t releaseAudioPatch(audio_patch_handle_t /*handle*/,
+ int /*delayMs*/) override { return 0; }
+ status_t setAudioPortConfig(const struct audio_port_config* /*config*/,
+ int /*delayMs*/) override { return 0; }
+ void onAudioPortListUpdate() override { }
+ void onAudioPatchListUpdate() override { }
+ audio_unique_id_t newAudioUniqueId(audio_unique_id_use_t /*use*/) override { return 0; }
+ void onDynamicPolicyMixStateUpdate(String8 /*regId*/, int32_t /*state*/) override { }
+ void onRecordingConfigurationUpdate(int /*event*/,
+ const record_client_info_t* /*clientInfo*/,
+ const struct audio_config_base* /*clientConfig*/,
+ const struct audio_config_base* /*deviceConfig*/,
+ audio_patch_handle_t /*patchHandle*/) override { }
+};
+
+} // namespace android
diff --git a/services/audiopolicy/tests/AudioPolicyTestManager.h b/services/audiopolicy/tests/AudioPolicyTestManager.h
new file mode 100644
index 0000000..fe543a6
--- /dev/null
+++ b/services/audiopolicy/tests/AudioPolicyTestManager.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+#pragma once
+
+#include "managerdefault/AudioPolicyManager.h"
+
+namespace android {
+
+class AudioPolicyTestManager : public AudioPolicyManager {
+ public:
+ explicit AudioPolicyTestManager(AudioPolicyClientInterface *clientInterface)
+ : AudioPolicyManager(clientInterface, true /*forTesting*/) { }
+ using AudioPolicyManager::getConfig;
+ using AudioPolicyManager::initialize;
+};
+
+} // namespace android
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
new file mode 100644
index 0000000..33b15c7
--- /dev/null
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2017 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 <gtest/gtest.h>
+
+#include "AudioPolicyTestClient.h"
+#include "AudioPolicyTestManager.h"
+
+using namespace android;
+
+TEST(AudioPolicyManager, CreateWithDummyClient) {
+ AudioPolicyTestClient client;
+ AudioPolicyTestManager manager(&client);
+ manager.getConfig().setDefault();
+ ASSERT_EQ(NO_INIT, manager.initialize());
+}