Merge "Release the mutex before calling hidl_cb" into oc-dr1-dev
diff --git a/media/libaaudio/examples/input_monitor/src/input_monitor.cpp b/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
index 715c5f8..f1593fe 100644
--- a/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
+++ b/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
@@ -22,6 +22,7 @@
 #include <stdlib.h>
 #include <math.h>
 #include <aaudio/AAudio.h>
+#include <aaudio/AAudioTesting.h>
 #include "AAudioExampleUtils.h"
 #include "AAudioSimpleRecorder.h"
 
@@ -42,13 +43,13 @@
     const aaudio_format_t requestedDataFormat = AAUDIO_FORMAT_PCM_I16;
     aaudio_format_t actualDataFormat;
 
-    const int requestedInputChannelCount = 1; // Can affect whether we get a FAST path.
+    const int requestedInputChannelCount = 2; // Can affect whether we get a FAST path.
 
     //aaudio_performance_mode_t requestedPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
     const aaudio_performance_mode_t requestedPerformanceMode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
     //aaudio_performance_mode_t requestedPerformanceMode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
-    const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_SHARED;
-    //const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE;
+    //const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_SHARED;
+    const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE;
     aaudio_sharing_mode_t actualSharingMode;
 
     AAudioStream *aaudioStream = nullptr;
@@ -61,6 +62,7 @@
     int16_t *data = nullptr;
     float peakLevel = 0.0;
     int loopCounter = 0;
+    int32_t deviceId;
 
     // Make printf print immediately so that debug info is not stuck
     // in a buffer if we hang or crash.
@@ -68,6 +70,8 @@
 
     printf("%s - Monitor input level using AAudio\n", argv[0]);
 
+    AAudio_setMMapPolicy(AAUDIO_POLICY_ALWAYS);
+
     recorder.setPerformanceMode(requestedPerformanceMode);
     recorder.setSharingMode(requestedSharingMode);
 
@@ -79,6 +83,9 @@
     }
     aaudioStream = recorder.getStream();
 
+    deviceId = AAudioStream_getDeviceId(aaudioStream);
+    printf("deviceId = %d\n", deviceId);
+
     actualSamplesPerFrame = AAudioStream_getSamplesPerFrame(aaudioStream);
     printf("SamplesPerFrame = %d\n", actualSamplesPerFrame);
     actualSampleRate = AAudioStream_getSampleRate(aaudioStream);
@@ -133,7 +140,7 @@
     framesLeft = framesToRecord;
     while (framesLeft > 0) {
         // Read audio data from the stream.
-        const int64_t timeoutNanos = 100 * NANOS_PER_MILLISECOND;
+        const int64_t timeoutNanos = 1000 * NANOS_PER_MILLISECOND;
         int minFrames = (framesToRecord < framesPerRead) ? framesToRecord : framesPerRead;
         int actual = AAudioStream_read(aaudioStream, data, minFrames, timeoutNanos);
         if (actual < 0) {
diff --git a/media/libaaudio/examples/write_sine/src/write_sine.cpp b/media/libaaudio/examples/write_sine/src/write_sine.cpp
index 6522ba4..b9269e6 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine.cpp
@@ -25,17 +25,17 @@
 #include "AAudioSimplePlayer.h"
 
 #define SAMPLE_RATE           48000
-#define NUM_SECONDS           20
+#define NUM_SECONDS           4
 
-#define MMAP_POLICY              AAUDIO_UNSPECIFIED
+//#define MMAP_POLICY              AAUDIO_UNSPECIFIED
 //#define MMAP_POLICY              AAUDIO_POLICY_NEVER
 //#define MMAP_POLICY              AAUDIO_POLICY_AUTO
-//#define MMAP_POLICY              AAUDIO_POLICY_ALWAYS
+#define MMAP_POLICY              AAUDIO_POLICY_ALWAYS
 
 #define REQUESTED_FORMAT         AAUDIO_FORMAT_PCM_I16
 
-#define REQUESTED_SHARING_MODE   AAUDIO_SHARING_MODE_SHARED
-//#define REQUESTED_SHARING_MODE   AAUDIO_SHARING_MODE_EXCLUSIVE
+//#define REQUESTED_SHARING_MODE   AAUDIO_SHARING_MODE_SHARED
+#define REQUESTED_SHARING_MODE   AAUDIO_SHARING_MODE_EXCLUSIVE
 
 
 int main(int argc, char **argv)
@@ -64,6 +64,7 @@
     int32_t  xRunCount = 0;
     float   *floatData = nullptr;
     int16_t *shortData = nullptr;
+    int32_t deviceId;
 
     // Make printf print immediately so that debug info is not stuck
     // in a buffer if we hang or crash.
@@ -86,6 +87,9 @@
     aaudioStream = player.getStream();
     // Request stream properties.
 
+    deviceId = AAudioStream_getDeviceId(aaudioStream);
+    printf("deviceId = %d\n", deviceId);
+
     state = AAudioStream_getState(aaudioStream);
     printf("after open, state = %s\n", AAudio_convertStreamStateToText(state));
 
diff --git a/media/libaaudio/src/Android.mk b/media/libaaudio/src/Android.mk
index 28c4d7f..7131c6c 100644
--- a/media/libaaudio/src/Android.mk
+++ b/media/libaaudio/src/Android.mk
@@ -52,6 +52,7 @@
     binding/AAudioBinderClient.cpp \
     binding/AAudioStreamRequest.cpp \
     binding/AAudioStreamConfiguration.cpp \
+    binding/IAAudioClient.cpp \
     binding/IAAudioService.cpp \
     binding/RingBufferParcelable.cpp \
     binding/SharedMemoryParcelable.cpp \
@@ -109,6 +110,7 @@
     binding/AAudioBinderClient.cpp \
     binding/AAudioStreamRequest.cpp \
     binding/AAudioStreamConfiguration.cpp \
+    binding/IAAudioClient.cpp \
     binding/IAAudioService.cpp \
     binding/RingBufferParcelable.cpp \
     binding/SharedMemoryParcelable.cpp \
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.cpp b/media/libaaudio/src/binding/AAudioBinderClient.cpp
index 435b30f..6464334 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.cpp
+++ b/media/libaaudio/src/binding/AAudioBinderClient.cpp
@@ -19,75 +19,101 @@
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
+#include <binder/IInterface.h>
 #include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
 #include <utils/Mutex.h>
 #include <utils/RefBase.h>
 #include <utils/Singleton.h>
+#include <media/AudioSystem.h>
 
 #include <aaudio/AAudio.h>
 
 #include "AudioEndpointParcelable.h"
-#include "binding/AAudioStreamRequest.h"
-#include "binding/AAudioStreamConfiguration.h"
-#include "binding/IAAudioService.h"
-#include "binding/AAudioServiceMessage.h"
+#include "binding/AAudioBinderClient.h"
+//#include "binding/AAudioStreamRequest.h"
+//#include "binding/AAudioStreamConfiguration.h"
+//#include "binding/IAAudioService.h"
+//#include "binding/AAudioServiceMessage.h"
 
-#include "AAudioBinderClient.h"
-#include "AAudioServiceInterface.h"
+//#include "AAudioServiceInterface.h"
 
 using android::String16;
 using android::IServiceManager;
 using android::defaultServiceManager;
 using android::interface_cast;
+using android::IInterface;
 using android::IAAudioService;
 using android::Mutex;
 using android::sp;
+using android::wp;
 
 using namespace aaudio;
 
-static android::Mutex gServiceLock;
-static sp<IAAudioService>  gAAudioService;
-
 ANDROID_SINGLETON_STATIC_INSTANCE(AAudioBinderClient);
 
+AAudioBinderClient::AAudioBinderClient()
+        : AAudioServiceInterface()
+        , Singleton<AAudioBinderClient>() {
+
+    mAAudioClient = new AAudioClient(this);
+    ALOGD("AAudioBinderClient() created mAAudioClient = %p", mAAudioClient.get());
+}
+
+AAudioBinderClient::~AAudioBinderClient() {
+    Mutex::Autolock _l(mServiceLock);
+    if (mAAudioService != 0) {
+        IInterface::asBinder(mAAudioService)->unlinkToDeath(mAAudioClient);
+    }
+}
+
 // TODO Share code with other service clients.
 // Helper function to get access to the "AAudioService" service.
 // This code was modeled after frameworks/av/media/libaudioclient/AudioSystem.cpp
-static const sp<IAAudioService> getAAudioService() {
-    sp<IBinder> binder;
-    Mutex::Autolock _l(gServiceLock);
-    if (gAAudioService == 0) {
-        sp<IServiceManager> sm = defaultServiceManager();
-        // Try several times to get the service.
-        int retries = 4;
-        do {
-            binder = sm->getService(String16(AAUDIO_SERVICE_NAME)); // This will wait a while.
+const sp<IAAudioService> AAudioBinderClient::getAAudioService() {
+    sp<IAAudioService> aaudioService;
+    bool needToRegister = false;
+    {
+        Mutex::Autolock _l(mServiceLock);
+        if (mAAudioService == 0) {
+            sp<IBinder> binder;
+            sp<IServiceManager> sm = defaultServiceManager();
+            // Try several times to get the service.
+            int retries = 4;
+            do {
+                binder = sm->getService(String16(AAUDIO_SERVICE_NAME)); // This will wait a while.
+                if (binder != 0) {
+                    break;
+                }
+            } while (retries-- > 0);
+
             if (binder != 0) {
-                break;
+                // Ask for notification if the service dies.
+                status_t status = binder->linkToDeath(mAAudioClient);
+                ALOGD("getAAudioService: linkToDeath(mAAudioClient = %p) returned %d",
+                      mAAudioClient.get(), status);
+                mAAudioService = interface_cast<IAAudioService>(binder);
+                needToRegister = true;
+                // Make sure callbacks can be received by mAAudioClient
+                android::ProcessState::self()->startThreadPool();
+            } else {
+                ALOGE("AAudioBinderClient could not connect to %s", AAUDIO_SERVICE_NAME);
             }
-        } while (retries-- > 0);
-
-        if (binder != 0) {
-            // TODO Add linkToDeath() like in frameworks/av/media/libaudioclient/AudioSystem.cpp
-            // TODO Create a DeathRecipient that disconnects all active streams.
-            gAAudioService = interface_cast<IAAudioService>(binder);
-        } else {
-            ALOGE("AudioStreamInternal could not get %s", AAUDIO_SERVICE_NAME);
         }
+        aaudioService = mAAudioService;
     }
-    return gAAudioService;
+    // Do this outside the mutex lock.
+    if (needToRegister && aaudioService != 0) { // new client?
+        aaudioService->registerClient(mAAudioClient);
+    }
+    return aaudioService;
 }
 
-static void dropAAudioService() {
-    Mutex::Autolock _l(gServiceLock);
-    gAAudioService.clear(); // force a reconnect
+void AAudioBinderClient::dropAAudioService() {
+    Mutex::Autolock _l(mServiceLock);
+    mAAudioService.clear(); // force a reconnect
 }
 
-AAudioBinderClient::AAudioBinderClient()
-        : AAudioServiceInterface()
-        , Singleton<AAudioBinderClient>() {}
-
-AAudioBinderClient::~AAudioBinderClient() {}
 
 /**
 * @param request info needed to create the stream
@@ -159,23 +185,19 @@
 * Manage the specified thread as a low latency audio thread.
 */
 aaudio_result_t AAudioBinderClient::registerAudioThread(aaudio_handle_t streamHandle,
-                                                        pid_t clientProcessId,
                                                         pid_t clientThreadId,
                                                         int64_t periodNanoseconds) {
     const sp<IAAudioService> &service = getAAudioService();
     if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
     return service->registerAudioThread(streamHandle,
-                                        clientProcessId,
                                         clientThreadId,
                                         periodNanoseconds);
 }
 
 aaudio_result_t AAudioBinderClient::unregisterAudioThread(aaudio_handle_t streamHandle,
-                                                          pid_t clientProcessId,
                                                           pid_t clientThreadId) {
     const sp<IAAudioService> &service = getAAudioService();
     if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
     return service->unregisterAudioThread(streamHandle,
-                                          clientProcessId,
                                           clientThreadId);
 }
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.h b/media/libaaudio/src/binding/AAudioBinderClient.h
index e223376..469f0a8 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.h
+++ b/media/libaaudio/src/binding/AAudioBinderClient.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_AAUDIO_AAUDIO_BINDER_CLIENT_H
 #define ANDROID_AAUDIO_AAUDIO_BINDER_CLIENT_H
 
+#include <utils/RefBase.h>
 #include <utils/Singleton.h>
 
 #include <aaudio/AAudio.h>
@@ -25,14 +26,16 @@
 #include "binding/AAudioStreamRequest.h"
 #include "binding/AAudioStreamConfiguration.h"
 #include "binding/AudioEndpointParcelable.h"
+#include "binding/IAAudioService.h"
 
 /**
- * Implements the AAudioServiceInterface by talking to the actual service through Binder.
+ * Implements the AAudioServiceInterface by talking to the service through Binder.
  */
 
 namespace aaudio {
 
-class AAudioBinderClient : public AAudioServiceInterface
+class AAudioBinderClient : public virtual android::RefBase
+        , public AAudioServiceInterface
         , public android::Singleton<AAudioBinderClient> {
 
 public:
@@ -41,6 +44,12 @@
 
     virtual ~AAudioBinderClient();
 
+    const android::sp<android::IAAudioService> getAAudioService();
+
+    void dropAAudioService();
+
+    void registerClient(const android::sp<android::IAAudioClient>& client __unused) override {}
+
     /**
      * @param request info needed to create the stream
      * @param configuration contains resulting information about the created stream
@@ -82,13 +91,50 @@
      * TODO Consider passing this information as part of the startStream() call.
      */
     aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
-                                                pid_t clientProcessId,
                                                 pid_t clientThreadId,
                                                 int64_t periodNanoseconds) override;
 
     aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
-                                                  pid_t clientProcessId,
                                                   pid_t clientThreadId) override;
+
+    void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) {
+        // TODO This is just a stub so we can have a client Binder to pass to the service.
+        // TODO Implemented in a later CL.
+        ALOGW("onStreamChange called!");
+    }
+
+    class AAudioClient : public android::IBinder::DeathRecipient , public android::BnAAudioClient
+    {
+    public:
+        AAudioClient(android::wp<AAudioBinderClient> aaudioBinderClient)
+            : mBinderClient(aaudioBinderClient) {
+        }
+
+        // implement DeathRecipient
+        virtual void binderDied(const android::wp<android::IBinder>& who __unused) {
+            android::sp<AAudioBinderClient> client = mBinderClient.promote();
+            if (client != 0) {
+                client->dropAAudioService();
+            }
+            ALOGW("AAudio service binderDied()!");
+        }
+
+        // implement BnAAudioClient
+        void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) {
+            android::sp<AAudioBinderClient> client = mBinderClient.promote();
+            if (client != 0) {
+                client->onStreamChange(handle, opcode, value);
+            }
+        }
+    private:
+        android::wp<AAudioBinderClient> mBinderClient;
+    };
+
+
+    android::Mutex               mServiceLock;
+    android::sp<android::IAAudioService>  mAAudioService;
+    android::sp<AAudioClient>    mAAudioClient;
+
 };
 
 
diff --git a/media/libaaudio/src/binding/AAudioServiceDefinitions.h b/media/libaaudio/src/binding/AAudioServiceDefinitions.h
index 638544e..8a2303c 100644
--- a/media/libaaudio/src/binding/AAudioServiceDefinitions.h
+++ b/media/libaaudio/src/binding/AAudioServiceDefinitions.h
@@ -29,8 +29,9 @@
 
 namespace android {
 
-enum aaudio_commands_t {
-    OPEN_STREAM = IBinder::FIRST_CALL_TRANSACTION,
+enum aaudio_service_commands_t {
+    REGISTER_CLIENT = IBinder::FIRST_CALL_TRANSACTION,
+    OPEN_STREAM,
     CLOSE_STREAM,
     GET_STREAM_DESCRIPTION,
     START_STREAM,
@@ -41,6 +42,10 @@
     UNREGISTER_AUDIO_THREAD
 };
 
+enum aaudio_client_commands_t {
+    ON_STREAM_CHANGE = IBinder::FIRST_CALL_TRANSACTION
+};
+
 } // namespace android
 
 namespace aaudio {
diff --git a/media/libaaudio/src/binding/AAudioServiceInterface.h b/media/libaaudio/src/binding/AAudioServiceInterface.h
index 824e5bc..7368062 100644
--- a/media/libaaudio/src/binding/AAudioServiceInterface.h
+++ b/media/libaaudio/src/binding/AAudioServiceInterface.h
@@ -17,10 +17,13 @@
 #ifndef ANDROID_AAUDIO_BINDING_AAUDIO_SERVICE_INTERFACE_H
 #define ANDROID_AAUDIO_BINDING_AAUDIO_SERVICE_INTERFACE_H
 
+#include <utils/StrongPointer.h>
+
 #include "binding/AAudioServiceDefinitions.h"
 #include "binding/AAudioStreamRequest.h"
 #include "binding/AAudioStreamConfiguration.h"
 #include "binding/AudioEndpointParcelable.h"
+#include "binding/IAAudioClient.h"
 
 /**
  * This has the same methods as IAAudioService but without the Binder features.
@@ -36,6 +39,8 @@
     AAudioServiceInterface() {};
     virtual ~AAudioServiceInterface() = default;
 
+    virtual void registerClient(const android::sp<android::IAAudioClient>& client) = 0;
+
     /**
      * @param request info needed to create the stream
      * @param configuration contains information about the created stream
@@ -76,12 +81,10 @@
      * Manage the specified thread as a low latency audio thread.
      */
     virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
-                                                pid_t clientProcessId,
                                                 pid_t clientThreadId,
                                                 int64_t periodNanoseconds) = 0;
 
     virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
-                                                  pid_t clientProcessId,
                                                   pid_t clientThreadId) = 0;
 };
 
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.cpp b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
index a5c27b9..8a765ad 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
@@ -45,8 +45,7 @@
 status_t AAudioStreamRequest::writeToParcel(Parcel* parcel) const {
     status_t status = parcel->writeInt32((int32_t) mUserId);
     if (status != NO_ERROR) goto error;
-    status = parcel->writeInt32((int32_t) mProcessId);
-    if (status != NO_ERROR) goto error;
+
     status = parcel->writeInt32((int32_t) mDirection);
     if (status != NO_ERROR) goto error;
 
@@ -70,10 +69,6 @@
 
     status = parcel->readInt32(&temp);
     if (status != NO_ERROR) goto error;
-    mProcessId = (pid_t) temp;
-
-    status = parcel->readInt32(&temp);
-    if (status != NO_ERROR) goto error;
     mDirection = (aaudio_direction_t) temp;
 
     status = parcel->readBool(&mSharingModeMatchRequired);
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.h b/media/libaaudio/src/binding/AAudioStreamRequest.h
index 77138da..462246b 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.h
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.h
@@ -68,7 +68,6 @@
         mSharingModeMatchRequired = required;
     }
 
-
     const AAudioStreamConfiguration &getConstantConfiguration() const {
         return mConfiguration;
     }
diff --git a/media/libaaudio/src/binding/IAAudioClient.cpp b/media/libaaudio/src/binding/IAAudioClient.cpp
new file mode 100644
index 0000000..c69c4e8
--- /dev/null
+++ b/media/libaaudio/src/binding/IAAudioClient.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <aaudio/AAudio.h>
+
+#include "binding/AAudioBinderClient.h"
+#include "binding/AAudioServiceDefinitions.h"
+#include "binding/IAAudioClient.h"
+#include "utility/AAudioUtilities.h"
+
+namespace android {
+
+using aaudio::aaudio_handle_t;
+
+/**
+ * This is used by the AAudio Service to talk to an AAudio Client.
+ *
+ * The order of parameters in the Parcels must match with code in AAudioClient.cpp.
+ */
+class BpAAudioClient : public BpInterface<IAAudioClient>
+{
+public:
+    explicit BpAAudioClient(const sp<IBinder>& impl)
+        : BpInterface<IAAudioClient>(impl)
+    {
+    }
+
+    void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) override {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAAudioClient::getInterfaceDescriptor());
+        data.writeInt32(handle);
+        data.writeInt32(opcode);
+        data.writeInt32(value);
+        remote()->transact(ON_STREAM_CHANGE, data,  &reply, IBinder::FLAG_ONEWAY);
+    }
+
+};
+
+// Implement an interface to the service.
+IMPLEMENT_META_INTERFACE(AAudioClient, "IAAudioClient");
+
+// The order of parameters in the Parcels must match with code in BpAAudioClient
+
+status_t BnAAudioClient::onTransact(uint32_t code, const Parcel& data,
+                                        Parcel* reply, uint32_t flags) {
+    aaudio_handle_t streamHandle;
+    int32_t opcode = 0;
+    int32_t value = 0;
+    ALOGV("BnAAudioClient::onTransact(%u) %u", code, flags);
+
+    switch(code) {
+        case ON_STREAM_CHANGE: {
+            CHECK_INTERFACE(IAAudioClient, data, reply);
+            data.readInt32(&streamHandle);
+            data.readInt32(&opcode);
+            data.readInt32(&value);
+            onStreamChange(streamHandle, opcode, value);
+            ALOGD("BnAAudioClient onStreamChange(%x, %d, %d)", streamHandle, opcode, value);
+            return NO_ERROR;
+        } break;
+
+        default:
+            // ALOGW("BnAAudioClient::onTransact not handled %u", code);
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+} /* namespace android */
diff --git a/media/libaaudio/src/binding/IAAudioClient.h b/media/libaaudio/src/binding/IAAudioClient.h
new file mode 100644
index 0000000..21cc33b
--- /dev/null
+++ b/media/libaaudio/src/binding/IAAudioClient.h
@@ -0,0 +1,48 @@
+/*
+ * 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_IAAUDIO_CLIENT_H
+#define ANDROID_AAUDIO_IAAUDIO_CLIENT_H
+
+#include <stdint.h>
+#include <binder/IInterface.h>
+
+#include <aaudio/AAudio.h>
+
+#include "utility/HandleTracker.h"
+
+namespace android {
+
+
+// Interface (our AIDL) - client methods called by service
+class IAAudioClient : public IInterface {
+public:
+
+    DECLARE_META_INTERFACE(AAudioClient);
+
+    virtual void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) = 0;
+
+};
+
+class BnAAudioClient : public BnInterface<IAAudioClient> {
+public:
+    virtual status_t onTransact(uint32_t code, const Parcel& data,
+                                Parcel* reply, uint32_t flags = 0);
+};
+
+} /* namespace android */
+
+#endif //ANDROID_AAUDIO_IAAUDIO_SERVICE_H
diff --git a/media/libaaudio/src/binding/IAAudioService.cpp b/media/libaaudio/src/binding/IAAudioService.cpp
index ef4a51f..97fbaaa 100644
--- a/media/libaaudio/src/binding/IAAudioService.cpp
+++ b/media/libaaudio/src/binding/IAAudioService.cpp
@@ -14,7 +14,12 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
 #include <aaudio/AAudio.h>
+#include <binder/IPCThreadState.h>
 
 #include "binding/AudioEndpointParcelable.h"
 #include "binding/AAudioStreamRequest.h"
@@ -40,8 +45,16 @@
     {
     }
 
-    virtual aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
-                                     aaudio::AAudioStreamConfiguration &configurationOutput) override {
+    void registerClient(const sp<IAAudioClient>& client) override
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
+        data.writeStrongBinder(IInterface::asBinder(client));
+        remote()->transact(REGISTER_CLIENT, data, &reply);
+    }
+
+    aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
+                               aaudio::AAudioStreamConfiguration &configurationOutput) override {
         Parcel data, reply;
         // send command
         data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
@@ -55,7 +68,6 @@
         // parse reply
         aaudio_handle_t stream;
         err = reply.readInt32(&stream);
-        ALOGD("BpAAudioService::client openStream returned stream = 0x%08x", stream);
         if (err != NO_ERROR) {
             ALOGE("BpAAudioService::client transact(OPEN_STREAM) readInt %d", err);
             return AAudioConvert_androidToAAudioResult(err);
@@ -185,15 +197,13 @@
     }
 
     virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
-                                              pid_t clientProcessId,
-                                              pid_t clientThreadId,
-                                              int64_t periodNanoseconds)
+                                                pid_t clientThreadId,
+                                                int64_t periodNanoseconds)
     override {
         Parcel data, reply;
         // send command
         data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
         data.writeInt32(streamHandle);
-        data.writeInt32((int32_t) clientProcessId);
         data.writeInt32((int32_t) clientThreadId);
         data.writeInt64(periodNanoseconds);
         status_t err = remote()->transact(REGISTER_AUDIO_THREAD, data, &reply);
@@ -207,14 +217,12 @@
     }
 
     virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
