aaudio: close MMAP stream if client dies

Notify client when audio service dies. Clear connection.
Notify AAudio service when client dies. Close client streams.

Use sp<> to track ServiceStreams.

Bug: 38267698
Test: test_no_close.cpp
Change-Id: I5f1699ed3b8b7bd960947c0028a89ca8419ce7a0
diff --git a/services/oboeservice/AAudioClientTracker.cpp b/services/oboeservice/AAudioClientTracker.cpp
new file mode 100644
index 0000000..da7b80f
--- /dev/null
+++ b/services/oboeservice/AAudioClientTracker.cpp
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ */
+
+
+#define LOG_TAG "AAudioService"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <assert.h>
+#include <binder/IPCThreadState.h>
+#include <map>
+#include <mutex>
+#include <utils/Singleton.h>
+
+#include "utility/AAudioUtilities.h"
+#include "AAudioEndpointManager.h"
+#include "AAudioServiceEndpoint.h"
+#include "AAudioClientTracker.h"
+
+using namespace android;
+using namespace aaudio;
+
+ANDROID_SINGLETON_STATIC_INSTANCE(AAudioClientTracker);
+
+AAudioClientTracker::AAudioClientTracker()
+        : Singleton<AAudioClientTracker>() {
+}
+
+// Create a tracker for the client.
+aaudio_result_t AAudioClientTracker::registerClient(pid_t pid,
+                                         const sp<IAAudioClient>& client) {
+    ALOGD("AAudioClientTracker::registerClient(), calling pid = %d, getpid() = %d\n",
+          pid, getpid());
+
+    std::lock_guard<std::mutex> lock(mLock);
+    if (mNotificationClients.count(pid) == 0) {
+        sp<NotificationClient> notificationClient = new NotificationClient(pid);
+        mNotificationClients[pid] = notificationClient;
+
+        sp<IBinder> binder = IInterface::asBinder(client);
+        status_t status = binder->linkToDeath(notificationClient);
+        ALOGW_IF(status != NO_ERROR,
+                 "AAudioClientTracker::registerClient() linkToDeath = %d\n", status);
+        return AAudioConvert_androidToAAudioResult(status);
+    } else {
+        ALOGW("AAudioClientTracker::registerClient(%d) already registered!", pid);
+        return AAUDIO_OK; // TODO should this be considered an error
+    }
+}
+
+void AAudioClientTracker::unregisterClient(pid_t pid) {
+    ALOGD("AAudioClientTracker::unregisterClient(), calling pid = %d, getpid() = %d\n",
+          pid, getpid());
+    std::lock_guard<std::mutex> lock(mLock);
+    mNotificationClients.erase(pid);
+}
+
+aaudio_result_t
+AAudioClientTracker::registerClientStream(pid_t pid, sp<AAudioServiceStreamBase> serviceStream) {
+    aaudio_result_t result = AAUDIO_OK;
+    ALOGV("AAudioClientTracker::registerClientStream(%d, %p)\n", pid, serviceStream.get());
+    std::lock_guard<std::mutex> lock(mLock);
+    sp<NotificationClient> notificationClient = mNotificationClients[pid];
+    if (notificationClient == 0) {
+        // This will get called the first time the audio server registers an internal stream.
+        ALOGV("AAudioClientTracker::registerClientStream(%d,) unrecognized pid\n", pid);
+        notificationClient = new NotificationClient(pid);
+        mNotificationClients[pid] = notificationClient;
+    }
+    notificationClient->registerClientStream(serviceStream);
+    return result;
+}
+
+// Find the tracker for this process and remove it.
+aaudio_result_t
+AAudioClientTracker::unregisterClientStream(pid_t pid,
+                                            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);
+    if (it != mNotificationClients.end()) {
+        it->second->unregisterClientStream(serviceStream);
+    }
+    return AAUDIO_OK;
+}
+
+AAudioClientTracker::NotificationClient::NotificationClient(pid_t pid)
+        : mProcessId(pid) {
+    //ALOGD("AAudioClientTracker::NotificationClient(%d) created %p\n", pid, this);
+}
+
+AAudioClientTracker::NotificationClient::~NotificationClient() {
+    //ALOGD("AAudioClientTracker::~NotificationClient() destroyed %p\n", this);
+}
+
+aaudio_result_t AAudioClientTracker::NotificationClient::registerClientStream(
+        sp<AAudioServiceStreamBase> serviceStream) {
+    std::lock_guard<std::mutex> lock(mLock);
+    mStreams.insert(serviceStream);
+    return AAUDIO_OK;
+}
+
+aaudio_result_t AAudioClientTracker::NotificationClient::unregisterClientStream(
+        sp<AAudioServiceStreamBase> serviceStream) {
+    std::lock_guard<std::mutex> lock(mLock);
+    mStreams.erase(serviceStream);
+    return AAUDIO_OK;
+}
+
+// Close any open streams for the client.
+void AAudioClientTracker::NotificationClient::binderDied(const wp<IBinder>& who __unused) {
+    AAudioService *aaudioService = AAudioClientTracker::getInstance().getAAudioService();
+    if (aaudioService != nullptr) {
+        // Copy the current list of streams to another vector because closing them below
+        // will cause unregisterClientStream() calls back to this object.
+        std::set<android::sp<AAudioServiceStreamBase>>  streamsToClose;
+
+        {
+            std::lock_guard<std::mutex> lock(mLock);
+            ALOGV("AAudioClientTracker::binderDied() pid = %d, # streams = %d\n",
+                  mProcessId, (int) mStreams.size());
+            for (auto serviceStream : mStreams) {
+                streamsToClose.insert(serviceStream);
+            }
+        }
+
+        for (auto serviceStream : streamsToClose) {
+            aaudio_handle_t handle = serviceStream->getHandle();
+            ALOGW("AAudioClientTracker::binderDied() close abandoned stream 0x%08X\n", handle);
+            aaudioService->closeStream(handle);
+        }
+        // mStreams should be empty now
+    }
+    sp<NotificationClient> keep(this);
+    AAudioClientTracker::getInstance().unregisterClient(mProcessId);
+}
diff --git a/services/oboeservice/AAudioClientTracker.h b/services/oboeservice/AAudioClientTracker.h
new file mode 100644
index 0000000..447665b
--- /dev/null
+++ b/services/oboeservice/AAudioClientTracker.h
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_AAUDIO_AAUDIO_CLIENT_TRACKER_H
+#define ANDROID_AAUDIO_AAUDIO_CLIENT_TRACKER_H
+
+#include <map>
+#include <mutex>
+#include <set>
+
+#include <utils/Singleton.h>
+
+#include <aaudio/AAudio.h>
+#include "binding/IAAudioClient.h"
+#include "AAudioService.h"
+
+namespace aaudio {
+
+class AAudioClientTracker : public android::Singleton<AAudioClientTracker>{
+public:
+    AAudioClientTracker();
+    ~AAudioClientTracker() = default;
+
+    aaudio_result_t registerClient(pid_t pid, const android::sp<android::IAAudioClient>& client);
+
+    void unregisterClient(pid_t pid);
+
+    aaudio_result_t registerClientStream(pid_t pid,
+                                         android::sp<AAudioServiceStreamBase> serviceStream);
+
+    aaudio_result_t unregisterClientStream(pid_t pid,
+                                           android::sp<AAudioServiceStreamBase> serviceStream);
+
+    android::AAudioService *getAAudioService() const {
+        return mAAudioService;
+    }
+
+    void setAAudioService(android::AAudioService *aaudioService) {
+        mAAudioService = aaudioService;
+    }
+
+private:
+    class NotificationClient : public IBinder::DeathRecipient {
+    public:
+        NotificationClient(pid_t pid);
+        virtual ~NotificationClient();
+
+        aaudio_result_t registerClientStream(android::sp<AAudioServiceStreamBase> serviceStream);
+
+        aaudio_result_t unregisterClientStream(android::sp<AAudioServiceStreamBase> serviceStream);
+
+        // IBinder::DeathRecipient
+        virtual     void    binderDied(const android::wp<IBinder>& who);
+
+    protected:
+        std::mutex                                      mLock;
+        const pid_t                                     mProcessId;
+        std::set<android::sp<AAudioServiceStreamBase>>  mStreams;
+    };
+
+    std::mutex                                       mLock;
+    std::map<pid_t, android::sp<NotificationClient>> mNotificationClients;
+    android::AAudioService                          *mAAudioService = nullptr;
+};
+
+} /* namespace aaudio */
+
+#endif //ANDROID_AAUDIO_AAUDIO_CLIENT_TRACKER_H
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index 5f6d599..94577a6 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -69,6 +69,8 @@
 AAudioServiceEndpoint *AAudioEndpointManager::openEndpoint(AAudioService &audioService, int32_t deviceId,
                                                            aaudio_direction_t direction) {
     AAudioServiceEndpoint *endpoint = nullptr;
+    AAudioServiceEndpointCapture *capture = nullptr;
+    AAudioServiceEndpointPlay *player = nullptr;
     std::lock_guard<std::mutex> lock(mLock);
 
     // Try to find an existing endpoint.
@@ -83,30 +85,41 @@
             assert(false); // There are only two possible directions.
             break;
     }
