Merge "AudioService: fix playback capture permission check"
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -8454,28 +8454,29 @@ 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.containsMatchAttributeRuleForUsage(
|
||||
AudioAttributes.USAGE_VOICE_COMMUNICATION)) {
|
||||
// then 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) {
|
||||
voiceCommunicationCaptureMixes = new ArrayList<AudioMix>();
|
||||
}
|
||||
voiceCommunicationCaptureMixes.add(mix);
|
||||
}
|
||||
// If mix is trying to explicitly capture USAGE_VOICE_COMMUNICATION
|
||||
if (mix.containsMatchAttributeRuleForUsage(
|
||||
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) {
|
||||
voiceCommunicationCaptureMixes = new ArrayList<AudioMix>();
|
||||
}
|
||||
voiceCommunicationCaptureMixes.add(mix);
|
||||
}
|
||||
|
||||
// If mix is RENDER|LOOPBACK, then an audio MediaProjection is enough
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user