AudioPolicyManager: abort when client is removed while active
This can result in a refcount mismatch. It is safer to
abort immediately.
Test: Audio sanity, phone call
Bug: 112067674
Change-Id: I7835e75342b4c1aa3d6d910ee782d3bc818bd553
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 4543dd0..6fa0b81 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -910,7 +910,7 @@
getStrategyForAttr(&attributes),
*flags);
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(*output);
- outputDesc->clientsMap().emplace(*portId, clientDesc);
+ outputDesc->addClient(clientDesc);
ALOGV(" getOutputForAttr() returns output %d selectedDeviceId %d for port ID %d",
*output, *selectedDeviceId, *portId);
@@ -1320,7 +1320,7 @@
ALOGW("startOutput() no output for client %d", portId);
return BAD_VALUE;
}
- sp<TrackClientDescriptor> client = outputDesc->clientsMap()[portId];
+ sp<TrackClientDescriptor> client = outputDesc->getClient(portId);
ALOGV("startOutput() output %d, stream %d, session %d",
outputDesc->mIoHandle, client->stream(), client->session());
@@ -1513,7 +1513,7 @@
ALOGW("stopOutput() no output for client %d", portId);
return BAD_VALUE;
}
- sp<TrackClientDescriptor> client = outputDesc->clientsMap()[portId];
+ sp<TrackClientDescriptor> client = outputDesc->getClient(portId);
ALOGV("stopOutput() output %d, stream %d, session %d",
outputDesc->mIoHandle, client->stream(), client->session());
@@ -1614,10 +1614,15 @@
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.getOutputForClient(portId);
if (outputDesc == 0) {
+ // If an output descriptor is closed due to a device routing change,
+ // then there are race conditions with releaseOutput from tracks
+ // that may be destroyed (with no PlaybackThread) or a PlaybackThread
+ // destroyed shortly thereafter.
+ //
+ // Here we just log a warning, instead of a fatal error.
ALOGW("releaseOutput() no output for client %d", portId);
return;
}
- sp<TrackClientDescriptor> client = outputDesc->clientsMap()[portId];
ALOGV("releaseOutput() %d", outputDesc->mIoHandle);
@@ -1632,10 +1637,12 @@
mpClientInterface->onAudioPortListUpdate();
}
}
- outputDesc->clientsMap().erase(portId);
+ // stopOutput() needs to be successfully called before releaseOutput()
+ // otherwise there may be inaccurate stream reference counts.
+ // This is checked in outputDesc->removeClient below.
+ outputDesc->removeClient(portId);
}
-
status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *input,
audio_session_t session,
@@ -1793,7 +1800,7 @@
*attr, *config, requestedDeviceId,
inputSource,flags, isSoundTrigger);
inputDesc = mInputs.valueFor(*input);
- inputDesc->clientsMap().emplace(*portId, clientDesc);
+ inputDesc->addClient(clientDesc);
ALOGV("getInputForAttr() returns input %d type %d selectedDeviceId %d for port ID %d",
*input, *inputType, *selectedDeviceId, *portId);
@@ -1968,7 +1975,7 @@
return BAD_VALUE;
}
audio_io_handle_t input = inputDesc->mIoHandle;
- sp<RecordClientDescriptor> client = inputDesc->clientsMap()[portId];
+ sp<RecordClientDescriptor> client = inputDesc->getClient(portId);
if (client->active()) {
ALOGW("%s input %d client %d already started", __FUNCTION__, input, client->portId());
return INVALID_OPERATION;
@@ -2137,7 +2144,7 @@
return BAD_VALUE;
}
audio_io_handle_t input = inputDesc->mIoHandle;
- sp<RecordClientDescriptor> client = inputDesc->clientsMap()[portId];
+ sp<RecordClientDescriptor> client = inputDesc->getClient(portId);
if (!client->active()) {
ALOGW("%s input %d client %d already stopped", __FUNCTION__, input, client->portId());
return INVALID_OPERATION;
@@ -2196,15 +2203,15 @@
ALOGW("%s no input for client %d", __FUNCTION__, portId);
return;
}
- sp<RecordClientDescriptor> client = inputDesc->clientsMap()[portId];
+ sp<RecordClientDescriptor> client = inputDesc->getClient(portId);
audio_io_handle_t input = inputDesc->mIoHandle;
ALOGV("%s %d", __FUNCTION__, input);
- inputDesc->clientsMap().erase(portId);
+ inputDesc->removeClient(portId);
- if (inputDesc->clientsMap().size() > 0) {
- ALOGV("%s %zu clients remaining", __FUNCTION__, inputDesc->clientsMap().size());
+ if (inputDesc->getClientCount() > 0) {
+ ALOGV("%s(%d) %zu clients remaining", __func__, portId, inputDesc->getClientCount());
return;
}
@@ -3311,11 +3318,10 @@
SortedVector<routing_strategy> affectedStrategies;
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(i);
- TrackClientMap clients = outputDesc->clientsMap();
- for (const auto& client : clients) {
- if (client.second->hasPreferredDevice() && client.second->uid() == uid) {
- client.second->setPreferredDeviceId(AUDIO_PORT_HANDLE_NONE);
- affectedStrategies.add(getStrategy(client.second->stream()));
+ for (const auto& client : outputDesc->getClientIterable()) {
+ if (client->hasPreferredDevice() && client->uid() == uid) {
+ client->setPreferredDeviceId(AUDIO_PORT_HANDLE_NONE);
+ affectedStrategies.add(getStrategy(client->stream()));
}
}
}
@@ -3328,11 +3334,10 @@
SortedVector<audio_source_t> affectedSources;
for (size_t i = 0; i < mInputs.size(); i++) {
sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(i);
- RecordClientMap clients = inputDesc->clientsMap();
- for (const auto& client : clients) {
- if (client.second->hasPreferredDevice() && client.second->uid() == uid) {
- client.second->setPreferredDeviceId(AUDIO_PORT_HANDLE_NONE);
- affectedSources.add(client.second->source());
+ for (const auto& client : inputDesc->getClientIterable()) {
+ if (client->hasPreferredDevice() && client->uid() == uid) {
+ client->setPreferredDeviceId(AUDIO_PORT_HANDLE_NONE);
+ affectedSources.add(client->source());
}
}
}