audio policy: remove AudioSession class

Now that clients are tracked individually, tracking by
audio session is no needed anymore.
Modify management of client activity, preempted sound trigger
sessions and silenced uids to rely on RecordClientDescriptor
instead of AudioSession.

Test: CTS test for AudioRecord
Test: manual capture audio tests for all use cases

Change-Id: Ieef3e05daea98aec9320412393f912bd6bd7e046
diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk
index 5ba2d4a..bacb780 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.mk
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -19,7 +19,6 @@
     src/SoundTriggerSession.cpp \
     src/VolumeCurve.cpp \
     src/TypeConverter.cpp \
-    src/AudioSession.cpp \
     src/ClientDescriptor.cpp
 
 LOCAL_SHARED_LIBRARIES := \
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index 0d1d8c3..72d5a8c 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -16,19 +16,19 @@
 
 #pragma once
 
-#include "AudioIODescriptorInterface.h"
-#include "AudioPort.h"
-#include "AudioSession.h"
-#include "ClientDescriptor.h"
-#include <utils/Errors.h>
 #include <system/audio.h>
+#include <utils/Errors.h>
 #include <utils/SortedVector.h>
 #include <utils/KeyedVector.h>
+#include "AudioIODescriptorInterface.h"
+#include "AudioPort.h"
+#include "ClientDescriptor.h"
 
 namespace android {
 
 class IOProfile;
 class AudioMix;
+class AudioPolicyClientInterface;
 
 // descriptor for audio inputs. Used to maintain current configuration of each opened audio input
 // and keep track of the usage of this input.
@@ -39,7 +39,6 @@
                                   AudioPolicyClientInterface *clientInterface);
     audio_port_handle_t getId() const;
     audio_module_handle_t getModuleHandle() const;
-    uint32_t getOpenRefCount() const;
 
     status_t    dump(int fd);
 
@@ -56,19 +55,13 @@
     SortedVector<audio_session_t> getPreemptedSessions() const;
     bool hasPreemptedSession(audio_session_t session) const;
     void clearPreemptedSessions();
-    bool isActive() const;
+    bool isActive() const { return mGlobalActiveCount > 0; }
     bool isSourceActive(audio_source_t source) const;
     audio_source_t inputSource(bool activeOnly = false) const;
     bool isSoundTrigger() const;
-    status_t addAudioSession(audio_session_t session,
-                             const sp<AudioSession>& audioSession);
-    status_t removeAudioSession(audio_session_t session);
-    sp<AudioSession> getAudioSession(audio_session_t session) const;
-    AudioSessionCollection getAudioSessions(bool activeOnly) const;
-    size_t getAudioSessionCount(bool activeOnly) const;
     audio_source_t getHighestPrioritySource(bool activeOnly) const;
-    void changeRefCount(audio_session_t session, int delta);
-
+    void setClientActive(const sp<RecordClientDescriptor>& client, bool active);
+    int32_t activeCount() { return mGlobalActiveCount; }
 
     // implementation of AudioIODescriptorInterface
     audio_config_base_t getConfig() const override;
@@ -82,10 +75,10 @@
                   audio_input_flags_t flags,
                   audio_io_handle_t *input);
     // Called when a stream is about to be started.
-    // Note: called after changeRefCount(session, 1)
+    // Note: called after setClientActive(client, true)
     status_t start();
     // Called after a stream is stopped
-    // Note: called after changeRefCount(session, -1)
+    // Note: called after setClientActive(client, false)
     void stop();
     void close();
 
@@ -96,12 +89,10 @@
 
  private:
 
-    void updateSessionRecordingConfiguration(int event, const sp<AudioSession>& audioSession);
+    void updateClientRecordingConfiguration(int event, const sp<RecordClientDescriptor>& client);
 
     audio_patch_handle_t          mPatchHandle;
     audio_port_handle_t           mId;
-    // audio sessions attached to this input
-    AudioSessionCollection        mSessions;
     // Because a preemptible capture session can preempt another one, we end up in an endless loop
     // situation were each session is allowed to restart after being preempted,
     // thus preempting the other one which restarts and so on.
@@ -110,7 +101,7 @@
     // We also inherit sessions from the preempted input to avoid a 3 way preemption loop etc...
     SortedVector<audio_session_t> mPreemptedSessions;
     AudioPolicyClientInterface *mClientInterface;
-    uint32_t mGlobalRefCount;  // non-session-specific ref count
+    int32_t mGlobalActiveCount;  // non-client-specific activity ref count
 
     RecordClientMap mClients;
 };
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
deleted file mode 100644
index 1636d3a..0000000
--- a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#pragma once
-
-#include <system/audio.h>
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <media/AudioPolicy.h>
-#include <media/IAudioPolicyServiceClient.h>
-#include "AudioIODescriptorInterface.h"
-
-namespace android {
-
-class AudioPolicyClientInterface;
-
-class AudioSession : public RefBase
-{
-public:
-    AudioSession(audio_session_t session,
-                 audio_source_t inputSource,
-                 audio_format_t format,
-                 uint32_t sampleRate,
-                 audio_channel_mask_t channelMask,
-                 audio_input_flags_t flags,
-                 uid_t uid,
-                 bool isSoundTrigger);
-
-    status_t dump(int fd, int spaces, int index) const;
-
-    audio_session_t session() const { return mRecordClientInfo.session; }
-    audio_source_t inputSource()const { return mRecordClientInfo.source; }
-    audio_format_t format() const { return mConfig.format; }
-    uint32_t sampleRate() const { return mConfig.sample_rate; }
-    audio_channel_mask_t channelMask() const { return mConfig.channel_mask; }
-    audio_config_base config() const { return mConfig; }
-    record_client_info_t recordClientInfo() const { return mRecordClientInfo; }
-    audio_input_flags_t flags() const { return mFlags; }
-    uid_t uid() const { return mRecordClientInfo.uid; }
-    void setUid(uid_t uid) { mRecordClientInfo.uid = uid; }
-    bool matches(const sp<AudioSession> &other) const;
-    bool isSoundTrigger() const { return mIsSoundTrigger; }
-    void setSilenced(bool silenced) { mSilenced = silenced; }
-    bool isSilenced() const { return mSilenced; }
-    uint32_t openCount() const { return mOpenCount; } ;
-    uint32_t activeCount() const { return mActiveCount; } ;
-
-    uint32_t changeOpenCount(int delta);
-    uint32_t changeActiveCount(int delta);
-
-private:
-    record_client_info_t mRecordClientInfo;
-    const struct audio_config_base mConfig;
-    const audio_input_flags_t mFlags;
-    bool  mIsSoundTrigger;
-    bool mSilenced;
-    uint32_t  mOpenCount;
-    uint32_t  mActiveCount;
-};
-
-class AudioSessionCollection :
-    public DefaultKeyedVector<audio_session_t, sp<AudioSession> >
-{
-public:
-    status_t addSession(audio_session_t session,
-                             const sp<AudioSession>& audioSession);
-
-    status_t removeSession(audio_session_t session);
-
-    uint32_t getOpenCount() const;
-
-    AudioSessionCollection getActiveSessions() const;
-    size_t getActiveSessionCount() const;
-    bool hasActiveSession() const;
-    bool isSourceActive(audio_source_t source) const;
-    audio_source_t getHighestPrioritySource(bool activeOnly) const;
-
-    status_t dump(int fd, int spaces) const;
-};
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
index cc751b1..1a3300d 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
@@ -107,9 +107,9 @@
     RecordClientDescriptor(audio_port_handle_t portId, uid_t uid, audio_session_t sessionId,
                         audio_attributes_t attributes, audio_config_base_t config,
                         audio_port_handle_t preferredDeviceId,
-                        audio_source_t source, audio_input_flags_t flags) :
+                        audio_source_t source, audio_input_flags_t flags, bool isSoundTrigger) :
         ClientDescriptor(portId, uid, sessionId, attributes, config, preferredDeviceId),
