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

Commit a6d358f8 authored by Atneya Nair's avatar Atneya Nair Committed by Android (Google) Code Review
Browse files

Merge "getInputForAttr perm check cleanup pt2" into main

parents 82d42141 25fbcf21
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -28,6 +28,8 @@ parcelable GetInputForAttrResponse {
    int selectedDeviceId;
    /** Interpreted as audio_port_handle_t. */
    int portId;
    /** The virtual device id corresponding to the opened input. */
    int virtualDeviceId;
    /** The suggested config if fails to get an input. **/
    AudioConfigBase config;
}
+22 −11
Original line number Diff line number Diff line
@@ -19,15 +19,17 @@

#include <android/media/DeviceConnectedState.h>
#include <android/media/TrackInternalMuteInfo.h>
#include <android/media/audio/common/AudioConfigBase.h>
#include <android/media/audio/common/AudioMMapPolicyInfo.h>
#include <android/media/audio/common/AudioMMapPolicyType.h>
#include <android/media/GetInputForAttrResponse.h>
#include <android/content/AttributionSourceState.h>
#include <media/AudioCommonTypes.h>
#include <media/AudioContainers.h>
#include <media/AudioDeviceTypeAddr.h>
#include <media/AudioSystem.h>
#include <media/AudioPolicy.h>
#include <media/AudioSystem.h>
#include <media/DeviceDescriptorBase.h>
#include <android/content/AttributionSourceState.h>
#include <utils/String8.h>

namespace android {
@@ -161,18 +163,27 @@ public:
    // releases the output, return true if the output descriptor is reopened.
    virtual bool releaseOutput(audio_port_handle_t portId) = 0;

