aaudio: steal exclusive streams
An app (B) that asks for an exclusive stream can steal
an exclusive stream from an earlier app (A).
App B will be given the MMAP resource as a SHARED stream.
The stream for app A will be disconnected and released
by the service.
If app A reopens a stream then it will get a SHARED
stream.
The order of the opening of the streams is controlled by using a
recursive_mutex in AAudioService::openStream().
Bug: 129846760
Test: media/libaaudio/tests/test_steal_exclusive.cpp
Test: also
Test: Launch AudioTroubleMaker. It should say "EXCLUSIVE".
Test: Press Home button.
Test: Siren sound from AudioTroubleMaker should continue.
Test: Launch OboeTester
Test: TEST OUTPUT, then Open, Start
Test: You should get an MMAP SHARED stream on Pixel.
Test: Go back to AudioTroubleMaker. It should say "SHARED".
Change-Id: I7f8339d8ed62546520a9b46ed398418b41ca2832
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index 82cc90e..c9bf72f 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -76,6 +76,7 @@
result << " ExclusiveFoundCount: " << mExclusiveFoundCount << "\n";
result << " ExclusiveOpenCount: " << mExclusiveOpenCount << "\n";
result << " ExclusiveCloseCount: " << mExclusiveCloseCount << "\n";
+ result << " ExclusiveStolenCount: " << mExclusiveStolenCount << "\n";
result << "\n";
if (isExclusiveLocked) {
@@ -142,7 +143,13 @@
sp<AAudioServiceEndpoint> AAudioEndpointManager::openEndpoint(AAudioService &audioService,
const aaudio::AAudioStreamRequest &request) {
if (request.getConstantConfiguration().getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
- return openExclusiveEndpoint(audioService, request);
+ sp<AAudioServiceEndpoint> endpointToSteal;
+ sp<AAudioServiceEndpoint> foundEndpoint =
+ openExclusiveEndpoint(audioService, request, endpointToSteal);
+ if (endpointToSteal.get()) {
+ endpointToSteal->releaseRegisteredStreams(); // free the MMAP resource
+ }
+ return foundEndpoint;
} else {
return openSharedEndpoint(audioService, request);
}
@@ -150,7 +157,8 @@
sp<AAudioServiceEndpoint> AAudioEndpointManager::openExclusiveEndpoint(
AAudioService &aaudioService,
- const aaudio::AAudioStreamRequest &request) {
+ const aaudio::AAudioStreamRequest &request,
+ sp<AAudioServiceEndpoint> &endpointToSteal) {
std::lock_guard<std::mutex> lock(mExclusiveLock);
@@ -161,18 +169,22 @@
// If we find an existing one then this one cannot be exclusive.
if (endpoint.get() != nullptr) {
- ALOGW("openExclusiveEndpoint() already in use");
- // Already open so do not allow a second stream.
+ if (kStealingEnabled
+ && !endpoint->isForSharing() // not currently SHARED
+ && !request.isSharingModeMatchRequired()) { // app did not request a shared stream
+ ALOGD("%s() endpoint in EXCLUSIVE use. Steal it!", __func__);
+ mExclusiveStolenCount++;
+ endpointToSteal = endpoint;
+ }
return nullptr;
} else {
sp<AAudioServiceEndpointMMAP> endpointMMap = new AAudioServiceEndpointMMAP(aaudioService);
- ALOGV("openExclusiveEndpoint(), no match so try to open MMAP %p for dev %d",
- endpointMMap.get(), configuration.getDeviceId());
+ ALOGV("%s(), no match so try to open MMAP %p for dev %d",
+ __func__, endpointMMap.get(), configuration.getDeviceId());
endpoint = endpointMMap;
aaudio_result_t result = endpoint->open(request);
if (result != AAUDIO_OK) {
- ALOGV("openExclusiveEndpoint(), open failed");
endpoint.clear();
} else {
mExclusiveStreams.push_back(endpointMMap);
@@ -183,7 +195,9 @@
if (endpoint.get() != nullptr) {
// Increment the reference count under this lock.
endpoint->setOpenCount(endpoint->getOpenCount() + 1);
+ endpoint->setForSharing(request.isSharingModeMatchRequired());
}
+
return endpoint;
}