+    ALOGD("AAudioEndpointManager::openEndpoint(), found %p for device = %d, dir = %d",
+          endpoint, deviceId, (int)direction);
 
     // If we can't find an existing one then open a new one.
-    if (endpoint != nullptr) {
-        ALOGD("AAudioEndpointManager::openEndpoint(), found %p for device = %d, dir = %d",
-              endpoint, deviceId, (int)direction);
-
-    } else {
-        if (direction == AAUDIO_DIRECTION_INPUT) {
-            AAudioServiceEndpointCapture *capture = new AAudioServiceEndpointCapture(audioService);
-            if (capture->open(deviceId) != AAUDIO_OK) {
-                ALOGE("AAudioEndpointManager::openEndpoint(), open input failed");
-                delete capture;
-            } else {
-                mInputs[deviceId] = capture;
+    if (endpoint == nullptr) {
+        switch(direction) {
+            case AAUDIO_DIRECTION_INPUT:
+                capture = new AAudioServiceEndpointCapture(audioService);
                 endpoint = capture;
-            }
-        } else if (direction == AAUDIO_DIRECTION_OUTPUT) {
-            AAudioServiceEndpointPlay *player = new AAudioServiceEndpointPlay(audioService);
-            if (player->open(deviceId) != AAUDIO_OK) {
-                ALOGE("AAudioEndpointManager::openEndpoint(), open output failed");
-                delete player;
-            } else {
-                mOutputs[deviceId] = player;
+                break;
+            case AAUDIO_DIRECTION_OUTPUT:
+                player = new AAudioServiceEndpointPlay(audioService);
                 endpoint = player;
+                break;
+            default:
+                break;
+        }
+    }
+
+    if (endpoint != nullptr) {
+        aaudio_result_t result = endpoint->open(deviceId);
+        if (result != AAUDIO_OK) {
+            ALOGE("AAudioEndpointManager::findEndpoint(), open failed");
+            delete endpoint;
+            endpoint = nullptr;
+        } else {
+            switch(direction) {
+                case AAUDIO_DIRECTION_INPUT:
+                    mInputs[deviceId] = capture;
+                    break;
+                case AAUDIO_DIRECTION_OUTPUT:
+                    mOutputs[deviceId] = player;
+                    break;
+                default:
+                    break;
             }
         }
         ALOGD("AAudioEndpointManager::openEndpoint(), created %p for device = %d, dir = %d",
@@ -148,6 +161,8 @@
             case AAUDIO_DIRECTION_OUTPUT:
                 mOutputs.erase(deviceId);
                 break;
+            default:
+                break;
         }
 
         serviceEndpoint->close();
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 443f40d..3718bee 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -27,6 +27,7 @@
 #include <utils/String16.h>
 
 #include "binding/AAudioServiceMessage.h"
+#include "AAudioClientTracker.h"
 #include "AAudioEndpointManager.h"
 #include "AAudioService.h"
 #include "AAudioServiceStreamMMAP.h"
@@ -49,6 +50,7 @@
     : BnAAudioService() {
     mCachedProcessId = getpid();
     mCachedUserId = getuid();   // TODO consider using geteuid()
+    AAudioClientTracker::getInstance().setAAudioService(this);
 }
 
 AAudioService::~AAudioService() {
@@ -71,10 +73,15 @@
     return NO_ERROR;
 }
 
+void AAudioService::registerClient(const sp<IAAudioClient>& client) {
+    pid_t pid = IPCThreadState::self()->getCallingPid();
+    AAudioClientTracker::getInstance().registerClient(pid, client);
+}
+
 aaudio_handle_t AAudioService::openStream(const aaudio::AAudioStreamRequest &request,
                                           aaudio::AAudioStreamConfiguration &configurationOutput) {
     aaudio_result_t result = AAUDIO_OK;
-    AAudioServiceStreamBase *serviceStream = nullptr;
+    sp<AAudioServiceStreamBase> serviceStream;
     const AAudioStreamConfiguration &configurationInput = request.getConstantConfiguration();
     bool sharingModeMatchRequired = request.isSharingModeMatchRequired();
     aaudio_sharing_mode_t sharingMode = configurationInput.getSharingMode();
@@ -89,9 +96,8 @@
         result = serviceStream->open(request, configurationOutput);
         if (result != AAUDIO_OK) {
             // fall back to using a shared stream
-            ALOGD("AAudioService::openStream(), EXCLUSIVE mode failed");
-            delete serviceStream;
-            serviceStream = nullptr;
+            ALOGW("AAudioService::openStream(), could not open in EXCLUSIVE mode");
+            serviceStream.clear();
         } else {
             configurationOutput.setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE);
         }
@@ -106,17 +112,22 @@
     }
 
     if (result != AAUDIO_OK) {
-        delete serviceStream;
-        ALOGE("AAudioService::openStream(): failed, return %d", result);
+        serviceStream.clear();
+        ALOGE("AAudioService::openStream(): failed, return %d = %s",
+              result, AAudio_convertResultToText(result));
         return result;
     } else {
         const uid_t ownerUserId = request.getUserId(); // only set by service, not by client
         serviceStream->setOwnerUserId(ownerUserId);
-        aaudio_handle_t handle = mHandleTracker.put(AAUDIO_HANDLE_TYPE_STREAM, serviceStream);
-        ALOGD("AAudioService::openStream(): handle = 0x%08X owned by %d", handle, ownerUserId);
+        aaudio_handle_t handle = mHandleTracker.put(AAUDIO_HANDLE_TYPE_STREAM, serviceStream.get());
         if (handle < 0) {
             ALOGE("AAudioService::openStream(): handle table full");
-            delete serviceStream;
+            serviceStream.clear();
+        } else {
+            ALOGD("AAudioService::openStream(): handle = 0x%08X", handle);
+            serviceStream->setHandle(handle);
+            pid_t pid = request.getProcessId();
+            AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream);
         }
         return handle;
     }
@@ -126,10 +137,11 @@
     AAudioServiceStreamBase *serviceStream = (AAudioServiceStreamBase *)
             mHandleTracker.remove(AAUDIO_HANDLE_TYPE_STREAM,
                                   streamHandle);
-    ALOGV("AAudioService.closeStream(0x%08X)", streamHandle);
+    ALOGD("AAudioService.closeStream(0x%08X)", streamHandle);
     if (serviceStream != nullptr) {
         serviceStream->close();
-        delete serviceStream;
+        pid_t pid = IPCThreadState::self()->getCallingPid();
+        AAudioClientTracker::getInstance().unregisterClientStream(pid, serviceStream);
         return AAUDIO_OK;
     }
     return AAUDIO_ERROR_INVALID_HANDLE;
@@ -209,8 +221,8 @@
 }
 
 aaudio_result_t AAudioService::registerAudioThread(aaudio_handle_t streamHandle,
-                                                         pid_t clientThreadId,
-                                                         int64_t periodNanoseconds) {
+                                                   pid_t clientThreadId,
+                                                   int64_t periodNanoseconds) {
     AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream == nullptr) {
         ALOGE("AAudioService::registerAudioThread(), illegal stream handle = 0x%0x", streamHandle);
diff --git a/services/oboeservice/AAudioService.h b/services/oboeservice/AAudioService.h
index 9b6b342..f84ac4c 100644
--- a/services/oboeservice/AAudioService.h
+++ b/services/oboeservice/AAudioService.h
@@ -46,8 +46,10 @@
 
     virtual status_t        dump(int fd, const Vector<String16>& args) override;
 
+    virtual void            registerClient(const sp<IAAudioClient>& client);
+
     virtual aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
-                                     aaudio::AAudioStreamConfiguration &configuration);
+                                     aaudio::AAudioStreamConfiguration &configurationOutput);
 
     virtual aaudio_result_t closeStream(aaudio_handle_t streamHandle);
 
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index cc2cb44..3815711 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -65,20 +65,20 @@
 }
 
 // TODO, maybe use an interface to reduce exposure
