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/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);