    // request an input appropriate for record from the supplied device with supplied parameters.
    virtual status_t getInputForAttr(const audio_attributes_t *attr,
                                     audio_io_handle_t *input,
    // Request an input appropriate for record from the supplied device with supplied parameters.
    // attr -- attributes for the requested record
    // requestedInput -- input only for MMAP mode where an input is re-used, otherwise output param
    // requestedDeviceId, config, flags -- additional params for matching
    // riid, session, attributionSource -- params which encapsulate client info to associate with
    // this input
    //
    // On most errors, return a Status describing the error in the error object.
    // However, in cases where an appropriate device cannot be found for a config, the error side of
    // the unexpected will contain a suggested config.
    virtual base::expected<media::GetInputForAttrResponse,
            std::variant<binder::Status, media::audio::common::AudioConfigBase>>
                     getInputForAttr(audio_attributes_t attributes,
                                     audio_io_handle_t requestedInput,
                                     audio_port_handle_t requestedDeviceId,
                                     audio_config_base_t config,
                                     audio_input_flags_t flags,
                                     audio_unique_id_t riid,
                                     audio_session_t session,
                                     const AttributionSourceState& attributionSource,
                                     audio_config_base_t *config,
                                     audio_input_flags_t flags,
                                     audio_port_handle_t *selectedDeviceId,
                                     input_type_t *inputType,
                                     audio_port_handle_t *portId,
                                     uint32_t *virtualDeviceId) = 0;
                                     input_type_t *inputType /* out param */) = 0;
    // indicates to the audio policy manager that the input starts being used.
    virtual status_t startInput(audio_port_handle_t portId) = 0;
    // indicates to the audio policy manager that the input stops being used.
+7 −6
Original line number Diff line number Diff line
@@ -286,7 +286,7 @@ bool AudioPolicyManagerFuzzer::getOutputForAttr(
bool AudioPolicyManagerFuzzer::getInputForAttr(
    const audio_attributes_t &attr, audio_unique_id_t riid, audio_port_handle_t *selectedDeviceId,
    audio_format_t format, audio_channel_mask_t channelMask, int sampleRate,
    audio_input_flags_t flags, audio_port_handle_t *portId, uint32_t *virtualDeviceId) {
    audio_input_flags_t flags, audio_port_handle_t *portId, uint32_t*) {
    audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
    audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
    config.sample_rate = sampleRate;
@@ -300,11 +300,12 @@ bool AudioPolicyManagerFuzzer::getInputForAttr(
    AttributionSourceState attributionSource;
    attributionSource.uid = 0;
    attributionSource.token = sp<BBinder>::make();
    if (mManager->getInputForAttr(&attr, &input, riid, AUDIO_SESSION_NONE, attributionSource,
            &config, flags, selectedDeviceId, &inputType, portId, virtualDeviceId) != OK) {
        return false;
    }
    if (*portId == AUDIO_PORT_HANDLE_NONE || input == AUDIO_IO_HANDLE_NONE) {
    const auto inputRes =
            mManager->getInputForAttr(attr, input, *selectedDeviceId, config, flags, riid,
                                      AUDIO_SESSION_NONE, attributionSource, &inputType);
    if (!inputRes.has_value()) return false;

    if (inputRes->portId == AUDIO_PORT_HANDLE_NONE || inputRes->input == AUDIO_IO_HANDLE_NONE) {
        return false;
    }
    return true;
+1 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ cc_library_shared {
        // a dependency on it in the device makefile. There will be no build time
        // conflict with libaudiopolicyenginedefault.
        "audioclient-types-aidl-cpp",
        "audiopolicy-aidl-cpp",
        // Flag support
        "android.media.audiopolicy-aconfig-cc",
        "com.android.media.audioserver-aconfig-cc",
+137 −148
Original line number Diff line number Diff line
@@ -14,7 +14,6 @@
 * limitations under the License.
 */

#include "utils/Errors.h"
#define LOG_TAG "APM_AudioPolicyManager"

// Need to keep the log statements even in production builds
@@ -46,6 +45,7 @@
#include <android_media_audiopolicy.h>
#include <com_android_media_audioserver.h>
#include <cutils/bitops.h>
#include <error/expected_utils.h>
#include <media/AudioParameter.h>
#include <policy.h>
#include <private/android_filesystem_config.h>
@@ -71,6 +71,8 @@ using android::media::audio::common::AudioMMapPolicyInfo;
using android::media::audio::common::AudioMMapPolicyType;
using android::media::audio::common::AudioPortDeviceExt;
using android::media::audio::common::AudioPortExt;
using android::media::audio::common::AudioConfigBase;
using binder::Status;
using com::android::media::audioserver::fix_call_audio_patch;
using content::AttributionSourceState;

@@ -2925,63 +2927,57 @@ bool AudioPolicyManager::releaseOutput(audio_port_handle_t portId)
    return false;
}

status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
                                             audio_io_handle_t *input,
base::expected<media::GetInputForAttrResponse, std::variant<binder::Status, AudioConfigBase>>
AudioPolicyManager::getInputForAttr(audio_attributes_t attributes,
                                     audio_io_handle_t requestedInput,
                                     audio_port_handle_t requestedDeviceId,
                                     audio_config_base_t config,
                                     audio_input_flags_t flags,
                                     audio_unique_id_t riid,
                                     audio_session_t session,
                                     const AttributionSourceState& attributionSource,
                                             audio_config_base_t *config,
                                             audio_input_flags_t flags,
                                             audio_port_handle_t *selectedDeviceId,
                                             input_type_t *inputType,
                                             audio_port_handle_t *portId,
                                             uint32_t *virtualDeviceId)
                                     input_type_t *inputType)
{
    ALOGV("%s() source %d, sampling rate %d, format %#x, channel mask %#x, session %d, "
          "flags %#x attributes=%s requested device ID %d",
          __func__, attr->source, config->sample_rate, config->format, config->channel_mask,
          session, flags, toString(*attr).c_str(), *selectedDeviceId);
          __func__, attributes.source, config.sample_rate, config.format, config.channel_mask,
          session, flags, toString(attributes).c_str(), requestedDeviceId);

    status_t status = NO_ERROR;
    audio_attributes_t attributes = *attr;
    sp<AudioPolicyMix> policyMix;
    sp<DeviceDescriptor> device;
    sp<AudioInputDescriptor> inputDesc;
    sp<AudioInputDescriptor> previousInputDesc;
    sp<RecordClientDescriptor> clientDesc;
    audio_port_handle_t requestedDeviceId = *selectedDeviceId;
    uid_t uid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_uid_t(attributionSource.uid));
    uid_t uid = static_cast<uid_t>(attributionSource.uid);
    bool isSoundTrigger;
    int vdi = 0 /* default device id */;
    audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;

    // The supplied portId must be AUDIO_PORT_HANDLE_NONE
    if (*portId != AUDIO_PORT_HANDLE_NONE) {
        return INVALID_OPERATION;
    }

    if (attr->source == AUDIO_SOURCE_DEFAULT) {
    if (attributes.source == AUDIO_SOURCE_DEFAULT) {
        attributes.source = AUDIO_SOURCE_MIC;
    }

    // Explicit routing?
    sp<DeviceDescriptor> explicitRoutingDevice =
            mAvailableInputDevices.getDeviceFromId(*selectedDeviceId);
            mAvailableInputDevices.getDeviceFromId(requestedDeviceId);

    // special case for mmap capture: if an input IO handle is specified, we reuse this input if
    // possible
    if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) == AUDIO_INPUT_FLAG_MMAP_NOIRQ &&
            *input != AUDIO_IO_HANDLE_NONE) {
        ssize_t index = mInputs.indexOfKey(*input);
            requestedInput != AUDIO_IO_HANDLE_NONE) {
        input = requestedInput;
        ssize_t index = mInputs.indexOfKey(requestedInput);
        if (index < 0) {
            ALOGW("getInputForAttr() unknown MMAP input %d", *input);
            status = BAD_VALUE;
            goto error;
            return base::unexpected{Status::fromExceptionCode(
                    EX_ILLEGAL_ARGUMENT,
                    String8::format("%s unknown MMAP input %d", __func__, requestedInput))};
        }
        sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
        RecordClientVector clients = inputDesc->getClientsForSession(session);
        if (clients.size() == 0) {
            ALOGW("getInputForAttr() unknown session %d on input %d", session, *input);
            status = BAD_VALUE;
            goto error;
            return base::unexpected{Status::fromExceptionCode(
                    EX_ILLEGAL_ARGUMENT, String8::format("%s unknown session %d on input %d",
                                                         __func__, session, requestedInput))};
        }
        // For MMAP mode, the first call to getInputForAttr() is made on behalf of audioflinger.
        // The second call is for the first active client and sets the UID. Any further call
@@ -2997,39 +2993,37 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
                    continue;
                }
                if (uid != client->uid() && !client->isSilenced()) {
                    ALOGW("getInputForAttr() bad uid %d for client %d uid %d",
                          uid, client->portId(), client->uid());
                    status = INVALID_OPERATION;
                    goto error;
                    return base::unexpected{Status::fromExceptionCode(
                            EX_ILLEGAL_STATE,
                            String8::format("%s bad uid %d for client %d uid %d", __func__, uid,
                                            client->portId(), client->uid()))};
                }
            }
        }
        *inputType = API_INPUT_LEGACY;
        device = inputDesc->getDevice();

        ALOGV("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
        goto exit;
    }

    *input = AUDIO_IO_HANDLE_NONE;
        ALOGV("%s reusing MMAP input %d for session %d", __FUNCTION__, requestedInput, session);
        // TODO perm check
    } else {
        *inputType = API_INPUT_INVALID;

        if (attributes.source == AUDIO_SOURCE_REMOTE_SUBMIX &&
                extractAddressFromAudioAttributes(attributes).has_value()) {
        status = mPolicyMixes.getInputMixForAttr(attributes, &policyMix);
            status_t status = mPolicyMixes.getInputMixForAttr(attributes, &policyMix);
            if (status != NO_ERROR) {
                ALOGW("%s could not find input mix for attr %s",
                        __func__, toString(attributes).c_str());
            goto error;
                return base::unexpected {aidl_utils::binderStatusFromStatusT(status)};
            }
            device = mAvailableInputDevices.getDevice(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
                                                  String8(attr->tags + strlen("addr=")),
                                                      String8(attributes.tags + strlen("addr=")),
                                                      AUDIO_FORMAT_DEFAULT);
            if (device == nullptr) {
            ALOGW("%s could not find in Remote Submix device for source %d, tags %s",
                    __func__, attributes.source, attributes.tags);
            status = BAD_VALUE;
            goto error;
                return base::unexpected{Status::fromExceptionCode(
                        EX_ILLEGAL_ARGUMENT,
                        String8::format(
                                "%s could not find in Remote Submix device for source %d, tags %s",
                                __func__, attributes.source, attributes.tags))};
            }

            if (is_mix_loopback_render(policyMix->mRouteFlags)) {
@@ -3037,9 +3031,8 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
            } else {
                *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
            }
        if (virtualDeviceId) {
            *virtualDeviceId = policyMix->mVirtualDeviceId;
        }
            // TODO is this correct?
            vdi = policyMix->mVirtualDeviceId;
        } else {
            if (explicitRoutingDevice != nullptr) {
                device = explicitRoutingDevice;
@@ -3051,9 +3044,10 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
                    __FUNCTION__, device->type());
            }
            if (device == nullptr) {
            ALOGW("getInputForAttr() could not find device for source %d", attributes.source);
            status = BAD_VALUE;
            goto error;
                return base::unexpected{Status::fromExceptionCode(
                        EX_ILLEGAL_ARGUMENT,
                        String8::format("%s could not find device for source %d", __func__,
                                        attributes.source))};
            }
            if (device->type() == AUDIO_DEVICE_IN_ECHO_REFERENCE) {
                *inputType = API_INPUT_MIX_CAPTURE;
@@ -3063,10 +3057,7 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
                // meaning it receives audio injected into the framework, so the recorder doesn't
                // know about it and is therefore considered "legacy"
                *inputType = API_INPUT_LEGACY;

            if (virtualDeviceId) {
                *virtualDeviceId = policyMix->mVirtualDeviceId;
            }
                vdi = policyMix->mVirtualDeviceId;
            } else if (audio_is_remote_submix_device(device->type())) {
                *inputType = API_INPUT_MIX_CAPTURE;
            } else if (device->type() == AUDIO_DEVICE_IN_TELEPHONY_RX) {
@@ -3074,69 +3065,67 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
            } else {
                *inputType = API_INPUT_LEGACY;
            }

        }

    *input = getInputForDevice(device, session, attributes, config, flags, policyMix);
    if (*input == AUDIO_IO_HANDLE_NONE) {
        status = INVALID_OPERATION;
        // TODO perm check

        input = getInputForDevice(device, session, attributes, config, flags, policyMix);
        if (input == AUDIO_IO_HANDLE_NONE) {
            AudioProfileVector profiles;
            status_t ret = getProfilesForDevices(
                    DeviceVector(device), profiles, flags, true /*isInput*/);
            if (ret == NO_ERROR && !profiles.empty()) {
                const auto channels = profiles[0]->getChannels();
            if (!channels.empty() && (channels.find(config->channel_mask) == channels.end())) {
                config->channel_mask = *channels.begin();
                if (!channels.empty() && (channels.find(config.channel_mask) == channels.end())) {
                    config.channel_mask = *channels.begin();
                }
                const auto sampleRates = profiles[0]->getSampleRates();
                if (!sampleRates.empty() &&
                    (sampleRates.find(config->sample_rate) == sampleRates.end())) {
                config->sample_rate = *sampleRates.begin();
                        (sampleRates.find(config.sample_rate) == sampleRates.end())) {
                    config.sample_rate = *sampleRates.begin();
                }
            config->format = profiles[0]->getFormat();
                config.format = profiles[0]->getFormat();
            }
        goto error;
            const auto suggestedConfig = VALUE_OR_FATAL(
                legacy2aidl_audio_config_base_t_AudioConfigBase(config, true /*isInput*/));
            return base::unexpected {suggestedConfig};
        }


    if (policyMix != nullptr && virtualDeviceId != nullptr) {
        *virtualDeviceId = policyMix->mVirtualDeviceId;
    }

exit:

    *selectedDeviceId = mAvailableInputDevices.contains(device) ?
    auto selectedDeviceId = mAvailableInputDevices.contains(device) ?
                device->getId() : AUDIO_PORT_HANDLE_NONE;

    isSoundTrigger = attributes.source == AUDIO_SOURCE_HOTWORD &&
        mSoundTriggerSessions.indexOfKey(session) >= 0;
    *portId = PolicyAudioPort::getNextUniqueId();

    clientDesc = new RecordClientDescriptor(*portId, riid, uid, session, attributes, *config,
    const auto allocatedPortId = PolicyAudioPort::getNextUniqueId();

    clientDesc = new RecordClientDescriptor(allocatedPortId, riid, uid, session, attributes, config,
                                            requestedDeviceId, attributes.source, flags,
                                            isSoundTrigger);
    inputDesc = mInputs.valueFor(*input);
    inputDesc = mInputs.valueFor(input);
    // Move (if found) effect for the client session to its input
    mEffects.moveEffectsForIo(session, *input, &mInputs, mpClientInterface);
    mEffects.moveEffectsForIo(session, input, &mInputs, mpClientInterface);
    inputDesc->addClient(clientDesc);

    ALOGV("getInputForAttr() returns input %d type %d selectedDeviceId %d for port ID %d",
            *input, *inputType, *selectedDeviceId, *portId);
            input, *inputType, selectedDeviceId, allocatedPortId);

    return NO_ERROR;

error:
    return status;
    auto ret = media::GetInputForAttrResponse {};
    ret.input = input;
    ret.selectedDeviceId = selectedDeviceId;
    ret.portId = allocatedPortId;
    ret.virtualDeviceId = vdi;
    ret.config = legacy2aidl_audio_config_base_t_AudioConfigBase(config, true /*isInput*/).value();
    return ret;
}


audio_io_handle_t AudioPolicyManager::getInputForDevice(const sp<DeviceDescriptor>& device,
                                                        audio_session_t session,
                                                        const audio_attributes_t& attributes,
                                                        audio_config_base_t *config,
                                                        const audio_config_base_t& config,
                                                        audio_input_flags_t flags,
                                                        const sp<AudioPolicyMix> &policyMix)
{
                                                        const sp<AudioPolicyMix>& policyMix) {
    audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
    audio_source_t halInputSource = attributes.source;
    bool isSoundTrigger = false;
@@ -3152,7 +3141,7 @@ audio_io_handle_t AudioPolicyManager::getInputForDevice(const sp<DeviceDescripto
            halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION;
        }
    } else if (attributes.source == AUDIO_SOURCE_VOICE_COMMUNICATION &&
               audio_is_linear_pcm(config->format)) {
               audio_is_linear_pcm(config.format)) {
        flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_VOIP_TX);
    }

