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

Commit 661c5953 authored by Jean-Michel Trivi's avatar Jean-Michel Trivi Committed by Android (Google) Code Review
Browse files

Merge "Dynamic audio policies on UID" into nyc-dev

parents e99556b8 e8decedb
Loading
Loading
Loading
Loading
+12 −9
Original line number Diff line number Diff line
@@ -30,9 +30,11 @@ namespace android {
#define RULE_EXCLUSION_MASK 0x8000
#define RULE_MATCH_ATTRIBUTE_USAGE           0x1
#define RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET (0x1 << 1)
#define RULE_MATCH_UID                      (0x1 << 2)
#define RULE_EXCLUDE_ATTRIBUTE_USAGE  (RULE_EXCLUSION_MASK|RULE_MATCH_ATTRIBUTE_USAGE)
#define RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET \
                                      (RULE_EXCLUSION_MASK|RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET)
#define RULE_EXCLUDE_UID              (RULE_EXCLUSION_MASK|RULE_MATCH_UID)

#define MIX_TYPE_INVALID -1
#define MIX_TYPE_PLAYERS 0
@@ -53,10 +55,10 @@ namespace android {
#define MAX_MIXES_PER_POLICY 10
#define MAX_CRITERIA_PER_MIX 20

class AttributeMatchCriterion {
class AudioMixMatchCriterion {
public:
    AttributeMatchCriterion() {}
    AttributeMatchCriterion(audio_usage_t usage, audio_source_t source, uint32_t rule);
    AudioMixMatchCriterion() {}
    AudioMixMatchCriterion(audio_usage_t usage, audio_source_t source, uint32_t rule);

    status_t readFromParcel(Parcel *parcel);
    status_t writeToParcel(Parcel *parcel) const;
@@ -64,7 +66,8 @@ public:
    union {
        audio_usage_t   mUsage;
        audio_source_t  mSource;
    } mAttr;
        uid_t           mUid;
    } mValue;
    uint32_t        mRule;
};

@@ -75,7 +78,7 @@ public:
    static const uint32_t kCbFlagNotifyActivity = 0x1;

    AudioMix() {}
    AudioMix(Vector<AttributeMatchCriterion> criteria, uint32_t mixType, audio_config_t format,
    AudioMix(Vector<AudioMixMatchCriterion> criteria, uint32_t mixType, audio_config_t format,
             uint32_t routeFlags, String8 registrationId, uint32_t flags) :
        mCriteria(criteria), mMixType(mixType), mFormat(format),
        mRouteFlags(routeFlags), mRegistrationId(registrationId), mCbFlags(flags){}
@@ -83,7 +86,7 @@ public:
    status_t readFromParcel(Parcel *parcel);
    status_t writeToParcel(Parcel *parcel) const;

    Vector<AttributeMatchCriterion> mCriteria;
    Vector<AudioMixMatchCriterion> mCriteria;
    uint32_t        mMixType;
    audio_config_t  mFormat;
    uint32_t        mRouteFlags;
+10 −10
Original line number Diff line number Diff line
@@ -22,37 +22,37 @@
namespace android {

//
//  AttributeMatchCriterion implementation
//  AudioMixMatchCriterion implementation
//
AttributeMatchCriterion::AttributeMatchCriterion(audio_usage_t usage,
AudioMixMatchCriterion::AudioMixMatchCriterion(audio_usage_t usage,
                                                 audio_source_t source,
                                                 uint32_t rule)
: mRule(rule)
{
    if (mRule == RULE_MATCH_ATTRIBUTE_USAGE ||
            mRule == RULE_EXCLUDE_ATTRIBUTE_USAGE) {
        mAttr.mUsage = usage;
        mValue.mUsage = usage;
    } else {
        mAttr.mSource = source;
        mValue.mSource = source;
    }
}

status_t AttributeMatchCriterion::readFromParcel(Parcel *parcel)
status_t AudioMixMatchCriterion::readFromParcel(Parcel *parcel)
{
    mRule = parcel->readInt32();
    if (mRule == RULE_MATCH_ATTRIBUTE_USAGE ||
            mRule == RULE_EXCLUDE_ATTRIBUTE_USAGE) {
        mAttr.mUsage = (audio_usage_t)parcel->readInt32();
        mValue.mUsage = (audio_usage_t)parcel->readInt32();
    } else {
        mAttr.mSource = (audio_source_t)parcel->readInt32();
        mValue.mSource = (audio_source_t)parcel->readInt32();
    }
    return NO_ERROR;
}

status_t AttributeMatchCriterion::writeToParcel(Parcel *parcel) const
status_t AudioMixMatchCriterion::writeToParcel(Parcel *parcel) const
{
    parcel->writeInt32(mRule);
    parcel->writeInt32(mAttr.mUsage);
    parcel->writeInt32(mValue.mUsage);
    return NO_ERROR;
}

@@ -74,7 +74,7 @@ status_t AudioMix::readFromParcel(Parcel *parcel)
        size = MAX_CRITERIA_PER_MIX;
    }
    for (size_t i = 0; i < size; i++) {
        AttributeMatchCriterion criterion;
        AudioMixMatchCriterion criterion;
        if (criterion.readFromParcel(parcel) == NO_ERROR) {
            mCriteria.add(criterion);
        }
+2 −1
Original line number Diff line number Diff line
@@ -69,7 +69,8 @@ public:
     * @return NO_ERROR if an output was found for the given attribute (in this case, the
     *                  descriptor output param is initialized), error code otherwise.
     */
    status_t getOutputForAttr(audio_attributes_t attributes, sp<SwAudioOutputDescriptor> &desc);
    status_t getOutputForAttr(audio_attributes_t attributes, uid_t uid,
            sp<SwAudioOutputDescriptor> &desc);

    audio_devices_t getDeviceAndMixForInputSource(audio_source_t inputSource,
                                                  audio_devices_t availableDeviceTypes,
+101 −11
Original line number Diff line number Diff line
@@ -98,30 +98,111 @@ void AudioPolicyMixCollection::closeOutput(sp<SwAudioOutputDescriptor> &desc)
    }
}

status_t AudioPolicyMixCollection::getOutputForAttr(audio_attributes_t attributes,
status_t AudioPolicyMixCollection::getOutputForAttr(audio_attributes_t attributes, uid_t uid,
                                                    sp<SwAudioOutputDescriptor> &desc)
{
    desc = 0;
    for (size_t i = 0; i < size(); i++) {
        sp<AudioPolicyMix> policyMix = valueAt(i);
        AudioMix *mix = policyMix->getMix();

        if (mix->mMixType == MIX_TYPE_PLAYERS) {
            // TODO if adding more player rules (currently only 2), make rule handling "generic"
            //      as there is no difference in the treatment of usage- or uid-based rules
            bool hasUsageMatchRules = false;
            bool hasUsageExcludeRules = false;
            bool usageMatchFound = false;
            bool usageExclusionFound = false;

            bool hasUidMatchRules = false;
            bool hasUidExcludeRules = false;
            bool uidMatchFound = false;
            bool uidExclusionFound = false;

            bool hasAddrMatch = false;

            // iterate over all mix criteria to list what rules this mix contains
            for (size_t j = 0; j < mix->mCriteria.size(); j++) {
                if ((RULE_MATCH_ATTRIBUTE_USAGE == mix->mCriteria[j].mRule &&
                     mix->mCriteria[j].mAttr.mUsage == attributes.usage) ||
                        (RULE_EXCLUDE_ATTRIBUTE_USAGE == mix->mCriteria[j].mRule &&
                         mix->mCriteria[j].mAttr.mUsage != attributes.usage)) {
                    desc = policyMix->getOutput();
                    break;
                }
                ALOGV("getOutputForAttr: inspecting mix %zu of %zu", i, mix->mCriteria.size());

                // if there is an address match, prioritize that match
                if (strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 &&
                        strncmp(attributes.tags + strlen("addr="),
                                mix->mRegistrationId.string(),
                                AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
                    desc = policyMix->getOutput();
                    hasAddrMatch = true;
                    break;
                }

                switch (mix->mCriteria[j].mRule) {
                case RULE_MATCH_ATTRIBUTE_USAGE:
                    ALOGV("\tmix has RULE_MATCH_ATTRIBUTE_USAGE for usage %d",
                                                mix->mCriteria[j].mValue.mUsage);
                    hasUsageMatchRules = true;
                    if (mix->mCriteria[j].mValue.mUsage == attributes.usage) {
                        // found one match against all allowed usages
                        usageMatchFound = true;
                    }
                    break;
                case RULE_EXCLUDE_ATTRIBUTE_USAGE:
                    ALOGV("\tmix has RULE_EXCLUDE_ATTRIBUTE_USAGE for usage %d",
                            mix->mCriteria[j].mValue.mUsage);
                    hasUsageExcludeRules = true;
                    if (mix->mCriteria[j].mValue.mUsage == attributes.usage) {
                        // found this usage is to be excluded
                        usageExclusionFound = true;
                    }
                    break;
                case RULE_MATCH_UID:
                    ALOGV("\tmix has RULE_MATCH_UID for uid %d", mix->mCriteria[j].mValue.mUid);
                    hasUidMatchRules = true;
                    if (mix->mCriteria[j].mValue.mUid == uid) {
                        // found one UID match against all allowed UIDs
                        uidMatchFound = true;
                    }
                    break;
                case RULE_EXCLUDE_UID:
                    ALOGV("\tmix has RULE_EXCLUDE_UID for uid %d", mix->mCriteria[j].mValue.mUid);
                    hasUidExcludeRules = true;
                    if (mix->mCriteria[j].mValue.mUid == uid) {
                        // found this UID is to be excluded
                        uidExclusionFound = true;
                    }
                    break;
                default:
                    break;
                }

                // consistency checks: for each "dimension" of rules (usage, uid...), we can
                // only have MATCH rules, or EXCLUDE rules in each dimension, not a combination
                if (hasUsageMatchRules && hasUsageExcludeRules) {
                    ALOGE("getOutputForAttr: invalid combination of RULE_MATCH_ATTRIBUTE_USAGE"
                            " and RULE_EXCLUDE_ATTRIBUTE_USAGE in mix %zu", i);
                    return BAD_VALUE;
                }
                if (hasUidMatchRules && hasUidExcludeRules) {
                    ALOGE("getOutputForAttr: invalid combination of RULE_MATCH_UID"
                            " and RULE_EXCLUDE_UID in mix %zu", i);
                    return BAD_VALUE;
                }

                if ((hasUsageExcludeRules && usageExclusionFound)
                        || (hasUidExcludeRules && uidExclusionFound)) {
                    break; // stop iterating on criteria because an exclusion was found (will fail)
                }

            }//iterate on mix criteria

            // determine if exiting on success (or implicit failure as desc is 0)
            if (hasAddrMatch ||
                    !((hasUsageExcludeRules && usageExclusionFound) ||
                      (hasUsageMatchRules && !usageMatchFound)  ||
                      (hasUidExcludeRules && uidExclusionFound) ||
                      (hasUidMatchRules && !uidMatchFound))) {
                ALOGV("\tgetOutputForAttr will use mix %zu", i);
                desc = policyMix->getOutput();
            }

        } else if (mix->mMixType == MIX_TYPE_RECORDERS) {
            if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE &&
                    strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 &&
@@ -151,9 +232,9 @@ audio_devices_t AudioPolicyMixCollection::getDeviceAndMixForInputSource(audio_so
        }
        for (size_t j = 0; j < mix->mCriteria.size(); j++) {
            if ((RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET == mix->mCriteria[j].mRule &&
                    mix->mCriteria[j].mAttr.mSource == inputSource) ||
                    mix->mCriteria[j].mValue.mSource == inputSource) ||
               (RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET == mix->mCriteria[j].mRule &&
                    mix->mCriteria[j].mAttr.mSource != inputSource)) {
                    mix->mCriteria[j].mValue.mSource != inputSource)) {
                if (availDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
                    if (policyMix != NULL) {
                        *policyMix = mix;
@@ -174,6 +255,15 @@ status_t AudioPolicyMixCollection::getInputMixForAttr(audio_attributes_t attr, A
    }
    String8 address(attr.tags + strlen("addr="));

#ifdef LOG_NDEBUG
    ALOGV("getInputMixForAttr looking for address %s\n  mixes available:", address.string());
    for (size_t i = 0; i < size(); i++) {
            sp<AudioPolicyMix> policyMix = valueAt(i);
            AudioMix *mix = policyMix->getMix();
            ALOGV("\tmix %zu address=%s", i, mix->mRegistrationId.string());
    }
#endif

    ssize_t index = indexOfKey(address);
    if (index < 0) {
        ALOGW("getInputMixForAttr() no policy for address %s", address.string());
+1 −1
Original line number Diff line number Diff line
@@ -709,7 +709,7 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
        stream_type_to_audio_attributes(*stream, &attributes);
    }
    sp<SwAudioOutputDescriptor> desc;
    if (mPolicyMixes.getOutputForAttr(attributes, desc) == NO_ERROR) {
    if (mPolicyMixes.getOutputForAttr(attributes, uid, desc) == NO_ERROR) {
        ALOG_ASSERT(desc != 0, "Invalid desc returned by getOutputForAttr");
        if (!audio_is_linear_pcm(format)) {
            return BAD_VALUE;