diff options
Diffstat (limited to 'services/audioflinger/Effects.cpp')
-rw-r--r-- | services/audioflinger/Effects.cpp | 327 |
1 files changed, 216 insertions, 111 deletions
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp index d46c10e..8a8b05b 100644 --- a/services/audioflinger/Effects.cpp +++ b/services/audioflinger/Effects.cpp @@ -59,8 +59,9 @@ AudioFlinger::EffectModule::EffectModule(ThreadBase *thread, const wp<AudioFlinger::EffectChain>& chain, effect_descriptor_t *desc, int id, - int sessionId) - : mPinned(sessionId > AUDIO_SESSION_OUTPUT_MIX), + audio_session_t sessionId, + bool pinned) + : mPinned(pinned), mThread(thread), mChain(chain), mId(id), mSessionId(sessionId), mDescriptor(*desc), // mConfig is set by configure() and not used before then @@ -71,7 +72,7 @@ AudioFlinger::EffectModule::EffectModule(ThreadBase *thread, mSuspended(false), mAudioFlinger(thread->mAudioFlinger) { - ALOGV("Constructor %p", this); + ALOGV("Constructor %p pinned %d", this, pinned); int lStatus; // create effect engine from effect factory @@ -86,6 +87,8 @@ AudioFlinger::EffectModule::EffectModule(ThreadBase *thread, goto Error; } + setOffloaded(thread->type() == ThreadBase::OFFLOAD, thread->id()); + ALOGV("Constructor success name %s, Interface %p", mDescriptor.name, mEffectInterface); return; Error: @@ -98,9 +101,8 @@ AudioFlinger::EffectModule::~EffectModule() { ALOGV("Destructor %p", this); if (mEffectInterface != NULL) { - remove_effect_from_hal_l(); - // release effect engine - EffectRelease(mEffectInterface); + ALOGW("EffectModule %p destructor called with unreleased interface", this); + release_l(); } } @@ -115,7 +117,7 @@ status_t AudioFlinger::EffectModule::addHandle(EffectHandle *handle) size_t i; for (i = 0; i < size; i++) { EffectHandle *h = mHandles[i]; - if (h == NULL || h->destroyed_l()) { + if (h == NULL || h->disconnected()) { continue; } // first non destroyed handle is considered in control @@ -143,9 +145,14 @@ status_t AudioFlinger::EffectModule::addHandle(EffectHandle *handle) return status; } -size_t AudioFlinger::EffectModule::removeHandle(EffectHandle *handle) +ssize_t AudioFlinger::EffectModule::removeHandle(EffectHandle *handle) { Mutex::Autolock _l(mLock); + return removeHandle_l(handle); +} + +ssize_t AudioFlinger::EffectModule::removeHandle_l(EffectHandle *handle) +{ size_t size = mHandles.size(); size_t i; for (i = 0; i < size; i++) { @@ -154,9 +161,10 @@ size_t AudioFlinger::EffectModule::removeHandle(EffectHandle *handle) } } if (i == size) { - return size; + ALOGW("%s %p handle not found %p", __FUNCTION__, this, handle); + return BAD_VALUE; } - ALOGV("removeHandle() %p removed handle %p in position %d", this, handle, i); + ALOGV("removeHandle_l() %p removed handle %p in position %zu", this, handle, i); mHandles.removeAt(i); // if removed from first place, move effect control from this handle to next in line @@ -183,7 +191,7 @@ AudioFlinger::EffectHandle *AudioFlinger::EffectModule::controlHandle_l() // the first valid handle in the list has control over the module for (size_t i = 0; i < mHandles.size(); i++) { EffectHandle *h = mHandles[i]; - if (h != NULL && !h->destroyed_l()) { + if (h != NULL && !h->disconnected()) { return h; } } @@ -191,29 +199,22 @@ AudioFlinger::EffectHandle *AudioFlinger::EffectModule::controlHandle_l() return NULL; } -size_t AudioFlinger::EffectModule::disconnect(EffectHandle *handle, bool unpinIfLast) +// unsafe method called when the effect parent thread has been destroyed +ssize_t AudioFlinger::EffectModule::disconnectHandle(EffectHandle *handle, bool unpinIfLast) { ALOGV("disconnect() %p handle %p", this, handle); - // keep a strong reference on this EffectModule to avoid calling the - // destructor before we exit - sp<EffectModule> keep(this); - { - if (removeHandle(handle) == 0) { - if (!isPinned() || unpinIfLast) { - sp<ThreadBase> thread = mThread.promote(); - if (thread != 0) { - Mutex::Autolock _l(thread->mLock); - thread->removeEffect_l(this); - } - sp<AudioFlinger> af = mAudioFlinger.promote(); - if (af != 0) { - af->updateOrphanEffectChains(this); - } - AudioSystem::unregisterEffect(mId); - } + Mutex::Autolock _l(mLock); + ssize_t numHandles = removeHandle_l(handle); + if ((numHandles == 0) && (!mPinned || unpinIfLast)) { + AudioSystem::unregisterEffect(mId); + sp<AudioFlinger> af = mAudioFlinger.promote(); + if (af != 0) { + mLock.unlock(); + af->updateOrphanEffectChains(this); + mLock.lock(); } } - return mHandles.size(); + return numHandles; } void AudioFlinger::EffectModule::updateState() { @@ -528,6 +529,17 @@ status_t AudioFlinger::EffectModule::stop_l() return status; } +// must be called with EffectChain::mLock held +void AudioFlinger::EffectModule::release_l() +{ + if (mEffectInterface != NULL) { + remove_effect_from_hal_l(); + // release effect engine + EffectRelease(mEffectInterface); + mEffectInterface = NULL; + } +} + status_t AudioFlinger::EffectModule::remove_effect_from_hal_l() { if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC || @@ -578,6 +590,22 @@ status_t AudioFlinger::EffectModule::command(uint32_t cmdCode, android_errorWriteLog(0x534e4554, "32438594"); return -EINVAL; } + if (cmdCode == EFFECT_CMD_GET_PARAM && + (sizeof(effect_param_t) > *replySize + || ((effect_param_t *)pCmdData)->psize > *replySize + - sizeof(effect_param_t) + || ((effect_param_t *)pCmdData)->vsize > *replySize + - sizeof(effect_param_t) + - ((effect_param_t *)pCmdData)->psize + || roundUpDelta(((effect_param_t *)pCmdData)->psize, (uint32_t)sizeof(int)) > + *replySize + - sizeof(effect_param_t) + - ((effect_param_t *)pCmdData)->psize + - ((effect_param_t *)pCmdData)->vsize)) { + ALOGV("\tLVM_ERROR : EFFECT_CMD_GET_PARAM: reply size inconsistent"); + android_errorWriteLog(0x534e4554, "32705438"); + return -EINVAL; + } if ((cmdCode == EFFECT_CMD_SET_PARAM || cmdCode == EFFECT_CMD_SET_PARAM_DEFERRED) && // DEFERRED not generally used (sizeof(effect_param_t) > cmdSize @@ -604,7 +632,7 @@ status_t AudioFlinger::EffectModule::command(uint32_t cmdCode, uint32_t size = (replySize == NULL) ? 0 : *replySize; for (size_t i = 1; i < mHandles.size(); i++) { EffectHandle *h = mHandles[i]; - if (h != NULL && !h->destroyed_l()) { + if (h != NULL && !h->disconnected()) { h->commandExecuted(cmdCode, cmdSize, pCmdData, size, pReplyData); } } @@ -657,7 +685,7 @@ status_t AudioFlinger::EffectModule::setEnabled_l(bool enabled) } for (size_t i = 1; i < mHandles.size(); i++) { EffectHandle *h = mHandles[i]; - if (h != NULL && !h->destroyed_l()) { + if (h != NULL && !h->disconnected()) { h->setEnabled(enabled); } } @@ -822,8 +850,7 @@ bool AudioFlinger::EffectModule::purgeHandles() Mutex::Autolock _l(mLock); for (size_t i = 0; i < mHandles.size(); i++) { EffectHandle *handle = mHandles[i]; - if (handle != NULL && !handle->destroyed_l()) { - handle->effect().clear(); + if (handle != NULL && !handle->disconnected()) { if (handle->hasControl()) { enabled = handle->enabled(); } @@ -1050,7 +1077,7 @@ void AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args __unu result.append("\t\t\t Pid Priority Ctrl Locked client server\n"); for (size_t i = 0; i < mHandles.size(); ++i) { EffectHandle *handle = mHandles[i]; - if (handle != NULL && !handle->destroyed_l()) { + if (handle != NULL && !handle->disconnected()) { handle->dumpToBuffer(buffer, SIZE); result.append(buffer); } @@ -1076,7 +1103,7 @@ AudioFlinger::EffectHandle::EffectHandle(const sp<EffectModule>& effect, int32_t priority) : BnEffect(), mEffect(effect), mEffectClient(effectClient), mClient(client), mCblk(NULL), - mPriority(priority), mHasControl(false), mEnabled(false), mDestroyed(false) + mPriority(priority), mHasControl(false), mEnabled(false), mDisconnected(false) { ALOGV("constructor %p", this); @@ -1099,14 +1126,6 @@ AudioFlinger::EffectHandle::EffectHandle(const sp<EffectModule>& effect, AudioFlinger::EffectHandle::~EffectHandle() { ALOGV("Destructor %p", this); - - if (mEffect == 0) { - mDestroyed = true; - return; - } - mEffect->lock(); - mDestroyed = true; - mEffect->unlock(); disconnect(false); } @@ -1117,13 +1136,15 @@ status_t AudioFlinger::EffectHandle::initCheck() status_t AudioFlinger::EffectHandle::enable() { + AutoMutex _l(mLock); ALOGV("enable %p", this); + sp<EffectModule> effect = mEffect.promote(); + if (effect == 0 || mDisconnected) { + return DEAD_OBJECT; + } if (!mHasControl) { return INVALID_OPERATION; } - if (mEffect == 0) { - return DEAD_OBJECT; - } if (mEnabled) { return NO_ERROR; @@ -1131,20 +1152,20 @@ status_t AudioFlinger::EffectHandle::enable() mEnabled = true; - sp<ThreadBase> thread = mEffect->thread().promote(); + sp<ThreadBase> thread = effect->thread().promote(); if (thread != 0) { - thread->checkSuspendOnEffectEnabled(mEffect, true, mEffect->sessionId()); + thread->checkSuspendOnEffectEnabled(effect, true, effect->sessionId()); } // checkSuspendOnEffectEnabled() can suspend this same effect when enabled - if (mEffect->suspended()) { + if (effect->suspended()) { return NO_ERROR; } - status_t status = mEffect->setEnabled(true); + status_t status = effect->setEnabled(true); if (status != NO_ERROR) { if (thread != 0) { - thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId()); + thread->checkSuspendOnEffectEnabled(effect, false, effect->sessionId()); } mEnabled = false; } else { @@ -1155,13 +1176,13 @@ status_t AudioFlinger::EffectHandle::enable() Mutex::Autolock _l(t->mLock); t->broadcast_l(); } - if (!mEffect->isOffloadable()) { + if (!effect->isOffloadable()) { if (thread->type() == ThreadBase::OFFLOAD || (thread->type() == ThreadBase::DIRECT && thread->mIsDirectPcm)) { PlaybackThread *t = (PlaybackThread *)thread.get(); t->invalidateTracks(AUDIO_STREAM_MUSIC); } - if (mEffect->sessionId() == AUDIO_SESSION_OUTPUT_MIX) { + if (effect->sessionId() == AUDIO_SESSION_OUTPUT_MIX) { thread->mAudioFlinger->onNonOffloadableGlobalEffectEnable(); } } @@ -1173,27 +1194,29 @@ status_t AudioFlinger::EffectHandle::enable() status_t AudioFlinger::EffectHandle::disable() { ALOGV("disable %p", this); + AutoMutex _l(mLock); + sp<EffectModule> effect = mEffect.promote(); + if (effect == 0 || mDisconnected) { + return DEAD_OBJECT; + } if (!mHasControl) { return INVALID_OPERATION; } - if (mEffect == 0) { - return DEAD_OBJECT; - } if (!mEnabled) { return NO_ERROR; } mEnabled = false; - if (mEffect->suspended()) { + if (effect->suspended()) { return NO_ERROR; } - status_t status = mEffect->setEnabled(false); + status_t status = effect->setEnabled(false); - sp<ThreadBase> thread = mEffect->thread().promote(); + sp<ThreadBase> thread = effect->thread().promote(); if (thread != 0) { - thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId()); + thread->checkSuspendOnEffectEnabled(effect, false, effect->sessionId()); if ((thread->type() == ThreadBase::OFFLOAD) || (thread->type() == ThreadBase::DIRECT && thread->mIsDirectPcm)){ PlaybackThread *t = (PlaybackThread *)thread.get(); @@ -1207,25 +1230,39 @@ status_t AudioFlinger::EffectHandle::disable() void AudioFlinger::EffectHandle::disconnect() { + ALOGV("%s %p", __FUNCTION__, this); disconnect(true); } void AudioFlinger::EffectHandle::disconnect(bool unpinIfLast) { - ALOGV("disconnect(%s)", unpinIfLast ? "true" : "false"); - if (mEffect == 0) { + AutoMutex _l(mLock); + ALOGV("disconnect(%s) %p", unpinIfLast ? "true" : "false", this); + if (mDisconnected) { + if (unpinIfLast) { + android_errorWriteLog(0x534e4554, "32707507"); + } return; } - // restore suspended effects if the disconnected handle was enabled and the last one. - if ((mEffect->disconnect(this, unpinIfLast) == 0) && mEnabled) { - sp<ThreadBase> thread = mEffect->thread().promote(); - if (thread != 0) { - thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId()); + mDisconnected = true; + sp<ThreadBase> thread; + { + sp<EffectModule> effect = mEffect.promote(); + if (effect != 0) { + thread = effect->thread().promote(); + } + } + if (thread != 0) { + thread->disconnectEffectHandle(this, unpinIfLast); + } else { + ALOGW("%s Effect handle %p disconnected after thread destruction", __FUNCTION__, this); + // try to cleanup as much as we can + sp<EffectModule> effect = mEffect.promote(); + if (effect != 0) { + effect->disconnectHandle(this, unpinIfLast); } } - // release sp on module => module destructor can be called now - mEffect.clear(); if (mClient != 0) { if (mCblk != NULL) { // unlike ~TrackBase(), mCblk is never a local new, so don't delete @@ -1245,55 +1282,99 @@ status_t AudioFlinger::EffectHandle::command(uint32_t cmdCode, void *pReplyData) { ALOGVV("command(), cmdCode: %d, mHasControl: %d, mEffect: %p", - cmdCode, mHasControl, (mEffect == 0) ? 0 : mEffect.get()); + cmdCode, mHasControl, mEffect.unsafe_get()); + if (cmdCode == EFFECT_CMD_ENABLE) { + if (*replySize < sizeof(int)) { + android_errorWriteLog(0x534e4554, "32095713"); + return BAD_VALUE; + } + *(int *)pReplyData = NO_ERROR; + *replySize = sizeof(int); + return enable(); + } else if (cmdCode == EFFECT_CMD_DISABLE) { + if (*replySize < sizeof(int)) { + android_errorWriteLog(0x534e4554, "32095713"); + return BAD_VALUE; + } + *(int *)pReplyData = NO_ERROR; + *replySize = sizeof(int); + return disable(); + } + + AutoMutex _l(mLock); + sp<EffectModule> effect = mEffect.promote(); + if (effect == 0 || mDisconnected) { + return DEAD_OBJECT; + } // only get parameter command is permitted for applications not controlling the effect if (!mHasControl && cmdCode != EFFECT_CMD_GET_PARAM) { return INVALID_OPERATION; } - if (mEffect == 0) { - return DEAD_OBJECT; - } if (mClient == 0) { return INVALID_OPERATION; } // handle commands that are not forwarded transparently to effect engine if (cmdCode == EFFECT_CMD_SET_PARAM_COMMIT) { + if (*replySize < sizeof(int)) { + android_errorWriteLog(0x534e4554, "32095713"); + return BAD_VALUE; + } + *(int *)pReplyData = NO_ERROR; + *replySize = sizeof(int); + // No need to trylock() here as this function is executed in the binder thread serving a // particular client process: no risk to block the whole media server process or mixer // threads if we are stuck here Mutex::Autolock _l(mCblk->lock); - if (mCblk->clientIndex > EFFECT_PARAM_BUFFER_SIZE || - mCblk->serverIndex > EFFECT_PARAM_BUFFER_SIZE) { + // keep local copy of index in case of client corruption b/32220769 + const uint32_t clientIndex = mCblk->clientIndex; + const uint32_t serverIndex = mCblk->serverIndex; + if (clientIndex > EFFECT_PARAM_BUFFER_SIZE || + serverIndex > EFFECT_PARAM_BUFFER_SIZE) { mCblk->serverIndex = 0; mCblk->clientIndex = 0; return BAD_VALUE; } status_t status = NO_ERROR; - while (mCblk->serverIndex < mCblk->clientIndex) { - int reply; - uint32_t rsize = sizeof(int); - int *p = (int *)(mBuffer + mCblk->serverIndex); - int size = *p++; - if (((uint8_t *)p + size) > mBuffer + mCblk->clientIndex) { + effect_param_t *param = NULL; + for (uint32_t index = serverIndex; index < clientIndex;) { + int *p = (int *)(mBuffer + index); + const int size = *p++; + if (size < 0 + || size > EFFECT_PARAM_BUFFER_SIZE + || ((uint8_t *)p + size) > mBuffer + clientIndex) { ALOGW("command(): invalid parameter block size"); + status = BAD_VALUE; break; } - effect_param_t *param = (effect_param_t *)p; - if (param->psize == 0 || param->vsize == 0) { - ALOGW("command(): null parameter or value size"); - mCblk->serverIndex += size; - continue; + + // copy to local memory in case of client corruption b/32220769 + param = (effect_param_t *)realloc(param, size); + if (param == NULL) { + ALOGW("command(): out of memory"); + status = NO_MEMORY; + break; } - uint32_t psize = sizeof(effect_param_t) + - ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + - param->vsize; - status_t ret = mEffect->command(EFFECT_CMD_SET_PARAM, - psize, - p, + memcpy(param, p, size); + + int reply = 0; + uint32_t rsize = sizeof(reply); + status_t ret = effect->command(EFFECT_CMD_SET_PARAM, + size, + param, &rsize, &reply); + + // verify shared memory: server index shouldn't change; client index can't go back. + if (serverIndex != mCblk->serverIndex + || clientIndex > mCblk->clientIndex) { + android_errorWriteLog(0x534e4554, "32220769"); + status = BAD_VALUE; + break; + } + // stop at first error encountered if (ret != NO_ERROR) { status = ret; @@ -1303,20 +1384,15 @@ status_t AudioFlinger::EffectHandle::command(uint32_t cmdCode, *(int *)pReplyData = reply; break; } - mCblk->serverIndex += size; + index += size; } + free(param); mCblk->serverIndex = 0; mCblk->clientIndex = 0; return status; - } else if (cmdCode == EFFECT_CMD_ENABLE) { - *(int *)pReplyData = NO_ERROR; - return enable(); - } else if (cmdCode == EFFECT_CMD_DISABLE) { - *(int *)pReplyData = NO_ERROR; - return disable(); } - return mEffect->command(cmdCode, cmdSize, pCmdData, replySize, pReplyData); + return effect->command(cmdCode, cmdSize, pCmdData, replySize, pReplyData); } void AudioFlinger::EffectHandle::setControl(bool hasControl, bool signal, bool enabled) @@ -1398,7 +1474,6 @@ AudioFlinger::EffectChain::~EffectChain() if (mOwnInBuffer) { delete mInBuffer; } - } // getEffectFromDesc_l() must be called with ThreadBase::mLock held @@ -1512,13 +1587,38 @@ void AudioFlinger::EffectChain::process_l() } } -// addEffect_l() must be called with PlaybackThread::mLock held +// createEffect_l() must be called with ThreadBase::mLock held +status_t AudioFlinger::EffectChain::createEffect_l(sp<EffectModule>& effect, + ThreadBase *thread, + effect_descriptor_t *desc, + int id, + audio_session_t sessionId, + bool pinned) +{ + Mutex::Autolock _l(mLock); + effect = new EffectModule(thread, this, desc, id, sessionId, pinned); + status_t lStatus = effect->status(); + if (lStatus == NO_ERROR) { + lStatus = addEffect_ll(effect); + } + if (lStatus != NO_ERROR) { + effect.clear(); + } + return lStatus; +} + +// addEffect_l() must be called with ThreadBase::mLock held status_t AudioFlinger::EffectChain::addEffect_l(const sp<EffectModule>& effect) { + Mutex::Autolock _l(mLock); + return addEffect_ll(effect); +} +// addEffect_l() must be called with ThreadBase::mLock and EffectChain::mLock held +status_t AudioFlinger::EffectChain::addEffect_ll(const sp<EffectModule>& effect) +{ effect_descriptor_t desc = effect->desc(); uint32_t insertPref = desc.flags & EFFECT_FLAG_INSERT_MASK; - Mutex::Autolock _l(mLock); effect->setChain(this); sp<ThreadBase> thread = mThread.promote(); if (thread == 0) { @@ -1628,8 +1728,9 @@ status_t AudioFlinger::EffectChain::addEffect_l(const sp<EffectModule>& effect) return NO_ERROR; } -// removeEffect_l() must be called with PlaybackThread::mLock held -size_t AudioFlinger::EffectChain::removeEffect_l(const sp<EffectModule>& effect) +// removeEffect_l() must be called with ThreadBase::mLock held +size_t AudioFlinger::EffectChain::removeEffect_l(const sp<EffectModule>& effect, + bool release) { Mutex::Autolock _l(mLock); size_t size = mEffects.size(); @@ -1644,6 +1745,10 @@ size_t AudioFlinger::EffectChain::removeEffect_l(const sp<EffectModule>& effect) mEffects[i]->state() == EffectModule::STOPPING) { mEffects[i]->stop(); } + if (release) { + mEffects[i]->release_l(); + } + if (type == EFFECT_FLAG_TYPE_AUXILIARY) { delete[] effect->inBuffer(); } else { @@ -1662,7 +1767,7 @@ size_t AudioFlinger::EffectChain::removeEffect_l(const sp<EffectModule>& effect) return mEffects.size(); } -// setDevice_l() must be called with PlaybackThread::mLock held +// setDevice_l() must be called with ThreadBase::mLock held void AudioFlinger::EffectChain::setDevice_l(audio_devices_t device) { size_t size = mEffects.size(); @@ -1671,7 +1776,7 @@ void AudioFlinger::EffectChain::setDevice_l(audio_devices_t device) } } -// setMode_l() must be called with PlaybackThread::mLock held +// setMode_l() must be called with ThreadBase::mLock held void AudioFlinger::EffectChain::setMode_l(audio_mode_t mode) { size_t size = mEffects.size(); @@ -1680,7 +1785,7 @@ void AudioFlinger::EffectChain::setMode_l(audio_mode_t mode) } } -// setAudioSource_l() must be called with PlaybackThread::mLock held +// setAudioSource_l() must be called with ThreadBase::mLock held void AudioFlinger::EffectChain::setAudioSource_l(audio_source_t source) { size_t size = mEffects.size(); @@ -1689,7 +1794,7 @@ void AudioFlinger::EffectChain::setAudioSource_l(audio_source_t source) } } -// setVolume_l() must be called with PlaybackThread::mLock held +// setVolume_l() must be called with ThreadBase::mLock held bool AudioFlinger::EffectChain::setVolume_l(uint32_t *left, uint32_t *right) { uint32_t newLeft = *left; @@ -1841,7 +1946,7 @@ void AudioFlinger::EffectChain::setEffectSuspended_l( effect->setSuspended(false); effect->lock(); EffectHandle *handle = effect->controlHandle_l(); - if (handle != NULL && !handle->destroyed_l()) { + if (handle != NULL && !handle->disconnected()) { effect->setEnabled_l(handle->enabled()); } effect->unlock(); |