audio policy: fix playback permission checks
Align playback permission checks implementation in getOutputforAttr() on
capture checks in getInputForAttr(): use an "output type" returned by
audio policy manager and check permission accordingly.
- Do not modify but reject request to play to call uplink when permission
is denied.
- Add missing permission check for injection to remote submix.
- Clarify permission check for record from remote submix by using the
uid/pid of client explicitly.
Bug:
Test: CTS test for AudioTrack and AudioREcord.
Test: GTS tests for dynamic policies and playback capture
Change-Id: Ic0eb3b9921a491e97c58fa8f637583059a54b3a2
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 10355bf..feb930e 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -181,13 +181,13 @@
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
- ALOGV("getOutputForAttr()");
+ ALOGV("%s()", __func__);
Mutex::Autolock _l(mLock);
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
if (!isAudioServerOrMediaServerUid(callingUid) || uid == (uid_t)-1) {
ALOGW_IF(uid != (uid_t)-1 && uid != callingUid,
- "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, uid);
+ "%s uid %d tried to pass itself off as %d", __func__, callingUid, uid);
uid = callingUid;
}
if (!mPackageManager.allowPlaybackCapture(uid)) {
@@ -197,27 +197,39 @@
&& !bypassInterruptionPolicyAllowed(pid, uid)) {
attr->flags &= ~(AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY|AUDIO_FLAG_BYPASS_MUTE);
}
- audio_output_flags_t originalFlags = flags;
AutoCallerClear acc;
+ AudioPolicyInterface::output_type_t outputType;
status_t result = mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid,
config,
&flags, selectedDeviceId, portId,
- secondaryOutputs);
+ secondaryOutputs,
+ &outputType);
// FIXME: Introduce a way to check for the the telephony device before opening the output
- if ((result == NO_ERROR) &&
- (flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) &&
- !modifyPhoneStateAllowed(pid, uid)) {
- // If the app tries to play music through the telephony device and doesn't have permission
- // the fallback to the default output device.
- mAudioPolicyManager->releaseOutput(*portId);
- flags = originalFlags;
- *selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
- *portId = AUDIO_PORT_HANDLE_NONE;
- secondaryOutputs->clear();
- result = mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid, config,
- &flags, selectedDeviceId, portId,
- secondaryOutputs);
+ if (result == NO_ERROR) {
+ // enforce permission (if any) required for each type of input
+ switch (outputType) {
+ case AudioPolicyInterface::API_OUTPUT_LEGACY:
+ break;
+ case AudioPolicyInterface::API_OUTPUT_TELEPHONY_TX:
+ if (!modifyPhoneStateAllowed(pid, uid)) {
+ ALOGE("%s() permission denied: modify phone state not allowed for uid %d",
+ __func__, uid);
+ result = PERMISSION_DENIED;
+ }
+ break;
+ case AudioPolicyInterface::API_OUT_MIX_PLAYBACK:
+ if (!modifyAudioRoutingAllowed(pid, uid)) {
+ ALOGE("%s() permission denied: modify audio routing not allowed for uid %d",
+ __func__, uid);
+ result = PERMISSION_DENIED;
+ }
+ break;
+ case AudioPolicyInterface::API_OUTPUT_INVALID:
+ default:
+ LOG_ALWAYS_FATAL("%s() encountered an invalid output type %d",
+ __func__, (int)outputType);
+ }
}
if (result == NO_ERROR) {
@@ -434,7 +446,7 @@
}
break;
case AudioPolicyInterface::API_INPUT_MIX_EXT_POLICY_REROUTE:
- if (!modifyAudioRoutingAllowed()) {
+ if (!modifyAudioRoutingAllowed(pid, uid)) {
ALOGE("getInputForAttr() permission denied: modify audio routing not allowed");
status = PERMISSION_DENIED;
}