reduce number of binder calls from mediaserver

Reduce the number of audio port, audio patch and
IO config changed binder calls from mediaserver to
client processes:
- Do not call IO config changed callback if selected
device is the same as previously selected one on a given
audio flinger playback or capture thread.
- Do not call the audio port or audo patch list update
callback on a client if this client as no listener registered.

Bug: 22045560.

Change-Id: If780e105404de79b7cb5c80c27b793ceb6b1c423
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 26cffa6..06116a5 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -408,8 +408,8 @@
         AudioPolicyServiceClient() {
         }
 
-        status_t addAudioPortCallback(const sp<AudioPortCallback>& callback);
-        status_t removeAudioPortCallback(const sp<AudioPortCallback>& callback);
+        int addAudioPortCallback(const sp<AudioPortCallback>& callback);
+        int removeAudioPortCallback(const sp<AudioPortCallback>& callback);
 
         // DeathRecipient
         virtual void binderDied(const wp<IBinder>& who);
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index ee462a0..6b93f6f 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -149,6 +149,8 @@
 
     virtual void registerClient(const sp<IAudioPolicyServiceClient>& client) = 0;
 
+    virtual void setAudioPortCallbacksEnabled(bool enabled) = 0;
+
     virtual status_t acquireSoundTriggerSession(audio_session_t *session,
                                            audio_io_handle_t *ioHandle,
                                            audio_devices_t *device) = 0;
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 6c2c226..f13bcf3 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -1043,7 +1043,11 @@
     if (gAudioPolicyServiceClient == 0) {
         return NO_INIT;
     }
-    return gAudioPolicyServiceClient->addAudioPortCallback(callback);
+    int ret = gAudioPolicyServiceClient->addAudioPortCallback(callback);
+    if (ret == 1) {
+        aps->setAudioPortCallbacksEnabled(true);
+    }
+    return (ret < 0) ? INVALID_OPERATION : NO_ERROR;
 }
 
 /*static*/
@@ -1056,7 +1060,11 @@
     if (gAudioPolicyServiceClient == 0) {
         return NO_INIT;
     }
-    return gAudioPolicyServiceClient->removeAudioPortCallback(callback);
+    int ret = gAudioPolicyServiceClient->removeAudioPortCallback(callback);
+    if (ret == 0) {
+        aps->setAudioPortCallbacksEnabled(false);
+    }
+    return (ret < 0) ? INVALID_OPERATION : NO_ERROR;
 }
 
 status_t AudioSystem::addAudioDeviceCallback(
@@ -1138,20 +1146,20 @@
 
 // ---------------------------------------------------------------------------
 
-status_t AudioSystem::AudioPolicyServiceClient::addAudioPortCallback(
+int AudioSystem::AudioPolicyServiceClient::addAudioPortCallback(
         const sp<AudioPortCallback>& callback)
 {
     Mutex::Autolock _l(mLock);
     for (size_t i = 0; i < mAudioPortCallbacks.size(); i++) {
         if (mAudioPortCallbacks[i] == callback) {
-            return INVALID_OPERATION;
+            return -1;
         }
     }
     mAudioPortCallbacks.add(callback);
-    return NO_ERROR;
+    return mAudioPortCallbacks.size();
 }
 
-status_t AudioSystem::AudioPolicyServiceClient::removeAudioPortCallback(
+int AudioSystem::AudioPolicyServiceClient::removeAudioPortCallback(
         const sp<AudioPortCallback>& callback)
 {
     Mutex::Autolock _l(mLock);
@@ -1162,10 +1170,10 @@
         }
     }
     if (i == mAudioPortCallbacks.size()) {
-        return INVALID_OPERATION;
+        return -1;
     }
     mAudioPortCallbacks.removeAt(i);
-    return NO_ERROR;
+    return mAudioPortCallbacks.size();
 }
 
 
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index fd18f17..3348441 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -72,7 +72,8 @@
     GET_PHONE_STATE,
     REGISTER_POLICY_MIXES,
     START_AUDIO_SOURCE,
-    STOP_AUDIO_SOURCE
+    STOP_AUDIO_SOURCE,
+    SET_AUDIO_PORT_CALLBACK_ENABLED,
 };
 
 #define MAX_ITEMS_PER_LIST 1024
@@ -646,6 +647,14 @@
         remote()->transact(REGISTER_CLIENT, data, &reply);
     }
 
+    virtual void setAudioPortCallbacksEnabled(bool enabled)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(enabled ? 1 : 0);
+        remote()->transact(SET_AUDIO_PORT_CALLBACK_ENABLED, data, &reply);
+    }
+
     virtual status_t acquireSoundTriggerSession(audio_session_t *session,
                                             audio_io_handle_t *ioHandle,
                                             audio_devices_t *device)
@@ -1219,6 +1228,12 @@
             return NO_ERROR;
         } break;
 
+        case SET_AUDIO_PORT_CALLBACK_ENABLED: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            setAudioPortCallbacksEnabled(data.readInt32() == 1);
+            return NO_ERROR;
+        } break;
+
         case ACQUIRE_SOUNDTRIGGER_SESSION: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
             sp<IAudioPolicyServiceClient> client = interface_cast<IAudioPolicyServiceClient>(
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 410fff5..c8f9be0 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -530,7 +530,7 @@
         // RecordThread::readInputParameters_l()
         //FIXME: mStandby should be true here. Is this some kind of hack?
         mStandby(false), mOutDevice(outDevice), mInDevice(inDevice),
-        mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),
+        mPrevInDevice(AUDIO_DEVICE_NONE), mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),
         // mName will be set by concrete (non-virtual) subclass
         mDeathRecipient(new PMDeathRecipient(this)),
         mSystemReady(systemReady)