-                                                  pid_t clientProcessId,
                                                   pid_t clientThreadId)
     override {
         Parcel data, reply;
         // send command
         data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
         data.writeInt32(streamHandle);
-        data.writeInt32((int32_t) clientProcessId);
         data.writeInt32((int32_t) clientThreadId);
         status_t err = remote()->transact(UNREGISTER_AUDIO_THREAD, data, &reply);
         if (err != NO_ERROR) {
@@ -236,43 +244,53 @@
 
 status_t BnAAudioService::onTransact(uint32_t code, const Parcel& data,
                                         Parcel* reply, uint32_t flags) {
-    aaudio_handle_t stream;
+    aaudio_handle_t streamHandle;
     aaudio::AAudioStreamRequest request;
     aaudio::AAudioStreamConfiguration configuration;
-    pid_t pid;
     pid_t tid;
     int64_t nanoseconds;
     aaudio_result_t result;
     ALOGV("BnAAudioService::onTransact(%i) %i", code, flags);
-    data.checkInterface(this);
 
     switch(code) {
-        case OPEN_STREAM: {
-            request.readFromParcel(&data);
+        case REGISTER_CLIENT: {
+            CHECK_INTERFACE(IAAudioService, data, reply);
+            sp<IAAudioClient> client = interface_cast<IAAudioClient>(
+                    data.readStrongBinder());
+            registerClient(client);
+            return NO_ERROR;
+        } break;
 
+        case OPEN_STREAM: {
+            CHECK_INTERFACE(IAAudioService, data, reply);
+            request.readFromParcel(&data);
             //ALOGD("BnAAudioService::client openStream request dump --------------------");
             //request.dump();
-
-            stream = openStream(request, configuration);
-            //ALOGD("BnAAudioService::onTransact OPEN_STREAM server handle = 0x%08X", stream);
-            reply->writeInt32(stream);
+            // Override the uid and pid from the client in case they are incorrect.
+            request.setUserId(IPCThreadState::self()->getCallingUid());
+            request.setProcessId(IPCThreadState::self()->getCallingPid());
+            streamHandle = openStream(request, configuration);
+            //ALOGD("BnAAudioService::onTransact OPEN_STREAM server handle = 0x%08X", streamHandle);
+            reply->writeInt32(streamHandle);
             configuration.writeToParcel(reply);
             return NO_ERROR;
         } break;
 
         case CLOSE_STREAM: {
-            data.readInt32(&stream);
-            result = closeStream(stream);
+            CHECK_INTERFACE(IAAudioService, data, reply);
+            data.readInt32(&streamHandle);
+            result = closeStream(streamHandle);
             //ALOGD("BnAAudioService::onTransact CLOSE_STREAM 0x%08X, result = %d",
-            //      stream, result);
+            //      streamHandle, result);
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
 
         case GET_STREAM_DESCRIPTION: {
-            data.readInt32(&stream);
+            CHECK_INTERFACE(IAAudioService, data, reply);
+            data.readInt32(&streamHandle);
             aaudio::AudioEndpointParcelable parcelable;
-            result = getStreamDescription(stream, parcelable);
+            result = getStreamDescription(streamHandle, parcelable);
             if (result != AAUDIO_OK) {
                 return AAudioConvert_aaudioToAndroidStatus(result);
             }
@@ -288,60 +306,64 @@
         } break;
 
         case START_STREAM: {
-            data.readInt32(&stream);
-            result = startStream(stream);
+            CHECK_INTERFACE(IAAudioService, data, reply);
+            data.readInt32(&streamHandle);
+            result = startStream(streamHandle);
             ALOGV("BnAAudioService::onTransact START_STREAM 0x%08X, result = %d",
-                    stream, result);
+                    streamHandle, result);
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
 
         case PAUSE_STREAM: {
-            data.readInt32(&stream);
-            result = pauseStream(stream);
+            CHECK_INTERFACE(IAAudioService, data, reply);
+            data.readInt32(&streamHandle);
+            result = pauseStream(streamHandle);
             ALOGV("BnAAudioService::onTransact PAUSE_STREAM 0x%08X, result = %d",
-                  stream, result);
+                  streamHandle, result);
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
 
         case STOP_STREAM: {
-            data.readInt32(&stream);
-            result = stopStream(stream);
+            CHECK_INTERFACE(IAAudioService, data, reply);
+            data.readInt32(&streamHandle);
+            result = stopStream(streamHandle);
             ALOGV("BnAAudioService::onTransact STOP_STREAM 0x%08X, result = %d",
-                  stream, result);
+                  streamHandle, result);
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
 
         case FLUSH_STREAM: {
-            data.readInt32(&stream);
-            result = flushStream(stream);
+            CHECK_INTERFACE(IAAudioService, data, reply);
+            data.readInt32(&streamHandle);
+            result = flushStream(streamHandle);
             ALOGV("BnAAudioService::onTransact FLUSH_STREAM 0x%08X, result = %d",
-                    stream, result);
+                    streamHandle, result);
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
 
         case REGISTER_AUDIO_THREAD: {
-            data.readInt32(&stream);
-            data.readInt32(&pid);
+            CHECK_INTERFACE(IAAudioService, data, reply);
+            data.readInt32(&streamHandle);
             data.readInt32(&tid);
             data.readInt64(&nanoseconds);
-            result = registerAudioThread(stream, pid, tid, nanoseconds);
+            result = registerAudioThread(streamHandle, tid, nanoseconds);
             ALOGV("BnAAudioService::onTransact REGISTER_AUDIO_THREAD 0x%08X, result = %d",
-                    stream, result);
+                    streamHandle, result);
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
 
         case UNREGISTER_AUDIO_THREAD: {
-            data.readInt32(&stream);
-            data.readInt32(&pid);
+            CHECK_INTERFACE(IAAudioService, data, reply);
+            data.readInt32(&streamHandle);
             data.readInt32(&tid);
-            result = unregisterAudioThread(stream, pid, tid);
+            result = unregisterAudioThread(streamHandle, tid);
             ALOGV("BnAAudioService::onTransact UNREGISTER_AUDIO_THREAD 0x%08X, result = %d",
-                    stream, result);
+                    streamHandle, result);
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
diff --git a/media/libaaudio/src/binding/IAAudioService.h b/media/libaaudio/src/binding/IAAudioService.h
index 44a5e12..30b3ead 100644
--- a/media/libaaudio/src/binding/IAAudioService.h
+++ b/media/libaaudio/src/binding/IAAudioService.h
@@ -28,18 +28,24 @@
 #include "binding/AudioEndpointParcelable.h"
 #include "binding/AAudioStreamRequest.h"
 #include "binding/AAudioStreamConfiguration.h"
+#include "binding/IAAudioClient.h"
 #include "utility/HandleTracker.h"
 
 namespace android {
 
 #define AAUDIO_SERVICE_NAME  "media.aaudio"
 
-// Interface (our AIDL) - Shared by server and client
+// Interface (our AIDL) - service methods called by client
 class IAAudioService : public IInterface {
 public:
 
     DECLARE_META_INTERFACE(AAudioService);
 
+    // Register an object to receive audio input/output change and track notifications.
+    // For a given calling pid, AAudio service disregards any registrations after the first.
+    // Thus the IAAudioClient must be a singleton per process.
+    virtual void registerClient(const sp<IAAudioClient>& client) = 0;
+
     /**
      * @param request info needed to create the stream
      * @param configuration contains information about the created stream
@@ -82,15 +88,12 @@
 
     /**
      * Manage the specified thread as a low latency audio thread.
-     * TODO Consider passing this information as part of the startStream() call.
      */
     virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
-                                              pid_t clientProcessId,
                                               pid_t clientThreadId,
                                               int64_t periodNanoseconds) = 0;
 
     virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
-                                                pid_t clientProcessId,
                                                 pid_t clientThreadId) = 0;
 };
 
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index b59c445..ff13fc2 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -115,6 +115,7 @@
         setSampleRate(configuration.getSampleRate());
         setSamplesPerFrame(configuration.getSamplesPerFrame());
         setDeviceId(configuration.getDeviceId());
+        setSharingMode(configuration.getSharingMode());
 
         // Save device format so we can do format conversion and volume scaling together.
         mDeviceFormat = configuration.getAudioFormat();
@@ -286,56 +287,6 @@
     }
 }
 
-aaudio_result_t AudioStreamInternal::requestPauseInternal()
-{
-    if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
-        ALOGE("AudioStreamInternal::requestPauseInternal() mServiceStreamHandle invalid = 0x%08X",
-              mServiceStreamHandle);
-        return AAUDIO_ERROR_INVALID_STATE;
-    }
-
-    mClockModel.stop(AudioClock::getNanoseconds());
-    setState(AAUDIO_STREAM_STATE_PAUSING);
-    return AAudioConvert_androidToAAudioResult(pauseWithStatus());
-}
-
-aaudio_result_t AudioStreamInternal::requestPause()
-{
-    aaudio_result_t result = stopCallback();
-    if (result != AAUDIO_OK) {
-        return result;
-    }
-    result = requestPauseInternal();
-    return result;
-}
-
-aaudio_result_t AudioStreamInternal::requestFlush() {
-    if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
-        ALOGE("AudioStreamInternal::requestFlush() mServiceStreamHandle invalid = 0x%08X",
-              mServiceStreamHandle);
-        return AAUDIO_ERROR_INVALID_STATE;
-    }
-
-    setState(AAUDIO_STREAM_STATE_FLUSHING);
-    return mServiceInterface.flushStream(mServiceStreamHandle);
-}
-
-// TODO for Play only
-void AudioStreamInternal::onFlushFromServer() {
-    int64_t readCounter = mAudioEndpoint.getDataReadCounter();
-    int64_t writeCounter = mAudioEndpoint.getDataWriteCounter();
-
-    // Bump offset so caller does not see the retrograde motion in getFramesRead().
-    int64_t framesFlushed = writeCounter - readCounter;
-    mFramesOffsetFromService += framesFlushed;
-    ALOGD("AudioStreamInternal::onFlushFromServer() readN = %lld, writeN = %lld, offset = %lld",
-          (long long)readCounter, (long long)writeCounter, (long long)mFramesOffsetFromService);
-
-    // Flush written frames by forcing writeCounter to readCounter.
-    // This is because we cannot move the read counter in the hardware.
-    mAudioEndpoint.setDataWriteCounter(readCounter);
-}
-
 aaudio_result_t AudioStreamInternal::requestStopInternal()
 {
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
@@ -364,7 +315,6 @@
         return AAUDIO_ERROR_INVALID_STATE;
     }
     return mServiceInterface.registerAudioThread(mServiceStreamHandle,
-                                              getpid(),
                                               gettid(),
                                               getPeriodNanoseconds());
 }
