aaudio: limit number of streams per process
Testing the new max streams restriction revealed the bug
involving the second shared stream.
Bug: 62951298
Bug: 63171495
Test: test_n_streams.cpp can open MAX_STREAMS_PER_PROCESS MMAP streams
Change-Id: Ibea7d9c4716326a37c669954b52f397ed2968caa
diff --git a/media/libaaudio/tests/Android.mk b/media/libaaudio/tests/Android.mk
index bd7169f..e4eef06 100644
--- a/media/libaaudio/tests/Android.mk
+++ b/media/libaaudio/tests/Android.mk
@@ -69,3 +69,13 @@
LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
LOCAL_MODULE := test_aaudio_recovery
include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := \
+ $(call include-path-for, audio-utils) \
+ frameworks/av/media/libaaudio/include \
+ frameworks/av/media/libaaudio/src
+LOCAL_SRC_FILES:= test_n_streams.cpp
+LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
+LOCAL_MODULE := test_n_streams
+include $(BUILD_NATIVE_TEST)
diff --git a/media/libaaudio/tests/test_n_streams.cpp b/media/libaaudio/tests/test_n_streams.cpp
new file mode 100644
index 0000000..bf4b64e
--- /dev/null
+++ b/media/libaaudio/tests/test_n_streams.cpp
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+// Try to create as many streams as possible and report the maximum.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <aaudio/AAudio.h>
+#include <aaudio/AAudioTesting.h>
+
+//#define MMAP_POLICY AAUDIO_UNSPECIFIED
+//#define MMAP_POLICY AAUDIO_POLICY_NEVER
+#define MMAP_POLICY AAUDIO_POLICY_AUTO
+//#define MMAP_POLICY AAUDIO_POLICY_ALWAYS
+
+#define MAX_STREAMS 100
+
+int main(int argc, char **argv)
+{
+ (void)argc; // unused
+ (void)argv; // unused
+
+ aaudio_result_t result = AAUDIO_OK;
+ AAudioStreamBuilder *aaudioBuilder = nullptr;
+ AAudioStream *aaudioStream[MAX_STREAMS];
+ int32_t numStreams = 0;
+
+ // Make printf print immediately so that debug info is not stuck
+ // in a buffer if we hang or crash.
+ setvbuf(stdout, NULL, _IONBF, (size_t) 0);
+
+ printf("Try to open a maximum of %d streams.\n", MAX_STREAMS);
+
+ AAudio_setMMapPolicy(MMAP_POLICY);
+ printf("requested MMapPolicy = %d\n", AAudio_getMMapPolicy());
+
+ result = AAudio_createStreamBuilder(&aaudioBuilder);
+ if (result != AAUDIO_OK) {
+ return 1;
+ }
+
+ for (int i = 0; i < MAX_STREAMS; i++) {
+ // Create an AAudioStream using the Builder.
+ result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream[i]);
+ if (result != AAUDIO_OK) {
+ printf("ERROR could not open AAudio stream, %d %s\n",
+ result, AAudio_convertResultToText(result));
+ break;
+ } else {
+ printf("AAudio stream[%2d] opened successfully. MMAP = %s\n",
+ i, AAudioStream_isMMapUsed(aaudioStream[i]) ? "YES" : "NO");
+ numStreams++;
+ }
+ }
+
+ printf("Created %d streams!\n", numStreams);
+
+ // Close all the streams.
+ for (int i = 0; i < numStreams; i++) {
+ result = AAudioStream_close(aaudioStream[i]);
+ if (result != AAUDIO_OK) {
+ printf("ERROR could not close AAudio stream, %d %s\n",
+ result, AAudio_convertResultToText(result));
+ break;
+ } else {
+ printf("AAudio stream[%2d] closed successfully.\n", i);
+ }
+ }
+
+ AAudioStreamBuilder_delete(aaudioBuilder);
+
+finish:
+ return (result != AAUDIO_OK) ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
diff --git a/services/oboeservice/AAudioClientTracker.cpp b/services/oboeservice/AAudioClientTracker.cpp
index da7b80f..c0dfc54 100644
--- a/services/oboeservice/AAudioClientTracker.cpp
+++ b/services/oboeservice/AAudioClientTracker.cpp
@@ -68,6 +68,16 @@
mNotificationClients.erase(pid);
}
+int32_t AAudioClientTracker::getStreamCount(pid_t pid) {
+ std::lock_guard<std::mutex> lock(mLock);
+ auto it = mNotificationClients.find(pid);
+ if (it != mNotificationClients.end()) {
+ return it->second->getStreamCount();
+ } else {
+ return 0; // no existing client
+ }
+}
+
aaudio_result_t
AAudioClientTracker::registerClientStream(pid_t pid, sp<AAudioServiceStreamBase> serviceStream) {
aaudio_result_t result = AAUDIO_OK;
@@ -90,8 +100,7 @@
sp<AAudioServiceStreamBase> serviceStream) {
ALOGV("AAudioClientTracker::unregisterClientStream(%d, %p)\n", pid, serviceStream.get());
std::lock_guard<std::mutex> lock(mLock);
- std::map<pid_t, android::sp<NotificationClient>>::iterator it;
- it = mNotificationClients.find(pid);
+ auto it = mNotificationClients.find(pid);
if (it != mNotificationClients.end()) {
it->second->unregisterClientStream(serviceStream);
}
@@ -107,6 +116,11 @@
//ALOGD("AAudioClientTracker::~NotificationClient() destroyed %p\n", this);
}
+int32_t AAudioClientTracker::NotificationClient::getStreamCount() {
+ std::lock_guard<std::mutex> lock(mLock);
+ return mStreams.size();
+}
+
aaudio_result_t AAudioClientTracker::NotificationClient::registerClientStream(
sp<AAudioServiceStreamBase> serviceStream) {
std::lock_guard<std::mutex> lock(mLock);
diff --git a/services/oboeservice/AAudioClientTracker.h b/services/oboeservice/AAudioClientTracker.h
index 447665b..e74c8bf 100644
--- a/services/oboeservice/AAudioClientTracker.h
+++ b/services/oboeservice/AAudioClientTracker.h
@@ -38,6 +38,8 @@
void unregisterClient(pid_t pid);
+ int32_t getStreamCount(pid_t pid);
+
aaudio_result_t registerClientStream(pid_t pid,
android::sp<AAudioServiceStreamBase> serviceStream);
@@ -53,11 +55,17 @@
}
private:
+
+ /**
+ * One per process.
+ */
class NotificationClient : public IBinder::DeathRecipient {
public:
NotificationClient(pid_t pid);
virtual ~NotificationClient();
+ int32_t getStreamCount();
+
aaudio_result_t registerClientStream(android::sp<AAudioServiceStreamBase> serviceStream);
aaudio_result_t unregisterClientStream(android::sp<AAudioServiceStreamBase> serviceStream);
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index d8b9101..36e678a 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -115,24 +115,24 @@
default:
break;
}
- }
- if (endpoint != nullptr) {
- aaudio_result_t result = endpoint->open(configuration);
- if (result != AAUDIO_OK) {
- ALOGE("AAudioEndpointManager::findEndpoint(), open failed");
- delete endpoint;
- endpoint = nullptr;
- } else {
- switch(direction) {
- case AAUDIO_DIRECTION_INPUT:
- mInputs.push_back(capture);
- break;
- case AAUDIO_DIRECTION_OUTPUT:
- mOutputs.push_back(player);
- break;
- default:
- break;
+ if (endpoint != nullptr) {
+ aaudio_result_t result = endpoint->open(configuration);
+ if (result != AAUDIO_OK) {
+ ALOGE("AAudioEndpointManager::findEndpoint(), open failed");
+ delete endpoint;
+ endpoint = nullptr;
+ } else {
+ switch(direction) {
+ case AAUDIO_DIRECTION_INPUT:
+ mInputs.push_back(capture);
+ break;
+ case AAUDIO_DIRECTION_OUTPUT:
+ mOutputs.push_back(player);
+ break;
+ default:
+ break;
+ }
}
}
ALOGD("AAudioEndpointManager::openEndpoint(), created %p for device = %d, dir = %d",
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 585341a..91f7885 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -40,6 +40,8 @@
using namespace android;
using namespace aaudio;
+#define MAX_STREAMS_PER_PROCESS 8
+
typedef enum
{
AAUDIO_HANDLE_TYPE_STREAM
@@ -86,6 +88,17 @@
bool sharingModeMatchRequired = request.isSharingModeMatchRequired();
aaudio_sharing_mode_t sharingMode = configurationInput.getSharingMode();
+ // Enforce limit on client processes.
+ pid_t pid = request.getProcessId();
+ if (pid != mCachedProcessId) {
+ int32_t count = AAudioClientTracker::getInstance().getStreamCount(pid);
+ if (count >= MAX_STREAMS_PER_PROCESS) {
+ ALOGE("AAudioService::openStream(): exceeded max streams per process %d >= %d",
+ count, MAX_STREAMS_PER_PROCESS);
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+ }
+
if (sharingMode != AAUDIO_SHARING_MODE_EXCLUSIVE && sharingMode != AAUDIO_SHARING_MODE_SHARED) {
ALOGE("AAudioService::openStream(): unrecognized sharing mode = %d", sharingMode);
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
@@ -135,7 +148,14 @@
}
aaudio_result_t AAudioService::closeStream(aaudio_handle_t streamHandle) {
- AAudioServiceStreamBase *serviceStream = (AAudioServiceStreamBase *)
+ // Check permission first.
+ AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
+ if (serviceStream == nullptr) {
+ ALOGE("AAudioService::startStream(), illegal stream handle = 0x%0x", streamHandle);
+ return AAUDIO_ERROR_INVALID_HANDLE;
+ }
+
+ serviceStream = (AAudioServiceStreamBase *)
mHandleTracker.remove(AAUDIO_HANDLE_TYPE_STREAM,
streamHandle);
ALOGD("AAudioService.closeStream(0x%08X)", streamHandle);