-        mSource(source), mFlags(flags) {}
+        mSource(source), mFlags(flags), mIsSoundTrigger(isSoundTrigger), mSilenced(false) {}
     ~RecordClientDescriptor() override = default;
 
     using ClientDescriptor::dump;
@@ -117,10 +117,15 @@
 
     audio_source_t source() const { return mSource; }
     audio_input_flags_t flags() const { return mFlags; }
+    bool isSoundTrigger() const { return mIsSoundTrigger; }
+    void setSilenced(bool silenced) { mSilenced = silenced; }
+    bool isSilenced() const { return mSilenced; }
 
 private:
     const audio_source_t mSource;
     const audio_input_flags_t mFlags;
+    const bool mIsSoundTrigger;
+          bool mSilenced;
 };
 
 class SourceClientDescriptor: public TrackClientDescriptor
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 3c7562e..e25b0fe 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -17,13 +17,13 @@
 #define LOG_TAG "APM::AudioInputDescriptor"
 //#define LOG_NDEBUG 0
 
+#include <media/AudioPolicy.h>
+#include <policy.h>
 #include <AudioPolicyInterface.h>
 #include "AudioInputDescriptor.h"
 #include "IOProfile.h"
 #include "AudioGain.h"
 #include "HwModule.h"
-#include <media/AudioPolicy.h>
-#include <policy.h>
 
 namespace android {
 
@@ -32,7 +32,7 @@
     : mIoHandle(0),
       mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL),
       mProfile(profile), mPatchHandle(AUDIO_PATCH_HANDLE_NONE), mId(0),
