Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 71a8e2f7 authored by Dan Pasanen's avatar Dan Pasanen
Browse files

Merge tag 'android-7.1.1_r25' into cm-14.1

Android 7.1.1 release 25

Change-Id: Ie45ce24e59a11eee0d7619eeb243d4ee1faac297
parents 93c6eb9a a0d2ff19
Loading
Loading
Loading
Loading
+12 −9
Original line number Diff line number Diff line
@@ -522,8 +522,6 @@ status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size)
        return ERROR_MALFORMED;
    }

    mSyncSampleOffset = data_offset;

    uint8_t header[8];
    if (mDataSource->readAt(
                data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
@@ -535,13 +533,13 @@ status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size)
        return ERROR_MALFORMED;
    }

    mNumSyncSamples = U32_AT(&header[4]);
    uint32_t numSyncSamples = U32_AT(&header[4]);

    if (mNumSyncSamples < 2) {
    if (numSyncSamples < 2) {
        ALOGV("Table of sync samples is empty or has only a single entry!");
    }

    uint64_t allocSize = (uint64_t)mNumSyncSamples * sizeof(uint32_t);
    uint64_t allocSize = (uint64_t)numSyncSamples * sizeof(uint32_t);
    if (allocSize > kMaxTotalSize) {
        ALOGE("Sync sample table size too large.");
        return ERROR_OUT_OF_RANGE;
@@ -559,22 +557,27 @@ status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size)
        return ERROR_OUT_OF_RANGE;
    }

    mSyncSamples = new (std::nothrow) uint32_t[mNumSyncSamples];
    mSyncSamples = new (std::nothrow) uint32_t[numSyncSamples];
    if (!mSyncSamples) {
        ALOGE("Cannot allocate sync sample table with %llu entries.",
                (unsigned long long)mNumSyncSamples);
                (unsigned long long)numSyncSamples);
        return ERROR_OUT_OF_RANGE;
    }

    if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples,
    if (mDataSource->readAt(data_offset + 8, mSyncSamples,
            (size_t)allocSize) != (ssize_t)allocSize) {
        delete mSyncSamples;
        mSyncSamples = NULL;
        return ERROR_IO;
    }

    for (size_t i = 0; i < mNumSyncSamples; ++i) {
    for (size_t i = 0; i < numSyncSamples; ++i) {
        mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1;
    }

    mSyncSampleOffset = data_offset;
    mNumSyncSamples = numSyncSamples;

    return OK;
}

+4 −1
Original line number Diff line number Diff line
@@ -456,7 +456,10 @@ bool IsIDR(const sp<ABuffer> &buffer) {
    const uint8_t *nalStart;
    size_t nalSize;
    while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) {
        CHECK_GT(nalSize, 0u);
        if (nalSize == 0u) {
            ALOGW("skipping empty nal unit from potentially malformed bitstream");
            continue;
        }

        unsigned nalType = nalStart[0] & 0x1f;

+18 −5
Original line number Diff line number Diff line
@@ -2447,6 +2447,18 @@ void AudioFlinger::releaseAudioSessionId(audio_session_t audioSession, pid_t pid
    ALOGW_IF(caller != getpid_cached, "session id %d not found for pid %d", audioSession, caller);
}

bool AudioFlinger::isSessionAcquired_l(audio_session_t audioSession)
{
    size_t num = mAudioSessionRefs.size();
    for (size_t i = 0; i < num; i++) {
        AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
        if (ref->mSessionid == audioSession) {
            return true;
        }
    }
    return false;
}

void AudioFlinger::purgeStaleEffects_l() {

    ALOGV("purging stale effects");
@@ -2840,8 +2852,9 @@ sp<IEffect> AudioFlinger::createEffect(
        sp<Client> client = registerPid(pid);

        // create effect on selected output thread
        bool pinned = (sessionId > AUDIO_SESSION_OUTPUT_MIX) && isSessionAcquired_l(sessionId);
        handle = thread->createEffect_l(client, effectClient, priority, sessionId,
                &desc, enabled, &lStatus);
                &desc, enabled, &lStatus, pinned);
        if (handle != 0 && id != NULL) {
            *id = handle->id();
        }
@@ -3046,7 +3059,7 @@ bool AudioFlinger::updateOrphanEffectChains(const sp<AudioFlinger::EffectModule>
    ALOGV("updateOrphanEffectChains session %d index %zd", session, index);
    if (index >= 0) {
        sp<EffectChain> chain = mOrphanEffectChains.valueAt(index);
        if (chain->removeEffect_l(effect) == 0) {
        if (chain->removeEffect_l(effect, true) == 0) {
            ALOGV("updateOrphanEffectChains removing effect chain at index %zd", index);
            mOrphanEffectChains.removeItemsAt(index);
        }
+1 −0
Original line number Diff line number Diff line
@@ -607,6 +607,7 @@ private:
                void        removeNotificationClient(pid_t pid);
                bool isNonOffloadableGlobalEffectEnabled_l();
                void onNonOffloadableGlobalEffectEnable();
                bool isSessionAcquired_l(audio_session_t audioSession);

                // Store an effect chain to mOrphanEffectChains keyed vector.
                // Called when a thread exits and effects are still attached to it.
+165 −94
Original line number Diff line number Diff line
@@ -78,8 +78,9 @@ AudioFlinger::EffectModule::EffectModule(ThreadBase *thread,
                                        const wp<AudioFlinger::EffectChain>& chain,
                                        effect_descriptor_t *desc,
                                        int id,
                                        audio_session_t 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
@@ -90,7 +91,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
@@ -105,6 +106,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:
@@ -117,9 +120,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();
    }
}

@@ -134,7 +136,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
@@ -162,9 +164,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++) {
@@ -173,9 +180,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 %zu", 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
@@ -202,7 +210,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;
        }
    }
@@ -210,29 +218,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);
                }
    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);
                }
                AudioSystem::unregisterEffect(mId);
            mLock.lock();
        }
    }
    }
    return mHandles.size();
    return numHandles;
}

