diff --git a/media/libaudioclient/AudioEffect.cpp b/media/libaudioclient/AudioEffect.cpp index 1cc5fe6610..b3862beeca 100644 --- a/media/libaudioclient/AudioEffect.cpp +++ b/media/libaudioclient/AudioEffect.cpp @@ -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, mStatus, mEnabled, mClientPid); - if (mSessionId > AUDIO_SESSION_OUTPUT_MIX) { + if (!audio_is_global_session(mSessionId)) { AudioSystem::acquireAudioSessionId(mSessionId, mClientPid); } @@ -184,7 +184,7 @@ AudioEffect::~AudioEffect() ALOGV("Destructor %p", this); if (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS) { - if (mSessionId > AUDIO_SESSION_OUTPUT_MIX) { + if (!audio_is_global_session(mSessionId)) { AudioSystem::releaseAudioSessionId(mSessionId, mClientPid); } if (mIEffect != NULL) { diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp index b13278256c..a77311e19e 100644 --- a/media/utils/ServiceUtilities.cpp +++ b/media/utils/ServiceUtilities.cpp @@ -181,12 +181,19 @@ bool modifyAudioRoutingAllowed(pid_t pid, uid_t uid) { } 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( "android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"); // IMPORTANT: Use PermissionCache - not a runtime permission and may not change. - bool ok = PermissionCache::checkCallingPermission(sModifyDefaultAudioEffectsAllowed); - - if (!ok) ALOGE("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"); + bool ok = PermissionCache::checkPermission(sModifyDefaultAudioEffectsAllowed, pid, uid); + ALOGE_IF(!ok, "%s(): android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS denied for uid %d", + __func__, uid); return ok; } diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h index 9e852fd7c7..e467058f33 100644 --- a/media/utils/include/mediautils/ServiceUtilities.h +++ b/media/utils/include/mediautils/ServiceUtilities.h @@ -87,6 +87,7 @@ bool settingsAllowed(); bool modifyAudioRoutingAllowed(); bool modifyAudioRoutingAllowed(pid_t pid, uid_t uid); bool modifyDefaultAudioEffectsAllowed(); +bool modifyDefaultAudioEffectsAllowed(pid_t pid, uid_t uid); bool dumpAllowed(); bool modifyPhoneStateAllowed(pid_t pid, uid_t uid); bool bypassInterruptionPolicyAllowed(pid_t pid, uid_t uid); diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 6ecb356deb..7b016905f1 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -2969,7 +2969,7 @@ std::vector> AudioFlinger::purgeStaleEffects_l() Mutex::Autolock _l(t->mLock); for (size_t j = 0; j < t->mEffectChains.size(); j++) { sp ec = t->mEffectChains[j]; - if (ec->sessionId() > AUDIO_SESSION_OUTPUT_MIX) { + if (!audio_is_global_session(ec->sessionId())) { chains.push(ec); } } @@ -3371,6 +3371,13 @@ sp AudioFlinger::createEffect( lStatus = BAD_VALUE; 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 { // general sessionId. @@ -3406,7 +3413,7 @@ sp AudioFlinger::createEffect( // check recording permission for visualizer 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? - !recordingAllowed(opPackageName, pid, IPCThreadState::self()->getCallingUid())) { + !recordingAllowed(opPackageName, pid, callingUid)) { lStatus = PERMISSION_DENIED; goto Exit; } @@ -3504,7 +3511,7 @@ sp AudioFlinger::createEffect( sp client = registerPid(pid); // 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, &desc, enabled, &lStatus, pinned); if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) { diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp index 1355b1b61a..eda9887cf7 100644 --- a/services/audioflinger/Effects.cpp +++ b/services/audioflinger/Effects.cpp @@ -637,7 +637,7 @@ status_t AudioFlinger::EffectModule::configure() mConfig.outputCfg.bufferProvider.releaseBuffer = NULL; mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; // 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 // - in other sessions: // 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"); return; } - bool isGlobalSession = (mSessionId == AUDIO_SESSION_OUTPUT_MIX) || - (mSessionId == AUDIO_SESSION_OUTPUT_STAGE); // never process effects when: // - on an OFFLOAD thread // - no more tracks are on the session and the effect tail has been rendered bool doProcess = (thread->type() != ThreadBase::OFFLOAD) && (thread->type() != ThreadBase::MMAP); - if (!isGlobalSession) { + if (!audio_is_global_session(mSessionId)) { bool tracksOnSession = (trackCnt() != 0); if (!tracksOnSession && mTailBufferCount == 0) { diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 63bbcc6cdb..e70c77697e 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -1164,7 +1164,7 @@ void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled_l(const spname, mThreadName); return BAD_VALUE; @@ -1254,6 +1255,13 @@ status_t AudioFlinger::PlaybackThread::checkEffectCompatibility_l( " on output stage session", desc->name); 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 { // no restriction on effects applied on non fast tracks if ((hasAudioSession_l(sessionId) & ThreadBase::FAST_SESSION) == 0) { @@ -1295,7 +1303,7 @@ status_t AudioFlinger::PlaybackThread::checkEffectCompatibility_l( return BAD_VALUE; } #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" " thread %s", desc->name, mThreadName); return BAD_VALUE; @@ -2051,6 +2059,7 @@ sp AudioFlinger::PlaybackThread::createTrac { // scope for mLock Mutex::Autolock _l(mLock); for (audio_session_t session : { + AUDIO_SESSION_DEVICE, AUDIO_SESSION_OUTPUT_STAGE, AUDIO_SESSION_OUTPUT_MIX, sessionId, @@ -3103,7 +3112,7 @@ status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp& c halOutBuffer = halInBuffer; effect_buffer_t *buffer = reinterpret_cast(halInBuffer->externalData()); 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 // the sink buffer as input if (mType != DIRECT) { @@ -3143,8 +3152,11 @@ status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp& c chain->setThread(this); chain->setInBuffer(halInBuffer); chain->setOutBuffer(halOutBuffer); - // Effect chain for session AUDIO_SESSION_OUTPUT_STAGE is inserted at end of effect - // chains list in order to be processed last as it contains output stage effects. + // 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 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 // session AUDIO_SESSION_OUTPUT_STAGE to be processed // after track specific effects and before output stage. @@ -3154,7 +3166,8 @@ status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp& c // chains list to be processed before output mix effects. Relative order between other // sessions is not important. 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"); size_t size = mEffectChains.size(); size_t i = 0; @@ -9099,8 +9112,8 @@ status_t AudioFlinger::MmapThread::checkEffectCompatibility_l( const effect_descriptor_t *desc, audio_session_t sessionId) { // No global effect sessions on mmap threads - if (sessionId == AUDIO_SESSION_OUTPUT_MIX || sessionId == AUDIO_SESSION_OUTPUT_STAGE) { - ALOGW("checkEffectCompatibility_l(): global effect %s on record thread %s", + if (audio_is_global_session(sessionId)) { + ALOGW("checkEffectCompatibility_l(): global effect %s on MMAP thread %s", desc->name, mThreadName); return BAD_VALUE; } @@ -9122,7 +9135,6 @@ status_t AudioFlinger::MmapThread::checkEffectCompatibility_l( } return NO_ERROR; - } void AudioFlinger::MmapThread::checkInvalidTracks_l()