You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

305 lines
11 KiB

/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
aaudio: indicate client UID and PID to audio flinger Implement correct indication of client UID and PID to audio flinger for AAudio MMAP streams in both exclusive mode and shared mode. - Add start/stop client methods on MMAP streams used only when the MMAP stream is in AAudio service and carries a mix of shared streams. - Add "In Service'" indication from "client" side to AAudioServiceStreamMMAP so that the behavior can be adapted accordingly. - Modify logic on audio flinger side with regard to mmap tracks and audio HAL stream activity: - use same audio session for all clients on a same stream to match audio policy logic to share same direct output stream for clients on same session. This is also more consistent with current volume and effect handling as all MMAP clients sharing the same output stream have the same volume and use case. - start/stop the HAL when the stream is started/stopped with the initial client handle (returned when the stream is opened) but do not create a track. AAudioService implementation will always send an additional start command before first client starts and a stop command after last client stops, in both shared and exclusive mode. - start/stop a track only if the start/stop stream command is received with a handle different from the initial handle. - Allow more than one active client from the same UID on a MMAP input in audio policy. Bug: 62950008 Test: verify playback and capture in mmap mode Change-Id: I86151bbb637ff172d2fd5f813056eab13a7bcd3c
7 years ago
#define LOG_TAG "AAudioEndpointManager"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
#include <assert.h>
#include <functional>
#include <map>
#include <mutex>
#include <sstream>
#include <utility/AAudioUtilities.h>
#include "AAudioEndpointManager.h"
#include "AAudioServiceEndpointShared.h"
#include "AAudioServiceEndpointMMAP.h"
#include "AAudioServiceEndpointCapture.h"
#include "AAudioServiceEndpointPlay.h"
using namespace android;
using namespace aaudio;
ANDROID_SINGLETON_STATIC_INSTANCE(AAudioEndpointManager);
AAudioEndpointManager::AAudioEndpointManager()
: Singleton<AAudioEndpointManager>()
, mSharedStreams()
, mExclusiveStreams() {
}
std::string AAudioEndpointManager::dump() const {
std::stringstream result;
int index = 0;
result << "AAudioEndpointManager:" << "\n";
const bool isSharedLocked = AAudio_tryUntilTrue(
[this]()->bool { return mSharedLock.try_lock(); } /* f */,
50 /* times */,
20 /* sleepMs */);
if (!isSharedLocked) {
result << "AAudioEndpointManager Shared may be deadlocked\n";
}
{
const bool isExclusiveLocked = AAudio_tryUntilTrue(
[this]() -> bool { return mExclusiveLock.try_lock(); } /* f */,
50 /* times */,
20 /* sleepMs */);
if (!isExclusiveLocked) {
result << "AAudioEndpointManager Exclusive may be deadlocked\n";
}
result << "Exclusive MMAP Endpoints: " << mExclusiveStreams.size() << "\n";
index = 0;
for (const auto &stream : mExclusiveStreams) {
result << " #" << index++ << ":";
result << stream->dump() << "\n";
}
result << " ExclusiveSearchCount: " << mExclusiveSearchCount << "\n";
result << " ExclusiveFoundCount: " << mExclusiveFoundCount << "\n";
result << " ExclusiveOpenCount: " << mExclusiveOpenCount << "\n";
result << " ExclusiveCloseCount: " << mExclusiveCloseCount << "\n";
result << " ExclusiveStolenCount: " << mExclusiveStolenCount << "\n";
result << "\n";
if (isExclusiveLocked) {
mExclusiveLock.unlock();
}
}
result << "Shared Endpoints: " << mSharedStreams.size() << "\n";
index = 0;
for (const auto &stream : mSharedStreams) {
result << " #" << index++ << ":";
result << stream->dump() << "\n";
}
result << " SharedSearchCount: " << mSharedSearchCount << "\n";
result << " SharedFoundCount: " << mSharedFoundCount << "\n";
result << " SharedOpenCount: " << mSharedOpenCount << "\n";
result << " SharedCloseCount: " << mSharedCloseCount << "\n";
result << "\n";
if (isSharedLocked) {
mSharedLock.unlock();
}
return result.str();
}
// Try to find an existing endpoint.
sp<AAudioServiceEndpoint> AAudioEndpointManager::findExclusiveEndpoint_l(
const AAudioStreamConfiguration &configuration) {
sp<AAudioServiceEndpoint> endpoint;
mExclusiveSearchCount++;
for (const auto& ep : mExclusiveStreams) {
if (ep->matches(configuration)) {
mExclusiveFoundCount++;
endpoint = ep;
break;
}
}
ALOGV("findExclusiveEndpoint_l(), found %p for device = %d, sessionId = %d",
endpoint.get(), configuration.getDeviceId(), configuration.getSessionId());
return endpoint;
}
// Try to find an existing endpoint.
sp<AAudioServiceEndpointShared> AAudioEndpointManager::findSharedEndpoint_l(
const AAudioStreamConfiguration &configuration) {
sp<AAudioServiceEndpointShared> endpoint;
mSharedSearchCount++;
for (const auto& ep : mSharedStreams) {
if (ep->matches(configuration)) {
mSharedFoundCount++;
endpoint = ep;
break;
}
}
ALOGV("findSharedEndpoint_l(), found %p for device = %d, sessionId = %d",
endpoint.get(), configuration.getDeviceId(), configuration.getSessionId());
return endpoint;
}
sp<AAudioServiceEndpoint> AAudioEndpointManager::openEndpoint(AAudioService &audioService,
const aaudio::AAudioStreamRequest &request) {
if (request.getConstantConfiguration().getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
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);
}
}
sp<AAudioServiceEndpoint> AAudioEndpointManager::openExclusiveEndpoint(
AAudioService &aaudioService,
const aaudio::AAudioStreamRequest &request,
sp<AAudioServiceEndpoint> &endpointToSteal) {
std::lock_guard<std::mutex> lock(mExclusiveLock);
const AAudioStreamConfiguration &configuration = request.getConstantConfiguration();
// Try to find an existing endpoint.
sp<AAudioServiceEndpoint> endpoint = findExclusiveEndpoint_l(configuration);
// If we find an existing one then this one cannot be exclusive.
if (endpoint.get() != nullptr) {
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("%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) {
endpoint.clear();
} else {
mExclusiveStreams.push_back(endpointMMap);
mExclusiveOpenCount++;
}
}
if (endpoint.get() != nullptr) {
// Increment the reference count under this lock.
endpoint->setOpenCount(endpoint->getOpenCount() + 1);
endpoint->setForSharing(request.isSharingModeMatchRequired());
}
return endpoint;
}
sp<AAudioServiceEndpoint> AAudioEndpointManager::openSharedEndpoint(
AAudioService &aaudioService,
const aaudio::AAudioStreamRequest &request) {
std::lock_guard<std::mutex> lock(mSharedLock);
const AAudioStreamConfiguration &configuration = request.getConstantConfiguration();
aaudio_direction_t direction = configuration.getDirection();
// Try to find an existing endpoint.
sp<AAudioServiceEndpointShared> endpoint = findSharedEndpoint_l(configuration);
// If we can't find an existing one then open a new one.
if (endpoint.get() == nullptr) {
aaudio: indicate client UID and PID to audio flinger Implement correct indication of client UID and PID to audio flinger for AAudio MMAP streams in both exclusive mode and shared mode. - Add start/stop client methods on MMAP streams used only when the MMAP stream is in AAudio service and carries a mix of shared streams. - Add "In Service'" indication from "client" side to AAudioServiceStreamMMAP so that the behavior can be adapted accordingly. - Modify logic on audio flinger side with regard to mmap tracks and audio HAL stream activity: - use same audio session for all clients on a same stream to match audio policy logic to share same direct output stream for clients on same session. This is also more consistent with current volume and effect handling as all MMAP clients sharing the same output stream have the same volume and use case. - start/stop the HAL when the stream is started/stopped with the initial client handle (returned when the stream is opened) but do not create a track. AAudioService implementation will always send an additional start command before first client starts and a stop command after last client stops, in both shared and exclusive mode. - start/stop a track only if the start/stop stream command is received with a handle different from the initial handle. - Allow more than one active client from the same UID on a MMAP input in audio policy. Bug: 62950008 Test: verify playback and capture in mmap mode Change-Id: I86151bbb637ff172d2fd5f813056eab13a7bcd3c
7 years ago
// we must call openStream with audioserver identity
int64_t token = IPCThreadState::self()->clearCallingIdentity();
switch (direction) {
case AAUDIO_DIRECTION_INPUT:
endpoint = new AAudioServiceEndpointCapture(aaudioService);
break;
case AAUDIO_DIRECTION_OUTPUT:
endpoint = new AAudioServiceEndpointPlay(aaudioService);
break;
default:
break;
}
if (endpoint.get() != nullptr) {
aaudio_result_t result = endpoint->open(request);
if (result != AAUDIO_OK) {
endpoint.clear();
} else {
mSharedStreams.push_back(endpoint);
mSharedOpenCount++;
}
}
ALOGV("%s(), created endpoint %p, requested device = %d, dir = %d",
__func__, endpoint.get(), configuration.getDeviceId(), (int)direction);
aaudio: indicate client UID and PID to audio flinger Implement correct indication of client UID and PID to audio flinger for AAudio MMAP streams in both exclusive mode and shared mode. - Add start/stop client methods on MMAP streams used only when the MMAP stream is in AAudio service and carries a mix of shared streams. - Add "In Service'" indication from "client" side to AAudioServiceStreamMMAP so that the behavior can be adapted accordingly. - Modify logic on audio flinger side with regard to mmap tracks and audio HAL stream activity: - use same audio session for all clients on a same stream to match audio policy logic to share same direct output stream for clients on same session. This is also more consistent with current volume and effect handling as all MMAP clients sharing the same output stream have the same volume and use case. - start/stop the HAL when the stream is started/stopped with the initial client handle (returned when the stream is opened) but do not create a track. AAudioService implementation will always send an additional start command before first client starts and a stop command after last client stops, in both shared and exclusive mode. - start/stop a track only if the start/stop stream command is received with a handle different from the initial handle. - Allow more than one active client from the same UID on a MMAP input in audio policy. Bug: 62950008 Test: verify playback and capture in mmap mode Change-Id: I86151bbb637ff172d2fd5f813056eab13a7bcd3c
7 years ago
IPCThreadState::self()->restoreCallingIdentity(token);
}
if (endpoint.get() != nullptr) {
// Increment the reference count under this lock.
endpoint->setOpenCount(endpoint->getOpenCount() + 1);
}
return endpoint;
}
void AAudioEndpointManager::closeEndpoint(sp<AAudioServiceEndpoint>serviceEndpoint) {
if (serviceEndpoint->getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
return closeExclusiveEndpoint(serviceEndpoint);
} else {
return closeSharedEndpoint(serviceEndpoint);
}
}
void AAudioEndpointManager::closeExclusiveEndpoint(sp<AAudioServiceEndpoint> serviceEndpoint) {
if (serviceEndpoint.get() == nullptr) {
return;
}
// Decrement the reference count under this lock.
std::lock_guard<std::mutex> lock(mExclusiveLock);
int32_t newRefCount = serviceEndpoint->getOpenCount() - 1;
serviceEndpoint->setOpenCount(newRefCount);
// If no longer in use then actually close it.
if (newRefCount <= 0) {
mExclusiveStreams.erase(
std::remove(mExclusiveStreams.begin(), mExclusiveStreams.end(), serviceEndpoint),
mExclusiveStreams.end());
serviceEndpoint->close();
mExclusiveCloseCount++;
ALOGV("%s() %p for device %d",
__func__, serviceEndpoint.get(), serviceEndpoint->getDeviceId());
}
}
void AAudioEndpointManager::closeSharedEndpoint(sp<AAudioServiceEndpoint> serviceEndpoint) {
if (serviceEndpoint.get() == nullptr) {
return;
}
// Decrement the reference count under this lock.
std::lock_guard<std::mutex> lock(mSharedLock);
int32_t newRefCount = serviceEndpoint->getOpenCount() - 1;
serviceEndpoint->setOpenCount(newRefCount);
// If no longer in use then actually close it.
if (newRefCount <= 0) {
mSharedStreams.erase(
std::remove(mSharedStreams.begin(), mSharedStreams.end(), serviceEndpoint),
mSharedStreams.end());
serviceEndpoint->close();
mSharedCloseCount++;
ALOGV("%s(%p) closed for device %d",
__func__, serviceEndpoint.get(), serviceEndpoint->getDeviceId());
}
}