bool AudioFlinger::EffectModule::updateState() {
@@ -576,6 +577,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 ||
@@ -668,7 +680,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);
            }
        }
@@ -721,7 +733,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);
            }
        }
@@ -888,8 +900,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();
            }
@@ -1116,7 +1127,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);
        }
@@ -1142,7 +1153,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);

@@ -1165,14 +1176,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);
}

@@ -1183,13 +1186,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;
@@ -1197,20 +1202,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 {
@@ -1221,13 +1226,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();
                }
            }
@@ -1239,27 +1244,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();
@@ -1273,25 +1280,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();
    mDisconnected = true;
    sp<ThreadBase> thread;
    {
        sp<EffectModule> effect = mEffect.promote();
        if (effect != 0) {
            thread = effect->thread().promote();
        }
    }
    if (thread != 0) {
            thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId());
        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
@@ -1311,26 +1332,52 @@ 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);

        // keep local copy of index in case of client corruption b/32220769
        const uint32_t clientIndex = mCblk->clientIndex;
        const uint32_t serverIndex = mCblk->serverIndex;
@@ -1364,7 +1411,7 @@ status_t AudioFlinger::EffectHandle::command(uint32_t cmdCode,

            int reply = 0;
            uint32_t rsize = sizeof(reply);
            status_t ret = mEffect->command(EFFECT_CMD_SET_PARAM,
            status_t ret = effect->command(EFFECT_CMD_SET_PARAM,
                                            size,
                                            param,
                                            &rsize,
@@ -1393,15 +1440,9 @@ status_t AudioFlinger::EffectHandle::command(uint32_t cmdCode,
        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)
@@ -1483,7 +1524,6 @@ AudioFlinger::EffectChain::~EffectChain()
    if (mOwnInBuffer) {
        delete mInBuffer;
    }

}

// getEffectFromDesc_l() must be called with ThreadBase::mLock held
@@ -1601,13 +1641,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) {
@@ -1721,8 +1786,9 @@ status_t AudioFlinger::EffectChain::addEffect_l(const sp<EffectModule>& effect)
#endif // LINE_ADDED_BY_DOLBY
}

// 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();
@@ -1737,6 +1803,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 {
@@ -1753,6 +1823,7 @@ size_t AudioFlinger::EffectChain::removeEffect_l(const sp<EffectModule>& effect)
                effect->setSuspended(false);
            }
#endif // DOLBY_END

            break;
        }
    }
@@ -1760,7 +1831,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();
@@ -1769,7 +1840,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();
@@ -1778,7 +1849,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();
@@ -1787,7 +1858,7 @@ void AudioFlinger::EffectChain::setAudioSource_l(audio_source_t source)
    }
}

// setVolume_l() must be called with PlaybackThread::mLock or EffectChain::mLock held
// setVolume_l() must be called with ThreadBase::mLock or EffectChain::mLock held
bool AudioFlinger::EffectChain::setVolume_l(uint32_t *left, uint32_t *right, bool force)
{
    uint32_t newLeft = *left;
@@ -1848,7 +1919,7 @@ bool AudioFlinger::EffectChain::setVolume_l(uint32_t *left, uint32_t *right, boo
    return hasControl;
}

// resetVolume_l() must be called with PlaybackThread::mLock or EffectChain::mLock held
// resetVolume_l() must be called with ThreadBase::mLock or EffectChain::mLock held
void AudioFlinger::EffectChain::resetVolume_l()
{
    if ((mLeftVolume != UINT_MAX) && (mRightVolume != UINT_MAX)) {
@@ -1949,7 +2020,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();
Loading