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

Commit bf1f1b0c authored by Oscar Azucena's avatar Oscar Azucena Committed by Android (Google) Code Review
Browse files

Merge "Disallowed explicit routing for user device affinities conflicts"

parents 68c28472 873d10f7
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -203,9 +203,10 @@ bool AudioMix::hasUserIdRule(bool match, int userId) const {
    return false;
}

bool AudioMix::hasMatchUserIdRule() const {
bool AudioMix::hasUserIdRule(bool match) const {
    const uint32_t rule = match ? RULE_MATCH_USERID : RULE_EXCLUDE_USERID;
    for (size_t i = 0; i < mCriteria.size(); i++) {
        if (mCriteria[i].mRule == RULE_MATCH_USERID) {
        if (mCriteria[i].mRule == rule) {
            return true;
        }
    }
+12 −4
Original line number Diff line number Diff line
@@ -61,7 +61,10 @@ namespace android {
#define MIX_ROUTE_FLAG_LOOP_BACK (0x1 << 1)
/** Loop back some audio while it is rendered */
#define MIX_ROUTE_FLAG_LOOP_BACK_AND_RENDER (MIX_ROUTE_FLAG_RENDER | MIX_ROUTE_FLAG_LOOP_BACK)
#define MIX_ROUTE_FLAG_ALL (MIX_ROUTE_FLAG_RENDER | MIX_ROUTE_FLAG_LOOP_BACK)
/** Control if audio routing disallows preferred device routing **/
#define MIX_ROUTE_FLAG_DISALLOWS_PREFERRED_DEVICE (0x1 << 2)
#define MIX_ROUTE_FLAG_ALL (MIX_ROUTE_FLAG_RENDER | MIX_ROUTE_FLAG_LOOP_BACK | \
    MIX_ROUTE_FLAG_DISALLOWS_PREFERRED_DEVICE)

#define MAX_MIXES_PER_POLICY 10
#define MAX_CRITERIA_PER_MIX 20
@@ -112,9 +115,9 @@ public:
    void setMatchUserId(int userId);
    /** returns true if this mix has a rule to match or exclude the given userId */
    bool hasUserIdRule(bool match, int userId) const;
    /** returns true if this mix has a rule for userId match (any userId) */
    bool hasMatchUserIdRule() const;
    /** returns true if this mix can be used for uid-device affinity routing */
    /** returns true if this mix has a rule to match or exclude (any userId) */
    bool hasUserIdRule(bool match) const;
    /** returns true if this mix has a rule for userId exclude (any userId) */
    bool isDeviceAffinityCompatible() const;

    std::vector<AudioMixMatchCriterion> mCriteria;
@@ -147,6 +150,11 @@ static inline bool is_mix_loopback(uint32_t routeFlags) {
           == MIX_ROUTE_FLAG_LOOP_BACK;
}

static inline bool is_mix_disallows_preferred_device(uint32_t routeFlags) {
    return (routeFlags & MIX_ROUTE_FLAG_DISALLOWS_PREFERRED_DEVICE)
           == MIX_ROUTE_FLAG_DISALLOWS_PREFERRED_DEVICE;
}

}; // namespace android

#endif  // ANDROID_AUDIO_POLICY_H
+28 −5
Original line number Diff line number Diff line
@@ -62,11 +62,24 @@ public:
    void closeOutput(sp<SwAudioOutputDescriptor> &desc);

    /**
     * Try to find an output descriptor for the given attributes.
     * Tries to find the best matching audio policy mix
     *
     * @param[in] attributes to consider for the research of the audio policy mix.
     * @param[in] config to consider for the research of the audio policy mix.
     * @param[in] uid to consider for the research of the audio policy mix.
     * @param[in] session to consider for the research of the audio policy mix.
     * @param[in] flags to consider for the research of the audio policy mix.
     * @param[in] availableOutputDevices available output devices can be use during the research
     *      of the audio policy mix
     * @param[in] requestedDevice currently requested device that can be used determined if the
     *      matching audio policy mix should be used instead of the currently set preferred device.
     * @param[out] primaryMix to return in case a matching audio plicy mix could be found.
     * @param[out] secondaryMixes that audio should be routed to in case a matching
     *      secondary mixes could be found.
     * @param[out] usePrimaryOutputFromPolicyMixes to return in case the audio policy mix
     *      should be use, including the case where the requested device is explicitly disallowed
     *      by the audio policy.
     *
     * @param[in] attributes to consider fowr the research of output descriptor.
     * @param[out] desc to return if an primary output could be found.
     * @param[out] secondaryDesc other desc that the audio should be routed to.
     * @return OK if the request is valid
     *         otherwise if the request is not supported
     */
@@ -75,8 +88,11 @@ public:
                              uid_t uid,
                              audio_session_t session,
                              audio_output_flags_t flags,
                              const DeviceVector &availableOutputDevices,
                              const sp<DeviceDescriptor>& requestedDevice,
                              sp<AudioPolicyMix> &primaryMix,
                              std::vector<sp<AudioPolicyMix>> *secondaryMixes);
                              std::vector<sp<AudioPolicyMix>> *secondaryMixes,
                              bool& usePrimaryOutputFromPolicyMixes);

    sp<DeviceDescriptor> getDeviceAndMixForInputSource(const audio_attributes_t& attributes,
                                                       const DeviceVector &availableDeviceTypes,
@@ -132,6 +148,13 @@ private:
                            const audio_config_base_t& config,
                            uid_t uid,
                            audio_session_t session);
    bool mixDisallowsRequestedDevice(const AudioMix* mix,
                            const sp<DeviceDescriptor>& requestedDevice,
                            const sp<DeviceDescriptor>& mixDevice,
                            const uid_t uid);

    sp<DeviceDescriptor> getOutputDeviceForMix(const AudioMix* mix,
                            const DeviceVector& availableOutputDevices);
};

