Dynamic audio policies: multi-zone through uid/device affinity
Setting audio device affinity for a given uid augments all
audio mix criteria that do not route to the given devices
to exclude the uid.
AudioPolicyManager: after changing the device affinity,
check the outputs addressing the devices to re-evaluate
audio routing
Bug: 111647296
Test: requires device with routing policy started by CarService
Change-Id: I72de54ae067151fe6ac2ec43b78fe544a9fd9888
diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk
index bfa1b5e..d71aa15 100644
--- a/services/audiopolicy/Android.mk
+++ b/services/audiopolicy/Android.mk
@@ -51,6 +51,7 @@
libcutils \
libutils \
liblog \
+ libaudioclient \
libsoundtrigger
ifeq ($(USE_CONFIGURABLE_AUDIO_POLICY), 1)
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index ad12a90..1c2b9d7 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -210,6 +210,10 @@
virtual status_t registerPolicyMixes(const Vector<AudioMix>& mixes) = 0;
virtual status_t unregisterPolicyMixes(Vector<AudioMix> mixes) = 0;
+ virtual status_t setUidDeviceAffinities(uid_t uid, const Vector<AudioDeviceTypeAddr>& devices)
+ = 0;
+ virtual status_t removeUidDeviceAffinities(uid_t uid) = 0;
+
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
audio_port_handle_t *portId,
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index 96c00ea..955e87b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -80,6 +80,10 @@
status_t getInputMixForAttr(audio_attributes_t attr, AudioMix **policyMix);
+ status_t setUidDeviceAffinities(uid_t uid, const Vector<AudioDeviceTypeAddr>& devices);
+ status_t removeUidDeviceAffinities(uid_t uid);
+ status_t getDevicesForUid(uid_t uid, Vector<AudioDeviceTypeAddr>& devices) const;
+
void dump(String8 *dst) const;
};
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 3cf8014..776d98f 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -340,6 +340,87 @@
return NO_ERROR;
}
+status_t AudioPolicyMixCollection::setUidDeviceAffinities(uid_t uid,
+ const Vector<AudioDeviceTypeAddr>& devices) {
+ // remove existing rules for this uid
+ removeUidDeviceAffinities(uid);
+
+ // for each player mix: add a rule to match or exclude the uid based on the device
+ for (size_t i = 0; i < size(); i++) {
+ const AudioMix *mix = valueAt(i)->getMix();
+ if (mix->mMixType != MIX_TYPE_PLAYERS) {
+ continue;
+ }
+ // check if this mix goes to a device in the list of devices
+ bool deviceMatch = false;
+ for (size_t j = 0; j < devices.size(); j++) {
+ if (devices[j].mType == mix->mDeviceType
+ && devices[j].mAddress == mix->mDeviceAddress) {
+ deviceMatch = true;
+ break;
+ }
+ }
+ if (!deviceMatch) {
+ // this mix doesn't go to one of the listed devices for the given uid,
+ // modify its rules to exclude the uid
+ mix->excludeUid(uid);
+ }
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioPolicyMixCollection::removeUidDeviceAffinities(uid_t uid) {
+ // for each player mix: remove existing rules that match or exclude this uid
+ for (size_t i = 0; i < size(); i++) {
+ bool foundUidRule = false;
+ AudioMix *mix = valueAt(i)->getMix();
+ if (mix->mMixType != MIX_TYPE_PLAYERS) {
+ continue;
+ }
+ std::vector<size_t> criteriaToRemove;
+ for (size_t j = 0; j < mix->mCriteria.size(); j++) {
+ const uint32_t rule = mix->mCriteria[j].mRule;
+ // is this rule affecting the uid?
+ if (rule == RULE_EXCLUDE_UID
+ && uid == mix->mCriteria[j].mValue.mUid) {
+ foundUidRule = true;
+ criteriaToRemove.push_back(j);
+ }
+ }
+ if (foundUidRule) {
+ for (size_t j = criteriaToRemove.size() - 1; j >= 0; j--) {
+ mix->mCriteria.removeAt(criteriaToRemove[j]);
+ }
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyMixCollection::getDevicesForUid(uid_t uid,
+ Vector<AudioDeviceTypeAddr>& devices) const {
+ // for each player mix: find rules that don't exclude this uid, and add the device to the list
+ for (size_t i = 0; i < size(); i++) {
+ bool ruleAllowsUid = true;
+ AudioMix *mix = valueAt(i)->getMix();
+ if (mix->mMixType != MIX_TYPE_PLAYERS) {
+ continue;
+ }
+ for (size_t j = 0; j < mix->mCriteria.size(); j++) {
+ const uint32_t rule = mix->mCriteria[j].mRule;
+ if (rule == RULE_EXCLUDE_UID
+ && uid == mix->mCriteria[j].mValue.mUid) {
+ ruleAllowsUid = false;
+ break;
+ }
+ }
+ if (ruleAllowsUid) {
+ devices.add(AudioDeviceTypeAddr(mix->mDeviceType, mix->mDeviceAddress));
+ }
+ }
+ return NO_ERROR;
+}
+
void AudioPolicyMixCollection::dump(String8 *dst) const
{
dst->append("\nAudio Policy Mix:\n");
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index aa205f0..baa5eb3 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2674,6 +2674,59 @@
}
}
+status_t AudioPolicyManager::setUidDeviceAffinities(uid_t uid,
+ const Vector<AudioDeviceTypeAddr>& devices) {
+ ALOGV("%s() uid=%d num devices %zu", __FUNCTION__, uid, devices.size());
+ // uid/device affinity is only for output devices
+ for (size_t i = 0; i < devices.size(); i++) {
+ if (!audio_is_output_device(devices[i].mType)) {
+ ALOGE("setUidDeviceAffinities() device=%08x is NOT an output device",
+ devices[i].mType);
+ return BAD_VALUE;
+ }
+ }
+ status_t res = mPolicyMixes.setUidDeviceAffinities(uid, devices);
+ if (res == NO_ERROR) {
+ // reevaluate outputs for all given devices
+ for (size_t i = 0; i < devices.size(); i++) {
+ sp<DeviceDescriptor> devDesc = mHwModules.getDeviceDescriptor(
+ devices[i].mType, devices[i].mAddress, String8());
+ SortedVector<audio_io_handle_t> outputs;
+ if (checkOutputsForDevice(devDesc, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ outputs,
+ devDesc->address()) != NO_ERROR) {
+ ALOGE("setUidDeviceAffinities() error in checkOutputsForDevice for device=%08x"
+ " addr=%s", devices[i].mType, devices[i].mAddress.string());
+ return INVALID_OPERATION;
+ }
+ }
+ }
+ return res;
+}
+
+status_t AudioPolicyManager::removeUidDeviceAffinities(uid_t uid) {
+ ALOGV("%s() uid=%d", __FUNCTION__, uid);
+ Vector<AudioDeviceTypeAddr> devices;
+ status_t res = mPolicyMixes.getDevicesForUid(uid, devices);
+ if (res == NO_ERROR) {
+ // reevaluate outputs for all found devices
+ for (size_t i = 0; i < devices.size(); i++) {
+ sp<DeviceDescriptor> devDesc = mHwModules.getDeviceDescriptor(
+ devices[i].mType, devices[i].mAddress, String8());
+ SortedVector<audio_io_handle_t> outputs;
+ if (checkOutputsForDevice(devDesc, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ outputs,
+ devDesc->address()) != NO_ERROR) {
+ ALOGE("%s() error in checkOutputsForDevice for device=%08x addr=%s",
+ __FUNCTION__, devices[i].mType, devices[i].mAddress.string());
+ return INVALID_OPERATION;
+ }
+ }
+ }
+
+ return res;
+}
+
void AudioPolicyManager::dump(String8 *dst) const
{
dst->appendFormat("\nAudioPolicyManager Dump: %p\n", this);
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 35dd87c..9eb1dcf 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -218,6 +218,9 @@
virtual status_t registerPolicyMixes(const Vector<AudioMix>& mixes);
virtual status_t unregisterPolicyMixes(Vector<AudioMix> mixes);
+ virtual status_t setUidDeviceAffinities(uid_t uid,
+ const Vector<AudioDeviceTypeAddr>& devices);
+ virtual status_t removeUidDeviceAffinities(uid_t uid);
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 439764b..80503fd 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -1037,6 +1037,31 @@
}
}
+status_t AudioPolicyService::setUidDeviceAffinities(uid_t uid,
+ const Vector<AudioDeviceTypeAddr>& devices) {
+ Mutex::Autolock _l(mLock);
+ if(!modifyAudioRoutingAllowed()) {
+ return PERMISSION_DENIED;
+ }
+ if (mAudioPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ AutoCallerClear acc;
+ return mAudioPolicyManager->setUidDeviceAffinities(uid, devices);
+}
+
+status_t AudioPolicyService::removeUidDeviceAffinities(uid_t uid) {
+ Mutex::Autolock _l(mLock);
+ if(!modifyAudioRoutingAllowed()) {
+ return PERMISSION_DENIED;
+ }
+ if (mAudioPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ AutoCallerClear acc;
+ return mAudioPolicyManager->removeUidDeviceAffinities(uid);
+}
+
status_t AudioPolicyService::startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
audio_port_handle_t *portId)
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index c44d816..959e757 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -199,6 +199,10 @@
virtual status_t registerPolicyMixes(const Vector<AudioMix>& mixes, bool registration);
+ virtual status_t setUidDeviceAffinities(uid_t uid, const Vector<AudioDeviceTypeAddr>& devices);
+
+ virtual status_t removeUidDeviceAffinities(uid_t uid);
+
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
audio_port_handle_t *portId);