Merge "APM: uid-device affinity: fix for multiple concurrent apps" into qt-dev am: b09f621af6
am: 5f5158fe34
Change-Id: Ic766a8ef35f7d4826819ca53a51def1f6c659882
diff --git a/media/libaudioclient/AudioPolicy.cpp b/media/libaudioclient/AudioPolicy.cpp
index 65e797f..3cdf095 100644
--- a/media/libaudioclient/AudioPolicy.cpp
+++ b/media/libaudioclient/AudioPolicy.cpp
@@ -159,4 +159,29 @@
mCriteria.add(crit);
}
+bool AudioMix::hasUidRule(bool match, uid_t uid) const {
+ const uint32_t rule = match ? RULE_MATCH_UID : RULE_EXCLUDE_UID;
+ for (size_t i = 0; i < mCriteria.size(); i++) {
+ if (mCriteria[i].mRule == rule
+ && mCriteria[i].mValue.mUid == uid) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AudioMix::hasMatchUidRule() const {
+ for (size_t i = 0; i < mCriteria.size(); i++) {
+ if (mCriteria[i].mRule == RULE_MATCH_UID) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AudioMix::isDeviceAffinityCompatible() const {
+ return ((mMixType == MIX_TYPE_PLAYERS)
+ && (mRouteFlags == MIX_ROUTE_FLAG_RENDER));
+}
+
} // namespace android
diff --git a/media/libaudioclient/include/media/AudioPolicy.h b/media/libaudioclient/include/media/AudioPolicy.h
index a40e019..ef39fd1 100644
--- a/media/libaudioclient/include/media/AudioPolicy.h
+++ b/media/libaudioclient/include/media/AudioPolicy.h
@@ -106,6 +106,12 @@
void setExcludeUid(uid_t uid) const;
void setMatchUid(uid_t uid) const;
+ /** returns true if this mix has a rule to match or exclude the given uid */
+ bool hasUidRule(bool match, uid_t uid) const;
+ /** returns true if this mix has a rule for uid match (any uid) */
+ bool hasMatchUidRule() const;
+ /** returns true if this mix can be used for uid-device affinity routing */
+ bool isDeviceAffinityCompatible() const;
mutable Vector<AudioMixMatchCriterion> mCriteria;
uint32_t mMixType;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index f2b51d9..12b5e7d 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -89,6 +89,16 @@
status_t getInputMixForAttr(audio_attributes_t attr, sp<AudioPolicyMix> *policyMix);
+ /**
+ * Updates the mix rules in order to make streams associated with the given uid
+ * be routed to the given audio devices.
+ * @param uid the uid for which the device affinity is set
+ * @param devices the vector of devices that this uid may be routed to. A typical
+ * use is to pass the devices associated with a given zone in a multi-zone setup.
+ * @return NO_ERROR if the update was successful, INVALID_OPERATION otherwise.
+ * An example of failure is when there are already rules in place to restrict
+ * a mix to the given uid (i.e. when a MATCH_UID rule was set for it).
+ */
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;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 26bb354..98a7800 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -400,13 +400,29 @@
status_t AudioPolicyMixCollection::setUidDeviceAffinities(uid_t uid,
const Vector<AudioDeviceTypeAddr>& devices) {
+ // verify feasibility: for each player mix: if it already contains a
+ // "match uid" rule for this uid, return an error
+ // (adding a uid-device affinity would result in contradictory rules)
+ for (size_t i = 0; i < size(); i++) {
+ const AudioPolicyMix* mix = valueAt(i).get();
+ if (!mix->isDeviceAffinityCompatible()) {
+ continue;
+ }
+ if (mix->hasUidRule(true /*match*/, uid)) {
+ return INVALID_OPERATION;
+ }
+ }
+
// 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 each player mix:
+ // IF device is not a target for the mix,
+ // AND it doesn't have a "match uid" rule
+ // THEN add a rule to exclude the uid
for (size_t i = 0; i < size(); i++) {
const AudioPolicyMix *mix = valueAt(i).get();
- if (mix->mMixType != MIX_TYPE_PLAYERS) {
+ if (!mix->isDeviceAffinityCompatible()) {
continue;
}
// check if this mix goes to a device in the list of devices
@@ -418,12 +434,14 @@
break;
}
}
- if (deviceMatch) {
- mix->setMatchUid(uid);
- } else {
+ if (!deviceMatch && !mix->hasMatchUidRule()) {
// this mix doesn't go to one of the listed devices for the given uid,
+ // and it's not already restricting the mix on a uid,
// modify its rules to exclude the uid
- mix->setExcludeUid(uid);
+ if (!mix->hasUidRule(false /*match*/, uid)) {
+ // no need to do it again if uid is already excluded
+ mix->setExcludeUid(uid);
+ }
}
}
@@ -435,14 +453,15 @@
for (size_t i = 0; i < size(); i++) {
bool foundUidRule = false;
const AudioPolicyMix *mix = valueAt(i).get();
- if (mix->mMixType != MIX_TYPE_PLAYERS) {
+ if (!mix->isDeviceAffinityCompatible()) {
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 || rule == RULE_MATCH_UID)
+ // is this rule excluding the uid? (not considering uid match rules
+ // as those are not used for uid-device affinity)
+ if (rule == RULE_EXCLUDE_UID
&& uid == mix->mCriteria[j].mValue.mUid) {
foundUidRule = true;
criteriaToRemove.insert(criteriaToRemove.begin(), j);