-      mClientInterface(clientInterface), mGlobalRefCount(0)
+      mClientInterface(clientInterface), mGlobalActiveCount(0)
 {
     if (profile != NULL) {
         profile->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
@@ -50,11 +50,6 @@
     return mProfile->getModuleHandle();
 }
 
-uint32_t AudioInputDescriptor::getOpenRefCount() const
-{
-    return mSessions.getOpenCount();
-}
-
 audio_port_handle_t AudioInputDescriptor::getId() const
 {
     return mId;
@@ -118,57 +113,45 @@
     mPreemptedSessions.clear();
 }
 
-bool AudioInputDescriptor::isActive() const {
-    return mSessions.hasActiveSession();
-}
-
 bool AudioInputDescriptor::isSourceActive(audio_source_t source) const
 {
-    return mSessions.isSourceActive(source);
+    for (const auto &client : mClients) {
+        if (client.second->active() &&
+            ((client.second->source() == source) ||
+                ((source == AUDIO_SOURCE_VOICE_RECOGNITION) &&
+                    (client.second->source() == AUDIO_SOURCE_HOTWORD) &&
+                    client.second->isSoundTrigger()))) {
+            return true;
+        }
+    }
+    return false;
 }
 
 audio_source_t AudioInputDescriptor::getHighestPrioritySource(bool activeOnly) const
 {
+    audio_source_t source = AUDIO_SOURCE_DEFAULT;
+    int32_t priority = -1;
 
-    return mSessions.getHighestPrioritySource(activeOnly);
+    for (const auto &client : mClients) {
+        if (activeOnly && !client.second->active() ) {
+            continue;
+        }
+        int32_t curPriority = source_priority(client.second->source());
+        if (curPriority > priority) {
+            priority = curPriority;
+            source = client.second->source();
+        }
+    }
+    return source;
 }
 
 bool AudioInputDescriptor::isSoundTrigger() const {
-    // sound trigger and non sound trigger sessions are not mixed
-    // on a given input
-    return mSessions.valueAt(0)->isSoundTrigger();
-}
-
-sp<AudioSession> AudioInputDescriptor::getAudioSession(
-                                              audio_session_t session) const {
-    return mSessions.valueFor(session);
-}
-
-AudioSessionCollection AudioInputDescriptor::getAudioSessions(bool activeOnly) const
-{
-    if (activeOnly) {
-        return mSessions.getActiveSessions();
-    } else {
-        return mSessions;
+    // sound trigger and non sound trigger clients are not mixed on a given input
+    // so check only first client
+    if (mClients.size() == 0) {
+        return false;
     }
-}
-
-size_t AudioInputDescriptor::getAudioSessionCount(bool activeOnly) const
-{
-    if (activeOnly) {
-        return mSessions.getActiveSessionCount();
-    } else {
-        return mSessions.size();
-    }
-}
-
-status_t AudioInputDescriptor::addAudioSession(audio_session_t session,
-                         const sp<AudioSession>& audioSession) {
-    return mSessions.addSession(session, audioSession);
-}
-
-status_t AudioInputDescriptor::removeAudioSession(audio_session_t session) {
-    return mSessions.removeSession(session);
+    return mClients.cbegin()->second->isSoundTrigger();
 }
 
 audio_patch_handle_t AudioInputDescriptor::getPatchHandle() const
@@ -179,9 +162,9 @@
 void AudioInputDescriptor::setPatchHandle(audio_patch_handle_t handle)
 {
     mPatchHandle = handle;
-    for (size_t i = 0; i < mSessions.size(); i++) {
-        if (mSessions[i]->activeCount() > 0) {
-            updateSessionRecordingConfiguration(RECORD_CONFIG_EVENT_START, mSessions[i]);
+    for (const auto &client : mClients) {
+        if (client.second->active()) {
+            updateClientRecordingConfiguration(RECORD_CONFIG_EVENT_START, client.second);
         }
     }
 }
@@ -243,7 +226,7 @@
 
 status_t AudioInputDescriptor::start()
 {
-    if (getAudioSessionCount(true/*activeOnly*/) == 1) {
+    if (mGlobalActiveCount == 1) {
         if (!mProfile->canStartNewIo()) {
             ALOGI("%s mProfile->curActiveCount %d", __func__, mProfile->curActiveCount);
             return INVALID_OPERATION;
@@ -270,7 +253,7 @@
         LOG_ALWAYS_FATAL_IF(mProfile->curOpenCount < 1, "%s profile open count %u",
                             __FUNCTION__, mProfile->curOpenCount);
         // do not call stop() here as stop() is supposed to be called after
-        //  changeRefCount(session, -1) and we don't know how many sessions
+        //  setClientActive(client, false) and we don't know how many clients
         // are still active at this time
         if (isActive()) {
             mProfile->curActiveCount--;
@@ -280,27 +263,28 @@
     }
 }
 
-void AudioInputDescriptor::changeRefCount(audio_session_t session, int delta)
+void AudioInputDescriptor::setClientActive(const sp<RecordClientDescriptor>& client, bool active)
 {
-    sp<AudioSession> audioSession = mSessions.valueFor(session);
-    if (audioSession == 0) {
+    if (mClients.find(client->portId()) == mClients.end()
+         || active == client->active()) {
         return;
     }
-    // handle session-independent ref count
-    uint32_t oldGlobalRefCount = mGlobalRefCount;
-    if ((delta + (int)mGlobalRefCount) < 0) {
-        ALOGW("changeRefCount() invalid delta %d globalRefCount %d", delta, mGlobalRefCount);
-        delta = -((int)mGlobalRefCount);
+
+    // Handle non-client-specific activity ref count
+    int32_t oldGlobalActiveCount = mGlobalActiveCount;
+    if (!active && mGlobalActiveCount < 1) {
+        ALOGW("%s invalid deactivation with globalRefCount %d", __FUNCTION__, mGlobalActiveCount);
+        mGlobalActiveCount = 1;
     }
-    mGlobalRefCount += delta;
-    if ((oldGlobalRefCount == 0) && (mGlobalRefCount > 0)) {
+    mGlobalActiveCount += active ? 1 : -1;
+
+    if ((oldGlobalActiveCount == 0) && (mGlobalActiveCount > 0)) {
         if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
         {
             mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
                                                             MIX_STATE_MIXING);
         }
-
-    } else if ((oldGlobalRefCount > 0) && (mGlobalRefCount == 0)) {
+    } else if ((oldGlobalActiveCount > 0) && (mGlobalActiveCount == 0)) {
         if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
         {
             mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
@@ -308,32 +292,18 @@
         }
     }
 
-    uint32_t oldActiveCount = audioSession->activeCount();
-    if ((delta + (int)oldActiveCount) < 0) {
-        ALOGW("changeRefCount() invalid delta %d for sesion %d active count %d",
-              delta, session, oldActiveCount);
-        delta = -((int)oldActiveCount);
-    }
+    client->setActive(active);
 
-    audioSession->changeActiveCount(delta);
-
-    int event = RECORD_CONFIG_EVENT_NONE;
-    if ((oldActiveCount == 0) && (audioSession->activeCount() > 0)) {
-        event = RECORD_CONFIG_EVENT_START;
-    } else if ((oldActiveCount > 0) && (audioSession->activeCount() == 0)) {
-        event = RECORD_CONFIG_EVENT_STOP;
-    }
-    if (event != RECORD_CONFIG_EVENT_NONE) {
-        updateSessionRecordingConfiguration(event, audioSession);
-    }
+    int event = active ? RECORD_CONFIG_EVENT_START : RECORD_CONFIG_EVENT_STOP;
+    updateClientRecordingConfiguration(event, client);
 
 }
 
-void AudioInputDescriptor::updateSessionRecordingConfiguration(
-    int event, const sp<AudioSession>& audioSession) {
-
-    const audio_config_base_t sessionConfig = audioSession->config();
-    const record_client_info_t recordClientInfo = audioSession->recordClientInfo();
+void AudioInputDescriptor::updateClientRecordingConfiguration(
+    int event, const sp<RecordClientDescriptor>& client)
+{
+    const audio_config_base_t sessionConfig = client->config();
+    const record_client_info_t recordClientInfo{client->uid(), client->session(), client->source()};
     const audio_config_base_t config = getConfig();
     mClientInterface->onRecordingConfigurationUpdate(event,
                                                      &recordClientInfo, &sessionConfig,
@@ -385,8 +355,6 @@
 
     write(fd, result.string(), result.size());
 
-    mSessions.dump(fd, 1);
-
     size_t index = 0;
     result = " AudioRecord clients:\n";
     for (const auto& client: mClients) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
deleted file mode 100644
index 5ea4c92..0000000
--- a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (C) 2015 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 "APM::AudioSession"
-//#define LOG_NDEBUG 0
-
-#include <AudioPolicyInterface.h>
-#include "policy.h"
-#include "AudioSession.h"
-#include "AudioGain.h"
-#include "TypeConverter.h"
-
-#include <log/log.h>
-#include <utils/String8.h>
-
-namespace android {
-
-AudioSession::AudioSession(audio_session_t session,
-                           audio_source_t inputSource,
-                           audio_format_t format,
-                           uint32_t sampleRate,
-                           audio_channel_mask_t channelMask,
-                           audio_input_flags_t flags,
-                           uid_t uid,
-                           bool isSoundTrigger) :
-    mRecordClientInfo({ .uid = uid, .session = session, .source = inputSource}),
-    mConfig({ .format = format, .sample_rate = sampleRate, .channel_mask = channelMask}),
-    mFlags(flags), mIsSoundTrigger(isSoundTrigger),
-    mOpenCount(1), mActiveCount(0)
-{
-}
-
-uint32_t AudioSession::changeOpenCount(int delta)
-{
-    if ((delta + (int)mOpenCount) < 0) {
-        ALOGW("%s invalid delta %d, open count %d",
-              __FUNCTION__, delta, mOpenCount);
-        mOpenCount = (uint32_t)(-delta);
-    }
-    mOpenCount += delta;
-    ALOGV("%s open count %d", __FUNCTION__, mOpenCount);
-    return mOpenCount;
-}
-
-uint32_t AudioSession::changeActiveCount(int delta)
-{
-    if ((delta + (int)mActiveCount) < 0) {
-        ALOGW("%s invalid delta %d, active count %d",
-              __FUNCTION__, delta, mActiveCount);
-        mActiveCount = (uint32_t)(-delta);
-    }
-    mActiveCount += delta;
-    ALOGV("%s active count %d", __FUNCTION__, mActiveCount);
-
-    return mActiveCount;
-}
-
-bool AudioSession::matches(const sp<AudioSession> &other) const
-{
-    if (other->session() == mRecordClientInfo.session &&
-        other->inputSource() == mRecordClientInfo.source &&
-        other->format() == mConfig.format &&
-        other->sampleRate() == mConfig.sample_rate &&
-        other->channelMask() == mConfig.channel_mask &&
-        other->flags() == mFlags &&
-        other->uid() == mRecordClientInfo.uid) {
-        return true;
-    }
-    return false;
-}
-
-status_t AudioSession::dump(int fd, int spaces, int index) const
-{
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    snprintf(buffer, SIZE, "%*sAudio session %d:\n", spaces, "", index+1);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- session: %2d\n", spaces, "", mRecordClientInfo.session);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- owner uid: %2d\n", spaces, "", mRecordClientInfo.uid);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- input source: %d\n", spaces, "", mRecordClientInfo.source);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- format: %08x\n", spaces, "", mConfig.format);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- sample: %d\n", spaces, "", mConfig.sample_rate);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- channel mask: %08x\n",
-             spaces, "", mConfig.channel_mask);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- is soundtrigger: %s\n",
-             spaces, "", mIsSoundTrigger ? "true" : "false");
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- open count: %d\n", spaces, "", mOpenCount);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- active count: %d\n", spaces, "", mActiveCount);
-    result.append(buffer);
-
-    write(fd, result.string(), result.size());
-    return NO_ERROR;
-}
-
-status_t AudioSessionCollection::addSession(audio_session_t session,
-                                         const sp<AudioSession>& audioSession)
-{
-    ssize_t index = indexOfKey(session);
-
-    if (index >= 0) {
-        ALOGW("addSession() session %d already in", session);
-        return ALREADY_EXISTS;
-    }
-    add(session, audioSession);
-    ALOGV("addSession() session %d  client %d source %d",
-            session, audioSession->uid(), audioSession->inputSource());
-    return NO_ERROR;
-}
-
-status_t AudioSessionCollection::removeSession(audio_session_t session)
-{
-    ssize_t index = indexOfKey(session);
-
-    if (index < 0) {
-        ALOGW("removeSession() session %d not in", session);
-        return ALREADY_EXISTS;
-    }
-    ALOGV("removeSession() session %d", session);
-    removeItemsAt(index);
-    return NO_ERROR;
-}
-
-uint32_t AudioSessionCollection::getOpenCount() const
-{
-    uint32_t openCount = 0;
-    for (size_t i = 0; i < size(); i++) {
-        openCount += valueAt(i)->openCount();
-    }
-    return openCount;
-}
-
-AudioSessionCollection AudioSessionCollection::getActiveSessions() const
-{
-    AudioSessionCollection activeSessions;
-    for (size_t i = 0; i < size(); i++) {
-        if (valueAt(i)->activeCount() != 0) {
-            activeSessions.add(valueAt(i)->session(), valueAt(i));
-        }
-    }
-    return activeSessions;
-}
-
-size_t AudioSessionCollection::getActiveSessionCount() const
-{
-    size_t activeCount = 0;
-    for (size_t i = 0; i < size(); i++) {
-        if (valueAt(i)->activeCount() != 0) {
-            activeCount++;
-        }
-    }
-    return activeCount;
-}
-
-bool AudioSessionCollection::hasActiveSession() const
-{
-    return getActiveSessionCount() != 0;
-}
-
-bool AudioSessionCollection::isSourceActive(audio_source_t source) const
-{
-    for (size_t i = 0; i < size(); i++) {
-        const sp<AudioSession>  audioSession = valueAt(i);
-        // AUDIO_SOURCE_HOTWORD is equivalent to AUDIO_SOURCE_VOICE_RECOGNITION only if it
-        // corresponds to an active capture triggered by a hardware hotword recognition
-        if (audioSession->activeCount() > 0 &&
-                ((audioSession->inputSource() == source) ||
-                ((source == AUDIO_SOURCE_VOICE_RECOGNITION) &&
-                 (audioSession->inputSource() == AUDIO_SOURCE_HOTWORD) &&
-                 audioSession->isSoundTrigger()))) {
-            return true;
-        }
-    }
-    return false;
-}
-
-audio_source_t AudioSessionCollection::getHighestPrioritySource(bool activeOnly) const
-{
-    audio_source_t source = AUDIO_SOURCE_DEFAULT;
-    int32_t priority = -1;
-
-    for (size_t i = 0; i < size(); i++) {
-        const sp<AudioSession>  audioSession = valueAt(i);
-        if (activeOnly && audioSession->activeCount() == 0) {
-            continue;
-        }
-        int32_t curPriority = source_priority(audioSession->inputSource());
-        if (curPriority > priority) {
-            priority = curPriority;
-            source = audioSession->inputSource();
-        }
-    }
-    return source;
-}
-
-status_t AudioSessionCollection::dump(int fd, int spaces) const
-{
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    snprintf(buffer, SIZE, "%*sAudio Sessions:\n", spaces, "");
-    write(fd, buffer, strlen(buffer));
-    for (size_t i = 0; i < size(); i++) {
-        valueAt(i)->dump(fd, spaces + 2, i);
-    }
-    return NO_ERROR;
-}
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
index 0cf206d..0d65a31 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
@@ -29,7 +29,6 @@
 
 namespace android {
 
-
 status_t ClientDescriptor::dump(int fd, int spaces, int index)
 {
     String8 out;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index cd40bc5..2335135 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -517,7 +517,7 @@
         // symmetric to the one in startInput()
         for (const auto& activeDesc : mInputs.getActiveInputs()) {
             if (activeDesc->hasSameHwModuleAs(txSourceDeviceDesc)) {
-                closeSessions(activeDesc, true  /*activeOnly*/);
+                closeActiveClients(activeDesc);
             }
         }
     }
@@ -791,6 +791,11 @@
     const audio_port_handle_t requestedDeviceId = *selectedDeviceId;
     audio_devices_t msdDevice = getMsdAudioOutDeviceTypes();
 
+    // The supplied portId must be AUDIO_PORT_HANDLE_NONE
+    if (*portId != AUDIO_PORT_HANDLE_NONE) {
+        return INVALID_OPERATION;
+    }
+
     if (attr != NULL) {
         if (!isValidAttributes(attr)) {
             ALOGE("getOutputForAttr() invalid attributes: usage=%d content=%d flags=0x%x tags=[%s]",
@@ -812,11 +817,6 @@
           attributes.usage, attributes.content_type, attributes.tags, attributes.flags,
           session, requestedDeviceId);
 
-    // TODO: check for existing client for this port ID
-    if (*portId == AUDIO_PORT_HANDLE_NONE) {
-        *portId = AudioPort::getNextUniqueId();
-    }
-
     *stream = streamTypefromAttributesInt(&attributes);
 
     strategy = getStrategyForAttr(&attributes);
@@ -902,6 +902,8 @@
     audio_config_base_t clientConfig = {.sample_rate = config->sample_rate,
         .format = config->format,
         .channel_mask = config->channel_mask };
+    *portId = AudioPort::getNextUniqueId();
+
     sp<TrackClientDescriptor> clientDesc =
         new TrackClientDescriptor(*portId, uid, session, attributes, clientConfig,
                                   requestedDeviceId, *stream,
@@ -1662,6 +1664,13 @@
     sp<AudioInputDescriptor> inputDesc;
     sp<RecordClientDescriptor> clientDesc;
     audio_port_handle_t requestedDeviceId = *selectedDeviceId;
+    bool isSoundTrigger;
+    audio_devices_t device;
+
+    // The supplied portId must be AUDIO_PORT_HANDLE_NONE
+    if (*portId != AUDIO_PORT_HANDLE_NONE) {
+        return INVALID_OPERATION;
+    }
 
     if (inputSource == AUDIO_SOURCE_DEFAULT) {
         inputSource = AUDIO_SOURCE_MIC;
@@ -1684,8 +1693,8 @@
             goto error;
         }
         sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
-        sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
-        if (audioSession == 0) {
+        RecordClientVector clients = inputDesc->getClientsForSession(session);
+        if (clients.size() == 0) {
             ALOGW("getInputForAttr() unknown session %d on input %d", session, *input);
             status = BAD_VALUE;
             goto error;
@@ -1694,28 +1703,27 @@
         // The second call is for the first active client and sets the UID. Any further call
         // corresponds to a new client and is only permitted from the same UID.
         // If the first UID is silenced, allow a new UID connection and replace with new UID
-        if (audioSession->openCount() == 1) {
-            audioSession->setUid(uid);
-        } else if (audioSession->uid() != uid) {
-            if (!audioSession->isSilenced()) {
-                ALOGW("getInputForAttr() bad uid %d for session %d uid %d",
-                      uid, session, audioSession->uid());
-                status = INVALID_OPERATION;
-                goto error;
+        if (clients.size() > 1) {
+            for (const auto& client : clients) {
+                // The client map is ordered by key values (portId) and portIds are allocated
+                // incrementaly. So the first client in this list is the one opened by audio flinger
+                // when the mmap stream is created and should be ignored as it does not correspond
+                // to an actual client
+                if (client == *clients.cbegin()) {
+                    continue;
+                }
+                if (uid != client->uid() && !client->isSilenced()) {
+                    ALOGW("getInputForAttr() bad uid %d for client %d uid %d",
+                          uid, client->portId(), client->uid());
+                    status = INVALID_OPERATION;
+                    goto error;
+                }
             }
-            audioSession->setUid(uid);
-            audioSession->setSilenced(false);
         }
-        audioSession->changeOpenCount(1);
         *inputType = API_INPUT_LEGACY;
-        if (*portId == AUDIO_PORT_HANDLE_NONE) {
-            *portId = AudioPort::getNextUniqueId();
-        }
-        inputDevices = mAvailableInputDevices.getDevicesFromTypeMask(inputDesc->mDevice);
-        *selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
-                : AUDIO_PORT_HANDLE_NONE;
-        ALOGI("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
+        device = inputDesc->mDevice;
 
+        ALOGI("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
         goto exit;
     }
 
@@ -1724,13 +1732,6 @@
 
     halInputSource = inputSource;
 
-    // TODO: check for existing client for this port ID
-    if (*portId == AUDIO_PORT_HANDLE_NONE) {
-        *portId = AudioPort::getNextUniqueId();
-    }
-
-    audio_devices_t device;
-
     if (inputSource == AUDIO_SOURCE_REMOTE_SUBMIX &&
             strncmp(attr->tags, "addr=", strlen("addr=")) == 0) {
         status = mPolicyMixes.getInputMixForAttr(*attr, &policyMix);
@@ -1774,7 +1775,7 @@
 
     }
 
-    *input = getInputForDevice(device, address, session, uid, inputSource,
+    *input = getInputForDevice(device, address, session, inputSource,
                                config, flags,
                                policyMix);
     if (*input == AUDIO_IO_HANDLE_NONE) {
@@ -1782,13 +1783,19 @@
         goto error;
     }
 
+exit:
+
     inputDevices = mAvailableInputDevices.getDevicesFromTypeMask(device);
     *selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
-            : AUDIO_PORT_HANDLE_NONE;
+                                                : AUDIO_PORT_HANDLE_NONE;
 
-exit:
+    isSoundTrigger = inputSource == AUDIO_SOURCE_HOTWORD &&
+        mSoundTriggerSessions.indexOfKey(session) > 0;
+    *portId = AudioPort::getNextUniqueId();
+
     clientDesc = new RecordClientDescriptor(*portId, uid, session,
-                                  *attr, *config, requestedDeviceId, inputSource, flags);
+                                  *attr, *config, requestedDeviceId,
+                                  inputSource,flags, isSoundTrigger);
     inputDesc = mInputs.valueFor(*input);
     inputDesc->clientsMap().emplace(*portId, clientDesc);
 
@@ -1805,7 +1812,6 @@
 audio_io_handle_t AudioPolicyManager::getInputForDevice(audio_devices_t device,
                                                         String8 address,
                                                         audio_session_t session,
-                                                        uid_t uid,
                                                         audio_source_t inputSource,
                                                         const audio_config_base_t *config,
                                                         audio_input_flags_t flags,
@@ -1867,15 +1873,6 @@
         return input;
     }
 
-    sp<AudioSession> audioSession = new AudioSession(session,
-                                                     inputSource,
-                                                     config->format,
-                                                     samplingRate,
-                                                     config->channel_mask,
-                                                     flags,
-                                                     uid,
-                                                     isSoundTrigger);
-
     if (!profile->canOpenNewIo()) {
         return AUDIO_IO_HANDLE_NONE;
     }
@@ -1911,7 +1908,6 @@
     }
 
     inputDesc->mPolicyMix = policyMix;
-    inputDesc->addAudioSession(session, audioSession);
 
     addInput(input, inputDesc);
     mpClientInterface->onAudioPortListUpdate();
@@ -1927,39 +1923,6 @@
             (source == AUDIO_SOURCE_FM_TUNER);
 }
 
-bool AudioPolicyManager::isConcurentCaptureAllowed(const sp<AudioInputDescriptor>& inputDesc,
-        const sp<AudioSession>& audioSession)
-{
-    // Do not allow capture if an active voice call is using a software patch and
-    // the call TX source device is on the same HW module.
-    // FIXME: would be better to refine to only inputs whose profile connects to the
-    // call TX device but this information is not in the audio patch
-    if (mCallTxPatch != 0 &&
-        inputDesc->getModuleHandle() == mCallTxPatch->mPatch.sources[0].ext.device.hw_module) {
-        return false;
-    }
-
-    // starting concurrent capture is enabled if:
-    // 1) capturing for re-routing
-    // 2) capturing for HOTWORD source
-    // 3) capturing for FM TUNER source
-    // 3) All other active captures are either for re-routing or HOTWORD
-
-    if (is_virtual_input_device(inputDesc->mDevice) ||
-            isConcurrentSource(audioSession->inputSource())) {
-        return true;
-    }
-
-    for (const auto& activeInput : mInputs.getActiveInputs()) {
-        if (!isConcurrentSource(activeInput->inputSource(true)) &&
-                !is_virtual_input_device(activeInput->mDevice)) {
-            return false;
-        }
-    }
-
-    return true;
-}
-
 // FIXME: remove when concurrent capture is ready. This is a hack to work around bug b/63083537.
 bool AudioPolicyManager::soundTriggerSupportsConcurrentCapture() {
     if (!mHasComputedSoundTriggerSupportsConcurrentCapture) {
@@ -2005,22 +1968,21 @@
 
     sp<AudioInputDescriptor> inputDesc = mInputs.getInputForClient(portId);
     if (inputDesc == 0) {
-        ALOGW("startInput() no input for client %d", portId);
+        ALOGW("%s no input for client %d", __FUNCTION__, portId);
         return BAD_VALUE;
     }
-    sp<RecordClientDescriptor> client = inputDesc->clientsMap()[portId];
-    audio_session_t session = client->session();
     audio_io_handle_t input = inputDesc->mIoHandle;
-
-    ALOGV("AudioPolicyManager::startInput(input:%d, session:%d, silenced:%d, concurrency:%d)",
-            input, session, silenced, *concurrency);
-
-    sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
-    if (audioSession == 0) {
-        ALOGW("startInput() unknown session %d on input %d", session, input);
-        return BAD_VALUE;
+    sp<RecordClientDescriptor> client = inputDesc->clientsMap()[portId];
+    if (client->active()) {
+        ALOGW("%s input %d client %d already started", __FUNCTION__, input, client->portId());
+        return INVALID_OPERATION;
     }
 
+    audio_session_t session = client->session();
+
+    ALOGV("%s input:%d, session:%d, silenced:%d, concurrency:%d)",
+        __FUNCTION__, input, session, silenced, *concurrency);
+
     if (!is_virtual_input_device(inputDesc->mDevice)) {
         if (mCallTxPatch != 0 &&
             inputDesc->getModuleHandle() == mCallTxPatch->mPatch.sources[0].ext.device.hw_module) {
@@ -2036,47 +1998,48 @@
         // favor of the new one - "There can be only one" TM
         if (!silenced) {
             for (const auto& activeDesc : activeInputs) {
-                if ((audioSession->flags() & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0 &&
+                if ((activeDesc->getAudioPort()->getFlags() & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0 &&
                         activeDesc->getId() == inputDesc->getId()) {
                      continue;
                 }
 
-                AudioSessionCollection activeSessions = activeDesc->getAudioSessions(
-                        true /*activeOnly*/);
-                sp<AudioSession> activeSession = activeSessions.valueAt(0);
-                if (activeSession->isSilenced()) {
-                    closeSession(activeDesc, activeSession);
-                    ALOGV("startInput() session %d stopping silenced session %d", session, activeSession->session());
-                    activeInputs = mInputs.getActiveInputs();
+                RecordClientVector activeClients = activeDesc->clientsList(true /*activeOnly*/);
+                for (const auto& activeClient : activeClients) {
+                    if (activeClient->isSilenced()) {
+                        closeClient(activeClient->portId());
+                        ALOGV("%s client %d stopping silenced client %d", __FUNCTION__,
+                              portId, activeClient->portId());
+                        activeInputs = mInputs.getActiveInputs();
+                    }
                 }
             }
         }
 
         for (const auto& activeDesc : activeInputs) {
-            if ((audioSession->flags() & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0 &&
+            if ((client->flags() & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0 &&
                     activeDesc->getId() == inputDesc->getId()) {
                 continue;
             }
 
             audio_source_t activeSource = activeDesc->inputSource(true);
-            if (audioSession->inputSource() == AUDIO_SOURCE_HOTWORD) {
+            if (client->source() == AUDIO_SOURCE_HOTWORD) {
                 if (activeSource == AUDIO_SOURCE_HOTWORD) {
                     if (activeDesc->hasPreemptedSession(session)) {
-                        ALOGW("startInput(%d) failed for HOTWORD: "
-                                "other input %d already started for HOTWORD",
+                        ALOGW("%s input %d failed for HOTWORD: "
+                                "other input %d already started for HOTWORD", __FUNCTION__,
                               input, activeDesc->mIoHandle);
                         *concurrency |= API_INPUT_CONCURRENCY_HOTWORD;
                         return INVALID_OPERATION;
                     }
                 } else {
-                    ALOGV("startInput(%d) failed for HOTWORD: other input %d already started",
-                          input, activeDesc->mIoHandle);
+                    ALOGV("%s input %d failed for HOTWORD: other input %d already started",
+                        __FUNCTION__, input, activeDesc->mIoHandle);
                     *concurrency |= API_INPUT_CONCURRENCY_CAPTURE;
                     return INVALID_OPERATION;
                 }
             } else {
                 if (activeSource != AUDIO_SOURCE_HOTWORD) {
-                    ALOGW("startInput(%d) failed: other input %d already started",
+                    ALOGW("%s input %d failed: other input %d already started", __FUNCTION__,
                           input, activeDesc->mIoHandle);
                     *concurrency |= API_INPUT_CONCURRENCY_CAPTURE;
                     return INVALID_OPERATION;
@@ -2095,78 +2058,75 @@
             if (allowConcurrentWithSoundTrigger && activeDesc->isSoundTrigger()) {
                 continue;
             }
-
-            audio_source_t activeSource = activeDesc->inputSource(true);
-            if (activeSource == AUDIO_SOURCE_HOTWORD) {
-                AudioSessionCollection activeSessions =
-                        activeDesc->getAudioSessions(true /*activeOnly*/);
-                sp<AudioSession> activeSession = activeSessions[0];
+            RecordClientVector activeHotwordClients =
+                activeDesc->clientsList(true, AUDIO_SOURCE_HOTWORD);
+            if (activeHotwordClients.size() > 0) {
                 SortedVector<audio_session_t> sessions = activeDesc->getPreemptedSessions();
-                *concurrency |= API_INPUT_CONCURRENCY_PREEMPT;
-                sessions.add(activeSession->session());
+
+                for (const auto& activeClient : activeHotwordClients) {
+                    *concurrency |= API_INPUT_CONCURRENCY_PREEMPT;
+                    sessions.add(activeClient->session());
+                    closeClient(activeClient->portId());
+                    ALOGV("%s input %d for HOTWORD preempting HOTWORD input %d", __FUNCTION__,
+                          input, activeDesc->mIoHandle);
+                }
+
                 inputDesc->setPreemptedSessions(sessions);
-                closeSession(inputDesc, activeSession);
-                ALOGV("startInput(%d) for HOTWORD preempting HOTWORD input %d",
-                      input, activeDesc->mIoHandle);
             }
         }
     }
 
     // Make sure we start with the correct silence state
-    audioSession->setSilenced(silenced);
+    client->setSilenced(silenced);
 
     // increment activity count before calling getNewInputDevice() below as only active sessions
     // are considered for device selection
-    inputDesc->changeRefCount(session, 1);
-    client->setActive(true);
+    inputDesc->setClientActive(client, true);
 
-    if (audioSession->activeCount() == 1 || client->hasPreferredDevice(true)) {
-        // indicate active capture to sound trigger service if starting capture from a mic on
-        // primary HW module
-        audio_devices_t device = getNewInputDevice(inputDesc);
-        setInputDevice(input, device, true /* force */);
+    // indicate active capture to sound trigger service if starting capture from a mic on
+    // primary HW module
+    audio_devices_t device = getNewInputDevice(inputDesc);
+    setInputDevice(input, device, true /* force */);
 
-        status_t status = inputDesc->start();
-        if (status != NO_ERROR) {
-            inputDesc->changeRefCount(session, -1);
-            client->setActive(false);
-            return status;
+    status_t status = inputDesc->start();
+    if (status != NO_ERROR) {
+        inputDesc->setClientActive(client, false);
+        return status;
+    }
+
+    if (inputDesc->activeCount()  == 1) {
+        // if input maps to a dynamic policy with an activity listener, notify of state change
+        if ((inputDesc->mPolicyMix != NULL)
+                && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
+            mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mDeviceAddress,
+                    MIX_STATE_MIXING);
         }
 
-        if (inputDesc->getAudioSessionCount(true/*activeOnly*/) == 1) {
-            // if input maps to a dynamic policy with an activity listener, notify of state change
-            if ((inputDesc->mPolicyMix != NULL)
-                    && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
-                mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mDeviceAddress,
-                        MIX_STATE_MIXING);
-            }
+        audio_devices_t primaryInputDevices = availablePrimaryInputDevices();
+        if (((device & primaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
+                mInputs.activeInputsCountOnDevices(primaryInputDevices) == 1) {
+            SoundTrigger::setCaptureState(true);
+        }
 
-            audio_devices_t primaryInputDevices = availablePrimaryInputDevices();
-            if (((device & primaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
-                    mInputs.activeInputsCountOnDevices(primaryInputDevices) == 1) {
-                SoundTrigger::setCaptureState(true);
+        // automatically enable the remote submix output when input is started if not
+        // used by a policy mix of type MIX_TYPE_RECORDERS
+        // For remote submix (a virtual device), we open only one input per capture request.
+        if (audio_is_remote_submix_device(inputDesc->mDevice)) {
+            String8 address = String8("");
+            if (inputDesc->mPolicyMix == NULL) {
+                address = String8("0");
+            } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
+                address = inputDesc->mPolicyMix->mDeviceAddress;
             }
-
-            // automatically enable the remote submix output when input is started if not
-            // used by a policy mix of type MIX_TYPE_RECORDERS
-            // For remote submix (a virtual device), we open only one input per capture request.
-            if (audio_is_remote_submix_device(inputDesc->mDevice)) {
-                String8 address = String8("");
-                if (inputDesc->mPolicyMix == NULL) {
-                    address = String8("0");
-                } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
-                    address = inputDesc->mPolicyMix->mDeviceAddress;
-                }
-                if (address != "") {
-                    setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
-                            AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
-                            address, "remote-submix");
-                }
+            if (address != "") {
+                setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+                        AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+                        address, "remote-submix");
             }
         }
     }
 
-    ALOGV("AudioPolicyManager::startInput() input source = %d", audioSession->inputSource());
+    ALOGV("%s input %d source = %d exit", __FUNCTION__, input, client->source());
 
     return NO_ERROR;
 }
@@ -2177,65 +2137,56 @@
 
     sp<AudioInputDescriptor> inputDesc = mInputs.getInputForClient(portId);
     if (inputDesc == 0) {
-        ALOGW("stopInput() no input for client %d", portId);
+        ALOGW("%s no input for client %d", __FUNCTION__, portId);
         return BAD_VALUE;
     }
-    sp<RecordClientDescriptor> client = inputDesc->clientsMap()[portId];
-    audio_session_t session = client->session();
     audio_io_handle_t input = inputDesc->mIoHandle;
-
-    ALOGV("stopInput() input %d", input);
-
-    sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
-
-    if (audioSession->activeCount() == 0) {
-        ALOGW("stopInput() input %d already stopped", input);
+    sp<RecordClientDescriptor> client = inputDesc->clientsMap()[portId];
+    if (!client->active()) {
+        ALOGW("%s input %d client %d already stopped", __FUNCTION__, input, client->portId());
         return INVALID_OPERATION;
     }
 
-    inputDesc->changeRefCount(session, -1);
-    client->setActive(false);
+    inputDesc->setClientActive(client, false);
 
-    if (audioSession->activeCount() == 0) {
-        inputDesc->stop();
-        if (inputDesc->isActive()) {
-            setInputDevice(input, getNewInputDevice(inputDesc), false /* force */);
-        } else {
-            // if input maps to a dynamic policy with an activity listener, notify of state change
-            if ((inputDesc->mPolicyMix != NULL)
-                    && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
-                mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mDeviceAddress,
-                        MIX_STATE_IDLE);
-            }
-
-            // automatically disable the remote submix output when input is stopped if not
-            // used by a policy mix of type MIX_TYPE_RECORDERS
-            if (audio_is_remote_submix_device(inputDesc->mDevice)) {
-                String8 address = String8("");
-                if (inputDesc->mPolicyMix == NULL) {
-                    address = String8("0");
-                } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
-                    address = inputDesc->mPolicyMix->mDeviceAddress;
-                }
-                if (address != "") {
-                    setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
-                                             AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
-                                             address, "remote-submix");
-                }
-            }
-
-            audio_devices_t device = inputDesc->mDevice;
-            resetInputDevice(input);
-
-            // indicate inactive capture to sound trigger service if stopping capture from a mic on
-            // primary HW module
-            audio_devices_t primaryInputDevices = availablePrimaryInputDevices();
-            if (((device & primaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
-                    mInputs.activeInputsCountOnDevices(primaryInputDevices) == 0) {
-                SoundTrigger::setCaptureState(false);
-            }
-            inputDesc->clearPreemptedSessions();
+    inputDesc->stop();
+    if (inputDesc->isActive()) {
+        setInputDevice(input, getNewInputDevice(inputDesc), false /* force */);
+    } else {
+        // if input maps to a dynamic policy with an activity listener, notify of state change
+        if ((inputDesc->mPolicyMix != NULL)
+                && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
+            mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mDeviceAddress,
+                    MIX_STATE_IDLE);
         }
+
+        // automatically disable the remote submix output when input is stopped if not
+        // used by a policy mix of type MIX_TYPE_RECORDERS
+        if (audio_is_remote_submix_device(inputDesc->mDevice)) {
+            String8 address = String8("");
+            if (inputDesc->mPolicyMix == NULL) {
+                address = String8("0");
+            } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
+                address = inputDesc->mPolicyMix->mDeviceAddress;
+            }
+            if (address != "") {
+                setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+                                         AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+                                         address, "remote-submix");
+            }
+        }
+
+        audio_devices_t device = inputDesc->mDevice;
+        resetInputDevice(input);
+
+        // indicate inactive capture to sound trigger service if stopping capture from a mic on
+        // primary HW module
+        audio_devices_t primaryInputDevices = availablePrimaryInputDevices();
+        if (((device & primaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
+                mInputs.activeInputsCountOnDevices(primaryInputDevices) == 0) {
+            SoundTrigger::setCaptureState(false);
+        }
+        inputDesc->clearPreemptedSessions();
     }
     return NO_ERROR;
 }
@@ -2246,61 +2197,40 @@
 
     sp<AudioInputDescriptor> inputDesc = mInputs.getInputForClient(portId);
     if (inputDesc == 0) {
-        ALOGW("releaseInput() no input for client %d", portId);
+        ALOGW("%s no input for client %d", __FUNCTION__, portId);
         return;
     }
     sp<RecordClientDescriptor> client = inputDesc->clientsMap()[portId];
-    audio_session_t session = client->session();
     audio_io_handle_t input = inputDesc->mIoHandle;
 
-    ALOGV("releaseInput() %d", input);
+    ALOGV("%s %d", __FUNCTION__, input);
 
-    sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
-    if (audioSession == 0) {
-        ALOGW("releaseInput() unknown session %d on input %d", session, input);
-        return;
-    }
+    inputDesc->clientsMap().erase(portId);
 
-    if (audioSession->openCount() == 0) {
-        ALOGW("releaseInput() invalid open count %d on session %d",
-              audioSession->openCount(), session);
-        return;
-    }
-
-    if (audioSession->changeOpenCount(-1) == 0) {
-        inputDesc->removeAudioSession(session);
-    }
-
-    if (inputDesc->getOpenRefCount() > 0) {
-        ALOGV("releaseInput() exit > 0");
+    if (inputDesc->clientsMap().size() > 0) {
+        ALOGV("%s %zu clients remaining", __FUNCTION__, inputDesc->clientsMap().size());
         return;
     }
 
     closeInput(input);
-    inputDesc->clientsMap().erase(portId);
     mpClientInterface->onAudioPortListUpdate();
-    ALOGV("releaseInput() exit");
+    ALOGV("%s exit", __FUNCTION__);
 }
 
-void AudioPolicyManager::closeSessions(const sp<AudioInputDescriptor>& input, bool activeOnly)
+void AudioPolicyManager::closeActiveClients(const sp<AudioInputDescriptor>& input)
 {
-    AudioSessionCollection sessions = input->getAudioSessions(activeOnly /*activeOnly*/);
-    for (size_t i = 0; i < sessions.size(); i++) {
-        closeSession(input, sessions[i]);
-    }
-}
-
-void AudioPolicyManager::closeSession(const sp<AudioInputDescriptor>& input,
-                                      const sp<AudioSession>& session)
-{
-    RecordClientVector clients = input->getClientsForSession(session->session());
+    RecordClientVector clients = input->clientsList(true);
 
     for (const auto& client : clients) {
-        stopInput(client->portId());
-        releaseInput(client->portId());
+        closeClient(client->portId());
     }
 }
 
+void AudioPolicyManager::closeClient(audio_port_handle_t portId)
+{
+    stopInput(portId);
+    releaseInput(portId);
+}
 
 void AudioPolicyManager::closeAllInputs() {
     bool patchRemoved = false;
@@ -3891,11 +3821,10 @@
     Vector<sp<AudioInputDescriptor> > activeInputs = mInputs.getActiveInputs();
     for (size_t i = 0; i < activeInputs.size(); i++) {
         sp<AudioInputDescriptor> activeDesc = activeInputs[i];
-        AudioSessionCollection activeSessions = activeDesc->getAudioSessions(true);
-        for (size_t j = 0; j < activeSessions.size(); j++) {
-            sp<AudioSession> activeSession = activeSessions.valueAt(j);
-            if (activeSession->uid() == uid) {
-                activeSession->setSilenced(silenced);
+        RecordClientVector clients = activeDesc->clientsList(true /*activeOnly*/);
+        for (const auto& client : clients) {
+            if (uid == client->uid()) {
+                client->setSilenced(silenced);
             }
         }
     }
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index cc5739b..6f4cce1 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -539,15 +539,11 @@
 
         static bool isConcurrentSource(audio_source_t source);
 
-        bool isConcurentCaptureAllowed(const sp<AudioInputDescriptor>& inputDesc,
-                const sp<AudioSession>& audioSession);
-
         static bool streamsMatchForvolume(audio_stream_type_t stream1,
                                           audio_stream_type_t stream2);
 
-        void closeSessions(const sp<AudioInputDescriptor>& input, bool activeOnly);
-        void closeSession(const sp<AudioInputDescriptor>& input,
-                          const sp<AudioSession>& session);
+        void closeActiveClients(const sp<AudioInputDescriptor>& input);
+        void closeClient(audio_port_handle_t portId);
 
         const uid_t mUidCached;                         // AID_AUDIOSERVER
         AudioPolicyClientInterface *mpClientInterface;  // audio policy client interface
@@ -667,7 +663,6 @@
         audio_io_handle_t getInputForDevice(audio_devices_t device,
                 String8 address,
                 audio_session_t session,
-                uid_t uid,
                 audio_source_t inputSource,
                 const audio_config_base_t *config,
                 audio_input_flags_t flags,