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

Commit c13a997a authored by Eric Laurent's avatar Eric Laurent Committed by Android (Google) Code Review
Browse files

Merge "AudioService: fix playback capture permission check"

parents 70fc9865 5e0b95fe
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1946,7 +1946,7 @@ static jint convertAudioMixToNative(JNIEnv *env,

    jobject jRule = env->GetObjectField(jAudioMix, gAudioMixFields.mRule);
    jobject jRuleCriteria = env->GetObjectField(jRule, gAudioMixingRuleFields.mCriteria);
    nAudioMix->mAllowPrivilegedPlaybackCapture =
    nAudioMix->mAllowPrivilegedMediaPlaybackCapture =
            env->GetBooleanField(jRule, gAudioMixingRuleFields.mAllowPrivilegedPlaybackCapture);
    nAudioMix->mVoiceCommunicationCaptureAllowed =
            env->GetBooleanField(jRule, gAudioMixingRuleFields.mVoiceCommunicationCaptureAllowed);
+3 −3
Original line number Diff line number Diff line
@@ -218,7 +218,7 @@ public class AudioMix {
    /** @return an error string if the format would not allow Privileged playbackCapture
     *          null otherwise
     * @hide */
    public static String canBeUsedForPrivilegedCapture(AudioFormat format) {
    public static String canBeUsedForPrivilegedMediaCapture(AudioFormat format) {
        int sampleRate = format.getSampleRate();
        if (sampleRate > PRIVILEDGED_CAPTURE_MAX_SAMPLE_RATE || sampleRate <= 0) {
            return "Privileged audio capture sample rate " + sampleRate
@@ -448,8 +448,8 @@ public class AudioMix {
                    }
                }
            }
            if (mRule.allowPrivilegedPlaybackCapture()) {
                String error = AudioMix.canBeUsedForPrivilegedCapture(mFormat);
            if (mRule.allowPrivilegedMediaPlaybackCapture()) {
                String error = AudioMix.canBeUsedForPrivilegedMediaCapture(mFormat);
                if (error != null) {
                    throw new IllegalArgumentException(error);
                }
+10 −6
Original line number Diff line number Diff line
@@ -46,11 +46,11 @@ import java.util.Objects;
public class AudioMixingRule {

    private AudioMixingRule(int mixType, ArrayList<AudioMixMatchCriterion> criteria,
                            boolean allowPrivilegedPlaybackCapture,
                            boolean allowPrivilegedMediaPlaybackCapture,
                            boolean voiceCommunicationCaptureAllowed) {
        mCriteria = criteria;
        mTargetMixType = mixType;
        mAllowPrivilegedPlaybackCapture = allowPrivilegedPlaybackCapture;
        mAllowPrivilegedPlaybackCapture = allowPrivilegedMediaPlaybackCapture;
        mVoiceCommunicationCaptureAllowed = voiceCommunicationCaptureAllowed;
    }

@@ -204,13 +204,17 @@ public class AudioMixingRule {
    private final ArrayList<AudioMixMatchCriterion> mCriteria;
    /** @hide */
    public ArrayList<AudioMixMatchCriterion> getCriteria() { return mCriteria; }
    /** Indicates that this rule is intended to capture media or game playback by a system component
      * with permission CAPTURE_MEDIA_OUTPUT or CAPTURE_AUDIO_OUTPUT.
      */
    //TODO b/177061175: rename to mAllowPrivilegedMediaPlaybackCapture
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    private boolean mAllowPrivilegedPlaybackCapture = false;
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    private boolean mVoiceCommunicationCaptureAllowed = false;

    /** @hide */
    public boolean allowPrivilegedPlaybackCapture() {
    public boolean allowPrivilegedMediaPlaybackCapture() {
        return mAllowPrivilegedPlaybackCapture;
    }

@@ -311,7 +315,7 @@ public class AudioMixingRule {
    public static class Builder {
        private ArrayList<AudioMixMatchCriterion> mCriteria;
        private int mTargetMixType = AudioMix.MIX_TYPE_INVALID;
        private boolean mAllowPrivilegedPlaybackCapture = false;
        private boolean mAllowPrivilegedMediaPlaybackCapture = false;
        // This value should be set internally according to a permission check
        private boolean mVoiceCommunicationCaptureAllowed = false;

@@ -434,7 +438,7 @@ public class AudioMixingRule {
         * @return the same Builder instance.
         */
        public @NonNull Builder allowPrivilegedPlaybackCapture(boolean allow) {
            mAllowPrivilegedPlaybackCapture = allow;
            mAllowPrivilegedMediaPlaybackCapture = allow;
            return this;
        }

@@ -639,7 +643,7 @@ public class AudioMixingRule {
         */
        public AudioMixingRule build() {
            return new AudioMixingRule(mTargetMixType, mCriteria,
                mAllowPrivilegedPlaybackCapture, mVoiceCommunicationCaptureAllowed);
                mAllowPrivilegedMediaPlaybackCapture, mVoiceCommunicationCaptureAllowed);
        }
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -97,7 +97,7 @@ public class AudioPolicyConfig implements Parcelable {
            dest.writeInt(mix.getFormat().getEncoding());
            dest.writeInt(mix.getFormat().getChannelMask());
            // write opt-out respect
            dest.writeBoolean(mix.getRule().allowPrivilegedPlaybackCapture());
            dest.writeBoolean(mix.getRule().allowPrivilegedMediaPlaybackCapture());
            // write voice communication capture allowed flag
            dest.writeBoolean(mix.getRule().voiceCommunicationCaptureAllowed());
            // write mix rules
@@ -172,7 +172,7 @@ public class AudioPolicyConfig implements Parcelable {
            textDump += "  channels=0x";
            textDump += Integer.toHexString(mix.getFormat().getChannelMask()).toUpperCase() + "\n";
            textDump += "  ignore playback capture opt out="
                    + mix.getRule().allowPrivilegedPlaybackCapture() + "\n";
                    + mix.getRule().allowPrivilegedMediaPlaybackCapture() + "\n";
            textDump += "  allow voice communication capture="
                    + mix.getRule().voiceCommunicationCaptureAllowed() + "\n";
            // write mix rules
+20 −19
Original line number Diff line number Diff line
@@ -8454,21 +8454,23 @@ public class AudioService extends IAudioService.Stub
        }
        for (AudioMix mix : policyConfig.getMixes()) {
            // If mix is requesting privileged capture
            if (mix.getRule().allowPrivilegedPlaybackCapture()) {
                // then it must have CAPTURE_MEDIA_OUTPUT or CAPTURE_AUDIO_OUTPUT permission
                requireCaptureAudioOrMediaOutputPerm |= true;

                // and its format must be low quality enough
                String error = mix.canBeUsedForPrivilegedCapture(mix.getFormat());
                if (error != null) {
                    Log.e(TAG, error);
            if (mix.getRule().allowPrivilegedMediaPlaybackCapture()) {
                // then its format must be low quality enough
                String privilegedMediaCaptureError =
                        mix.canBeUsedForPrivilegedMediaCapture(mix.getFormat());
                if (privilegedMediaCaptureError != null) {
                    Log.e(TAG, privilegedMediaCaptureError);
                    return false;
                }
                // and it must have CAPTURE_MEDIA_OUTPUT or CAPTURE_AUDIO_OUTPUT permission
                requireCaptureAudioOrMediaOutputPerm |= true;

                // If mix is trying to excplicitly capture USAGE_VOICE_COMMUNICATION
            }
            // If mix is trying to explicitly capture USAGE_VOICE_COMMUNICATION
            if (mix.containsMatchAttributeRuleForUsage(
                        AudioAttributes.USAGE_VOICE_COMMUNICATION)) {
                    // then it must have CAPTURE_USAGE_VOICE_COMMUNICATION_OUTPUT permission
                    AudioAttributes.USAGE_VOICE_COMMUNICATION)
                    && (mix.getRouteFlags() == mix.ROUTE_FLAG_LOOP_BACK_RENDER)) {
                // It must have CAPTURE_USAGE_VOICE_COMMUNICATION_OUTPUT permission
                // Note that for UID, USERID or EXCLDUE rules, the capture will be silenced
                // in AudioPolicyMix
                if (voiceCommunicationCaptureMixes == null) {
@@ -8476,7 +8478,6 @@ public class AudioService extends IAudioService.Stub
                }
                voiceCommunicationCaptureMixes.add(mix);
            }
            }

            // If mix is RENDER|LOOPBACK, then an audio MediaProjection is enough
            // otherwise MODIFY_AUDIO_ROUTING permission is required
@@ -8498,7 +8499,7 @@ public class AudioService extends IAudioService.Stub
        if (voiceCommunicationCaptureMixes != null && voiceCommunicationCaptureMixes.size() > 0) {
            if (!callerHasPermission(
                    android.Manifest.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT)) {
                Log.e(TAG, "Privileged audio capture for voice communication requires "
                Log.e(TAG, "Audio capture for voice communication requires "
                        + "CAPTURE_VOICE_COMMUNICATION_OUTPUT system permission");
                return false;
            }