libaudiohal@aidl: Synchronize commands sending
Although FMQs implement thread-safe blocking reads and
writes, using two queues (one for sending a command,
another for receiving a reply) is not an atomic operation
by itself. Add synchronization for this pair of operations
so that they work as intended.
Bug: 333116473
Test: play notification sounds in parallel with music
Change-Id: Ia29c6c4698499acc600f9b6fe02befddd5de5326
diff --git a/media/libaudiohal/impl/StreamHalAidl.h b/media/libaudiohal/impl/StreamHalAidl.h
index 53d46e5..b20eb00 100644
--- a/media/libaudiohal/impl/StreamHalAidl.h
+++ b/media/libaudiohal/impl/StreamHalAidl.h
@@ -243,6 +243,15 @@
const bool mIsInput;
const audio_config_base_t mConfig;
const StreamContextAidl mContext;
+ // This lock is used to make sending of a command and receiving a reply an atomic
+ // operation. Otherwise, when two threads are trying to send a command, they may both advance to
+ // reading of the reply once the HAL has consumed the command from the MQ, and that creates a
+ // race condition between them.
+ //
+ // Note that only access to command and reply MQs needs to be protected because the data MQ is
+ // only accessed by the I/O thread. Also, there is no need to protect lookup operations on the
+ // queues as they are thread-safe, only send/receive operation must be protected.
+ std::mutex mCommandReplyLock;
private:
static audio_config_base_t configToBase(const audio_config& config) {
@@ -256,6 +265,8 @@
std::lock_guard l(mLock);
return mLastReply.state;
}
+ // Note: Since `sendCommand` takes mLock while holding mCommandReplyLock, never call
+ // it with `mLock` being held.
status_t sendCommand(
const ::aidl::android::hardware::audio::core::StreamDescriptor::Command &command,
::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply = nullptr,