libaudiohal@aidl: Fix deadlock when stream goes away
Split the lock for accessing 'DeviceHalAidl::mCallbacks'
from the main lock 'DeviceHalAidl::mLock'. This is needed
to handle the case when the code of 'Hal2AidlMapper'
becomes the sole owner of the stream and ends up destroying
it, triggering a callbacks cleanup call. Since all calls to
'Hal2AidlMapper' are protected by 'mLock', it can not be
used for implementing exclusive access to 'mCallbacks'.
To avoid introducing deadlocks due to use of two mutexes,
the new mutex 'mCallbacksLock' is used only to guard
access to 'mCallbacks', effectively making it a synchronized
map.
Bug: 357487484
Test: atest CoreAudioHalAidlTest
Change-Id: Ic7e5314ad62954f9f8347af2049a5216cab01b7f
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index 86dd663..2f2f69f 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -487,8 +487,11 @@
*outStream = stream;
/* StreamOutHalInterface* */ void* cbCookie = (*outStream).get();
{
- std::lock_guard l(mLock);
+ std::lock_guard l(mCallbacksLock);
mCallbacks.emplace(cbCookie, Callbacks{});
+ }
+ {
+ std::lock_guard l(mLock);
mMapper.addStream(*outStream, mixPortConfig.id, aidlPatch.id);
}
if (streamCb) {
@@ -1328,7 +1331,7 @@
}
void DeviceHalAidl::clearCallbacks(void* cookie) {
- std::lock_guard l(mLock);
+ std::lock_guard l(mCallbacksLock);
mCallbacks.erase(cookie);
}
@@ -1361,18 +1364,21 @@
setCallbackImpl(cookie, &Callbacks::latency, cb);
}
-template<class C>
+template <class C>
sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
- std::lock_guard l(mLock);
- if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
- return ((it->second).*field).promote();
+ wp<C> result;
+ {
+ std::lock_guard l(mCallbacksLock);
+ if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
+ result = (it->second).*field;
+ }
}
- return nullptr;
+ return result.promote();
}
template<class C>
void DeviceHalAidl::setCallbackImpl(
void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
- std::lock_guard l(mLock);
+ std::lock_guard l(mCallbacksLock);
if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
(it->second).*field = cb;
}