@@ -373,7 +323,7 @@
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
         return AAUDIO_ERROR_INVALID_STATE;
     }
-    return mServiceInterface.unregisterAudioThread(mServiceStreamHandle, getpid(), gettid());
+    return mServiceInterface.unregisterAudioThread(mServiceStreamHandle, gettid());
 }
 
 aaudio_result_t AudioStreamInternal::getTimestamp(clockid_t clockId,
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index c2c6419..257a702 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -41,13 +41,8 @@
     AudioStreamInternal(AAudioServiceInterface  &serviceInterface, bool inService);
     virtual ~AudioStreamInternal();
 
-    // =========== Begin ABSTRACT methods ===========================
     aaudio_result_t requestStart() override;
 
-    aaudio_result_t requestPause() override;
-
-    aaudio_result_t requestFlush() override;
-
     aaudio_result_t requestStop() override;
 
     aaudio_result_t getTimestamp(clockid_t clockId,
@@ -55,7 +50,6 @@
                                        int64_t *timeNanoseconds) override;
 
     virtual aaudio_result_t updateStateWhileWaiting() override;
-    // =========== End ABSTRACT methods ===========================
 
     aaudio_result_t open(const AudioStreamBuilder &builder) override;
 
@@ -113,13 +107,12 @@
 
     aaudio_result_t processCommands();
 
-    aaudio_result_t requestPauseInternal();
     aaudio_result_t requestStopInternal();
 
     aaudio_result_t stopCallback();
 
 
-    void onFlushFromServer();
+    virtual void onFlushFromServer() {}
 
     aaudio_result_t onEventFromServer(AAudioServiceMessage *message);
 
@@ -160,6 +153,8 @@
     // The service uses this for SHARED mode.
     bool                     mInService = false;  // Is this running in the client or the service?
 
+    AAudioServiceInterface  &mServiceInterface;   // abstract interface to the service
+
 private:
     /*
      * Asynchronous write with data conversion.
@@ -175,7 +170,6 @@
 
     AudioEndpointParcelable  mEndPointParcelable; // description of the buffers filled by service
     EndpointDescriptor       mEndpointDescriptor; // buffer description with resolved addresses
-    AAudioServiceInterface  &mServiceInterface;   // abstract interface to the service
 
 };
 
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index 76ecbf9..1b18577 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -34,6 +34,55 @@
 AudioStreamInternalPlay::~AudioStreamInternalPlay() {}
 
 
+aaudio_result_t AudioStreamInternalPlay::requestPauseInternal()
+{
+    if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
+        ALOGE("AudioStreamInternal::requestPauseInternal() mServiceStreamHandle invalid = 0x%08X",
+              mServiceStreamHandle);
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+
+    mClockModel.stop(AudioClock::getNanoseconds());
+    setState(AAUDIO_STREAM_STATE_PAUSING);
+    return AAudioConvert_androidToAAudioResult(pauseWithStatus());
+}
+
+aaudio_result_t AudioStreamInternalPlay::requestPause()
+{
+    aaudio_result_t result = stopCallback();
+    if (result != AAUDIO_OK) {
+        return result;
+    }
+    result = requestPauseInternal();
+    return result;
+}
+
+aaudio_result_t AudioStreamInternalPlay::requestFlush() {
+    if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
+        ALOGE("AudioStreamInternal::requestFlush() mServiceStreamHandle invalid = 0x%08X",
+              mServiceStreamHandle);
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+
+    setState(AAUDIO_STREAM_STATE_FLUSHING);
+    return mServiceInterface.flushStream(mServiceStreamHandle);
+}
+
+void AudioStreamInternalPlay::onFlushFromServer() {
+    int64_t readCounter = mAudioEndpoint.getDataReadCounter();
+    int64_t writeCounter = mAudioEndpoint.getDataWriteCounter();
+
+    // Bump offset so caller does not see the retrograde motion in getFramesRead().
+    int64_t framesFlushed = writeCounter - readCounter;
+    mFramesOffsetFromService += framesFlushed;
+    ALOGD("AudioStreamInternal::onFlushFromServer() readN = %lld, writeN = %lld, offset = %lld",
+          (long long)readCounter, (long long)writeCounter, (long long)mFramesOffsetFromService);
+
+    // Flush written frames by forcing writeCounter to readCounter.
+    // This is because we cannot move the read counter in the hardware.
+    mAudioEndpoint.setDataWriteCounter(readCounter);
+}
+
 // Write the data, block if needed and timeoutMillis > 0
 aaudio_result_t AudioStreamInternalPlay::write(const void *buffer, int32_t numFrames,
                                            int64_t timeoutNanoseconds)
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.h b/media/libaaudio/src/client/AudioStreamInternalPlay.h
index b043f67..e59d02c 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.h
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.h
@@ -33,6 +33,10 @@
     AudioStreamInternalPlay(AAudioServiceInterface  &serviceInterface, bool inService = false);
     virtual ~AudioStreamInternalPlay();
 
+    aaudio_result_t requestPause() override;
+
+    aaudio_result_t requestFlush() override;
+
     aaudio_result_t write(const void *buffer,
                           int32_t numFrames,
                           int64_t timeoutNanoseconds) override;
@@ -47,6 +51,11 @@
     }
 
 protected:
+
+    aaudio_result_t requestPauseInternal();
+
+    void onFlushFromServer() override;
+
 /**
  * Low level write that will not block. It will just write as much as it can.
  *
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 7c7fcc5..e5fdcc6 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -48,8 +48,18 @@
      * Use waitForStateChange() to wait for completion.
      */
     virtual aaudio_result_t requestStart() = 0;
-    virtual aaudio_result_t requestPause() = 0;
-    virtual aaudio_result_t requestFlush() = 0;
+
+    virtual aaudio_result_t requestPause()
+    {
+        // Only implement this for OUTPUT streams.
+        return AAUDIO_ERROR_UNIMPLEMENTED;
+    }
+
+    virtual aaudio_result_t requestFlush() {
+        // Only implement this for OUTPUT streams.
+        return AAUDIO_ERROR_UNIMPLEMENTED;
+    }
+
     virtual aaudio_result_t requestStop() = 0;
 
     virtual aaudio_result_t getTimestamp(clockid_t clockId,
@@ -84,9 +94,7 @@
         return AAUDIO_OK;
     }
 
-    virtual aaudio_result_t setBufferSize(int32_t requestedFrames) {
-        return AAUDIO_ERROR_UNIMPLEMENTED;
-    }
+    virtual aaudio_result_t setBufferSize(int32_t requestedFrames) = 0;
 
     virtual aaudio_result_t createThread(int64_t periodNanoseconds,
                                        aaudio_audio_thread_proc_t threadProc,
@@ -214,15 +222,15 @@
 
     // ============== I/O ===========================
     // A Stream will only implement read() or write() depending on its direction.
-    virtual aaudio_result_t write(const void *buffer,
-                             int32_t numFrames,
-                             int64_t timeoutNanoseconds) {
+    virtual aaudio_result_t write(const void *buffer __unused,
+                             int32_t numFrames __unused,
+                             int64_t timeoutNanoseconds __unused) {
         return AAUDIO_ERROR_UNIMPLEMENTED;
     }
 
-    virtual aaudio_result_t read(void *buffer,
-                            int32_t numFrames,
-                            int64_t timeoutNanoseconds) {
+    virtual aaudio_result_t read(void *buffer __unused,
+                            int32_t numFrames __unused,
+                            int64_t timeoutNanoseconds __unused) {
         return AAUDIO_ERROR_UNIMPLEMENTED;
     }
 
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 8a481c0..6c4aa59 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -138,6 +138,12 @@
     bool allowMMap = mmapPolicy != AAUDIO_POLICY_NEVER;
     bool allowLegacy = mmapPolicy != AAUDIO_POLICY_ALWAYS;
 
+    // TODO Support other performance settings in MMAP mode.
+    // Disable MMAP if low latency not requested.
+    if (getPerformanceMode() != AAUDIO_PERFORMANCE_MODE_LOW_LATENCY) {
+        allowMMap = false;
+    }
+
     result = builder_createStream(getDirection(), sharingMode, allowMMap, &audioStream);
     if (result == AAUDIO_OK) {
         // Open the stream using the parameters from the builder.
@@ -247,4 +253,4 @@
     }
 
     return AAUDIO_OK;
-}
\ No newline at end of file
+}
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 156e83d..8e8070c 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -55,7 +55,7 @@
 
     // Try to create an AudioRecord
 
-    // TODO Support UNSPECIFIED in AudioTrack. For now, use stereo if unspecified.
+    // TODO Support UNSPECIFIED in AudioRecord. For now, use stereo if unspecified.
     int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED)
                               ? 2 : getSamplesPerFrame();
     audio_channel_mask_t channelMask = audio_channel_in_mask_from_count(samplesPerFrame);
@@ -130,8 +130,8 @@
         return AAudioConvert_androidToAAudioResult(status);
     }
 
-    // Get the actual rate.
-    setSampleRate(mAudioRecord->getSampleRate());
+    // Get the actual values from the AudioRecord.
+    setSamplesPerFrame(mAudioRecord->channelCount());
     setFormat(AAudioConvert_androidToAAudioDataFormat(mAudioRecord->format()));
 
     int32_t actualSampleRate = mAudioRecord->getSampleRate();
@@ -223,18 +223,6 @@
     return AAUDIO_OK;
 }
 
-aaudio_result_t AudioStreamRecord::requestPause()
-{
-    // This does not make sense for an input stream.
-    // There is no real difference between pause() and stop().
-    return AAUDIO_ERROR_UNIMPLEMENTED;
-}
-
-aaudio_result_t AudioStreamRecord::requestFlush() {
-    // This does not make sense for an input stream.
-    return AAUDIO_ERROR_UNIMPLEMENTED;
-}
-
 aaudio_result_t AudioStreamRecord::requestStop() {
     if (mAudioRecord.get() == nullptr) {
         return AAUDIO_ERROR_INVALID_STATE;
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.h b/media/libaaudio/src/legacy/AudioStreamRecord.h
index 90000fc..2c6a7eb 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.h
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.h
@@ -41,8 +41,6 @@
     aaudio_result_t close() override;
 
     aaudio_result_t requestStart() override;
-    aaudio_result_t requestPause() override;
-    aaudio_result_t requestFlush() override;
     aaudio_result_t requestStop() override;
 
     virtual aaudio_result_t getTimestamp(clockid_t clockId,
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index f894bc0..efd663d 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -17,6 +17,8 @@
 #ifndef UTILITY_AAUDIO_UTILITIES_H
 #define UTILITY_AAUDIO_UTILITIES_H
 
+#include <algorithm>
+#include <functional>
 #include <stdint.h>
 #include <sys/types.h>
 
@@ -211,4 +213,27 @@
  */
 int32_t AAudioProperty_getHardwareBurstMinMicros();
 
+/**
+ * Try a function f until it returns true.
+ *
+ * The function is always called at least once.
+ *
+ * @param f the function to evaluate, which returns a bool.
+ * @param times the number of times to evaluate f.
+ * @param sleepMs the sleep time per check of f, if greater than 0.
+ * @return true if f() eventually returns true.
+ */
+static inline bool AAudio_tryUntilTrue(
+        std::function<bool()> f, int times, int sleepMs) {
+    static const useconds_t US_PER_MS = 1000;
+
+    sleepMs = std::max(sleepMs, 0);
+    for (;;) {
+        if (f()) return true;
+        if (times <= 1) return false;
+        --times;
+        usleep(sleepMs * US_PER_MS);
+    }
+}
+
 #endif //UTILITY_AAUDIO_UTILITIES_H
diff --git a/media/libaaudio/src/utility/HandleTracker.cpp b/media/libaaudio/src/utility/HandleTracker.cpp
index f957234..35ce95a 100644
--- a/media/libaaudio/src/utility/HandleTracker.cpp
+++ b/media/libaaudio/src/utility/HandleTracker.cpp
@@ -20,11 +20,15 @@
 #include <utils/Log.h>
 
 #include <assert.h>
+#include <functional>
+#include <iomanip>
 #include <new>
+#include <sstream>
 #include <stdint.h>
 #include <utils/Mutex.h>
 
 #include <aaudio/AAudio.h>
+#include "AAudioUtilities.h"
 #include "HandleTracker.h"
 
 using android::Mutex;
@@ -93,6 +97,47 @@
     return mHandleAddresses != nullptr;
 }
 
+
+
+std::string HandleTracker::dump() const {
+    if (!isInitialized()) {
+        return "HandleTracker is not initialized\n";
+    }
+
+    std::stringstream result;
+    const bool isLocked = AAudio_tryUntilTrue(
+            [this]()->bool { return mLock.tryLock(); } /* f */,
+            50 /* times */,
+            20 /* sleepMs */);
+    if (!isLocked) {
+        result << "HandleTracker may be deadlocked\n";
+    }
+
+    result << "HandleTracker:\n";
+    result << "  HandleHeaders:\n";
+    // atLineStart() can be changed to support an arbitrary line breaking algorithm;
+    // it should return true when a new line starts.
+    // For simplicity, we will use a constant 16 items per line.
+    const auto atLineStart = [](int index) -> bool {
+        // Magic constant of 0xf used for mask to detect start every 16 items.
+        return (index & 0xf) == 0; };
+    const auto atLineEnd = [this, &atLineStart](int index) -> bool {
+        return atLineStart(index + 1) || index == mMaxHandleCount - 1; };
+
+    for (int i = 0; i < mMaxHandleCount; ++i) {
+        if (atLineStart(i)) {
+            result << "    ";
+        }
+        result << std::hex << std::setw(4) << std::setfill('0') << mHandleHeaders[i]
+               << (atLineEnd(i) ? "\n" : " ");
+    }
+
+    if (isLocked) {
+        mLock.unlock();
+    }
+    return result.str();
+}
+
 handle_tracker_slot_t HandleTracker::allocateSlot_l() {
     void **allocated = mNextFreeAddress;
     if (allocated == nullptr) {
diff --git a/media/libaaudio/src/utility/HandleTracker.h b/media/libaaudio/src/utility/HandleTracker.h
index 23a73ed..a4c51c0 100644
--- a/media/libaaudio/src/utility/HandleTracker.h
+++ b/media/libaaudio/src/utility/HandleTracker.h
@@ -18,6 +18,7 @@
 #define UTILITY_HANDLE_TRACKER_H
 
 #include <stdint.h>
+#include <string>
 #include <utils/Mutex.h>
 
 typedef int32_t  aaudio_handle_t;
@@ -53,6 +54,18 @@
     bool isInitialized() const;
 
     /**
+     * Returns HandleTracker information.
+     *
+     * Will attempt to get the object lock, but will proceed
+     * even if it cannot.
+     *
+     * Each line of information ends with a newline.
+     *
+     * @return a string representing the HandleTracker info.
+     */
+    std::string dump() const;
+
+    /**
      * Store a pointer and return a handle that can be used to retrieve the pointer.
      *
      * It is safe to call put() or remove() from multiple threads.
@@ -99,7 +112,7 @@
     // This Mutex protects the linked list of free nodes.
     // The list is managed using mHandleAddresses and mNextFreeAddress.
     // The data in mHandleHeaders is only changed by put() and remove().
-    android::Mutex              mLock;
+    mutable android::Mutex      mLock;
 
     /**
      * Pull slot off of a list of empty slots.
diff --git a/media/libaaudio/tests/Android.mk b/media/libaaudio/tests/Android.mk
index e6c779b..e4eef06 100644
--- a/media/libaaudio/tests/Android.mk
+++ b/media/libaaudio/tests/Android.mk
@@ -49,3 +49,33 @@
 LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
 LOCAL_MODULE := test_open_params
 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_no_close.cpp
+LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
+LOCAL_MODULE := test_no_close
+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_recovery.cpp
+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/media/libaaudio/tests/test_no_close.cpp b/media/libaaudio/tests/test_no_close.cpp
new file mode 100644
index 0000000..2dbf153
--- /dev/null
+++ b/media/libaaudio/tests/test_no_close.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 a resource leak in the server by opening a stream and then not closing it.
+// Return 0 if the stream opened, 1 if it failed.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <aaudio/AAudio.h>
+
+int main(int argc, char **argv)
+{
+    (void)argc; // unused
+    (void)argv; // unused
+
+    aaudio_result_t result = AAUDIO_OK;
+    AAudioStreamBuilder *aaudioBuilder = nullptr;
+    AAudioStream *aaudioStream = nullptr;
+
+    result = AAudio_createStreamBuilder(&aaudioBuilder);
+    if (result != AAUDIO_OK) {
+        goto finish;
+    }
+
+    // Create an AAudioStream using the Builder.
+    result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream);
+    if (result != AAUDIO_OK) {
+        printf("ERROR could not open AAudio stream, %d\n", result);
+        goto finish;
+    } else {
+        printf("AAudio stream opened successfully.\n");
+    }
+
+    printf("Exit without closing the stream!\n");
+
+finish:
+    return (result != AAUDIO_OK) ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
diff --git a/media/libaaudio/tests/test_recovery.cpp b/media/libaaudio/tests/test_recovery.cpp
new file mode 100644
index 0000000..7268a30
--- /dev/null
+++ b/media/libaaudio/tests/test_recovery.cpp
@@ -0,0 +1,155 @@
+/*
+ * 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.
+ */
+
+// Play silence and recover from dead servers or disconnected devices.
+
+#include <stdio.h>
+
+#include <aaudio/AAudio.h>
+
+
+#define DEFAULT_TIMEOUT_NANOS  ((int64_t)1000000000)
+
+static const char *getSharingModeText(aaudio_sharing_mode_t mode) {
+    const char *modeText = "unknown";
+    switch (mode) {
+        case AAUDIO_SHARING_MODE_EXCLUSIVE:
+            modeText = "EXCLUSIVE";
+            break;
+        case AAUDIO_SHARING_MODE_SHARED:
+            modeText = "SHARED";
+            break;
+        default:
+            break;
+    }
+    return modeText;
+}
+
+int main(int argc, char **argv) {
+    (void) argc;
+    (void *)argv;
+
+    aaudio_result_t result = AAUDIO_OK;
+
+    int32_t triesLeft = 3;
+    int32_t bufferCapacity;
+    int32_t framesPerBurst = 0;
+    float *buffer = nullptr;
+
+    int32_t actualChannelCount = 0;
+    int32_t actualSampleRate = 0;
+    aaudio_format_t actualDataFormat = AAUDIO_FORMAT_PCM_FLOAT;
+    aaudio_sharing_mode_t actualSharingMode = AAUDIO_SHARING_MODE_SHARED;
+
+    AAudioStreamBuilder *aaudioBuilder = nullptr;
+    AAudioStream *aaudioStream = nullptr;
+
+    // Make printf print immediately so that debug info is not stuck
+    // in a buffer if we hang or crash.
+    setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
+
+    printf("TestRecovery:\n");
+
+    // Use an AAudioStreamBuilder to contain requested parameters.
+    result = AAudio_createStreamBuilder(&aaudioBuilder);
+    if (result != AAUDIO_OK) {
+        printf("AAudio_createStreamBuilder returned %s",
+               AAudio_convertResultToText(result));
+        goto finish;
+    }
+
+    // Request stream properties.
+    AAudioStreamBuilder_setFormat(aaudioBuilder, AAUDIO_FORMAT_PCM_FLOAT);
+
+    while (triesLeft-- > 0) {
+        // Create an AAudioStream using the Builder.
+        result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream);
+        if (result != AAUDIO_OK) {
+            printf("AAudioStreamBuilder_openStream returned %s",
+                   AAudio_convertResultToText(result));
+            goto finish;
+        }
+
+        // Check to see what kind of stream we actually got.
+        actualSampleRate = AAudioStream_getSampleRate(aaudioStream);
+        actualChannelCount = AAudioStream_getChannelCount(aaudioStream);
+        actualDataFormat = AAudioStream_getFormat(aaudioStream);
+
+        printf("-------- chans = %3d, rate = %6d format = %d\n",
+                actualChannelCount, actualSampleRate, actualDataFormat);
+
+        // This is the number of frames that are read in one chunk by a DMA controller
+        // or a DSP or a mixer.
+        framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream);
+        bufferCapacity = AAudioStream_getBufferCapacityInFrames(aaudioStream);
+        printf("         bufferCapacity = %d, framesPerBurst = %d\n",
+        bufferCapacity, framesPerBurst);
+
+        int samplesPerBurst = framesPerBurst * actualChannelCount;
+        buffer = new float[samplesPerBurst];
+
+        result = AAudioStream_requestStart(aaudioStream);
+        if (result != AAUDIO_OK) {
+            printf("AAudioStream_requestStart returned %s",
+                   AAudio_convertResultToText(result));
+            goto finish;
+        }
+
+        // Play silence for awhile.
+        int32_t framesMax = actualSampleRate * 20;
+        int64_t framesTotal = 0;
+        int64_t printAt = actualSampleRate;
+        while (result == AAUDIO_OK && framesTotal < framesMax) {
+            int32_t framesWritten = AAudioStream_write(aaudioStream,
+                                                       buffer, framesPerBurst,
+                                                       DEFAULT_TIMEOUT_NANOS);
+            if (framesWritten < 0) {
+                result = framesWritten;
+                printf("write() returned %s, frames = %d\n",
+                       AAudio_convertResultToText(result), (int)framesTotal);
+                printf("  frames = %d\n", (int)framesTotal);
+            } else if (framesWritten != framesPerBurst) {
+                printf("write() returned %d, frames = %d\n", framesWritten, (int)framesTotal);
+                result = AAUDIO_ERROR_TIMEOUT;
+            } else {
+                framesTotal += framesWritten;
+                if (framesTotal >= printAt) {
+                    printf("frames = %d\n", (int)framesTotal);
+                    printAt += actualSampleRate;
+                }
+            }
+        }
+        result = AAudioStream_requestStop(aaudioStream);
+        if (result != AAUDIO_OK) {
+            printf("AAudioStream_requestStop returned %s\n",
+                   AAudio_convertResultToText(result));
+        }
+        result = AAudioStream_close(aaudioStream);
+        if (result != AAUDIO_OK) {
+            printf("AAudioStream_close returned %s\n",
+                   AAudio_convertResultToText(result));
+        }
+        aaudioStream = nullptr;
+    }
+
+finish:
+    if (aaudioStream != nullptr) {
+        AAudioStream_close(aaudioStream);
+    }
+    AAudioStreamBuilder_delete(aaudioBuilder);
+    delete[] buffer;
+    printf("          result = %d = %s\n", result, AAudio_convertResultToText(result));
+}
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 13198e8..611cde7 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -69,7 +69,8 @@
     : mActive(false), mStatus(NO_INIT), mOpPackageName(opPackageName),
       mSessionId(AUDIO_SESSION_ALLOCATE),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT),
-      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), mPortId(AUDIO_PORT_HANDLE_NONE)
+      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
+      mPortId(AUDIO_PORT_HANDLE_NONE)
 {
 }
 
