Soundtrigger service: fix cross deadlock with audio policy service
Do not hold Module mutex when calling into audio policy manager to
avoid cross deadlock with audio poicy service mutex: Audio policy manager
can call into sound trigger service with its mutex held in methods like
stopInput().
Regression introduced by fix for b/64340921 commit f759b8c4
Bug: 64340921
Bug: 67310830
Test: repro steps in b/67310830
Merged-In: Ie50b2e7c55fe9828a3fd8de6b31eb4a492791583
Change-Id: Ie50b2e7c55fe9828a3fd8de6b31eb4a492791583
diff --git a/services/audiopolicy/common/managerdefinitions/src/SoundTriggerSession.cpp b/services/audiopolicy/common/managerdefinitions/src/SoundTriggerSession.cpp
index 8ca3ae0..0383b0e 100644
--- a/services/audiopolicy/common/managerdefinitions/src/SoundTriggerSession.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/SoundTriggerSession.cpp
@@ -34,7 +34,7 @@
{
ssize_t index = indexOfKey(session);
if (index < 0) {
- ALOGW("acquireSoundTriggerSession() session %d not registered", session);
+ ALOGW("releaseSession() session %d not registered", session);
return BAD_VALUE;
}
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index 5b8d990..19dd41e 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -528,37 +528,45 @@
void SoundTriggerHwService::Module::detach(const sp<ModuleClient>& moduleClient)
{
ALOGV("Module::detach()");
- AutoMutex lock(mLock);
- ssize_t index = -1;
+ Vector<audio_session_t> releasedSessions;
- for (size_t i = 0; i < mModuleClients.size(); i++) {
- if (mModuleClients[i] == moduleClient) {
- index = i;
- break;
- }
- }
- if (index == -1) {
- return;
- }
+ {
+ AutoMutex lock(mLock);
+ ssize_t index = -1;
- ALOGV("remove client %p", moduleClient.get());
- mModuleClients.removeAt(index);
-
- // Iterate in reverse order as models are removed from list inside the loop.
- for (size_t i = mModels.size(); i > 0; i--) {
- sp<Model> model = mModels.valueAt(i - 1);
- if (moduleClient == model->mModuleClient) {
- mModels.removeItemsAt(i - 1);
- ALOGV("detach() unloading model %d", model->mHandle);
- if (mHalInterface != 0) {
- if (model->mState == Model::STATE_ACTIVE) {
- mHalInterface->stopRecognition(model->mHandle);
- }
- mHalInterface->unloadSoundModel(model->mHandle);
+ for (size_t i = 0; i < mModuleClients.size(); i++) {
+ if (mModuleClients[i] == moduleClient) {
+ index = i;
+ break;
}
- AudioSystem::releaseSoundTriggerSession(model->mCaptureSession);
- mHalInterface->unloadSoundModel(model->mHandle);
}
+ if (index == -1) {
+ return;
+ }
+
+ ALOGV("remove client %p", moduleClient.get());
+ mModuleClients.removeAt(index);
+
+ // Iterate in reverse order as models are removed from list inside the loop.
+ for (size_t i = mModels.size(); i > 0; i--) {
+ sp<Model> model = mModels.valueAt(i - 1);
+ if (moduleClient == model->mModuleClient) {
+ mModels.removeItemsAt(i - 1);
+ ALOGV("detach() unloading model %d", model->mHandle);
+ if (mHalInterface != 0) {
+ if (model->mState == Model::STATE_ACTIVE) {
+ mHalInterface->stopRecognition(model->mHandle);
+ }
+ mHalInterface->unloadSoundModel(model->mHandle);
+ }
+ releasedSessions.add(model->mCaptureSession);
+ }
+ }
+ }
+
+ for (size_t i = 0; i < releasedSessions.size(); i++) {
+ // do not call AudioSystem methods with mLock held
+ AudioSystem::releaseSoundTriggerSession(releasedSessions[i]);
}
}
@@ -593,61 +601,71 @@
return BAD_VALUE;
}
- AutoMutex lock(mLock);
-
- if (mModels.size() >= mDescriptor.properties.max_sound_models) {
- ALOGW("loadSoundModel(): Not loading, max number of models (%d) would be exceeded",
- mDescriptor.properties.max_sound_models);
- return INVALID_OPERATION;
- }
-
- status_t status = mHalInterface->loadSoundModel(sound_model,
- SoundTriggerHwService::soundModelCallback,
- this, handle);
-
- if (status != NO_ERROR) {
- return status;
- }
audio_session_t session;
audio_io_handle_t ioHandle;
audio_devices_t device;
-
- status = AudioSystem::acquireSoundTriggerSession(&session, &ioHandle, &device);
+ // do not call AudioSystem methods with mLock held
+ status_t status = AudioSystem::acquireSoundTriggerSession(&session, &ioHandle, &device);
if (status != NO_ERROR) {
return status;
}
- sp<Model> model = new Model(*handle, session, ioHandle, device, sound_model->type,
- moduleClient);
- mModels.replaceValueFor(*handle, model);
+ {
+ AutoMutex lock(mLock);
+ if (mModels.size() >= mDescriptor.properties.max_sound_models) {
+ ALOGW("loadSoundModel(): Not loading, max number of models (%d) would be exceeded",
+ mDescriptor.properties.max_sound_models);
+ status = INVALID_OPERATION;
+ goto exit;
+ }
+
+ status = mHalInterface->loadSoundModel(sound_model,
+ SoundTriggerHwService::soundModelCallback,
+ this, handle);
+ if (status != NO_ERROR) {
+ goto exit;
+ }
+
+ sp<Model> model = new Model(*handle, session, ioHandle, device, sound_model->type,
+ moduleClient);
+ mModels.replaceValueFor(*handle, model);
+ }
+exit:
+ if (status != NO_ERROR) {
+ // do not call AudioSystem methods with mLock held
+ AudioSystem::releaseSoundTriggerSession(session);
+ }
return status;
}
status_t SoundTriggerHwService::Module::unloadSoundModel(sound_model_handle_t handle)
{
ALOGV("unloadSoundModel() model handle %d", handle);
- AutoMutex lock(mLock);
- return unloadSoundModel_l(handle);
-}
+ status_t status;
+ audio_session_t session;
-status_t SoundTriggerHwService::Module::unloadSoundModel_l(sound_model_handle_t handle)
-{
- if (mHalInterface == 0) {
- return NO_INIT;
+ {
+ AutoMutex lock(mLock);
+ if (mHalInterface == 0) {
+ return NO_INIT;
+ }
+ ssize_t index = mModels.indexOfKey(handle);
+ if (index < 0) {
+ return BAD_VALUE;
+ }
+ sp<Model> model = mModels.valueAt(index);
+ mModels.removeItem(handle);
+ if (model->mState == Model::STATE_ACTIVE) {
+ mHalInterface->stopRecognition(model->mHandle);
+ model->mState = Model::STATE_IDLE;
+ }
+ status = mHalInterface->unloadSoundModel(handle);
+ session = model->mCaptureSession;
}
- ssize_t index = mModels.indexOfKey(handle);
- if (index < 0) {
- return BAD_VALUE;
- }
- sp<Model> model = mModels.valueAt(index);
- mModels.removeItem(handle);
- if (model->mState == Model::STATE_ACTIVE) {
- mHalInterface->stopRecognition(model->mHandle);
- model->mState = Model::STATE_IDLE;
- }
- AudioSystem::releaseSoundTriggerSession(model->mCaptureSession);
- return mHalInterface->unloadSoundModel(handle);
+ // do not call AudioSystem methods with mLock held
+ AudioSystem::releaseSoundTriggerSession(session);
+ return status;
}
status_t SoundTriggerHwService::Module::startRecognition(sound_model_handle_t handle,
diff --git a/services/soundtrigger/SoundTriggerHwService.h b/services/soundtrigger/SoundTriggerHwService.h
index 60ebb35..95efc4b 100644
--- a/services/soundtrigger/SoundTriggerHwService.h
+++ b/services/soundtrigger/SoundTriggerHwService.h
@@ -140,8 +140,6 @@
private:
- status_t unloadSoundModel_l(sound_model_handle_t handle);
-
Mutex mLock;
wp<SoundTriggerHwService> mService;
sp<SoundTriggerHalInterface> mHalInterface;