Fix issue 2153835: AudioFlinger: setParameters() can remain stuck if output thread is terminated.
Wait for the parameter set completed condition with a time out in ThreadBase::setParameters().
Also lock AudioFlinger mutex before accessing thread list in AudioFlinger::setParameters() and keep a strong reference
on the thread being used in case it is exited while processing the request.
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 2ed5d3b..8e967fb 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -603,18 +603,19 @@
return result;
}
- // Check if parameters are for an output
- PlaybackThread *playbackThread = checkPlaybackThread_l(ioHandle);
- if (playbackThread != NULL) {
- return playbackThread->setParameters(keyValuePairs);
+ // hold a strong ref on thread in case closeOutput() or closeInput() is called
+ // and the thread is exited once the lock is released
+ sp<ThreadBase> thread;
+ {
+ Mutex::Autolock _l(mLock);
+ thread = checkPlaybackThread_l(ioHandle);
+ if (thread == NULL) {
+ thread = checkRecordThread_l(ioHandle);
+ }
}
-
- // Check if parameters are for an input
- RecordThread *recordThread = checkRecordThread_l(ioHandle);
- if (recordThread != NULL) {
- return recordThread->setParameters(keyValuePairs);
+ if (thread != NULL) {
+ return thread->setParameters(keyValuePairs);
}
-
return BAD_VALUE;
}
@@ -626,6 +627,9 @@
if (ioHandle == 0) {
return mAudioHardware->getParameters(keys);
}
+
+ Mutex::Autolock _l(mLock);
+
PlaybackThread *playbackThread = checkPlaybackThread_l(ioHandle);
if (playbackThread != NULL) {
return playbackThread->getParameters(keys);
@@ -736,7 +740,7 @@
void AudioFlinger::ThreadBase::exit()
{
- // keep a strong ref on ourself so that we want get
+ // keep a strong ref on ourself so that we wont get
// destroyed in the middle of requestExitAndWait()
sp <ThreadBase> strongMe = this;
@@ -778,9 +782,14 @@
mNewParameters.add(keyValuePairs);
mWaitWorkCV.signal();
- mParamCond.wait(mLock);
- status = mParamStatus;
- mWaitWorkCV.signal();
+ // wait condition with timeout in case the thread loop has exited
+ // before the request could be processed
+ if (mParamCond.waitRelative(mLock, seconds(2)) == NO_ERROR) {
+ status = mParamStatus;
+ mWaitWorkCV.signal();
+ } else {
+ status = TIMED_OUT;
+ }
return status;
}