@@ -503,7 +504,14 @@
     if (mInput == AUDIO_IO_HANDLE_NONE) {
         return AUDIO_PORT_HANDLE_NONE;
     }
-    return AudioSystem::getDeviceIdForIo(mInput);
+    // if the input stream does not have an active audio patch, use either the device initially
+    // selected by audio policy manager or the last routed device
+    audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mInput);
+    if (deviceId == AUDIO_PORT_HANDLE_NONE) {
+        deviceId = mRoutedDeviceId;
+    }
+    mRoutedDeviceId = deviceId;
+    return deviceId;
 }
 
 // -------------------------------------------------------------------------
@@ -550,13 +558,14 @@
             .channel_mask = mChannelMask,
             .format = mFormat
         };
+    mRoutedDeviceId = mSelectedDeviceId;
     status = AudioSystem::getInputForAttr(&mAttributes, &input,
                                         mSessionId,
                                         // FIXME compare to AudioTrack
                                         mClientPid,
                                         mClientUid,
                                         &config,
-                                        mFlags, mSelectedDeviceId, &mPortId);
+                                        mFlags, &mRoutedDeviceId, &mPortId);
 
     if (status != NO_ERROR || input == AUDIO_IO_HANDLE_NONE) {
         ALOGE("Could not get audio input for session %d, record source %d, sample rate %u, "
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index ed1e6d1..2f710bd 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -819,7 +819,7 @@
                                         uid_t uid,
                                         const audio_config_t *config,
                                         audio_output_flags_t flags,
-                                        audio_port_handle_t selectedDeviceId,
+                                        audio_port_handle_t *selectedDeviceId,
                                         audio_port_handle_t *portId)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
@@ -863,7 +863,7 @@
                                 uid_t uid,
                                 const audio_config_base_t *config,
                                 audio_input_flags_t flags,
-                                audio_port_handle_t selectedDeviceId,
+                                audio_port_handle_t *selectedDeviceId,
                                 audio_port_handle_t *portId)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index e1805a7..b0b01db 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -184,6 +184,7 @@
       mPreviousSchedulingGroup(SP_DEFAULT),
       mPausedPosition(0),
       mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
+      mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
       mPortId(AUDIO_PORT_HANDLE_NONE)
 {
     mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN;
@@ -1226,7 +1227,14 @@
     if (mOutput == AUDIO_IO_HANDLE_NONE) {
         return AUDIO_PORT_HANDLE_NONE;
     }
-    return AudioSystem::getDeviceIdForIo(mOutput);
+    // if the output stream does not have an active audio patch, use either the device initially
+    // selected by audio policy manager or the last routed device
+    audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mOutput);
+    if (deviceId == AUDIO_PORT_HANDLE_NONE) {
+        deviceId = mRoutedDeviceId;
+    }
+    mRoutedDeviceId = deviceId;
+    return deviceId;
 }
 
 status_t AudioTrack::attachAuxEffect(int effectId)
@@ -1306,10 +1314,11 @@
     config.channel_mask = mChannelMask;
     config.format = mFormat;
     config.offload_info = mOffloadInfoCopy;
+    mRoutedDeviceId = mSelectedDeviceId;
     status = AudioSystem::getOutputForAttr(attr, &output,
                                            mSessionId, &streamType, mClientUid,
                                            &config,
-                                           mFlags, mSelectedDeviceId, &mPortId);
+                                           mFlags, &mRoutedDeviceId, &mPortId);
 
     if (status != NO_ERROR || output == AUDIO_IO_HANDLE_NONE) {
         ALOGE("Could not get audio output for session %d, stream type %d, usage %d, sample rate %u,"
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index b72047b..d320320 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -193,7 +193,7 @@
                                         uid_t uid,
                                         const audio_config_t *config,
                                         audio_output_flags_t flags,
-                                        audio_port_handle_t selectedDeviceId,
+                                        audio_port_handle_t *selectedDeviceId,
                                         audio_port_handle_t *portId)
         {
             Parcel data, reply;
@@ -212,6 +212,10 @@
                 ALOGE("getOutputForAttr NULL output - shouldn't happen");
                 return BAD_VALUE;
             }
+            if (selectedDeviceId == NULL) {
+                ALOGE("getOutputForAttr NULL selectedDeviceId - shouldn't happen");
+                return BAD_VALUE;
+            }
             if (portId == NULL) {
                 ALOGE("getOutputForAttr NULL portId - shouldn't happen");
                 return BAD_VALUE;
@@ -232,7 +236,7 @@
             data.writeInt32(uid);
             data.write(config, sizeof(audio_config_t));
             data.writeInt32(static_cast <uint32_t>(flags));
-            data.writeInt32(selectedDeviceId);
+            data.writeInt32(*selectedDeviceId);
             data.writeInt32(*portId);
             status_t status = remote()->transact(GET_OUTPUT_FOR_ATTR, data, &reply);
             if (status != NO_ERROR) {
@@ -247,6 +251,7 @@
             if (stream != NULL) {
                 *stream = lStream;
             }
+            *selectedDeviceId = (audio_port_handle_t)reply.readInt32();
             *portId = (audio_port_handle_t)reply.readInt32();
             return status;
         }
@@ -296,7 +301,7 @@
                                      uid_t uid,
                                      const audio_config_base_t *config,
                                      audio_input_flags_t flags,
-                                     audio_port_handle_t selectedDeviceId,
+                                     audio_port_handle_t *selectedDeviceId,
                                      audio_port_handle_t *portId)
     {
         Parcel data, reply;
@@ -309,6 +314,10 @@
             ALOGE("getInputForAttr NULL input - shouldn't happen");
             return BAD_VALUE;
         }
+        if (selectedDeviceId == NULL) {
+            ALOGE("getInputForAttr NULL selectedDeviceId - shouldn't happen");
+            return BAD_VALUE;
+        }
         if (portId == NULL) {
             ALOGE("getInputForAttr NULL portId - shouldn't happen");
             return BAD_VALUE;
@@ -319,7 +328,7 @@
         data.writeInt32(uid);
         data.write(config, sizeof(audio_config_base_t));
         data.writeInt32(flags);
-        data.writeInt32(selectedDeviceId);
+        data.writeInt32(*selectedDeviceId);
         data.writeInt32(*portId);
         status_t status = remote()->transact(GET_INPUT_FOR_ATTR, data, &reply);
         if (status != NO_ERROR) {
@@ -330,6 +339,7 @@
             return status;
         }
         *input = (audio_io_handle_t)reply.readInt32();
+        *selectedDeviceId = (audio_port_handle_t)reply.readInt32();
         *portId = (audio_port_handle_t)reply.readInt32();
         return NO_ERROR;
     }
@@ -968,10 +978,11 @@
             status_t status = getOutputForAttr(hasAttributes ? &attr : NULL,
                     &output, session, &stream, uid,
                     &config,
-                    flags, selectedDeviceId, &portId);
+                    flags, &selectedDeviceId, &portId);
             reply->writeInt32(status);
             reply->writeInt32(output);
             reply->writeInt32(stream);
+            reply->writeInt32(selectedDeviceId);
             reply->writeInt32(portId);
             return NO_ERROR;
         } break;
@@ -1025,10 +1036,11 @@
             audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
             status_t status = getInputForAttr(&attr, &input, session, pid, uid,
                                               &config,
-                                              flags, selectedDeviceId, &portId);
+                                              flags, &selectedDeviceId, &portId);
             reply->writeInt32(status);
             if (status == NO_ERROR) {
                 reply->writeInt32(input);
+                reply->writeInt32(selectedDeviceId);
                 reply->writeInt32(portId);
             }
             return NO_ERROR;
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index 825a0a0..e6a5efb 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -661,7 +661,10 @@
 
     // For Device Selection API
     //  a value of AUDIO_PORT_HANDLE_NONE indicated default (AudioPolicyManager) routing.
-    audio_port_handle_t    mSelectedDeviceId;
+    audio_port_handle_t     mSelectedDeviceId; // Device requested by the application.
+    audio_port_handle_t     mRoutedDeviceId;   // Device actually selected by audio policy manager:
+                                              // May not match the app selection depending on other
+                                              // activity and connected devices
     sp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
     audio_port_handle_t    mPortId;  // unique ID allocated by audio policy
 
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 2875794..2e39d23 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -224,7 +224,7 @@
                                      uid_t uid,
                                      const audio_config_t *config,
                                      audio_output_flags_t flags,
-                                     audio_port_handle_t selectedDeviceId,
+                                     audio_port_handle_t *selectedDeviceId,
                                      audio_port_handle_t *portId);
     static status_t startOutput(audio_io_handle_t output,
                                 audio_stream_type_t stream,
@@ -245,7 +245,7 @@
                                     uid_t uid,
                                     const audio_config_base_t *config,
                                     audio_input_flags_t flags,
-                                    audio_port_handle_t selectedDeviceId,
+                                    audio_port_handle_t *selectedDeviceId,
                                     audio_port_handle_t *portId);
 
     static status_t startInput(audio_io_handle_t input,
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index c5dfedc..b168fc9 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -1141,7 +1141,10 @@
 
     // For Device Selection API
     //  a value of AUDIO_PORT_HANDLE_NONE indicated default (AudioPolicyManager) routing.
-    audio_port_handle_t     mSelectedDeviceId;
+    audio_port_handle_t    mSelectedDeviceId; // Device requested by the application.
+    audio_port_handle_t    mRoutedDeviceId;   // Device actually selected by audio policy manager:
+                                              // May not match the app selection depending on other
+                                              // activity and connected devices.
 
     sp<VolumeHandler>       mVolumeHandler;
 
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index ac71873..9b3e35e 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -68,7 +68,7 @@
                                       uid_t uid,
                                       const audio_config_t *config,
                                       audio_output_flags_t flags,
-                                      audio_port_handle_t selectedDeviceId,
+                                      audio_port_handle_t *selectedDeviceId,
                                       audio_port_handle_t *portId) = 0;
     virtual status_t startOutput(audio_io_handle_t output,
                                  audio_stream_type_t stream,
@@ -86,7 +86,7 @@
                               uid_t uid,
                               const audio_config_base_t *config,
                               audio_input_flags_t flags,
-                              audio_port_handle_t selectedDeviceId,
+                              audio_port_handle_t *selectedDeviceId,
                               audio_port_handle_t *portId) = 0;
     virtual status_t startInput(audio_io_handle_t input,
                                 audio_session_t session) = 0;
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 52e1626..27c121f 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -112,6 +112,7 @@
     int64_t getDurationUs() const;
     int64_t getEstimatedTrackSizeBytes() const;
     void writeTrackHeader(bool use32BitOffset = true);
+    int64_t getMinCttsOffsetTimeUs();
     void bufferChunk(int64_t timestampUs);
     bool isAvc() const { return mIsAvc; }
     bool isHevc() const { return mIsHevc; }
@@ -307,7 +308,8 @@
     ListTableEntries<uint32_t, 2> *mCttsTableEntries;
 
     int64_t mMinCttsOffsetTimeUs;
-    int64_t mMaxCttsOffsetTimeUs;
+    int64_t mMinCttsOffsetTicks;
+    int64_t mMaxCttsOffsetTicks;
 
     // Save the last 10 frames' timestamp for debug.
     std::list<std::pair<int64_t, int64_t>> mTimestampDebugHelper;
@@ -343,7 +345,7 @@
 
     void dumpTimeStamps();
 
-    int64_t getStartTimeOffsetScaledTimeUs() const;
+    int64_t getStartTimeOffsetTimeUs() const;
     int32_t getStartTimeOffsetScaledTime() const;
 
     static void *ThreadWrapper(void *me);
@@ -1134,9 +1136,22 @@
         writeUdtaBox();
     }
     writeMetaBox();
-    int32_t id = 1;
+    // Loop through all the tracks to get the global time offset if there is
+    // any ctts table appears in a video track.
+    int64_t minCttsOffsetTimeUs = kMaxCttsOffsetTimeUs;
     for (List<Track *>::iterator it = mTracks.begin();
-        it != mTracks.end(); ++it, ++id) {
+        it != mTracks.end(); ++it) {
+        minCttsOffsetTimeUs =
+            std::min(minCttsOffsetTimeUs, (*it)->getMinCttsOffsetTimeUs());
+    }
+    ALOGI("Ajust the moov start time from %lld us -> %lld us",
+            (long long)mStartTimestampUs,
+            (long long)(mStartTimestampUs + minCttsOffsetTimeUs - kMaxCttsOffsetTimeUs));
+    // Adjust the global start time.
+    mStartTimestampUs += minCttsOffsetTimeUs - kMaxCttsOffsetTimeUs;
+
+    for (List<Track *>::iterator it = mTracks.begin();
+        it != mTracks.end(); ++it) {
         (*it)->writeTrackHeader(mUse32BitOffset);
     }
     endBox();  // moov
