aaudio: close MMAP stream if client dies

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

Use sp<> to track ServiceStreams.

Bug: 38267698
Test: test_no_close.cpp
Change-Id: I5f1699ed3b8b7bd960947c0028a89ca8419ce7a0
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.cpp b/media/libaaudio/src/binding/AAudioBinderClient.cpp
index c45bd71..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
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.h b/media/libaaudio/src/binding/AAudioBinderClient.h
index 7cf7bf8..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
@@ -87,6 +96,45 @@
 
     aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
                                                   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 d6a130f..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
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 e4bf82a..97fbaaa 100644
--- a/media/libaaudio/src/binding/IAAudioService.cpp
+++ b/media/libaaudio/src/binding/IAAudioService.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
 #include <aaudio/AAudio.h>
 #include <binder/IPCThreadState.h>
 
@@ -41,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());
@@ -56,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);
@@ -233,7 +244,7 @@
 
 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 tid;
@@ -242,6 +253,14 @@
     ALOGV("BnAAudioService::onTransact(%i) %i", code, flags);
 
     switch(code) {
+        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);
@@ -250,28 +269,28 @@
             // Override the uid and pid from the client in case they are incorrect.
             request.setUserId(IPCThreadState::self()->getCallingUid());
             request.setProcessId(IPCThreadState::self()->getCallingPid());
-            stream = openStream(request, configuration);
-            //ALOGD("BnAAudioService::onTransact OPEN_STREAM server handle = 0x%08X ----", stream);
-            reply->writeInt32(stream);
+            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: {
             CHECK_INTERFACE(IAAudioService, data, reply);
-            data.readInt32(&stream);
-            result = closeStream(stream);
+            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: {
             CHECK_INTERFACE(IAAudioService, data, reply);
-            data.readInt32(&stream);
+            data.readInt32(&streamHandle);
             aaudio::AudioEndpointParcelable parcelable;
-            result = getStreamDescription(stream, parcelable);
+            result = getStreamDescription(streamHandle, parcelable);
             if (result != AAUDIO_OK) {
                 return AAudioConvert_aaudioToAndroidStatus(result);
             }
@@ -288,63 +307,63 @@
 
         case START_STREAM: {
             CHECK_INTERFACE(IAAudioService, data, reply);
-            data.readInt32(&stream);
-            result = startStream(stream);
+            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: {
             CHECK_INTERFACE(IAAudioService, data, reply);
-            data.readInt32(&stream);
-            result = pauseStream(stream);
+            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: {
             CHECK_INTERFACE(IAAudioService, data, reply);
-            data.readInt32(&stream);
-            result = stopStream(stream);
+            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: {
             CHECK_INTERFACE(IAAudioService, data, reply);
-            data.readInt32(&stream);
-            result = flushStream(stream);
+            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: {
             CHECK_INTERFACE(IAAudioService, data, reply);
-            data.readInt32(&stream);
+            data.readInt32(&streamHandle);
             data.readInt32(&tid);
             data.readInt64(&nanoseconds);
-            result = registerAudioThread(stream, 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: {
             CHECK_INTERFACE(IAAudioService, data, reply);
-            data.readInt32(&stream);
+            data.readInt32(&streamHandle);
             data.readInt32(&tid);
-            result = unregisterAudioThread(stream, 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 071c5b8..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