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

Commit 97bb33f5 authored by Jean-Michel Trivi's avatar Jean-Michel Trivi
Browse files

Fix permission check for audio recording

Define input types covering the different usecases for audio
  recording, and check the corresponding permissions when
  starting to record.
Move the permission check from audio flinger to audio policy,
  as only the policy has the information to determine which
  permission to enforce.
Fix missing permission when an application records audio
  and the audio is injected by an external policy.

Bug 18736417

Change-Id: If7ec040502242c990ac8ea464db484339bdce573
parent 6e430fbd
Loading
Loading
Loading
Loading
+0 −7
Original line number Diff line number Diff line
@@ -1433,13 +1433,6 @@ sp<IAudioRecord> AudioFlinger::openRecord(
            goto Exit;
        }

        if (deviceRequiresCaptureAudioOutputPermission(thread->inDevice())
                && !captureAudioOutputAllowed()) {
            ALOGE("openRecord() permission denied: capture not allowed");
            lStatus = PERMISSION_DENIED;
            goto Exit;
        }

        pid_t pid = IPCThreadState::self()->getCallingPid();
        client = registerPid(pid);

+7 −0
Original line number Diff line number Diff line
@@ -188,6 +188,13 @@ static audio_io_handle_t open_input(audio_module_handle_t module,
    if (pSamplingRate == NULL || pFormat == NULL || pChannelMask == NULL || pDevices == NULL) {
        return AUDIO_IO_HANDLE_NONE;
    }

    if (((*pDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) == AUDIO_DEVICE_IN_REMOTE_SUBMIX)
            && !captureAudioOutputAllowed()) {
        ALOGE("open_input() permission denied: capture not allowed");
        return AUDIO_IO_HANDLE_NONE;
    }

    audio_config_t config = AUDIO_CONFIG_INITIALIZER;;
    config.sample_rate = *pSamplingRate;
    config.format = *pFormat;
+12 −1
Original line number Diff line number Diff line
@@ -56,6 +56,16 @@ namespace android {
class AudioPolicyInterface
{

public:
    typedef enum {
        API_INPUT_INVALID = -1,
        API_INPUT_LEGACY  = 0,// e.g. audio recording from a microphone
        API_INPUT_MIX_CAPTURE,// used for "remote submix", capture of the media to play it remotely
        API_INPUT_MIX_EXT_POLICY_REROUTE,// used for platform audio rerouting, where mixes are
                                         // handled by external and dynamically installed
                                         // policies which reroute audio mixes
    } input_type_t;

public:
    virtual ~AudioPolicyInterface() {}
    //
@@ -120,7 +130,8 @@ public:
                                     uint32_t samplingRate,
                                     audio_format_t format,
                                     audio_channel_mask_t channelMask,
                                     audio_input_flags_t flags) = 0;
                                     audio_input_flags_t flags,
                                     input_type_t *inputType) = 0;
    // indicates to the audio policy manager that the input starts being used.
    virtual status_t startInput(audio_io_handle_t input,
                                audio_session_t session) = 0;
+34 −4
Original line number Diff line number Diff line
@@ -266,17 +266,47 @@ status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr,
    }
    sp<AudioPolicyEffects>audioPolicyEffects;
    status_t status;
    AudioPolicyInterface::input_type_t inputType;
    {
        Mutex::Autolock _l(mLock);
        // the audio_in_acoustics_t parameter is ignored by get_input()
        status = mAudioPolicyManager->getInputForAttr(attr, input, session,
                                                     samplingRate, format, channelMask,
                                                     flags);
                                                     flags, &inputType);
        audioPolicyEffects = mAudioPolicyEffects;

        if (status == NO_ERROR) {
            // enforce permission (if any) required for each type of input
            switch (inputType) {
            case AudioPolicyInterface::API_INPUT_LEGACY:
                break;
            case AudioPolicyInterface::API_INPUT_MIX_CAPTURE:
                if (!captureAudioOutputAllowed()) {
                    ALOGE("getInputForAttr() permission denied: capture not allowed");
                    status = PERMISSION_DENIED;
                }
                break;
            case AudioPolicyInterface::API_INPUT_MIX_EXT_POLICY_REROUTE:
                if (!modifyAudioRoutingAllowed()) {
                    ALOGE("getInputForAttr() permission denied: modify audio routing not allowed");
                    status = PERMISSION_DENIED;
                }
                break;
            case AudioPolicyInterface::API_INPUT_INVALID:
            default:
                LOG_ALWAYS_FATAL("getInputForAttr() encountered an invalid input type %d",
                        (int)inputType);
            }
        }

        if (status != NO_ERROR) {
            if (status == PERMISSION_DENIED) {
                mAudioPolicyManager->releaseInput(*input, session);
            }
            return status;
        }
    }

    if (audioPolicyEffects != 0) {
        // create audio pre processors according to input source
        status_t status = audioPolicyEffects->addInputEffects(*input, attr->source, session);
+19 −1
Original line number Diff line number Diff line
@@ -1419,13 +1419,15 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
                                             uint32_t samplingRate,
                                             audio_format_t format,
                                             audio_channel_mask_t channelMask,
                                             audio_input_flags_t flags)
                                             audio_input_flags_t flags,
                                             input_type_t *inputType)
{
    ALOGV("getInputForAttr() source %d, samplingRate %d, format %d, channelMask %x,"
            "session %d, flags %#x",
          attr->source, samplingRate, format, channelMask, session, flags);

    *input = AUDIO_IO_HANDLE_NONE;
    *inputType = API_INPUT_INVALID;
    audio_devices_t device;
    // handle legacy remote submix case where the address was not always specified
    String8 address = String8("");
@@ -1447,6 +1449,7 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
            return BAD_VALUE;
        }
        policyMix = &mPolicyMixes[index]->mMix;
        *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
    } else {
        device = getDeviceAndMixForInputSource(attr->source, &policyMix);
        if (device == AUDIO_DEVICE_NONE) {
@@ -1455,8 +1458,21 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
        }
        if (policyMix != NULL) {
            address = policyMix->mRegistrationId;
            if (policyMix->mMixType == MIX_TYPE_RECORDERS) {
                // there is an external policy, but this input is attached to a mix of recorders,
                // 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;
            } else {
                // recording a mix of players defined by an external policy, we're rerouting for
                // an external policy
                *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
            }
        } else if (audio_is_remote_submix_device(device)) {
            address = String8("0");
            *inputType = API_INPUT_MIX_CAPTURE;
        } else {
            *inputType = API_INPUT_LEGACY;
        }
        // adapt channel selection to input source
        switch (attr->source) {
@@ -1546,6 +1562,8 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
    inputDesc->mIsSoundTrigger = isSoundTrigger;
    inputDesc->mPolicyMix = policyMix;

    ALOGV("getInputForAttr() returns input type = %d", inputType);

    addInput(*input, inputDesc);
    mpClientInterface->onAudioPortListUpdate();
    return NO_ERROR;
Loading