@@ -1626,10 +1641,14 @@
       mStssTableEntries(new ListTableEntries<uint32_t, 1>(1000)),
       mSttsTableEntries(new ListTableEntries<uint32_t, 2>(1000)),
       mCttsTableEntries(new ListTableEntries<uint32_t, 2>(1000)),
+      mMinCttsOffsetTimeUs(0),
+      mMinCttsOffsetTicks(0),
+      mMaxCttsOffsetTicks(0),
       mCodecSpecificData(NULL),
       mCodecSpecificDataSize(0),
       mGotAllCodecSpecificData(false),
       mReachedEOS(false),
+      mStartTimestampUs(-1),
       mRotation(0) {
     getCodecSpecificDataFromInputFormatIfPossible();
 
@@ -2813,16 +2832,16 @@
 
             // Update ctts time offset range
             if (mStszTableEntries->count() == 0) {
-                mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks;
-                mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks;
+                mMinCttsOffsetTicks = currCttsOffsetTimeTicks;
+                mMaxCttsOffsetTicks = currCttsOffsetTimeTicks;
             } else {
-                if (currCttsOffsetTimeTicks > mMaxCttsOffsetTimeUs) {
-                    mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks;
-                } else if (currCttsOffsetTimeTicks < mMinCttsOffsetTimeUs) {
-                    mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks;
+                if (currCttsOffsetTimeTicks > mMaxCttsOffsetTicks) {
+                    mMaxCttsOffsetTicks = currCttsOffsetTimeTicks;
+                } else if (currCttsOffsetTimeTicks < mMinCttsOffsetTicks) {
+                    mMinCttsOffsetTicks = currCttsOffsetTimeTicks;
+                    mMinCttsOffsetTimeUs = cttsOffsetTimeUs;
                 }
             }
-
         }
 
         if (mOwner->isRealTimeRecording()) {
@@ -3163,7 +3182,7 @@
 }
 
 int64_t MPEG4Writer::Track::getDurationUs() const {
-    return mTrackDurationUs + getStartTimeOffsetScaledTimeUs();
+    return mTrackDurationUs + getStartTimeOffsetTimeUs();
 }
 
 int64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const {
@@ -3218,6 +3237,16 @@
     mOwner->endBox();  // trak
 }
 
+int64_t MPEG4Writer::Track::getMinCttsOffsetTimeUs() {
+    // For video tracks with ctts table, this should return the minimum ctts
+    // offset in the table. For non-video tracks or video tracks without ctts
+    // table, this will return kMaxCttsOffsetTimeUs.
+    if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) {
+        return kMaxCttsOffsetTimeUs;
+    }
+    return mMinCttsOffsetTimeUs;
+}
+
 void MPEG4Writer::Track::writeStblBox(bool use32BitOffset) {
     mOwner->beginBox("stbl");
     mOwner->beginBox("stsd");
@@ -3647,10 +3676,10 @@
     mOwner->endBox();  // pasp
 }
 
-int64_t MPEG4Writer::Track::getStartTimeOffsetScaledTimeUs() const {
+int64_t MPEG4Writer::Track::getStartTimeOffsetTimeUs() const {
     int64_t trackStartTimeOffsetUs = 0;
     int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
-    if (mStartTimestampUs != moovStartTimeUs) {
+    if (mStartTimestampUs != -1 && mStartTimestampUs != moovStartTimeUs) {
         CHECK_GT(mStartTimestampUs, moovStartTimeUs);
         trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
     }
@@ -3658,23 +3687,30 @@
 }
 
 int32_t MPEG4Writer::Track::getStartTimeOffsetScaledTime() const {
-    return (getStartTimeOffsetScaledTimeUs() *  mTimeScale + 500000LL) / 1000000LL;
+    return (getStartTimeOffsetTimeUs() * mTimeScale + 500000LL) / 1000000LL;
 }
 
 void MPEG4Writer::Track::writeSttsBox() {
     mOwner->beginBox("stts");
     mOwner->writeInt32(0);  // version=0, flags=0
-    uint32_t duration;
-    CHECK(mSttsTableEntries->get(duration, 1));
-    duration = htonl(duration);  // Back to host byte order
-    mSttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime()), 1);
+    if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) {
+        // For non-vdeio tracks or video tracks without ctts table,
+        // adjust duration of first sample for tracks to account for
+        // first sample not starting at the media start time.
+        // TODO: consider signaling this using some offset
+        // as this is not quite correct.
+        uint32_t duration;
+        CHECK(mSttsTableEntries->get(duration, 1));
+        duration = htonl(duration);  // Back to host byte order
+        mSttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime()), 1);
+    }
     mSttsTableEntries->write(mOwner);
     mOwner->endBox();  // stts
 }
 
 void MPEG4Writer::Track::writeCttsBox() {
     // There is no B frame at all
-    if (mMinCttsOffsetTimeUs == mMaxCttsOffsetTimeUs) {
+    if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) {
         return;
     }
 
@@ -3684,11 +3720,12 @@
     }
 
     ALOGV("ctts box has %d entries with range [%" PRId64 ", %" PRId64 "]",
-            mCttsTableEntries->count(), mMinCttsOffsetTimeUs, mMaxCttsOffsetTimeUs);
+            mCttsTableEntries->count(), mMinCttsOffsetTicks, mMaxCttsOffsetTicks);
 
     mOwner->beginBox("ctts");
     mOwner->writeInt32(0);  // version=0, flags=0
-    int64_t delta = mMinCttsOffsetTimeUs - getStartTimeOffsetScaledTime();
+    int64_t deltaTimeUs = kMaxCttsOffsetTimeUs - getStartTimeOffsetTimeUs();
+    int64_t delta = (deltaTimeUs * mTimeScale + 500000LL) / 1000000LL;
     mCttsTableEntries->adjustEntries([delta](size_t /* ix */, uint32_t (&value)[2]) {
         // entries are <count, ctts> pairs; adjust only ctts
         uint32_t duration = htonl(value[1]); // back to host byte order
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index cfee943..d808e5b 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -44,6 +44,9 @@
 const int32_t kDefaultVideoEncoderDataSpace = HAL_DATASPACE_V0_BT709;
 
 const int kStopTimeoutUs = 300000; // allow 1 sec for shutting down encoder
+// allow maximum 1 sec for stop time offset. This limits the the delay in the
+// input source.
+const int kMaxStopTimeOffsetUs = 1000000;
 
 struct MediaCodecSource::Puller : public AHandler {
     explicit Puller(const sp<MediaSource> &source);
@@ -1017,7 +1020,15 @@
             if (mEncoder->getInputFormat(&inputFormat) == OK &&
                     inputFormat->findInt64("android._stop-time-offset-us", &stopTimeOffsetUs) &&
                     stopTimeOffsetUs > 0) {
+                if (stopTimeOffsetUs > kMaxStopTimeOffsetUs) {
+                    ALOGW("Source stopTimeOffsetUs %lld too large, limit at %lld us",
+                        (long long)stopTimeOffsetUs, (long long)kMaxStopTimeOffsetUs);
+                    stopTimeOffsetUs = kMaxStopTimeOffsetUs;
+                }
                 timeoutUs += stopTimeOffsetUs;
+            } else {
+                // Use kMaxStopTimeOffsetUs if stop time offset is not provided by input source
+                timeoutUs = kMaxStopTimeOffsetUs;
             }
         } else {
             mPuller->stop();
diff --git a/media/libstagefright/include/media/stagefright/MPEG4Writer.h b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
index 1c4827f..dd357cc 100644
--- a/media/libstagefright/include/media/stagefright/MPEG4Writer.h
+++ b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
@@ -83,6 +83,10 @@
         kWhatSwitch                          = 'swch',
     };
 
+    enum {
+        kMaxCttsOffsetTimeUs = 1000000LL,  // 1 second
+    };
+
     int  mFd;
     int mNextFd;
     sp<MetaData> mStartMeta;
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 2f6fec8..ef4d745 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -1229,7 +1229,8 @@
         ALOGW("Fail to return stopTimeOffsetUs as stop time is not set");
         return INVALID_OPERATION;
     }
-    *stopTimeOffsetUs = mStopTimeUs - mLastFrameTimestampUs;
+    *stopTimeOffsetUs =
+        mLastFrameTimestampUs == -1 ? 0 : mStopTimeUs - mLastFrameTimestampUs;
     return OK;
 }
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index c379c89..d850aa9 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -306,14 +306,14 @@
                                             &fullConfig,
                                             (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ |
                                                     AUDIO_OUTPUT_FLAG_DIRECT),
-                                            *deviceId, &portId);
+                                            deviceId, &portId);
     } else {
         ret = AudioSystem::getInputForAttr(attr, &io,
                                               sessionId,
                                               client.clientPid,
                                               client.clientUid,
                                               config,
-                                              AUDIO_INPUT_FLAG_MMAP_NOIRQ, *deviceId, &portId);
+                                              AUDIO_INPUT_FLAG_MMAP_NOIRQ, deviceId, &portId);
     }
     if (ret != NO_ERROR) {
         return ret;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index df10d23..085be00 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -7650,26 +7650,28 @@
             audio_stream_type_t stream = streamType();
             audio_output_flags_t flags =
                     (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT);
+            audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
             ret = AudioSystem::getOutputForAttr(&mAttr, &io,
                                                 sessionId,
                                                 &stream,
                                                 client.clientUid,
                                                 &config,
                                                 flags,
-                                                AUDIO_PORT_HANDLE_NONE,
+                                                &deviceId,
                                                 &portId);
         } else {
             audio_config_base_t config;
             config.sample_rate = mSampleRate;
             config.channel_mask = mChannelMask;
             config.format = mFormat;
+            audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
             ret = AudioSystem::getInputForAttr(&mAttr, &io,
                                                   sessionId,
                                                   client.clientPid,
                                                   client.clientUid,
                                                   &config,
                                                   AUDIO_INPUT_FLAG_MMAP_NOIRQ,
-                                                  AUDIO_PORT_HANDLE_NONE,
+                                                  &deviceId,
                                                   &portId);
         }
         // APM should not chose a different input or output stream for the same set of attributes
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 84e9426..c868206 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -122,7 +122,7 @@
                                         uid_t uid,
                                         const audio_config_t *config,
                                         audio_output_flags_t flags,
-                                        int selectedDeviceId,
+                                        audio_port_handle_t *selectedDeviceId,
                                         audio_port_handle_t *portId) = 0;
     // indicates to the audio policy manager that the output starts being used by corresponding stream.
     virtual status_t startOutput(audio_io_handle_t output,
@@ -144,7 +144,7 @@
                                      uid_t uid,
                                      const audio_config_base_t *config,
                                      audio_input_flags_t flags,
-                                     audio_port_handle_t selectedDeviceId,
+                                     audio_port_handle_t *selectedDeviceId,
                                      input_type_t *inputType,
                                      audio_port_handle_t *portId) = 0;
     // indicates to the audio policy manager that the input starts being used.
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index b6fff8c..9bdb98c 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -277,8 +277,11 @@
                 device &= ~AUDIO_DEVICE_OUT_SPEAKER;
             }
         } else if (outputs.isStreamActive(
-                                AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
-            // while media is playing (or has recently played), use the same device
+                                AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)
+                    || outputs.isStreamActive(
+                            AUDIO_STREAM_ACCESSIBILITY, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY))
+        {
+            // while media/a11y is playing (or has recently played), use the same device
             device = getDeviceForStrategyInt(
                     STRATEGY_MEDIA, availableOutputDevices, availableInputDevices, outputs);
         } else {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 72924b8..77b0182 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -769,7 +769,7 @@
                                               uid_t uid,
                                               const audio_config_t *config,
                                               audio_output_flags_t flags,
-                                              audio_port_handle_t selectedDeviceId,
+                                              audio_port_handle_t *selectedDeviceId,
                                               audio_port_handle_t *portId)
 {
     audio_attributes_t attributes;
@@ -813,16 +813,18 @@
     ALOGV("getOutputForAttr() usage=%d, content=%d, tag=%s flags=%08x"
             " session %d selectedDeviceId %d",
             attributes.usage, attributes.content_type, attributes.tags, attributes.flags,
-            session, selectedDeviceId);
+            session, *selectedDeviceId);
 
     *stream = streamTypefromAttributesInt(&attributes);
 
     // Explicit routing?
     sp<DeviceDescriptor> deviceDesc;
-    for (size_t i = 0; i < mAvailableOutputDevices.size(); i++) {
-        if (mAvailableOutputDevices[i]->getId() == selectedDeviceId) {
-            deviceDesc = mAvailableOutputDevices[i];
-            break;
+    if (*selectedDeviceId != AUDIO_PORT_HANDLE_NONE) {
+        for (size_t i = 0; i < mAvailableOutputDevices.size(); i++) {
+            if (mAvailableOutputDevices[i]->getId() == *selectedDeviceId) {
+                deviceDesc = mAvailableOutputDevices[i];
+                break;
+            }
         }
     }
     mOutputRoutes.addRoute(session, *stream, SessionRoute::SOURCE_TYPE_NA, deviceDesc, uid);
@@ -845,6 +847,12 @@
         return INVALID_OPERATION;
     }
 
+    DeviceVector outputDevices = mAvailableOutputDevices.getDevicesFromType(device);
+    *selectedDeviceId = outputDevices.size() > 0 ? outputDevices.itemAt(0)->getId()
+            : AUDIO_PORT_HANDLE_NONE;
+
+    ALOGV("  getOutputForAttr() returns output %d selectedDeviceId %d", *output, *selectedDeviceId);
+
     return NO_ERROR;
 }
 
@@ -1085,8 +1093,6 @@
     ALOGW_IF((output == 0), "getOutput() could not find output for stream %d, samplingRate %d,"
             "format %d, channels %x, flags %x", stream, samplingRate, format, channelMask, flags);
 
-    ALOGV("  getOutputForDevice() returns output %d", output);
-
     return output;
 }
 
@@ -1481,7 +1487,7 @@
                                              uid_t uid,
                                              const audio_config_base_t *config,
                                              audio_input_flags_t flags,
-                                             audio_port_handle_t selectedDeviceId,
+                                             audio_port_handle_t *selectedDeviceId,
                                              input_type_t *inputType,
                                              audio_port_handle_t *portId)
 {
@@ -1511,10 +1517,12 @@
 
     // Explicit routing?
     sp<DeviceDescriptor> deviceDesc;
-    for (size_t i = 0; i < mAvailableInputDevices.size(); i++) {
-        if (mAvailableInputDevices[i]->getId() == selectedDeviceId) {
-            deviceDesc = mAvailableInputDevices[i];
-            break;
+    if (*selectedDeviceId != AUDIO_PORT_HANDLE_NONE) {
+        for (size_t i = 0; i < mAvailableInputDevices.size(); i++) {
+            if (mAvailableInputDevices[i]->getId() == *selectedDeviceId) {
+                deviceDesc = mAvailableInputDevices[i];
+                break;
+            }
         }
     }
     mInputRoutes.addRoute(session, SessionRoute::STREAM_TYPE_NA, inputSource, deviceDesc, uid);
@@ -1565,7 +1573,13 @@
         return INVALID_OPERATION;
     }
 
-    ALOGV("getInputForAttr() returns input type = %d", *inputType);
+    DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(device);
+    *selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
+            : AUDIO_PORT_HANDLE_NONE;
+
+    ALOGV("getInputForAttr() returns input %d type %d selectedDeviceId %d",
+            *input, *inputType, *selectedDeviceId);
+
     return NO_ERROR;
 }
 
@@ -1801,6 +1815,40 @@
     return true;
 }
 
+// FIXME: remove when concurrent capture is ready. This is a hack to work around bug b/63083537.
+bool AudioPolicyManager::soundTriggerSupportsConcurrentCapture() {
+    if (!mHasComputedSoundTriggerSupportsConcurrentCapture) {
+        bool soundTriggerSupportsConcurrentCapture = false;
+        unsigned int numModules = 0;
+        struct sound_trigger_module_descriptor* nModules = NULL;
+
+        status_t status = SoundTrigger::listModules(nModules, &numModules);
+        if (status == NO_ERROR && numModules != 0) {
+            nModules = (struct sound_trigger_module_descriptor*) calloc(
+                    numModules, sizeof(struct sound_trigger_module_descriptor));
+            if (nModules == NULL) {
+              // We failed to malloc the buffer, so just say no for now, and hope that we have more
+              // ram the next time this function is called.
+              ALOGE("Failed to allocate buffer for module descriptors");
+              return false;
+            }
+
+            status = SoundTrigger::listModules(nModules, &numModules);
+            if (status == NO_ERROR) {
+                soundTriggerSupportsConcurrentCapture = true;
+                for (size_t i = 0; i < numModules; ++i) {
+                    soundTriggerSupportsConcurrentCapture &=
+                            nModules[i].properties.concurrent_capture;
+                }
+            }
+            free(nModules);
+        }
+        mSoundTriggerSupportsConcurrentCapture = soundTriggerSupportsConcurrentCapture;
+        mHasComputedSoundTriggerSupportsConcurrentCapture = true;
+    }
+    return mSoundTriggerSupportsConcurrentCapture;
+}
+
 
 status_t AudioPolicyManager::startInput(audio_io_handle_t input,
                                         audio_session_t session,
@@ -1873,6 +1921,12 @@
             }
         }
 