-aaudio_result_t AAudioServiceEndpoint::registerStream(AAudioServiceStreamShared *sharedStream) {
+aaudio_result_t AAudioServiceEndpoint::registerStream(sp<AAudioServiceStreamShared>sharedStream) {
     std::lock_guard<std::mutex> lock(mLockStreams);
     mRegisteredStreams.push_back(sharedStream);
     return AAUDIO_OK;
 }
 
-aaudio_result_t AAudioServiceEndpoint::unregisterStream(AAudioServiceStreamShared *sharedStream) {
+aaudio_result_t AAudioServiceEndpoint::unregisterStream(sp<AAudioServiceStreamShared>sharedStream) {
     std::lock_guard<std::mutex> lock(mLockStreams);
     mRegisteredStreams.erase(std::remove(mRegisteredStreams.begin(), mRegisteredStreams.end(), sharedStream),
               mRegisteredStreams.end());
     return AAUDIO_OK;
 }
 
-aaudio_result_t AAudioServiceEndpoint::startStream(AAudioServiceStreamShared *sharedStream) {
+aaudio_result_t AAudioServiceEndpoint::startStream(sp<AAudioServiceStreamShared> sharedStream) {
     // TODO use real-time technique to avoid mutex, eg. atomic command FIFO
     std::lock_guard<std::mutex> lock(mLockStreams);
     mRunningStreams.push_back(sharedStream);
@@ -88,7 +88,7 @@
     return AAUDIO_OK;
 }
 
-aaudio_result_t AAudioServiceEndpoint::stopStream(AAudioServiceStreamShared *sharedStream) {
+aaudio_result_t AAudioServiceEndpoint::stopStream(sp<AAudioServiceStreamShared> sharedStream) {
     int numRunningStreams = 0;
     {
         std::lock_guard<std::mutex> lock(mLockStreams);
@@ -130,11 +130,11 @@
 
 void AAudioServiceEndpoint::disconnectRegisteredStreams() {
     std::lock_guard<std::mutex> lock(mLockStreams);
-    for(AAudioServiceStreamShared *sharedStream : mRunningStreams) {
-        sharedStream->onStop();
+    for(auto baseStream : mRunningStreams) {
+        baseStream->onStop();
     }
     mRunningStreams.clear();
-    for(AAudioServiceStreamShared *sharedStream : mRegisteredStreams) {
+    for(auto sharedStream : mRegisteredStreams) {
         sharedStream->onDisconnect();
     }
     mRegisteredStreams.clear();
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index c271dbd..090b1dd 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -42,10 +42,10 @@
     int32_t getSamplesPerFrame() const { return mStreamInternal->getSamplesPerFrame();  }
     int32_t getFramesPerBurst() const { return mStreamInternal->getFramesPerBurst();  }
 
-    aaudio_result_t registerStream(AAudioServiceStreamShared *sharedStream);
-    aaudio_result_t unregisterStream(AAudioServiceStreamShared *sharedStream);
-    aaudio_result_t startStream(AAudioServiceStreamShared *sharedStream);
-    aaudio_result_t stopStream(AAudioServiceStreamShared *sharedStream);
+    aaudio_result_t registerStream(android::sp<AAudioServiceStreamShared> sharedStream);
+    aaudio_result_t unregisterStream(android::sp<AAudioServiceStreamShared> sharedStream);
+    aaudio_result_t startStream(android::sp<AAudioServiceStreamShared> sharedStream);
+    aaudio_result_t stopStream(android::sp<AAudioServiceStreamShared> sharedStream);
     aaudio_result_t close();
 
     int32_t getRequestedDeviceId() const { return mRequestedDeviceId; }
@@ -73,8 +73,9 @@
 
     std::mutex               mLockStreams;
 
-    std::vector<AAudioServiceStreamShared *> mRegisteredStreams;
-    std::vector<AAudioServiceStreamShared *> mRunningStreams;
+    std::vector<android::sp<AAudioServiceStreamShared>> mRegisteredStreams;
+
+    std::vector<android::sp<AAudioServiceStreamShared>> mRunningStreams;
 
 private:
     aaudio_result_t startSharingThread_l();
diff --git a/services/oboeservice/AAudioServiceEndpointCapture.cpp b/services/oboeservice/AAudioServiceEndpointCapture.cpp
index 29d6cb9..2bb79bf 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.cpp
+++ b/services/oboeservice/AAudioServiceEndpointCapture.cpp
@@ -78,7 +78,7 @@
         // Distribute data to each active stream.
         { // use lock guard
             std::lock_guard <std::mutex> lock(mLockStreams);
-            for (AAudioServiceStreamShared *sharedStream : mRunningStreams) {
+            for (sp<AAudioServiceStreamShared> sharedStream : mRunningStreams) {
                 FifoBuffer *fifo = sharedStream->getDataFifoBuffer();
                 if (fifo->getFifoControllerBase()->getEmptyFramesAvailable() <
                     getFramesPerBurst()) {
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index cc09cc3..bbe4788 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -79,7 +79,7 @@
         mMixer.clear();
         { // use lock guard
             std::lock_guard <std::mutex> lock(mLockStreams);
-            for (AAudioServiceStreamShared *sharedStream : mRunningStreams) {
+            for (sp<AAudioServiceStreamShared> sharedStream : mRunningStreams) {
                 FifoBuffer *fifo = sharedStream->getDataFifoBuffer();
                 float volume = 0.5; // TODO get from system
                 bool underflowed = mMixer.mix(fifo, volume);
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index ee0e7ed..c415f25 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -42,6 +42,7 @@
 
 AAudioServiceStreamBase::~AAudioServiceStreamBase() {
     close();
+    ALOGD("AAudioServiceStreamBase::~AAudioServiceStreamBase() destroyed %p", this);
 }
 
 aaudio_result_t AAudioServiceStreamBase::open(const aaudio::AAudioStreamRequest &request,
@@ -56,6 +57,7 @@
 }
 
 aaudio_result_t AAudioServiceStreamBase::close() {
+    stop();
     std::lock_guard<std::mutex> lock(mLockUpMessageQueue);
     delete mUpMessageQueue;
     mUpMessageQueue = nullptr;
@@ -71,28 +73,34 @@
 }
 
 aaudio_result_t AAudioServiceStreamBase::pause() {
-    sendCurrentTimestamp();
-    mThreadEnabled.store(false);
-    aaudio_result_t result = mAAudioThread.stop();
-    if (result != AAUDIO_OK) {
-        processFatalError();
-        return result;
+    aaudio_result_t result = AAUDIO_OK;
+    if (isRunning()) {
+        sendCurrentTimestamp();
+        mThreadEnabled.store(false);
+        result = mAAudioThread.stop();
+        if (result != AAUDIO_OK) {
+            processFatalError();
+            return result;
+        }
+        sendServiceEvent(AAUDIO_SERVICE_EVENT_PAUSED);
     }
-    sendServiceEvent(AAUDIO_SERVICE_EVENT_PAUSED);
     mState = AAUDIO_STREAM_STATE_PAUSED;
     return result;
 }
 
 aaudio_result_t AAudioServiceStreamBase::stop() {
-    // TODO wait for data to be played out
-    sendCurrentTimestamp();
-    mThreadEnabled.store(false);
-    aaudio_result_t result = mAAudioThread.stop();
-    if (result != AAUDIO_OK) {
-        processFatalError();
-        return result;
+    aaudio_result_t result = AAUDIO_OK;
+    if (isRunning()) {
+        // TODO wait for data to be played out
+        sendCurrentTimestamp();
+        mThreadEnabled.store(false);
+        result = mAAudioThread.stop();
+        if (result != AAUDIO_OK) {
+            processFatalError();
+            return result;
+        }
+        sendServiceEvent(AAUDIO_SERVICE_EVENT_STOPPED);
     }
-    sendServiceEvent(AAUDIO_SERVICE_EVENT_STOPPED);
     mState = AAUDIO_STREAM_STATE_STOPPED;
     return result;
 }
@@ -178,4 +186,4 @@
     mUpMessageQueue->fillParcelable(parcelable,
                                     parcelable.mUpMessageQueueParcelable);
     return getDownDataDescription(parcelable);
-}
\ No newline at end of file
+}
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index da0b537..d83d5ab 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -20,6 +20,8 @@
 #include <assert.h>
 #include <mutex>
 
+#include <utils/RefBase.h>
+
 #include "fifo/FifoBuffer.h"
 #include "binding/IAAudioService.h"
 #include "binding/AudioEndpointParcelable.h"
@@ -39,7 +41,8 @@
  * Base class for a stream in the AAudio service.
  */
 class AAudioServiceStreamBase
-    : public Runnable  {
+    : public virtual android::RefBase
+    , public Runnable  {
 
 public:
     AAudioServiceStreamBase();
@@ -78,6 +81,9 @@
      */
     virtual aaudio_result_t flush();
 
+    bool isRunning() const {
+        return mState == AAUDIO_STREAM_STATE_STARTED;
+    }
     // -------------------------------------------------------------------
 
     /**
@@ -120,6 +126,13 @@
         mOwnerUserId = uid;
     }
 
+    aaudio_handle_t getHandle() const {
+        return mHandle;
+    }
+    void setHandle(aaudio_handle_t handle) {
+        mHandle = handle;
+    }
+
 protected:
     aaudio_result_t writeUpMessageQueue(AAudioServiceMessage *command);
 
@@ -146,6 +159,8 @@
     int32_t            mSampleRate = AAUDIO_UNSPECIFIED;
     int32_t            mCapacityInFrames = AAUDIO_UNSPECIFIED;
     uid_t              mOwnerUserId = -1;
+private:
+    aaudio_handle_t    mHandle = -1;
 };
 
 } /* namespace aaudio */
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index 2f3ec27..4083bcc 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -38,7 +38,7 @@
 #define AAUDIO_SAMPLE_RATE_DEFAULT    48000
 
 /**
- * Stream that uses an MMAP buffer.
+ * Service Stream that uses an MMAP buffer.
  */
 
 AAudioServiceStreamMMAP::AAudioServiceStreamMMAP()
@@ -244,7 +244,6 @@
     return AAudioServiceStreamBase::flush();;
 }
 
-
 aaudio_result_t AAudioServiceStreamMMAP::getFreeRunningPosition(int64_t *positionFrames,
                                                                 int64_t *timeNanos) {
     struct audio_mmap_position position;
@@ -266,7 +265,7 @@
 }
 
 void AAudioServiceStreamMMAP::onTearDown() {
-    ALOGE("AAudioServiceStreamMMAP::onTearDown() called - TODO");
+    ALOGD("AAudioServiceStreamMMAP::onTearDown() called"); // TODO what is needed here?
 };
 
 void AAudioServiceStreamMMAP::onVolumeChanged(audio_channel_mask_t channels,
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index f246fc02..7515ea7 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -52,7 +52,7 @@
                                                            int32_t framesPerBurst) {
 
     if (requestedCapacityFrames > MAX_FRAMES_PER_BUFFER) {
-        ALOGE("AAudioServiceStreamShared::open(), requested capacity %d > max %d",
+        ALOGE("AAudioServiceStreamShared::calculateBufferCapacity() requested capacity %d > max %d",
               requestedCapacityFrames, MAX_FRAMES_PER_BUFFER);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
@@ -77,7 +77,7 @@
     }
     // Check for numeric overflow.
     if (numBursts > 0x8000 || framesPerBurst > 0x8000) {
-        ALOGE("AAudioServiceStreamShared::open(), numeric overflow, capacity = %d * %d",
+        ALOGE("AAudioServiceStreamShared::calculateBufferCapacity() overflow, capacity = %d * %d",
               numBursts, framesPerBurst);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
@@ -85,11 +85,11 @@
 
     // Final sanity check.
     if (capacityInFrames > MAX_FRAMES_PER_BUFFER) {
-        ALOGE("AAudioServiceStreamShared::open(), calculated capacity %d > max %d",
+        ALOGE("AAudioServiceStreamShared::calculateBufferCapacity() calc capacity %d > max %d",
               capacityInFrames, MAX_FRAMES_PER_BUFFER);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
-    ALOGD("AAudioServiceStreamShared::open(), requested capacity = %d frames, actual = %d",
+    ALOGD("AAudioServiceStreamShared::calculateBufferCapacity() requested %d frames, actual = %d",
           requestedCapacityFrames, capacityInFrames);
     return capacityInFrames;
 }
@@ -97,6 +97,8 @@
 aaudio_result_t AAudioServiceStreamShared::open(const aaudio::AAudioStreamRequest &request,
                      aaudio::AAudioStreamConfiguration &configurationOutput)  {
 
+    sp<AAudioServiceStreamShared> keep(this);
+
     aaudio_result_t result = AAudioServiceStreamBase::open(request, configurationOutput);
     if (result != AAUDIO_OK) {
         ALOGE("AAudioServiceStreamBase open() returned %d", result);
@@ -110,7 +112,7 @@
     AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
     mServiceEndpoint = mEndpointManager.openEndpoint(mAudioService, deviceId, direction);
     if (mServiceEndpoint == nullptr) {
-        ALOGE("AAudioServiceStreamShared::open(), mServiceEndPoint = %p", mServiceEndpoint);
+        ALOGE("AAudioServiceStreamShared::open() mServiceEndPoint = %p", mServiceEndpoint);
         return AAUDIO_ERROR_UNAVAILABLE;
     }
 
@@ -119,7 +121,7 @@
     if (mAudioFormat == AAUDIO_FORMAT_UNSPECIFIED) {
         mAudioFormat = AAUDIO_FORMAT_PCM_FLOAT;
     } else if (mAudioFormat != AAUDIO_FORMAT_PCM_FLOAT) {
-        ALOGE("AAudioServiceStreamShared::open(), mAudioFormat = %d, need FLOAT", mAudioFormat);
+        ALOGE("AAudioServiceStreamShared::open() mAudioFormat = %d, need FLOAT", mAudioFormat);
         result = AAUDIO_ERROR_INVALID_FORMAT;
         goto error;
     }
@@ -128,7 +130,7 @@
     if (mSampleRate == AAUDIO_UNSPECIFIED) {
         mSampleRate = mServiceEndpoint->getSampleRate();
     } else if (mSampleRate != mServiceEndpoint->getSampleRate()) {
-        ALOGE("AAudioServiceStreamShared::open(), mSampleRate = %d, need %d",
+        ALOGE("AAudioServiceStreamShared::open() mSampleRate = %d, need %d",
               mSampleRate, mServiceEndpoint->getSampleRate());
         result = AAUDIO_ERROR_INVALID_RATE;
         goto error;
@@ -138,14 +140,14 @@
     if (mSamplesPerFrame == AAUDIO_UNSPECIFIED) {
         mSamplesPerFrame = mServiceEndpoint->getSamplesPerFrame();
     } else if (mSamplesPerFrame != mServiceEndpoint->getSamplesPerFrame()) {
-        ALOGE("AAudioServiceStreamShared::open(), mSamplesPerFrame = %d, need %d",
+        ALOGE("AAudioServiceStreamShared::open() mSamplesPerFrame = %d, need %d",
               mSamplesPerFrame, mServiceEndpoint->getSamplesPerFrame());
         result = AAUDIO_ERROR_OUT_OF_RANGE;
         goto error;
     }
 
     mFramesPerBurst = mServiceEndpoint->getFramesPerBurst();
-    ALOGD("AAudioServiceStreamShared::open(), mSampleRate = %d, mFramesPerBurst = %d",
+    ALOGD("AAudioServiceStreamShared::open() mSampleRate = %d, mFramesPerBurst = %d",
           mSampleRate, mFramesPerBurst);
 
     mCapacityInFrames = calculateBufferCapacity(configurationInput.getBufferCapacity(),
@@ -160,7 +162,7 @@
     mAudioDataQueue = new SharedRingBuffer();
     result = mAudioDataQueue->allocate(calculateBytesPerFrame(), mCapacityInFrames);
     if (result != AAUDIO_OK) {
-        ALOGE("AAudioServiceStreamShared::open(), could not allocate FIFO with %d frames",
+        ALOGE("AAudioServiceStreamShared::open() could not allocate FIFO with %d frames",
               mCapacityInFrames);
         result = AAUDIO_ERROR_NO_MEMORY;
         goto error;
@@ -175,7 +177,7 @@
     configurationOutput.setAudioFormat(mAudioFormat);
     configurationOutput.setDeviceId(mServiceEndpoint->getDeviceId());
 
-    result = mServiceEndpoint->registerStream(this);
+    result = mServiceEndpoint->registerStream(keep);
     if (result != AAUDIO_OK) {
         goto error;
     }
@@ -263,7 +265,8 @@
     // TODO wait for pause() to synchronize
     AAudioServiceEndpoint *endpoint = mServiceEndpoint;
     if (endpoint != nullptr) {
-        endpoint->unregisterStream(this);
+        sp<AAudioServiceStreamShared> keep(this);
+        endpoint->unregisterStream(keep);
 
         AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
         mEndpointManager.closeEndpoint(endpoint);
@@ -292,8 +295,7 @@
 }
 
 void AAudioServiceStreamShared::onDisconnect() {
-    mServiceEndpoint->close();
-    mServiceEndpoint = nullptr;
+    processFatalError();
 }
 
 void AAudioServiceStreamShared::markTransferTime(int64_t nanoseconds) {
diff --git a/services/oboeservice/Android.mk b/services/oboeservice/Android.mk
index 12f7e04..a896a7a 100644
--- a/services/oboeservice/Android.mk
+++ b/services/oboeservice/Android.mk
@@ -25,6 +25,7 @@
     $(LIBAAUDIO_SRC_DIR)/utility/HandleTracker.cpp \
     SharedMemoryProxy.cpp \
     SharedRingBuffer.cpp \
+    AAudioClientTracker.cpp \
     AAudioEndpointManager.cpp \
     AAudioMixer.cpp \
     AAudioService.cpp \