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

Commit 59a89230 authored by Eric Laurent's avatar Eric Laurent
Browse files

audio policy service: fix potential deadlock in destructor

In the AudioCommandThread loop, release mLock before releasing
the strong reference on the service as AudioPolicyService destructor
calls AudioCommandThread::exit() which acquires mLock.

Also check exiPending in thread loop before processing pending
commands or sleeping.

Bug: 15449050.

Change-Id: I148bf21bd67ef721b5b5ee2c1a6afb185c59daa3
parent 7e45ef9d
Loading
Loading
Loading
Loading
+16 −8
Original line number Original line Diff line number Diff line
@@ -399,7 +399,8 @@ bool AudioPolicyService::AudioCommandThread::threadLoop()
    mLock.lock();
    mLock.lock();
    while (!exitPending())
    while (!exitPending())
    {
    {
        while (!mAudioCommands.isEmpty()) {
        sp<AudioPolicyService> svc;
        while (!mAudioCommands.isEmpty() && !exitPending()) {
            nsecs_t curTime = systemTime();
            nsecs_t curTime = systemTime();
            // commands are sorted by increasing time stamp: execute them from index 0 and up
            // commands are sorted by increasing time stamp: execute them from index 0 and up
            if (mAudioCommands[0]->mTime <= curTime) {
            if (mAudioCommands[0]->mTime <= curTime) {
@@ -452,7 +453,7 @@ bool AudioPolicyService::AudioCommandThread::threadLoop()
                    StopOutputData *data = (StopOutputData *)command->mParam.get();
                    StopOutputData *data = (StopOutputData *)command->mParam.get();
                    ALOGV("AudioCommandThread() processing stop output %d",
                    ALOGV("AudioCommandThread() processing stop output %d",
                            data->mIO);
                            data->mIO);
                    sp<AudioPolicyService> svc = mService.promote();
                    svc = mService.promote();
                    if (svc == 0) {
                    if (svc == 0) {
                        break;
                        break;
                    }
                    }
@@ -464,7 +465,7 @@ bool AudioPolicyService::AudioCommandThread::threadLoop()
                    ReleaseOutputData *data = (ReleaseOutputData *)command->mParam.get();
                    ReleaseOutputData *data = (ReleaseOutputData *)command->mParam.get();
                    ALOGV("AudioCommandThread() processing release output %d",
                    ALOGV("AudioCommandThread() processing release output %d",
                            data->mIO);
                            data->mIO);
                    sp<AudioPolicyService> svc = mService.promote();
                    svc = mService.promote();
                    if (svc == 0) {
                    if (svc == 0) {
                        break;
                        break;
                    }
                    }
@@ -494,7 +495,7 @@ bool AudioPolicyService::AudioCommandThread::threadLoop()
                    } break;
                    } break;
                case UPDATE_AUDIOPORT_LIST: {
                case UPDATE_AUDIOPORT_LIST: {
                    ALOGV("AudioCommandThread() processing update audio port list");
                    ALOGV("AudioCommandThread() processing update audio port list");
                    sp<AudioPolicyService> svc = mService.promote();
                    svc = mService.promote();
                    if (svc == 0) {
                    if (svc == 0) {
                        break;
                        break;
                    }
                    }
@@ -504,7 +505,7 @@ bool AudioPolicyService::AudioCommandThread::threadLoop()
                    }break;
                    }break;
                case UPDATE_AUDIOPATCH_LIST: {
                case UPDATE_AUDIOPATCH_LIST: {
                    ALOGV("AudioCommandThread() processing update audio patch list");
                    ALOGV("AudioCommandThread() processing update audio patch list");
                    sp<AudioPolicyService> svc = mService.promote();
                    svc = mService.promote();
                    if (svc == 0) {
                    if (svc == 0) {
                        break;
                        break;
                    }
                    }
@@ -542,10 +543,17 @@ bool AudioPolicyService::AudioCommandThread::threadLoop()
        if (mAudioCommands.isEmpty()) {
        if (mAudioCommands.isEmpty()) {
            release_wake_lock(mName.string());
            release_wake_lock(mName.string());
        }
        }
        // release mLock before releasing strong reference on the service as
        // AudioPolicyService destructor calls AudioCommandThread::exit() which acquires mLock.
        mLock.unlock();
        svc.clear();
        mLock.lock();
        if (!exitPending()) {
            ALOGV("AudioCommandThread() going to sleep");
            ALOGV("AudioCommandThread() going to sleep");
            mWaitWorkCV.waitRelative(mLock, waitTime);
            mWaitWorkCV.waitRelative(mLock, waitTime);
            ALOGV("AudioCommandThread() waking up");
            ALOGV("AudioCommandThread() waking up");
        }
        }
    }
    mLock.unlock();
    mLock.unlock();
    return false;
    return false;
}
}