+        // We only need to check if the sound trigger session supports concurrent capture if the
+        // input is also a sound trigger input. Otherwise, we should preempt any hotword stream
+        // that's running.
+        const bool allowConcurrentWithSoundTrigger =
+            inputDesc->isSoundTrigger() ? soundTriggerSupportsConcurrentCapture() : false;
+
         // if capture is allowed, preempt currently active HOTWORD captures
         for (size_t i = 0; i < activeInputs.size(); i++) {
             sp<AudioInputDescriptor> activeDesc = activeInputs[i];
@@ -1881,6 +1935,10 @@
                 continue;
             }
 
+            if (allowConcurrentWithSoundTrigger && activeDesc->isSoundTrigger()) {
+                continue;
+            }
+
             audio_source_t activeSource = activeDesc->inputSource(true);
             if (activeSource == AUDIO_SOURCE_HOTWORD) {
                 AudioSessionCollection activeSessions =
@@ -2151,7 +2209,8 @@
                 continue;
             }
             routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
-            audio_devices_t curStreamDevice = getDeviceForStrategy(curStrategy, false /*fromCache*/);
+            audio_devices_t curStreamDevice = Volume::getDeviceForVolume(getDeviceForStrategy(
+                    curStrategy, false /*fromCache*/));
             if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) &&
                     ((curStreamDevice & device) == 0)) {
                 continue;
@@ -2162,7 +2221,7 @@
                 applyVolume = (curDevice & curStreamDevice) != 0;
             } else {
                 applyVolume = !mVolumeCurves->hasVolumeIndexForDevice(
-                        stream, Volume::getDeviceForVolume(curStreamDevice));
+                        stream, curStreamDevice);
             }
 
             if (applyVolume) {
@@ -3476,7 +3535,8 @@
     mBeaconMuted(false),
     mTtsOutputAvailable(false),
     mMasterMono(false),
-    mMusicEffectOutput(AUDIO_IO_HANDLE_NONE)
+    mMusicEffectOutput(AUDIO_IO_HANDLE_NONE),
+    mHasComputedSoundTriggerSupportsConcurrentCapture(false)
 {
     mUidCached = getuid();
     mpClientInterface = clientInterface;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index c62ba25..82c4c35 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -116,7 +116,7 @@
                                           uid_t uid,
                                           const audio_config_t *config,
                                           audio_output_flags_t flags,
-                                          audio_port_handle_t selectedDeviceId,
+                                          audio_port_handle_t *selectedDeviceId,
                                           audio_port_handle_t *portId);
         virtual status_t startOutput(audio_io_handle_t output,
                                      audio_stream_type_t stream,
@@ -133,7 +133,7 @@
                                          uid_t uid,
                                          const audio_config_base_t *config,
                                          audio_input_flags_t flags,
-                                         audio_port_handle_t selectedDeviceId,
+                                         audio_port_handle_t *selectedDeviceId,
                                          input_type_t *inputType,
                                          audio_port_handle_t *portId);
 
@@ -671,6 +671,10 @@
             param.addInt(String8(AudioParameter::keyMonoOutput), (int)mMasterMono);
             mpClientInterface->setParameters(output, param.toString());
         }
+
+        bool soundTriggerSupportsConcurrentCapture();
+        bool mSoundTriggerSupportsConcurrentCapture;
+        bool mHasComputedSoundTriggerSupportsConcurrentCapture;
 };
 
 };
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 8a2f1dc..7d7cd93 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -167,7 +167,7 @@
                                               uid_t uid,
                                               const audio_config_t *config,
                                               audio_output_flags_t flags,
-                                              audio_port_handle_t selectedDeviceId,
+                                              audio_port_handle_t *selectedDeviceId,
                                               audio_port_handle_t *portId)
 {
     if (mAudioPolicyManager == NULL) {
@@ -277,7 +277,7 @@
                                              uid_t uid,
                                              const audio_config_base_t *config,
                                              audio_input_flags_t flags,
-                                             audio_port_handle_t selectedDeviceId,
+                                             audio_port_handle_t *selectedDeviceId,
                                              audio_port_handle_t *portId)
 {
     if (mAudioPolicyManager == NULL) {
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 2cd26ac..35542f1 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -82,7 +82,7 @@
                                       uid_t uid,
                                       const audio_config_t *config,
                                       audio_output_flags_t flags,
-                                      audio_port_handle_t selectedDeviceId,
+                                      audio_port_handle_t *selectedDeviceId,
                                       audio_port_handle_t *portId);
     virtual status_t startOutput(audio_io_handle_t output,
                                  audio_stream_type_t stream,
@@ -100,7 +100,7 @@
                                      uid_t uid,
                                      const audio_config_base_t *config,
                                      audio_input_flags_t flags,
-                                     audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE,
+                                     audio_port_handle_t *selectedDeviceId = NULL,
                                      audio_port_handle_t *portId = NULL);
     virtual status_t startInput(audio_io_handle_t input,
                                 audio_session_t session);
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index c2b71a2..c175259 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -231,29 +231,33 @@
 
     for (auto& cameraId : mCameraProviderManager->getCameraDeviceIds()) {
         String8 id8 = String8(cameraId.c_str());
+        bool cameraFound = false;
         {
+
             Mutex::Autolock lock(mCameraStatesLock);
             auto iter = mCameraStates.find(id8);
             if (iter != mCameraStates.end()) {
-                continue;
+                cameraFound = true;
             }
         }
 
-        hardware::camera::common::V1_0::CameraResourceCost cost;
-        res = mCameraProviderManager->getResourceCost(cameraId, &cost);
-        if (res != OK) {
-            ALOGE("Failed to query device resource cost: %s (%d)", strerror(-res), res);
-            continue;
-        }
-        std::set<String8> conflicting;
-        for (size_t i = 0; i < cost.conflictingDevices.size(); i++) {
-            conflicting.emplace(String8(cost.conflictingDevices[i].c_str()));
-        }
+        if (!cameraFound) {
+            hardware::camera::common::V1_0::CameraResourceCost cost;
+            res = mCameraProviderManager->getResourceCost(cameraId, &cost);
+            if (res != OK) {
+                ALOGE("Failed to query device resource cost: %s (%d)", strerror(-res), res);
+                continue;
+            }
+            std::set<String8> conflicting;
+            for (size_t i = 0; i < cost.conflictingDevices.size(); i++) {
+                conflicting.emplace(String8(cost.conflictingDevices[i].c_str()));
+            }
 
-        {
-            Mutex::Autolock lock(mCameraStatesLock);
-            mCameraStates.emplace(id8,
-                std::make_shared<CameraState>(id8, cost.resourceCost, conflicting));
+            {
+                Mutex::Autolock lock(mCameraStatesLock);
+                mCameraStates.emplace(id8,
+                    std::make_shared<CameraState>(id8, cost.resourceCost, conflicting));
+            }
         }
 
         onDeviceStatusChanged(id8, CameraDeviceStatus::PRESENT);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index a11f4e2..e022057 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2326,7 +2326,11 @@
     if (res < 0) return res;
 
     if (mInFlightMap.size() == 1) {
-        mStatusTracker->markComponentActive(mInFlightStatusId);
+        // hold mLock to prevent race with disconnect
+        Mutex::Autolock l(mLock);
+        if (mStatusTracker != nullptr) {
+            mStatusTracker->markComponentActive(mInFlightStatusId);
+        }
     }
 
     return OK;
@@ -2353,7 +2357,11 @@
 
     // Indicate idle inFlightMap to the status tracker
     if (mInFlightMap.size() == 0) {
-        mStatusTracker->markComponentIdle(mInFlightStatusId, Fence::NO_FENCE);
+        // hold mLock to prevent race with disconnect
+        Mutex::Autolock l(mLock);
+        if (mStatusTracker != nullptr) {
+            mStatusTracker->markComponentIdle(mInFlightStatusId, Fence::NO_FENCE);
+        }
     }
 }
 
@@ -3590,7 +3598,8 @@
             // Abort the input buffers for reprocess requests.
             if ((*it)->mInputStream != NULL) {
                 camera3_stream_buffer_t inputBuffer;
-                status_t res = (*it)->mInputStream->getInputBuffer(&inputBuffer);
+                status_t res = (*it)->mInputStream->getInputBuffer(&inputBuffer,
+                        /*respectHalLimit*/ false);
                 if (res != OK) {
                     ALOGW("%s: %d: couldn't get input buffer while clearing the request "
                             "list: %s (%d)", __FUNCTION__, __LINE__, strerror(-res), res);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index bfb58c6..5549dd1 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -189,7 +189,7 @@
     static const size_t        kDumpSleepDuration = 100000; // 0.10 sec
     static const nsecs_t       kShutdownTimeout   = 5000000000; // 5 sec
     static const nsecs_t       kActiveTimeout     = 500000000;  // 500 ms
-    static const size_t        kInFlightWarnLimit = 20;
+    static const size_t        kInFlightWarnLimit = 30;
     static const size_t        kInFlightWarnLimitHighSpeed = 256; // batch size 32 * pipe depth 8
     // SCHED_FIFO priority for request submission thread in HFR mode
     static const int           kRequestThreadPriority = 1;
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index ba352c4..9297ac8 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -544,7 +544,7 @@
     return res;
 }
 
-status_t Camera3Stream::getInputBuffer(camera3_stream_buffer *buffer) {
+status_t Camera3Stream::getInputBuffer(camera3_stream_buffer *buffer, bool respectHalLimit) {
     ATRACE_CALL();
     Mutex::Autolock l(mLock);
     status_t res = OK;
@@ -557,7 +557,7 @@
     }
 
     // Wait for new buffer returned back if we are running into the limit.
-    if (getHandoutInputBufferCountLocked() == camera3_stream::max_buffers) {
+    if (getHandoutInputBufferCountLocked() == camera3_stream::max_buffers && respectHalLimit) {
         ALOGV("%s: Already dequeued max input buffers (%d), wait for next returned one.",
                 __FUNCTION__, camera3_stream::max_buffers);
         res = mInputBufferReturnedSignal.waitRelative(mLock, kWaitForBufferDuration);
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index b5a9c5d..b6c8396 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -308,8 +308,10 @@
      * For bidirectional streams, this method applies to the input-side
      * buffers.
      *
+     * Normally this call will block until the handed out buffer count is less than the stream
+     * max buffer count; if respectHalLimit is set to false, this is ignored.
      */
-    status_t         getInputBuffer(camera3_stream_buffer *buffer);
+    status_t         getInputBuffer(camera3_stream_buffer *buffer, bool respectHalLimit = true);
 
     /**
      * Return a buffer to the stream after use by the HAL.
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 37b7c36..c695a10 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -232,8 +232,10 @@
      * For bidirectional streams, this method applies to the input-side
      * buffers.
      *
+     * Normally this call will block until the handed out buffer count is less than the stream
+     * max buffer count; if respectHalLimit is set to false, this is ignored.
      */
-    virtual status_t getInputBuffer(camera3_stream_buffer *buffer) = 0;
+    virtual status_t getInputBuffer(camera3_stream_buffer *buffer, bool respectHalLimit = true) = 0;
 
     /**
      * Return a buffer to the stream after use by the HAL.
diff --git a/services/oboeservice/AAudioClientTracker.cpp b/services/oboeservice/AAudioClientTracker.cpp
new file mode 100644
index 0000000..c0bea13
--- /dev/null
+++ b/services/oboeservice/AAudioClientTracker.cpp
@@ -0,0 +1,217 @@
+/*
+ * 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>() {
+}
+
+
+std::string AAudioClientTracker::dump() const {
+    std::stringstream result;
+    const bool isLocked = AAudio_tryUntilTrue(
+            [this]()->bool { return mLock.try_lock(); } /* f */,
+            50 /* times */,
+            20 /* sleepMs */);
+    if (!isLocked) {
+        result << "AAudioClientTracker may be deadlocked\n";
+    }
+
+    result << "AAudioClientTracker:\n";
+    for (const auto&  it : mNotificationClients) {
+        result << it.second->dump();
+    }
+
+    if (isLocked) {
+        mLock.unlock();
+    }
+    return result.str();
+}
+
+// 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);
+}
+
+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;
+    ALOGD("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.
+        ALOGD("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) {
+    ALOGD("AAudioClientTracker::unregisterClientStream(%d, %p)\n", pid, serviceStream.get());
+    std::lock_guard<std::mutex> lock(mLock);
+    auto it = mNotificationClients.find(pid);
+    if (it != mNotificationClients.end()) {
+        ALOGD("AAudioClientTracker::unregisterClientStream(%d, %p) found NotificationClient\n",
+              pid, serviceStream.get());
+        it->second->unregisterClientStream(serviceStream);
+    } else {
+        ALOGE("AAudioClientTracker::unregisterClientStream(%d, %p) missing NotificationClient\n",
+              pid, serviceStream.get());
+    }
+    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);
+}
+
+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);
+    mStreams.insert(serviceStream);
+    return AAUDIO_OK;
+}
+
+aaudio_result_t AAudioClientTracker::NotificationClient::unregisterClientStream(
+        sp<AAudioServiceStreamBase> serviceStream) {
+    std::lock_guard<std::mutex> lock(mLock);
+    ALOGD("AAudioClientTracker::NotificationClient() before erase() count = %d\n",
+          (int)mStreams.size());
+    mStreams.erase(serviceStream);
+    ALOGD("AAudioClientTracker::NotificationClient() after erase() count = %d\n",
+          (int)mStreams.size());
+    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<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);
+}
+
+
+std::string AAudioClientTracker::NotificationClient::dump() const {
+    std::stringstream result;
+    const bool isLocked = AAudio_tryUntilTrue(
+            [this]()->bool { return mLock.try_lock(); } /* f */,
+            50 /* times */,
+            20 /* sleepMs */);
+    if (!isLocked) {
+        result << "AAudioClientTracker::NotificationClient may be deadlocked\n";
+    }
+
+    result << "  client: pid = " << mProcessId << " has " << mStreams.size() << " streams\n";
+    for (auto serviceStream : mStreams) {
+        result << "     stream: 0x" << std::hex << serviceStream->getHandle() << std::dec << "\n";
+    }
+
+    if (isLocked) {
+        mLock.unlock();
+    }
+    return result.str();
+}
diff --git a/services/oboeservice/AAudioClientTracker.h b/services/oboeservice/AAudioClientTracker.h
new file mode 100644
index 0000000..accf1a7
--- /dev/null
+++ b/services/oboeservice/AAudioClientTracker.h
@@ -0,0 +1,103 @@
+/*
+ * 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;
+
+    /**
+     * Returns information about the state of the this class.
+     *
+     * Will attempt to get the object lock, but will proceed
+     * even if it cannot.
+     *
+     * Each line of information ends with a newline.
+     *
+     * @return a string with useful information
+     */
+    std::string dump() const;
+
+    aaudio_result_t registerClient(pid_t pid, const android::sp<android::IAAudioClient>& client);
+
+    void unregisterClient(pid_t pid);
+
+    int32_t getStreamCount(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:
+
+    /**
+     * One per process.
+     */
+    class NotificationClient : public IBinder::DeathRecipient {
+    public:
+        NotificationClient(pid_t pid);
+        virtual ~NotificationClient();
+
+        int32_t getStreamCount();
+
+        std::string dump() const;
+
+        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:
+        mutable std::mutex                              mLock;
+        const pid_t                                     mProcessId;
+        std::set<android::sp<AAudioServiceStreamBase>>  mStreams;
+    };
+
+    mutable 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 5c6825d..02d4a19 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -19,8 +19,11 @@
 #include <utils/Log.h>
 
 #include <assert.h>
+#include <functional>
 #include <map>
 #include <mutex>
+#include <sstream>
+#include <utility/AAudioUtilities.h>
 
 #include "AAudioEndpointManager.h"
 
@@ -35,51 +38,106 @@
         , mOutputs() {
 }
 
-AAudioServiceEndpoint *AAudioEndpointManager::openEndpoint(AAudioService &audioService, int32_t deviceId,
-                                                           aaudio_direction_t direction) {
+std::string AAudioEndpointManager::dump() const {
+    std::stringstream result;
+    const bool isLocked = AAudio_tryUntilTrue(
+            [this]()->bool { return mLock.try_lock(); } /* f */,
+            50 /* times */,
+            20 /* sleepMs */);
+    if (!isLocked) {
+        result << "EndpointManager may be deadlocked\n";
+    }
+
+    result << "AAudioEndpointManager:" << "\n";
+    size_t inputs = mInputs.size();
+    result << "Input Endpoints: " << inputs << "\n";
+    for (const auto &input : mInputs) {
+        result << "  Input: " << input->dump() << "\n";
+    }
+
+    size_t outputs = mOutputs.size();
+    result << "Output Endpoints: " << outputs << "\n";
+    for (const auto &output : mOutputs) {
+        result << "  Output: " << output->dump() << "\n";
+    }
+
+    if (isLocked) {
+        mLock.unlock();
+    }
+    return result.str();
+}
+
+AAudioServiceEndpoint *AAudioEndpointManager::openEndpoint(AAudioService &audioService,
+        const AAudioStreamConfiguration& configuration, 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.
+
+
+
     switch (direction) {
         case AAUDIO_DIRECTION_INPUT:
-            endpoint = mInputs[deviceId];
+            for (AAudioServiceEndpoint *ep : mInputs) {
+                if (ep->matches(configuration)) {
+                    endpoint = ep;
+                    break;
+                }
+            }
             break;
         case AAUDIO_DIRECTION_OUTPUT:
-            endpoint = mOutputs[deviceId];
+            for (AAudioServiceEndpoint *ep : mOutputs) {
+                if (ep->matches(configuration)) {
+                    endpoint = ep;
+                    break;
+                }
+            }
             break;
         default:
             assert(false); // There are only two possible directions.
             break;
     }
+    ALOGD("AAudioEndpointManager::openEndpoint(), found %p for device = %d, dir = %d",
+          endpoint, configuration.getDeviceId(), (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(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",
-              endpoint, deviceId, (int)direction);
+              endpoint, configuration.getDeviceId(), (int)direction);
     }
 
     if (endpoint != nullptr) {
@@ -112,10 +170,14 @@
 
         switch (direction) {
             case AAUDIO_DIRECTION_INPUT:
-                mInputs.erase(deviceId);
+                mInputs.erase(
+                  std::remove(mInputs.begin(), mInputs.end(), serviceEndpoint), mInputs.end());
                 break;
             case AAUDIO_DIRECTION_OUTPUT:
-                mOutputs.erase(deviceId);
+                mOutputs.erase(
+                  std::remove(mOutputs.begin(), mOutputs.end(), serviceEndpoint), mOutputs.end());
+                break;
+            default:
                 break;
         }
 
diff --git a/services/oboeservice/AAudioEndpointManager.h b/services/oboeservice/AAudioEndpointManager.h
index 899ea35..2511b2f 100644
--- a/services/oboeservice/AAudioEndpointManager.h
+++ b/services/oboeservice/AAudioEndpointManager.h
@@ -34,6 +34,18 @@
     ~AAudioEndpointManager() = default;
 
     /**
+     * Returns information about the state of the this class.
+     *
+     * Will attempt to get the object lock, but will proceed
+     * even if it cannot.
+     *
+     * Each line of information ends with a newline.
+     *
+     * @return a string with useful information
+     */
+    std::string dump() const;
+
+    /**
      * Find a service endpoint for the given deviceId and direction.
      * If an endpoint does not already exist then try to create one.
      *
@@ -42,17 +54,17 @@
      * @return endpoint or nullptr
      */
     AAudioServiceEndpoint *openEndpoint(android::AAudioService &audioService,
-                                        int32_t deviceId,
+                                        const AAudioStreamConfiguration& configuration,
                                         aaudio_direction_t direction);
 
     void closeEndpoint(AAudioServiceEndpoint *serviceEndpoint);
 
 private:
 
-    std::mutex    mLock;
+    mutable std::mutex mLock;
 
-    std::map<int32_t, AAudioServiceEndpointCapture *> mInputs;
-    std::map<int32_t, AAudioServiceEndpointPlay *> mOutputs;
+    std::vector<AAudioServiceEndpointCapture *> mInputs;
+    std::vector<AAudioServiceEndpointPlay *> mOutputs;
 
 };
 
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index b0e0a74..4ccd2f6 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -18,6 +18,7 @@
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
+#include <sstream>
 //#include <time.h>
 //#include <pthread.h>
 
@@ -26,16 +27,21 @@
 #include <utils/String16.h>
 
 #include "binding/AAudioServiceMessage.h"
+#include "AAudioClientTracker.h"
+#include "AAudioEndpointManager.h"
 #include "AAudioService.h"
 #include "AAudioServiceStreamMMAP.h"
 #include "AAudioServiceStreamShared.h"
 #include "AAudioServiceStreamMMAP.h"
 #include "binding/IAAudioService.h"
+#include "ServiceUtilities.h"
 #include "utility/HandleTracker.h"
 
 using namespace android;
 using namespace aaudio;
 
+#define MAX_STREAMS_PER_PROCESS   8
+
 typedef enum
 {
     AAUDIO_HANDLE_TYPE_STREAM
@@ -44,32 +50,69 @@
 
 android::AAudioService::AAudioService()
     : BnAAudioService() {
+    mCachedProcessId = getpid();
+    mCachedUserId = getuid();   // TODO consider using geteuid()
+    AAudioClientTracker::getInstance().setAAudioService(this);
 }
 
 AAudioService::~AAudioService() {
 }
 
+status_t AAudioService::dump(int fd, const Vector<String16>& args) {
+    std::string result;
+
+    if (!dumpAllowed()) {
+        std::stringstream ss;
+        ss << "Permission denial: can't dump AAudioService from pid="
+                << IPCThreadState::self()->getCallingPid() << ", uid="
+                << IPCThreadState::self()->getCallingUid() << "\n";
+        result = ss.str();
+        ALOGW("%s", result.c_str());
+    } else {
+        result = mHandleTracker.dump()
+                 + AAudioClientTracker::getInstance().dump()
+                 + AAudioEndpointManager::getInstance().dump();
+    }
+    (void)write(fd, result.c_str(), result.size());
+    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();
 
+    // 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;
     }
 
     if (sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE) {
-        serviceStream = new AAudioServiceStreamMMAP();
+        serviceStream = new AAudioServiceStreamMMAP(mCachedUserId);
         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);
         }
@@ -84,28 +127,45 @@
     }
 
     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 {
-        aaudio_handle_t handle = mHandleTracker.put(AAUDIO_HANDLE_TYPE_STREAM, serviceStream);
-        ALOGD("AAudioService::openStream(): handle = 0x%08X", handle);
+        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.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();
+            serviceStream->setOwnerProcessId(pid);
+            AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream);
         }
         return handle;
     }
 }
 
 aaudio_result_t AAudioService::closeStream(aaudio_handle_t streamHandle) {
-    AAudioServiceStreamBase *serviceStream = (AAudioServiceStreamBase *)
+    // Check permission and ownership first.
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream == nullptr) {
+        ALOGE("AAudioService::startStream(), illegal stream handle = 0x%0x", streamHandle);
+        return AAUDIO_ERROR_INVALID_HANDLE;
+    }
+
+    ALOGD("AAudioService.closeStream(0x%08X)", streamHandle);
+    // Remove handle from tracker so that we cannot look up the raw address any more.
+    serviceStream = (AAudioServiceStreamBase *)
             mHandleTracker.remove(AAUDIO_HANDLE_TYPE_STREAM,
                                   streamHandle);