@@ -3131,6 +3131,7 @@
     for (size_t i = 0; i < mEffectChains.size(); i++) {
         mEffectChains[i]->setDevice_l(type);
     }
+    bool configChanged = mOutDevice != type;
     mOutDevice = type;
     mPatch = *patch;
 
@@ -3159,7 +3160,9 @@
                 param.toString().string());
         *handle = AUDIO_PATCH_HANDLE_NONE;
     }
-    sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
+    if (configChanged) {
+        sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
+    }
     return status;
 }
 
@@ -6796,6 +6799,9 @@
             status = BAD_VALUE;
         } else {
             mInDevice = value;
+            if (value != AUDIO_DEVICE_NONE) {
+                mPrevInDevice = value;
+            }
             // disable AEC and NS if the device is a BT SCO headset supporting those
             // pre processings
             if (mTracks.size() > 0) {
@@ -7079,7 +7085,10 @@
         *handle = AUDIO_PATCH_HANDLE_NONE;
     }
 
-    sendIoConfigEvent_l(AUDIO_INPUT_CONFIG_CHANGED);
+    if (mInDevice != mPrevInDevice) {
+        sendIoConfigEvent_l(AUDIO_INPUT_CONFIG_CHANGED);
+        mPrevInDevice = mInDevice;
+    }
 
     return status;
 }
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index b12b091..0783371 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -436,6 +436,7 @@
                 bool                    mStandby;     // Whether thread is currently in standby.
                 audio_devices_t         mOutDevice;   // output device
                 audio_devices_t         mInDevice;    // input device
+                audio_devices_t         mPrevInDevice;    // previous input device
                 struct audio_patch      mPatch;
                 audio_source_t          mAudioSource;
 
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index c5f4fb7..fbe4f18 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -166,6 +166,17 @@
     }
 }
 
+void AudioPolicyService::setAudioPortCallbacksEnabled(bool enabled)
+{
+    Mutex::Autolock _l(mNotificationClientsLock);
+
+    uid_t uid = IPCThreadState::self()->getCallingUid();
+    if (mNotificationClients.indexOfKey(uid) < 0) {
+        return;
+    }
+    mNotificationClients.valueFor(uid)->setAudioPortCallbacksEnabled(enabled);
+}
+
 // removeNotificationClient() is called when the client process dies.
 void AudioPolicyService::removeNotificationClient(uid_t uid)
 {
@@ -246,7 +257,8 @@
 AudioPolicyService::NotificationClient::NotificationClient(const sp<AudioPolicyService>& service,
                                                      const sp<IAudioPolicyServiceClient>& client,
                                                      uid_t uid)
-    : mService(service), mUid(uid), mAudioPolicyServiceClient(client)
+    : mService(service), mUid(uid), mAudioPolicyServiceClient(client),
+      mAudioPortCallbacksEnabled(false)
 {
 }
 
@@ -265,14 +277,14 @@
 
 void AudioPolicyService::NotificationClient::onAudioPortListUpdate()
 {
-    if (mAudioPolicyServiceClient != 0) {
+    if (mAudioPolicyServiceClient != 0 && mAudioPortCallbacksEnabled) {
         mAudioPolicyServiceClient->onAudioPortListUpdate();
     }
 }
 
 void AudioPolicyService::NotificationClient::onAudioPatchListUpdate()
 {
-    if (mAudioPolicyServiceClient != 0) {
+    if (mAudioPolicyServiceClient != 0 && mAudioPortCallbacksEnabled) {
         mAudioPolicyServiceClient->onAudioPatchListUpdate();
     }
 }
@@ -285,6 +297,12 @@
     }
 }
 
+void AudioPolicyService::NotificationClient::setAudioPortCallbacksEnabled(bool enabled)
+{
+    mAudioPortCallbacksEnabled = enabled;
+}
+
+
 void AudioPolicyService::binderDied(const wp<IBinder>& who) {
     ALOGW("binderDied() %p, calling pid %d", who.unsafe_get(),
             IPCThreadState::self()->getCallingPid());
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index eb50cdd..a0d5aa2 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -185,6 +185,8 @@
 
     virtual void registerClient(const sp<IAudioPolicyServiceClient>& client);
 
+    virtual void setAudioPortCallbacksEnabled(bool enabled);
+
     virtual status_t acquireSoundTriggerSession(audio_session_t *session,
                                            audio_io_handle_t *ioHandle,
                                            audio_devices_t *device);
@@ -507,6 +509,7 @@
                             void      onAudioPortListUpdate();
                             void      onAudioPatchListUpdate();
                             void      onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
+                            void      setAudioPortCallbacksEnabled(bool enabled);
 
                 // IBinder::DeathRecipient
                 virtual     void        binderDied(const wp<IBinder>& who);
@@ -518,6 +521,7 @@
         const wp<AudioPolicyService>        mService;
         const uid_t                         mUid;
         const sp<IAudioPolicyServiceClient> mAudioPolicyServiceClient;
+              bool                          mAudioPortCallbacksEnabled;
     };
 
     // Internal dump utilities.