AudioFlinger: add audio session for device effects

Add specific audio session ID for effects applied to a
particular audio device.
Device specific effects will be attached to a particular audio sink or
source device identified by its unique audio port ID and will all use
this same session ID.
Only one session of this type exists on a given playback or record
thread.
All effects in this session apply to the same device ID and are created/released
when the routing (audio patch) of this thread output or input stream is updated.

Bug: 136294538
Test: make

Change-Id: I4e3a55ed1244b918429dd9e217b6efecc1ec6449
gugelfrei
Eric Laurent 5 years ago
parent 602e1ae3a3
commit 3f75a5bc38

@ -171,7 +171,7 @@ status_t AudioEffect::set(const effect_uuid_t *type,
ALOGV("set() %p OK effect: %s id: %d status %d enabled %d pid %d", this, mDescriptor.name, mId, ALOGV("set() %p OK effect: %s id: %d status %d enabled %d pid %d", this, mDescriptor.name, mId,
mStatus, mEnabled, mClientPid); mStatus, mEnabled, mClientPid);
if (mSessionId > AUDIO_SESSION_OUTPUT_MIX) { if (!audio_is_global_session(mSessionId)) {
AudioSystem::acquireAudioSessionId(mSessionId, mClientPid); AudioSystem::acquireAudioSessionId(mSessionId, mClientPid);
} }
@ -184,7 +184,7 @@ AudioEffect::~AudioEffect()
ALOGV("Destructor %p", this); ALOGV("Destructor %p", this);
if (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS) { if (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS) {
if (mSessionId > AUDIO_SESSION_OUTPUT_MIX) { if (!audio_is_global_session(mSessionId)) {
AudioSystem::releaseAudioSessionId(mSessionId, mClientPid); AudioSystem::releaseAudioSessionId(mSessionId, mClientPid);
} }
if (mIEffect != NULL) { if (mIEffect != NULL) {

@ -181,12 +181,19 @@ bool modifyAudioRoutingAllowed(pid_t pid, uid_t uid) {
} }
bool modifyDefaultAudioEffectsAllowed() { bool modifyDefaultAudioEffectsAllowed() {
return modifyDefaultAudioEffectsAllowed(
IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid());
}
bool modifyDefaultAudioEffectsAllowed(pid_t pid, uid_t uid) {
if (isAudioServerUid(IPCThreadState::self()->getCallingUid())) return true;
static const String16 sModifyDefaultAudioEffectsAllowed( static const String16 sModifyDefaultAudioEffectsAllowed(
"android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"); "android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS");
// IMPORTANT: Use PermissionCache - not a runtime permission and may not change. // IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
bool ok = PermissionCache::checkCallingPermission(sModifyDefaultAudioEffectsAllowed); bool ok = PermissionCache::checkPermission(sModifyDefaultAudioEffectsAllowed, pid, uid);
ALOGE_IF(!ok, "%s(): android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS denied for uid %d",
if (!ok) ALOGE("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"); __func__, uid);
return ok; return ok;
} }

@ -87,6 +87,7 @@ bool settingsAllowed();
bool modifyAudioRoutingAllowed(); bool modifyAudioRoutingAllowed();
bool modifyAudioRoutingAllowed(pid_t pid, uid_t uid); bool modifyAudioRoutingAllowed(pid_t pid, uid_t uid);
bool modifyDefaultAudioEffectsAllowed(); bool modifyDefaultAudioEffectsAllowed();
bool modifyDefaultAudioEffectsAllowed(pid_t pid, uid_t uid);
bool dumpAllowed(); bool dumpAllowed();
bool modifyPhoneStateAllowed(pid_t pid, uid_t uid); bool modifyPhoneStateAllowed(pid_t pid, uid_t uid);
bool bypassInterruptionPolicyAllowed(pid_t pid, uid_t uid); bool bypassInterruptionPolicyAllowed(pid_t pid, uid_t uid);

@ -2969,7 +2969,7 @@ std::vector<sp<AudioFlinger::EffectModule>> AudioFlinger::purgeStaleEffects_l()
Mutex::Autolock _l(t->mLock); Mutex::Autolock _l(t->mLock);
for (size_t j = 0; j < t->mEffectChains.size(); j++) { for (size_t j = 0; j < t->mEffectChains.size(); j++) {
sp<EffectChain> ec = t->mEffectChains[j]; sp<EffectChain> ec = t->mEffectChains[j];
if (ec->sessionId() > AUDIO_SESSION_OUTPUT_MIX) { if (!audio_is_global_session(ec->sessionId())) {
chains.push(ec); chains.push(ec);
} }
} }
@ -3371,6 +3371,13 @@ sp<IEffect> AudioFlinger::createEffect(
lStatus = BAD_VALUE; lStatus = BAD_VALUE;
goto Exit; goto Exit;
} }
} else if (sessionId == AUDIO_SESSION_DEVICE) {
if (!modifyDefaultAudioEffectsAllowed(pid, callingUid)) {
ALOGE("%s: device effect permission denied for uid %d", __func__, callingUid);
lStatus = PERMISSION_DENIED;
goto Exit;
}
//TODO: add check on device ID when added to arguments
} else { } else {
// general sessionId. // general sessionId.
@ -3406,7 +3413,7 @@ sp<IEffect> AudioFlinger::createEffect(
// check recording permission for visualizer // check recording permission for visualizer
if ((memcmp(&desc.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) && if ((memcmp(&desc.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) &&
// TODO: Do we need to start/stop op - i.e. is there recording being performed? // TODO: Do we need to start/stop op - i.e. is there recording being performed?
!recordingAllowed(opPackageName, pid, IPCThreadState::self()->getCallingUid())) { !recordingAllowed(opPackageName, pid, callingUid)) {
lStatus = PERMISSION_DENIED; lStatus = PERMISSION_DENIED;
goto Exit; goto Exit;
} }
@ -3504,7 +3511,7 @@ sp<IEffect> AudioFlinger::createEffect(
sp<Client> client = registerPid(pid); sp<Client> client = registerPid(pid);
// create effect on selected output thread // create effect on selected output thread
bool pinned = (sessionId > AUDIO_SESSION_OUTPUT_MIX) && isSessionAcquired_l(sessionId); bool pinned = !audio_is_global_session(sessionId) && isSessionAcquired_l(sessionId);
handle = thread->createEffect_l(client, effectClient, priority, sessionId, handle = thread->createEffect_l(client, effectClient, priority, sessionId,
&desc, enabled, &lStatus, pinned); &desc, enabled, &lStatus, pinned);
if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) { if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) {

@ -637,7 +637,7 @@ status_t AudioFlinger::EffectModule::configure()
mConfig.outputCfg.bufferProvider.releaseBuffer = NULL; mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
// Insert effect: // Insert effect:
// - in session AUDIO_SESSION_OUTPUT_MIX or AUDIO_SESSION_OUTPUT_STAGE, // - in global sessions (e.g AUDIO_SESSION_OUTPUT_MIX),
// always overwrites output buffer: input buffer == output buffer // always overwrites output buffer: input buffer == output buffer
// - in other sessions: // - in other sessions:
// last effect in the chain accumulates in output buffer: input buffer != output buffer // last effect in the chain accumulates in output buffer: input buffer != output buffer
@ -2062,14 +2062,12 @@ void AudioFlinger::EffectChain::process_l()
ALOGW("process_l(): cannot promote mixer thread"); ALOGW("process_l(): cannot promote mixer thread");
return; return;
} }
bool isGlobalSession = (mSessionId == AUDIO_SESSION_OUTPUT_MIX) ||
(mSessionId == AUDIO_SESSION_OUTPUT_STAGE);
// never process effects when: // never process effects when:
// - on an OFFLOAD thread // - on an OFFLOAD thread
// - no more tracks are on the session and the effect tail has been rendered // - no more tracks are on the session and the effect tail has been rendered
bool doProcess = (thread->type() != ThreadBase::OFFLOAD) bool doProcess = (thread->type() != ThreadBase::OFFLOAD)
&& (thread->type() != ThreadBase::MMAP); && (thread->type() != ThreadBase::MMAP);
if (!isGlobalSession) { if (!audio_is_global_session(mSessionId)) {
bool tracksOnSession = (trackCnt() != 0); bool tracksOnSession = (trackCnt() != 0);
if (!tracksOnSession && mTailBufferCount == 0) { if (!tracksOnSession && mTailBufferCount == 0) {

@ -1164,7 +1164,7 @@ void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled_l(const sp<EffectModu
// and applications not using global effects. // and applications not using global effects.
// Enabling post processing in AUDIO_SESSION_OUTPUT_STAGE session does not affect // Enabling post processing in AUDIO_SESSION_OUTPUT_STAGE session does not affect
// global effects // global effects
if ((sessionId != AUDIO_SESSION_OUTPUT_MIX) && (sessionId != AUDIO_SESSION_OUTPUT_STAGE)) { if (!audio_is_global_session(sessionId)) {
setEffectSuspended_l(NULL, enabled, AUDIO_SESSION_OUTPUT_MIX); setEffectSuspended_l(NULL, enabled, AUDIO_SESSION_OUTPUT_MIX);
} }
} }
@ -1179,8 +1179,9 @@ void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled_l(const sp<EffectModu
status_t AudioFlinger::RecordThread::checkEffectCompatibility_l( status_t AudioFlinger::RecordThread::checkEffectCompatibility_l(
const effect_descriptor_t *desc, audio_session_t sessionId) const effect_descriptor_t *desc, audio_session_t sessionId)
{ {
// No global effect sessions on record threads // No global output effect sessions on record threads
if (sessionId == AUDIO_SESSION_OUTPUT_MIX || sessionId == AUDIO_SESSION_OUTPUT_STAGE) { if (sessionId == AUDIO_SESSION_OUTPUT_MIX
|| sessionId == AUDIO_SESSION_OUTPUT_STAGE) {
ALOGW("checkEffectCompatibility_l(): global effect %s on record thread %s", ALOGW("checkEffectCompatibility_l(): global effect %s on record thread %s",
desc->name, mThreadName); desc->name, mThreadName);
return BAD_VALUE; return BAD_VALUE;
@ -1254,6 +1255,13 @@ status_t AudioFlinger::PlaybackThread::checkEffectCompatibility_l(
" on output stage session", desc->name); " on output stage session", desc->name);
return BAD_VALUE; return BAD_VALUE;
} }
} else if (sessionId == AUDIO_SESSION_DEVICE) {
// only post processing on output stage session
if ((desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_POST_PROC) {
ALOGW("checkEffectCompatibility_l(): non post processing effect %s not allowed"
" on device session", desc->name);
return BAD_VALUE;
}
} else { } else {
// no restriction on effects applied on non fast tracks // no restriction on effects applied on non fast tracks
if ((hasAudioSession_l(sessionId) & ThreadBase::FAST_SESSION) == 0) { if ((hasAudioSession_l(sessionId) & ThreadBase::FAST_SESSION) == 0) {
@ -1295,7 +1303,7 @@ status_t AudioFlinger::PlaybackThread::checkEffectCompatibility_l(
return BAD_VALUE; return BAD_VALUE;
} }
#endif #endif
if ((sessionId == AUDIO_SESSION_OUTPUT_STAGE) || (sessionId == AUDIO_SESSION_OUTPUT_MIX)) { if (audio_is_global_session(sessionId)) {
ALOGW("checkEffectCompatibility_l(): global effect %s on DUPLICATING" ALOGW("checkEffectCompatibility_l(): global effect %s on DUPLICATING"
" thread %s", desc->name, mThreadName); " thread %s", desc->name, mThreadName);
return BAD_VALUE; return BAD_VALUE;
@ -2051,6 +2059,7 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac
{ // scope for mLock { // scope for mLock
Mutex::Autolock _l(mLock); Mutex::Autolock _l(mLock);
for (audio_session_t session : { for (audio_session_t session : {
AUDIO_SESSION_DEVICE,
AUDIO_SESSION_OUTPUT_STAGE, AUDIO_SESSION_OUTPUT_STAGE,
AUDIO_SESSION_OUTPUT_MIX, AUDIO_SESSION_OUTPUT_MIX,
sessionId, sessionId,
@ -3103,7 +3112,7 @@ status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& c
halOutBuffer = halInBuffer; halOutBuffer = halInBuffer;
effect_buffer_t *buffer = reinterpret_cast<effect_buffer_t*>(halInBuffer->externalData()); effect_buffer_t *buffer = reinterpret_cast<effect_buffer_t*>(halInBuffer->externalData());
ALOGV("addEffectChain_l() %p on thread %p for session %d", chain.get(), this, session); ALOGV("addEffectChain_l() %p on thread %p for session %d", chain.get(), this, session);
if (session > AUDIO_SESSION_OUTPUT_MIX) { if (!audio_is_global_session(session)) {
// Only one effect chain can be present in direct output thread and it uses // Only one effect chain can be present in direct output thread and it uses
// the sink buffer as input // the sink buffer as input
if (mType != DIRECT) { if (mType != DIRECT) {
@ -3143,8 +3152,11 @@ status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& c
chain->setThread(this); chain->setThread(this);
chain->setInBuffer(halInBuffer); chain->setInBuffer(halInBuffer);
chain->setOutBuffer(halOutBuffer); chain->setOutBuffer(halOutBuffer);
// Effect chain for session AUDIO_SESSION_OUTPUT_STAGE is inserted at end of effect // Effect chain for session AUDIO_SESSION_DEVICE is inserted at end of effect
// chains list in order to be processed last as it contains output stage effects. // chains list in order to be processed last as it contains output device effects.
// Effect chain for session AUDIO_SESSION_OUTPUT_STAGE is inserted just before to apply post
// processing effects specific to an output stream before effects applied to all streams
// routed to a given device.
// Effect chain for session AUDIO_SESSION_OUTPUT_MIX is inserted before // Effect chain for session AUDIO_SESSION_OUTPUT_MIX is inserted before
// session AUDIO_SESSION_OUTPUT_STAGE to be processed // session AUDIO_SESSION_OUTPUT_STAGE to be processed
// after track specific effects and before output stage. // after track specific effects and before output stage.
@ -3154,7 +3166,8 @@ status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& c
// chains list to be processed before output mix effects. Relative order between other // chains list to be processed before output mix effects. Relative order between other
// sessions is not important. // sessions is not important.
static_assert(AUDIO_SESSION_OUTPUT_MIX == 0 && static_assert(AUDIO_SESSION_OUTPUT_MIX == 0 &&
AUDIO_SESSION_OUTPUT_STAGE < AUDIO_SESSION_OUTPUT_MIX, AUDIO_SESSION_OUTPUT_STAGE < AUDIO_SESSION_OUTPUT_MIX &&
AUDIO_SESSION_DEVICE < AUDIO_SESSION_OUTPUT_STAGE,
"audio_session_t constants misdefined"); "audio_session_t constants misdefined");
size_t size = mEffectChains.size(); size_t size = mEffectChains.size();
size_t i = 0; size_t i = 0;
@ -9099,8 +9112,8 @@ status_t AudioFlinger::MmapThread::checkEffectCompatibility_l(
const effect_descriptor_t *desc, audio_session_t sessionId) const effect_descriptor_t *desc, audio_session_t sessionId)
{ {
// No global effect sessions on mmap threads // No global effect sessions on mmap threads
if (sessionId == AUDIO_SESSION_OUTPUT_MIX || sessionId == AUDIO_SESSION_OUTPUT_STAGE) { if (audio_is_global_session(sessionId)) {
ALOGW("checkEffectCompatibility_l(): global effect %s on record thread %s", ALOGW("checkEffectCompatibility_l(): global effect %s on MMAP thread %s",
desc->name, mThreadName); desc->name, mThreadName);
return BAD_VALUE; return BAD_VALUE;
} }
@ -9122,7 +9135,6 @@ status_t AudioFlinger::MmapThread::checkEffectCompatibility_l(
} }
return NO_ERROR; return NO_ERROR;
} }
void AudioFlinger::MmapThread::checkInvalidTracks_l() void AudioFlinger::MmapThread::checkInvalidTracks_l()

Loading…
Cancel
Save