-    ALOGV("AAudioService.closeStream(0x%08X)", streamHandle);
     if (serviceStream != nullptr) {
         serviceStream->close();
-        delete serviceStream;
+        pid_t pid = serviceStream->getOwnerProcessId();
+        AAudioClientTracker::getInstance().unregisterClientStream(pid, serviceStream);
         return AAUDIO_OK;
     }
     return AAUDIO_ERROR_INVALID_HANDLE;
@@ -113,8 +173,23 @@
 
 AAudioServiceStreamBase *AAudioService::convertHandleToServiceStream(
         aaudio_handle_t streamHandle) const {
-    return (AAudioServiceStreamBase *) mHandleTracker.get(AAUDIO_HANDLE_TYPE_STREAM,
-                              (aaudio_handle_t)streamHandle);
+    AAudioServiceStreamBase *serviceStream = (AAudioServiceStreamBase *)
+            mHandleTracker.get(AAUDIO_HANDLE_TYPE_STREAM, (aaudio_handle_t)streamHandle);
+    if (serviceStream != nullptr) {
+        // Only allow owner or the aaudio service to access the stream.
+        const uid_t callingUserId = IPCThreadState::self()->getCallingUid();
+        const uid_t ownerUserId = serviceStream->getOwnerUserId();
+        bool callerOwnsIt = callingUserId == ownerUserId;
+        bool serverCalling = callingUserId == mCachedUserId;
+        bool serverOwnsIt = ownerUserId == mCachedUserId;
+        bool allowed = callerOwnsIt || serverCalling || serverOwnsIt;
+        if (!allowed) {
+            ALOGE("AAudioService: calling uid %d cannot access stream 0x%08X owned by %d",
+                  callingUserId, streamHandle, ownerUserId);
+            serviceStream = nullptr;
+        }
+    }
+    return serviceStream;
 }
 
 aaudio_result_t AAudioService::getStreamDescription(
@@ -170,9 +245,8 @@
 }
 
 aaudio_result_t AAudioService::registerAudioThread(aaudio_handle_t streamHandle,
-                                                         pid_t clientProcessId,
-                                                         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);
@@ -182,12 +256,14 @@
         ALOGE("AAudioService::registerAudioThread(), thread already registered");
         return AAUDIO_ERROR_INVALID_STATE;
     }
+
+    const pid_t ownerPid = IPCThreadState::self()->getCallingPid(); // TODO review
     serviceStream->setRegisteredThread(clientThreadId);
-    int err = android::requestPriority(clientProcessId, clientThreadId,
+    int err = android::requestPriority(ownerPid, clientThreadId,
                                        DEFAULT_AUDIO_PRIORITY, true /* isForApp */);
     if (err != 0){
-        ALOGE("AAudioService::registerAudioThread() failed, errno = %d, priority = %d",
-              errno, DEFAULT_AUDIO_PRIORITY);
+        ALOGE("AAudioService::registerAudioThread(%d) failed, errno = %d, priority = %d",
+              clientThreadId, errno, DEFAULT_AUDIO_PRIORITY);
         return AAUDIO_ERROR_INTERNAL;
     } else {
         return AAUDIO_OK;
@@ -195,7 +271,6 @@
 }
 
 aaudio_result_t AAudioService::unregisterAudioThread(aaudio_handle_t streamHandle,
-                                                     pid_t clientProcessId,
                                                      pid_t clientThreadId) {
     AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream == nullptr) {
diff --git a/services/oboeservice/AAudioService.h b/services/oboeservice/AAudioService.h
index f5a7d2f..f84ac4c 100644
--- a/services/oboeservice/AAudioService.h
+++ b/services/oboeservice/AAudioService.h
@@ -44,8 +44,12 @@
 
     static const char* getServiceName() { return AAUDIO_SERVICE_NAME; }
 
+    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);
 
@@ -62,11 +66,11 @@
     virtual aaudio_result_t flushStream(aaudio_handle_t streamHandle);
 
     virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
-                                              pid_t pid, pid_t tid,
-                                              int64_t periodNanoseconds) ;
+                                                pid_t tid,
+                                                int64_t periodNanoseconds) ;
 
     virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
-                                                  pid_t pid, pid_t tid);
+                                                  pid_t tid);
 
 private:
 
@@ -74,6 +78,9 @@
 
     HandleTracker mHandleTracker;
 
+    uid_t   mCachedUserId = -1;
+    pid_t   mCachedProcessId = -1;
+
     enum constants {
         DEFAULT_AUDIO_PRIORITY = 2
     };
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index cc2cb44..b519829 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -18,16 +18,17 @@
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
+#include <algorithm>
 #include <assert.h>
 #include <map>
 #include <mutex>
+#include <sstream>
+#include <vector>
+
 #include <utils/Singleton.h>
 
 #include "AAudioEndpointManager.h"
 #include "AAudioServiceEndpoint.h"
-#include <algorithm>
-#include <mutex>
-#include <vector>
 
 #include "core/AudioStreamBuilder.h"
 #include "AAudioServiceEndpoint.h"
@@ -44,16 +45,48 @@
 // This is the maximum size in frames. The effective size can be tuned smaller at runtime.
 #define DEFAULT_BUFFER_CAPACITY   (48 * 8)
 
+std::string AAudioServiceEndpoint::dump() const {
+    std::stringstream result;
+
+    const bool isLocked = AAudio_tryUntilTrue(
+            [this]()->bool { return mLockStreams.try_lock(); } /* f */,
+            50 /* times */,
+            20 /* sleepMs */);
+    if (!isLocked) {
+        result << "EndpointManager may be deadlocked\n";
+    }
+
+    AudioStreamInternal     *stream = mStreamInternal;
+    if (stream == nullptr) {
+        result << "null stream!" << "\n";
+    } else {
+        result << "mmap stream: rate = " << stream->getSampleRate() << "\n";
+    }
+
+    result << "    Registered Streams:" << "\n";
+    for (sp<AAudioServiceStreamShared> sharedStream : mRegisteredStreams) {
+        result << sharedStream->dump();
+    }
+
+    if (isLocked) {
+        mLockStreams.unlock();
+    }
+    return result.str();
+}
+
 // Set up an EXCLUSIVE MMAP stream that will be shared.
-aaudio_result_t AAudioServiceEndpoint::open(int32_t deviceId) {
-    mRequestedDeviceId = deviceId;
+aaudio_result_t AAudioServiceEndpoint::open(const AAudioStreamConfiguration& configuration) {
+    mRequestedDeviceId = configuration.getDeviceId();
     mStreamInternal = getStreamInternal();
 
     AudioStreamBuilder builder;
     builder.setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE);
     // Don't fall back to SHARED because that would cause recursion.
     builder.setSharingModeMatchRequired(true);
-    builder.setDeviceId(deviceId);
+    builder.setDeviceId(mRequestedDeviceId);
+    builder.setFormat(configuration.getAudioFormat());
+    builder.setSampleRate(configuration.getSampleRate());
+    builder.setSamplesPerFrame(configuration.getSamplesPerFrame());
     builder.setDirection(getDirection());
     builder.setBufferCapacity(DEFAULT_BUFFER_CAPACITY);
 
@@ -65,20 +98,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 +121,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,12 +163,29 @@
 
 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) {
-        sharedStream->onDisconnect();
+    for(auto sharedStream : mRegisteredStreams) {
+        sharedStream->disconnect();
     }
     mRegisteredStreams.clear();
 }
+
+bool AAudioServiceEndpoint::matches(const AAudioStreamConfiguration& configuration) {
+    if (configuration.getDeviceId() != AAUDIO_UNSPECIFIED &&
+            configuration.getDeviceId() != mStreamInternal->getDeviceId()) {
+        return false;
+    }
+    if (configuration.getSampleRate() != AAUDIO_UNSPECIFIED &&
+            configuration.getSampleRate() != mStreamInternal->getSampleRate()) {
+        return false;
+    }
+    if (configuration.getSamplesPerFrame() != AAUDIO_UNSPECIFIED &&
+            configuration.getSamplesPerFrame() != mStreamInternal->getSamplesPerFrame()) {
+        return false;
+    }
+
+    return true;
+}
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index c271dbd..a78d3fa 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -36,16 +36,18 @@
 public:
     virtual ~AAudioServiceEndpoint() = default;
 
-    virtual aaudio_result_t open(int32_t deviceId);
+    std::string dump() const;
+
+    virtual aaudio_result_t open(const AAudioStreamConfiguration& configuration);
 
     int32_t getSampleRate() const { return mStreamInternal->getSampleRate(); }
     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; }
@@ -67,14 +69,17 @@
         mReferenceCount = count;
     }
 
+    bool matches(const AAudioStreamConfiguration& configuration);
+
     virtual AudioStreamInternal *getStreamInternal() = 0;
 
     std::atomic<bool>        mCallbackEnabled;
 
-    std::mutex               mLockStreams;
+    mutable 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..a144c54 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.cpp
+++ b/services/oboeservice/AAudioServiceEndpointCapture.cpp
@@ -42,8 +42,8 @@
     delete mDistributionBuffer;
 }
 