@@ -3161,10 +3150,10 @@ audio_io_handle_t AudioPolicyManager::getInputForDevice(const sp<DeviceDescripto
    }

    // sampling rate and flags may be updated by getInputProfile
    uint32_t profileSamplingRate = (config->sample_rate == 0) ?
            SAMPLE_RATE_HZ_DEFAULT : config->sample_rate;
    audio_format_t profileFormat = config->format;
    audio_channel_mask_t profileChannelMask = config->channel_mask;
    uint32_t profileSamplingRate = (config.sample_rate == 0) ?
            SAMPLE_RATE_HZ_DEFAULT : config.sample_rate;
    audio_format_t profileFormat = config.format;
    audio_channel_mask_t profileChannelMask = config.channel_mask;
    audio_input_flags_t profileFlags = flags;
    // find a compatible input profile (not necessarily identical in parameters)
    sp<IOProfile> profile = getInputProfile(
@@ -3174,7 +3163,7 @@ audio_io_handle_t AudioPolicyManager::getInputForDevice(const sp<DeviceDescripto
    }

    // Pick input sampling rate if not specified by client
    uint32_t samplingRate = config->sample_rate;
    uint32_t samplingRate = config.sample_rate;
    if (samplingRate == 0) {
        samplingRate = profileSamplingRate;
    }
Loading