std::optional<std::string> extractAddressFromAudioAttributes(const audio_attributes_t& attr);
+53 −9
Original line number Diff line number Diff line
@@ -259,14 +259,25 @@ status_t AudioPolicyMixCollection::getOutputForAttr(
        const audio_attributes_t& attributes, const audio_config_base_t& config, const uid_t uid,
        const audio_session_t session,
        audio_output_flags_t flags,
        const DeviceVector &availableOutputDevices,
        const sp<DeviceDescriptor>& requestedDevice,
        sp<AudioPolicyMix> &primaryMix,
        std::vector<sp<AudioPolicyMix>> *secondaryMixes)
        std::vector<sp<AudioPolicyMix>> *secondaryMixes,
        bool& usePrimaryOutputFromPolicyMixes)
{
    ALOGV("getOutputForAttr() querying %zu mixes:", size());
    primaryMix.clear();
    bool mixesDisallowsRequestedDevice = false;
    for (size_t i = 0; i < size(); i++) {
        sp<AudioPolicyMix> policyMix = itemAt(i);
        const bool primaryOutputMix = !is_mix_loopback_render(policyMix->mRouteFlags);
        sp<DeviceDescriptor> mixDevice = getOutputDeviceForMix(policyMix.get(),
            availableOutputDevices);
        if (mixDisallowsRequestedDevice(policyMix.get(), requestedDevice, mixDevice, uid)) {
            ALOGV("%s: Mix %zu: does not allows device", __func__, i);
            mixesDisallowsRequestedDevice = true;
        }

        if (!primaryOutputMix && (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ)) {
            // AAudio does not support MMAP_NO_IRQ loopback render, and there is no way with
            // the current MmapStreamInterface::start to reject a specific client added to a shared
@@ -288,6 +299,11 @@ status_t AudioPolicyMixCollection::getOutputForAttr(
            continue; // skip the mix
        }

        if (mixDevice != nullptr && mixDevice->equals(requestedDevice)) {
            ALOGV("%s: Mix %zu: requested device mathches", __func__, i);
            mixesDisallowsRequestedDevice = false;
        }

        if (primaryOutputMix) {
            primaryMix = policyMix;
            ALOGV("%s: Mix %zu: set primary desc", __func__, i);
@@ -298,9 +314,36 @@ status_t AudioPolicyMixCollection::getOutputForAttr(
            }
        }
    }

    // Explicit routing is higher priority than dynamic policy primary output, but policy may
    // explicitly deny it
    usePrimaryOutputFromPolicyMixes =
        (mixesDisallowsRequestedDevice || requestedDevice == nullptr) && primaryMix != nullptr;

    return NO_ERROR;
}

sp<DeviceDescriptor> AudioPolicyMixCollection::getOutputDeviceForMix(const AudioMix* mix,
                                                    const DeviceVector& availableOutputDevices) {
    ALOGV("%s: device (0x%x, addr=%s) forced by mix", __func__, mix->mDeviceType,
        mix->mDeviceAddress.c_str());
    return availableOutputDevices.getDevice(mix->mDeviceType, mix->mDeviceAddress,
        AUDIO_FORMAT_DEFAULT);
}

bool AudioPolicyMixCollection::mixDisallowsRequestedDevice(const AudioMix* mix,
                                                     const sp<DeviceDescriptor>& requestedDevice,
                                                     const sp<DeviceDescriptor>& mixDevice,
                                                     const uid_t uid) {
    if (requestedDevice == nullptr || mixDevice == nullptr) {
        return false;
    }

    return is_mix_disallows_preferred_device(mix->mRouteFlags)
        && requestedDevice->equals(mixDevice)
        && mix->hasUserIdRule(false /* match */, multiuser_get_user_id(uid));
}

bool AudioPolicyMixCollection::mixMatch(const AudioMix* mix, size_t mixIndex,
    const audio_attributes_t& attributes, const audio_config_base_t& config,
    uid_t uid, audio_session_t session) {
@@ -361,11 +404,7 @@ sp<DeviceDescriptor> AudioPolicyMixCollection::getDeviceAndMixForOutput(
    for (size_t i = 0; i < size(); i++) {
        if (itemAt(i)->getOutput() == output) {
            // This Desc is involved in a Mix, which has the highest prio
            audio_devices_t deviceType = itemAt(i)->mDeviceType;
            String8 address = itemAt(i)->mDeviceAddress;
            ALOGV("%s: device (0x%x, addr=%s) forced by mix",
                  __FUNCTION__, deviceType, address.c_str());
            return availableOutputDevices.getDevice(deviceType, address, AUDIO_FORMAT_DEFAULT);
            return getOutputDeviceForMix(itemAt(i).get(), availableOutputDevices);
        }
    }
    return nullptr;
@@ -568,13 +607,14 @@ status_t AudioPolicyMixCollection::setUserIdDeviceAffinities(int userId,
                break;
            }
        }
        if (!deviceMatch && !mix->hasMatchUserIdRule()) {
        if (!deviceMatch && !mix->hasUserIdRule(true /*match*/)) {
            // this mix doesn't go to one of the listed devices for the given userId,
            // and it's not already restricting the mix on a userId,
            // modify its rules to exclude the userId
            if (!mix->hasUserIdRule(false /* match */, userId)) {
                // no need to do it again if userId is already excluded
                mix->setExcludeUserId(userId);
                mix->mRouteFlags = mix->mRouteFlags | MIX_ROUTE_FLAG_DISALLOWS_PREFERRED_DEVICE;
            }
        }
    }
@@ -595,6 +635,10 @@ status_t AudioPolicyMixCollection::removeUserIdDeviceAffinities(int userId) {
        EraseCriteriaIf(mix->mCriteria, [userId](const AudioMixMatchCriterion& c) {
            return c.mRule == RULE_EXCLUDE_USERID && c.mValue.mUserId == userId;
        });

        if (!mix->hasUserIdRule(false /* match */)) {
            mix->mRouteFlags = mix->mRouteFlags & ~MIX_ROUTE_FLAG_DISALLOWS_PREFERRED_DEVICE;
        }
    }
    return NO_ERROR;
}
+16 −8
Original line number Diff line number Diff line
@@ -1168,6 +1168,8 @@ status_t AudioPolicyManager::getOutputForAttrInt(
    ALOGV("%s() attributes=%s stream=%s session %d selectedDeviceId %d", __func__,
          toString(*resultAttr).c_str(), toString(*stream).c_str(), session, requestedPortId);

    bool usePrimaryOutputFromPolicyMixes = false;

    // The primary output is the explicit routing (eg. setPreferredDevice) if specified,
    //       otherwise, fallback to the dynamic policies, if none match, query the engine.
    // Secondary outputs are always found by dynamic policies as the engine do not support them
@@ -1177,14 +1179,12 @@ status_t AudioPolicyManager::getOutputForAttrInt(
        .format = config->format,
    };
    status = mPolicyMixes.getOutputForAttr(*resultAttr, clientConfig, uid, session, *flags,
                                           primaryMix, secondaryMixes);
                                           mAvailableOutputDevices, requestedDevice, primaryMix,
                                           secondaryMixes, usePrimaryOutputFromPolicyMixes);
    if (status != OK) {
        return status;
    }

    // Explicit routing is higher priority then any dynamic policy primary output
    bool usePrimaryOutputFromPolicyMixes = requestedDevice == nullptr && primaryMix != nullptr;

    // FIXME: in case of RENDER policy, the output capabilities should be checked
    if ((secondaryMixes != nullptr && !secondaryMixes->empty())
            && !audio_is_linear_pcm(config->format)) {
@@ -6730,6 +6730,7 @@ void AudioPolicyManager::checkOutputForAttributes(const audio_attributes_t &attr
    SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevices(newDevices, mOutputs);

    uint32_t maxLatency = 0;
    bool unneededUsePrimaryOutputFromPolicyMixes = false;
    std::vector<sp<SwAudioOutputDescriptor>> invalidatedOutputs;
    // take into account dynamic audio policies related changes: if a client is now associated
    // to a different policy mix than at creation time, invalidate corresponding stream
@@ -6744,7 +6745,9 @@ void AudioPolicyManager::checkOutputForAttributes(const audio_attributes_t &attr
            }
            sp<AudioPolicyMix> primaryMix;
            status_t status = mPolicyMixes.getOutputForAttr(client->attributes(), client->config(),
                    client->uid(), client->session(), client->flags(), primaryMix, nullptr);
                    client->uid(), client->session(), client->flags(), mAvailableOutputDevices,
                    nullptr /* requestedDevice */, primaryMix, nullptr /* secondaryMixes */,
                    unneededUsePrimaryOutputFromPolicyMixes);
            if (status != OK) {
                continue;
            }
@@ -6842,13 +6845,16 @@ void AudioPolicyManager::checkOutputForAllStrategies()
void AudioPolicyManager::checkSecondaryOutputs() {
    PortHandleVector clientsToInvalidate;
    TrackSecondaryOutputsMap trackSecondaryOutputs;
    bool unneededUsePrimaryOutputFromPolicyMixes = false;
    for (size_t i = 0; i < mOutputs.size(); i++) {
        const sp<SwAudioOutputDescriptor>& outputDescriptor = mOutputs[i];
        for (const sp<TrackClientDescriptor>& client : outputDescriptor->getClientIterable()) {
            sp<AudioPolicyMix> primaryMix;
            std::vector<sp<AudioPolicyMix>> secondaryMixes;
            status_t status = mPolicyMixes.getOutputForAttr(client->attributes(), client->config(),
                    client->uid(), client->session(), client->flags(), primaryMix, &secondaryMixes);
                    client->uid(), client->session(), client->flags(), mAvailableOutputDevices,
                    nullptr /* requestedDevice */, primaryMix, &secondaryMixes,
                    unneededUsePrimaryOutputFromPolicyMixes);
            std::vector<sp<SwAudioOutputDescriptor>> secondaryDescs;
            for (auto &secondaryMix : secondaryMixes) {
                sp<SwAudioOutputDescriptor> outputDesc = secondaryMix->getOutput();
@@ -8282,9 +8288,11 @@ status_t AudioPolicyManager::getDevicesForAttributes(
    // check dynamic policies but only for primary descriptors (secondary not used for audible
    // audio routing, only used for duplication for playback capture)
    sp<AudioPolicyMix> policyMix;
    bool unneededUsePrimaryOutputFromPolicyMixes = false;
    status_t status = mPolicyMixes.getOutputForAttr(attr, AUDIO_CONFIG_BASE_INITIALIZER,
            0 /*uid unknown here*/, AUDIO_SESSION_NONE, AUDIO_OUTPUT_FLAG_NONE, policyMix,
            nullptr /* secondaryMixes */);
            0 /*uid unknown here*/, AUDIO_SESSION_NONE, AUDIO_OUTPUT_FLAG_NONE,
            mAvailableOutputDevices, nullptr /* requestedDevice */, policyMix,
            nullptr /* secondaryMixes */, unneededUsePrimaryOutputFromPolicyMixes);
    if (status != OK) {
        return status;
    }
Loading