-aaudio_result_t AAudioServiceEndpointCapture::open(int32_t deviceId) {
-    aaudio_result_t result = AAudioServiceEndpoint::open(deviceId);
+aaudio_result_t AAudioServiceEndpointCapture::open(const AAudioStreamConfiguration& configuration) {
+    aaudio_result_t result = AAudioServiceEndpoint::open(configuration);
     if (result == AAUDIO_OK) {
         delete mDistributionBuffer;
         int distributionBufferSizeBytes = getStreamInternal()->getFramesPerBurst()
@@ -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/AAudioServiceEndpointCapture.h b/services/oboeservice/AAudioServiceEndpointCapture.h
index 35857d1..8a3d72f 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.h
+++ b/services/oboeservice/AAudioServiceEndpointCapture.h
@@ -27,7 +27,7 @@
     explicit AAudioServiceEndpointCapture(android::AAudioService &audioService);
     virtual ~AAudioServiceEndpointCapture();
 
-    aaudio_result_t open(int32_t deviceId) override;
+    aaudio_result_t open(const AAudioStreamConfiguration& configuration) override;
 
     AudioStreamInternal *getStreamInternal() override {
         return &mStreamInternalCapture;
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index cc09cc3..1afcc1e 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -46,8 +46,8 @@
 AAudioServiceEndpointPlay::~AAudioServiceEndpointPlay() {
 }
 
-aaudio_result_t AAudioServiceEndpointPlay::open(int32_t deviceId) {
-    aaudio_result_t result = AAudioServiceEndpoint::open(deviceId);
+aaudio_result_t AAudioServiceEndpointPlay::open(const AAudioStreamConfiguration& configuration) {
+    aaudio_result_t result = AAudioServiceEndpoint::open(configuration);
     if (result == AAUDIO_OK) {
         mMixer.allocate(getStreamInternal()->getSamplesPerFrame(),
                         getStreamInternal()->getFramesPerBurst());
@@ -79,9 +79,9 @@
         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
+                float volume = 1.0; // to match legacy volume
                 bool underflowed = mMixer.mix(fifo, volume);
                 underflowCount += underflowed ? 1 : 0;
                 // TODO log underflows in each stream
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.h b/services/oboeservice/AAudioServiceEndpointPlay.h
index 89935ae..c22f510 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.h
+++ b/services/oboeservice/AAudioServiceEndpointPlay.h
@@ -40,7 +40,7 @@
     explicit AAudioServiceEndpointPlay(android::AAudioService &audioService);
     virtual ~AAudioServiceEndpointPlay();
 
-    aaudio_result_t open(int32_t deviceId) override;
+    aaudio_result_t open(const AAudioStreamConfiguration& configuration) override;
 
     AudioStreamInternal *getStreamInternal() override {
         return &mStreamInternalPlay;
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index ee0e7ed..2e20287 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -41,7 +41,25 @@
 }
 
 AAudioServiceStreamBase::~AAudioServiceStreamBase() {
-    close();
+    ALOGD("AAudioServiceStreamBase::~AAudioServiceStreamBase() destroying %p", this);
+    // If the stream is deleted without closing then audio resources will leak.
+    // Not being closed here would indicate an internal error. So we want to find this ASAP.
+    LOG_ALWAYS_FATAL_IF(mState != AAUDIO_STREAM_STATE_CLOSED,
+                        "service stream not closed, state = %d", mState);
+}
+
+std::string AAudioServiceStreamBase::dump() const {
+    std::stringstream result;
+
+    result << "      -------- handle = 0x" << std::hex << mHandle << std::dec << "\n";
+    result << "      state          = " << AAudio_convertStreamStateToText(mState) << "\n";
+    result << "      format         = " << mAudioFormat << "\n";
+    result << "      framesPerBurst = " << mFramesPerBurst << "\n";
+    result << "      channelCount   = " << mSamplesPerFrame << "\n";
+    result << "      capacityFrames = " << mCapacityInFrames << "\n";
+    result << "      owner uid      = " << mOwnerUserId << "\n";
+
+    return result.str();
 }
 
 aaudio_result_t AAudioServiceStreamBase::open(const aaudio::AAudioStreamRequest &request,
@@ -56,10 +74,13 @@
 }
 
 aaudio_result_t AAudioServiceStreamBase::close() {
-    std::lock_guard<std::mutex> lock(mLockUpMessageQueue);
-    delete mUpMessageQueue;
-    mUpMessageQueue = nullptr;
-
+    if (mState != AAUDIO_STREAM_STATE_CLOSED) {
+        stopTimestampThread();
+        std::lock_guard<std::mutex> lock(mLockUpMessageQueue);
+        delete mUpMessageQueue;
+        mUpMessageQueue = nullptr;
+        mState = AAUDIO_STREAM_STATE_CLOSED;
+    }
     return AAUDIO_OK;
 }
 
@@ -71,32 +92,46 @@
 }
 
 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) {
+            disconnect();
+            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(); // warning - this calls a virtual function
+        result = stopTimestampThread();
+        if (result != AAUDIO_OK) {
+            disconnect();
+            return result;
+        }
+        sendServiceEvent(AAUDIO_SERVICE_EVENT_STOPPED);
     }
-    sendServiceEvent(AAUDIO_SERVICE_EVENT_STOPPED);
     mState = AAUDIO_STREAM_STATE_STOPPED;
     return result;
 }
 
+aaudio_result_t AAudioServiceStreamBase::stopTimestampThread() {
+    aaudio_result_t result = AAUDIO_OK;
+    // clear flag that tells thread to loop
+    if (mThreadEnabled.exchange(false)) {
+        result = mAAudioThread.stop();
+    }
+    return result;
+}
+
 aaudio_result_t AAudioServiceStreamBase::flush() {
     sendServiceEvent(AAUDIO_SERVICE_EVENT_FLUSHED);
     mState = AAUDIO_STREAM_STATE_FLUSHED;
@@ -119,14 +154,18 @@
             nextTime = timestampScheduler.nextAbsoluteTime();
         } else  {
             // Sleep until it is time to send the next timestamp.
+            // TODO Wait for a signal with a timeout so that we can stop more quickly.
             AudioClock::sleepUntilNanoTime(nextTime);
         }
     }
     ALOGD("AAudioServiceStreamBase::run() exiting ----------------");
 }
 
-void AAudioServiceStreamBase::processFatalError() {
-    sendServiceEvent(AAUDIO_SERVICE_EVENT_DISCONNECTED);
+void AAudioServiceStreamBase::disconnect() {
+    if (mState != AAUDIO_STREAM_STATE_DISCONNECTED) {
+        sendServiceEvent(AAUDIO_SERVICE_EVENT_DISCONNECTED);
+        mState = AAUDIO_STREAM_STATE_DISCONNECTED;
+    }
 }
 
 aaudio_result_t AAudioServiceStreamBase::sendServiceEvent(aaudio_service_event_t event,
@@ -178,4 +217,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 46ceeae..eed1a03 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();
@@ -49,6 +52,8 @@
         ILLEGAL_THREAD_ID = 0
     };
 
+    std::string dump() const;
+
     // -------------------------------------------------------------------
     /**
      * Open the device.
@@ -73,11 +78,16 @@
      */
     virtual aaudio_result_t stop();
 
+    aaudio_result_t stopTimestampThread();
+
     /**
      *  Discard any data held by the underlying HAL or Service.
      */
     virtual aaudio_result_t flush();
 
+    bool isRunning() const {
+        return mState == AAUDIO_STREAM_STATE_STARTED;
+    }
     // -------------------------------------------------------------------
 
     /**
@@ -111,9 +121,31 @@
 
     void run() override; // to implement Runnable
 
-    void processFatalError();
+    void disconnect();
+
+    uid_t getOwnerUserId() const {
+        return mOwnerUserId;
+    }
+    void setOwnerUserId(uid_t uid) {
+        mOwnerUserId = uid;
+    }
+
+    pid_t getOwnerProcessId() const {
+        return mOwnerProcessId;
+    }
+    void setOwnerProcessId(pid_t pid) {
+        mOwnerProcessId = pid;
+    }
+
+    aaudio_handle_t getHandle() const {
+        return mHandle;
+    }
+    void setHandle(aaudio_handle_t handle) {
+        mHandle = handle;
+    }
 
 protected:
+
     aaudio_result_t writeUpMessageQueue(AAudioServiceMessage *command);
 
     aaudio_result_t sendCurrentTimestamp();
@@ -138,6 +170,10 @@
     int32_t            mSamplesPerFrame = AAUDIO_UNSPECIFIED;
     int32_t            mSampleRate = AAUDIO_UNSPECIFIED;
     int32_t            mCapacityInFrames = AAUDIO_UNSPECIFIED;
+    uid_t              mOwnerUserId = -1;
+    pid_t              mOwnerProcessId = -1;
+private:
+    aaudio_handle_t    mHandle = -1;
 };
 
 } /* namespace aaudio */
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index 2f3ec27..da18f44 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -38,26 +38,29 @@
 #define AAUDIO_SAMPLE_RATE_DEFAULT    48000
 
 /**
- * Stream that uses an MMAP buffer.
+ * Service Stream that uses an MMAP buffer.
  */
 
-AAudioServiceStreamMMAP::AAudioServiceStreamMMAP()
+AAudioServiceStreamMMAP::AAudioServiceStreamMMAP(uid_t serviceUid)
         : AAudioServiceStreamBase()
         , mMmapStreamCallback(new MyMmapStreamCallback(*this))
         , mPreviousFrameCounter(0)
-        , mMmapStream(nullptr) {
-}
-
-AAudioServiceStreamMMAP::~AAudioServiceStreamMMAP() {
-    close();
+        , mMmapStream(nullptr)
+        , mCachedUserId(serviceUid) {
 }
 
 aaudio_result_t AAudioServiceStreamMMAP::close() {
-    mMmapStream.clear(); // TODO review. Is that all we have to do?
-    // Apparently the above close is asynchronous. An attempt to open a new device
-    // right after a close can fail. Also some callbacks may still be in flight!
-    // FIXME Make closing synchronous.
-    AudioClock::sleepForNanos(100 * AAUDIO_NANOS_PER_MILLISECOND);
+    if (mState == AAUDIO_STREAM_STATE_CLOSED) {
+        return AAUDIO_OK;
+    }
+
+    if (mMmapStream != 0) {
+        mMmapStream.clear(); // TODO review. Is that all we have to do?
+        // Apparently the above close is asynchronous. An attempt to open a new device
+        // right after a close can fail. Also some callbacks may still be in flight!
+        // FIXME Make closing synchronous.
+        AudioClock::sleepForNanos(100 * AAUDIO_NANOS_PER_MILLISECOND);
+    }
 
     if (mAudioDataFileDescriptor != -1) {
         ::close(mAudioDataFileDescriptor);
@@ -153,10 +156,29 @@
               status);
         return AAUDIO_ERROR_UNAVAILABLE;
     } else {
-        ALOGD("createMmapBuffer status %d shared_address = %p buffer_size %d burst_size %d",
+        ALOGD("createMmapBuffer status %d shared_address = %p buffer_size %d burst_size %d"
+                "Sharable FD: %s",
               status, mMmapBufferinfo.shared_memory_address,
-              mMmapBufferinfo.buffer_size_frames,
-              mMmapBufferinfo.burst_size_frames);
+              abs(mMmapBufferinfo.buffer_size_frames),
+              mMmapBufferinfo.burst_size_frames,
+              mMmapBufferinfo.buffer_size_frames < 0 ? "Yes" : "No");
+    }
+
+    mCapacityInFrames = mMmapBufferinfo.buffer_size_frames;
+    // FIXME: the audio HAL indicates if the shared memory fd can be shared outside of audioserver
+    // by returning a negative buffer size
+    if (mCapacityInFrames < 0) {
+        // Exclusive mode is possible from any client
+        mCapacityInFrames = -mCapacityInFrames;
+    } else {
+        // exclusive mode is only possible if the final fd destination is inside audioserver
+        if ((mMmapClient.clientUid != mCachedUserId) &&
+                configurationInput.getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
+            // Fallback is handled by caller but indicate what is possible in case
+            // this is used in the future
+            configurationOutput.setSharingMode(AAUDIO_SHARING_MODE_SHARED);
+            return AAUDIO_ERROR_UNAVAILABLE;
+        }
     }
 
     // Get information about the stream and pass it back to the caller.
@@ -166,7 +188,6 @@
 
     mAudioDataFileDescriptor = mMmapBufferinfo.shared_memory_fd;
     mFramesPerBurst = mMmapBufferinfo.burst_size_frames;
-    mCapacityInFrames = mMmapBufferinfo.buffer_size_frames;
     mAudioFormat = AAudioConvert_androidToAAudioDataFormat(config.format);
     mSampleRate = config.sample_rate;
 
@@ -206,7 +227,7 @@
     status_t status = mMmapStream->start(mMmapClient, &mPortHandle);
     if (status != OK) {
         ALOGE("AAudioServiceStreamMMAP::start() mMmapStream->start() returned %d", status);
-        processFatalError();
+        disconnect();
         result = AAudioConvert_androidToAAudioResult(status);
     } else {
         result = AAudioServiceStreamBase::start();
@@ -244,18 +265,17 @@
     return AAudioServiceStreamBase::flush();;
 }
 
-
 aaudio_result_t AAudioServiceStreamMMAP::getFreeRunningPosition(int64_t *positionFrames,
                                                                 int64_t *timeNanos) {
     struct audio_mmap_position position;
     if (mMmapStream == nullptr) {
-        processFatalError();
+        disconnect();
         return AAUDIO_ERROR_NULL;
     }
     status_t status = mMmapStream->getMmapPosition(&position);
     if (status != OK) {
         ALOGE("sendCurrentTimestamp(): getMmapPosition() returned %d", status);
-        processFatalError();
+        disconnect();
         return AAudioConvert_androidToAAudioResult(status);
     } else {
         mFramesRead.update32(position.position_frames);
@@ -266,7 +286,8 @@
 }
 
 void AAudioServiceStreamMMAP::onTearDown() {
-    ALOGE("AAudioServiceStreamMMAP::onTearDown() called - TODO");
+    ALOGD("AAudioServiceStreamMMAP::onTearDown() called");
+    disconnect();
 };
 
 void AAudioServiceStreamMMAP::onVolumeChanged(audio_channel_mask_t channels,
@@ -281,7 +302,7 @@
     ALOGD("AAudioServiceStreamMMAP::onRoutingChanged() called with %d, old = %d",
           deviceId, mPortHandle);
     if (mPortHandle > 0 && mPortHandle != deviceId) {
-        sendServiceEvent(AAUDIO_SERVICE_EVENT_DISCONNECTED);
+        disconnect();
     }
     mPortHandle = deviceId;
 };
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.h b/services/oboeservice/AAudioServiceStreamMMAP.h
index fe75a10..257bea9 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.h
+++ b/services/oboeservice/AAudioServiceStreamMMAP.h
@@ -43,9 +43,8 @@
     , public android::MmapStreamCallback {
 
 public:
-    AAudioServiceStreamMMAP();
-    virtual ~AAudioServiceStreamMMAP();
-
+    AAudioServiceStreamMMAP(uid_t serviceUid);
+    virtual ~AAudioServiceStreamMMAP() = default;
 
     aaudio_result_t open(const aaudio::AAudioStreamRequest &request,
                                  aaudio::AAudioStreamConfiguration &configurationOutput) override;
@@ -134,6 +133,7 @@
     struct audio_mmap_buffer_info             mMmapBufferinfo;
     android::MmapStreamInterface::Client      mMmapClient;
     audio_port_handle_t                       mPortHandle = -1; // TODO review best default
+    uid_t                                     mCachedUserId = -1;
 };
 
 } // namespace aaudio
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index f246fc02..9cc5cbc 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -44,15 +44,11 @@
     {
 }
 
-AAudioServiceStreamShared::~AAudioServiceStreamShared() {
-    close();
-}
-
 int32_t AAudioServiceStreamShared::calculateBufferCapacity(int32_t requestedCapacityFrames,
                                                            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 +73,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 +81,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 +93,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);
@@ -104,13 +102,12 @@
     }
 
     const AAudioStreamConfiguration &configurationInput = request.getConstantConfiguration();
-    int32_t deviceId = configurationInput.getDeviceId();
     aaudio_direction_t direction = request.getDirection();
 
     AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
-    mServiceEndpoint = mEndpointManager.openEndpoint(mAudioService, deviceId, direction);
+    mServiceEndpoint = mEndpointManager.openEndpoint(mAudioService, configurationOutput, direction);
     if (mServiceEndpoint == nullptr) {
-        ALOGE("AAudioServiceStreamShared::open(), mServiceEndPoint = %p", mServiceEndpoint);
+        ALOGE("AAudioServiceStreamShared::open() mServiceEndPoint = %p", mServiceEndpoint);
         return AAUDIO_ERROR_UNAVAILABLE;
     }
 
@@ -119,7 +116,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 +125,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 +135,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 +157,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 +172,7 @@
     configurationOutput.setAudioFormat(mAudioFormat);
     configurationOutput.setDeviceId(mServiceEndpoint->getDeviceId());
 
-    result = mServiceEndpoint->registerStream(this);
+    result = mServiceEndpoint->registerStream(keep);
     if (result != AAUDIO_OK) {
         goto error;
     }
@@ -201,7 +198,7 @@
     aaudio_result_t result = endpoint->startStream(this);
     if (result != AAUDIO_OK) {
         ALOGE("AAudioServiceStreamShared::start() mServiceEndpoint returned %d", result);
-        processFatalError();
+        disconnect();
     } else {
         result = AAudioServiceStreamBase::start();
     }
@@ -221,7 +218,7 @@
     aaudio_result_t result = endpoint->stopStream(this);
     if (result != AAUDIO_OK) {
         ALOGE("AAudioServiceStreamShared::pause() mServiceEndpoint returned %d", result);
-        processFatalError();
+        disconnect(); // TODO should we return or pause Base first?
     }
     return AAudioServiceStreamBase::pause();
 }
@@ -234,7 +231,7 @@
     aaudio_result_t result = endpoint->stopStream(this);
     if (result != AAUDIO_OK) {
         ALOGE("AAudioServiceStreamShared::stop() mServiceEndpoint returned %d", result);
-        processFatalError();
+        disconnect();
     }
     return AAudioServiceStreamBase::stop();
 }
@@ -259,20 +256,27 @@
 }
 
 aaudio_result_t AAudioServiceStreamShared::close()  {
-    pause();
-    // TODO wait for pause() to synchronize
-    AAudioServiceEndpoint *endpoint = mServiceEndpoint;
-    if (endpoint != nullptr) {
-        endpoint->unregisterStream(this);
-
-        AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
-        mEndpointManager.closeEndpoint(endpoint);
-        mServiceEndpoint = nullptr;
+    if (mState == AAUDIO_STREAM_STATE_CLOSED) {
+        return AAUDIO_OK;
     }
+
+    AAudioServiceEndpoint *endpoint = mServiceEndpoint;
+    if (endpoint == nullptr) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+    endpoint->stopStream(this);
+
+    endpoint->unregisterStream(this);
+
+    AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
+    mEndpointManager.closeEndpoint(endpoint);
+    mServiceEndpoint = nullptr;
+
     if (mAudioDataQueue != nullptr) {
         delete mAudioDataQueue;
         mAudioDataQueue = nullptr;
     }
+
     return AAudioServiceStreamBase::close();
 }
 
@@ -291,11 +295,6 @@
 void AAudioServiceStreamShared::onStop() {
 }
 
-void AAudioServiceStreamShared::onDisconnect() {
-    mServiceEndpoint->close();
-    mServiceEndpoint = nullptr;
-}
-
 void AAudioServiceStreamShared::markTransferTime(int64_t nanoseconds) {
     mMarkedPosition = mAudioDataQueue->getFifoBuffer()->getReadCounter();
     mMarkedTime = nanoseconds;
diff --git a/services/oboeservice/AAudioServiceStreamShared.h b/services/oboeservice/AAudioServiceStreamShared.h
index 35af434..742c5af 100644
--- a/services/oboeservice/AAudioServiceStreamShared.h
+++ b/services/oboeservice/AAudioServiceStreamShared.h
@@ -44,7 +44,7 @@
 
 public:
     AAudioServiceStreamShared(android::AAudioService &aAudioService);
-    virtual ~AAudioServiceStreamShared();
+    virtual ~AAudioServiceStreamShared() = default;
 
     aaudio_result_t open(const aaudio::AAudioStreamRequest &request,
                          aaudio::AAudioStreamConfiguration &configurationOutput) override;
@@ -89,8 +89,6 @@
 
     void onStop();
 
-    void onDisconnect();
-
 protected:
 
     aaudio_result_t getDownDataDescription(AudioEndpointParcelable &parcelable) override;
diff --git a/services/oboeservice/Android.mk b/services/oboeservice/Android.mk
index 7f7d465..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 \
@@ -50,6 +51,7 @@
     libbinder \
     libcutils \
     libmediautils \
+    libserviceutility \
     libutils \
     liblog