Merge "Don't record audio if UID is idle - media framework"
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 50fe385..16150f6 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -39,8 +39,7 @@
 sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient;
 audio_error_callback AudioSystem::gAudioErrorCallback = NULL;
 dynamic_policy_callback AudioSystem::gDynPolicyCallback = NULL;
-record_config_callback  AudioSystem::gRecordConfigCallback = NULL;
-
+record_config_callback AudioSystem::gRecordConfigCallback = NULL;
 
 // establish binder interface to AudioFlinger service
 const sp<IAudioFlinger> AudioSystem::get_audio_flinger()
@@ -917,11 +916,14 @@
 }
 
 status_t AudioSystem::startInput(audio_io_handle_t input,
-                                 audio_session_t session)
+                                 audio_session_t session,
+                                 audio_devices_t device,
+                                 uid_t uid,
+                                 bool *silenced)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return PERMISSION_DENIED;
-    return aps->startInput(input, session);
+    return aps->startInput(input, session, device, uid, silenced);
 }
 
 status_t AudioSystem::stopInput(audio_io_handle_t input,
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 56ddd4f..6507a5c 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -48,6 +48,7 @@
     SET_MODE,
     SET_MIC_MUTE,
     GET_MIC_MUTE,
+    SET_RECORD_SILENCED,
     SET_PARAMETERS,
     GET_PARAMETERS,
     REGISTER_CLIENT,
@@ -306,6 +307,15 @@
         return reply.readInt32();
     }
 
+    virtual void setRecordSilenced(uid_t uid, bool silenced)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(uid);
+        data.writeInt32(silenced ? 1 : 0);
+        remote()->transact(SET_RECORD_SILENCED, data, &reply);
+    }
+
     virtual status_t setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs)
     {
         Parcel data, reply;
@@ -859,6 +869,7 @@
         case RELEASE_AUDIO_PATCH:
         case LIST_AUDIO_PATCHES:
         case SET_AUDIO_PORT_CONFIG:
+        case SET_RECORD_SILENCED:
             ALOGW("%s: transaction %d received from PID %d",
                   __func__, code, IPCThreadState::self()->getCallingPid());
             return INVALID_OPERATION;
@@ -1024,6 +1035,15 @@
             reply->writeInt32( getMicMute() );
             return NO_ERROR;
         } break;
+        case SET_RECORD_SILENCED: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            uid_t uid = data.readInt32();
+            audio_source_t source;
+            data.read(&source, sizeof(audio_source_t));
+            bool silenced = data.readInt32() == 1;
+            setRecordSilenced(uid, silenced);
+            return NO_ERROR;
+        } break;
         case SET_PARAMETERS: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             audio_io_handle_t ioHandle = (audio_io_handle_t) data.readInt32();
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index 53bc1b7..c0e53b3 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -330,14 +330,22 @@
     }
 
     virtual status_t startInput(audio_io_handle_t input,
-                                audio_session_t session)
+                                audio_session_t session,
+                                audio_devices_t device,
+                                uid_t uid,
+                                bool *silenced)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
         data.writeInt32(input);
         data.writeInt32(session);
+        data.writeInt32(device);
+        data.writeInt32(uid);
+        data.writeInt32(*silenced ? 1 : 0);
         remote()->transact(START_INPUT, data, &reply);
-        return static_cast <status_t> (reply.readInt32());
+        status_t status = static_cast <status_t> (reply.readInt32());
+        *silenced = reply.readInt32() == 1;
+        return status;
     }
 
     virtual status_t stopInput(audio_io_handle_t input,
@@ -1045,7 +1053,12 @@
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
             audio_io_handle_t input = static_cast <audio_io_handle_t>(data.readInt32());
             audio_session_t session = static_cast <audio_session_t>(data.readInt32());
-            reply->writeInt32(static_cast <uint32_t>(startInput(input, session)));
+            audio_devices_t device = static_cast <audio_devices_t>(data.readInt32());
+            uid_t uid = static_cast <uid_t>(data.readInt32());
+            bool silenced = data.readInt32() == 1;
+            status_t status = startInput(input, session, device, uid, &silenced);
+            reply->writeInt32(static_cast <uint32_t>(status));
+            reply->writeInt32(silenced ? 1 : 0);
             return NO_ERROR;
         } break;
 
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 24a6e22..d6cc37a 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -244,7 +244,10 @@
                                     audio_port_handle_t *portId);
 
     static status_t startInput(audio_io_handle_t input,
-                               audio_session_t session);
+                               audio_session_t session,
+                               audio_devices_t device,
+                               uid_t uid,
+                               bool *silenced);
     static status_t stopInput(audio_io_handle_t input,
                               audio_session_t session);
     static void releaseInput(audio_io_handle_t input,
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 57d9778..472a3da 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -368,6 +368,7 @@
     // mic mute/state
     virtual     status_t    setMicMute(bool state) = 0;
     virtual     bool        getMicMute() const = 0;
+    virtual     void        setRecordSilenced(uid_t uid, bool silenced) = 0;
 
     virtual     status_t    setParameters(audio_io_handle_t ioHandle,
                                     const String8& keyValuePairs) = 0;
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index 5558b77..7e9413d 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -84,7 +84,10 @@
                               audio_port_handle_t *selectedDeviceId,
                               audio_port_handle_t *portId) = 0;
     virtual status_t startInput(audio_io_handle_t input,
-                                audio_session_t session) = 0;
+                                audio_session_t session,
+                                audio_devices_t device,
+                                uid_t uid,
+                                bool *silenced) = 0;
     virtual status_t stopInput(audio_io_handle_t input,
                                audio_session_t session) = 0;
     virtual void releaseInput(audio_io_handle_t input,
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 2a2f6fc..a9d0054 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -993,6 +993,21 @@
     return mute;
 }
 
+void AudioFlinger::setRecordSilenced(uid_t uid, bool silenced)
+{
+    ALOGV("AudioFlinger::setRecordSilenced(uid:%d, silenced:%d)", uid, silenced);
+
+    // TODO: Notify MmapThreads
+
+    AutoMutex lock(mLock);
+    for (size_t i = 0; i < mRecordThreads.size(); i++) {
+        sp<RecordThread> thread = mRecordThreads.valueAt(i);
+        if (thread != 0) {
+            thread->setRecordSilenced(uid, silenced);
+        }
+    }
+}
+
 status_t AudioFlinger::setMasterMute(bool muted)
 {
     status_t ret = initCheck();
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 5a64f0b..a1c3f36 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -147,6 +147,8 @@
     virtual     status_t    setMicMute(bool state);
     virtual     bool        getMicMute() const;
 
+    virtual     void        setRecordSilenced(uid_t uid, bool silenced);
+
     virtual     status_t    setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs);
     virtual     String8     getParameters(audio_io_handle_t ioHandle, const String8& keys) const;
 
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index f8da780..63a3d98 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -63,6 +63,9 @@
 
     virtual bool        isFastTrack() const { return (mFlags & AUDIO_INPUT_FLAG_FAST) != 0; }
 
+            void        setSilenced(bool silenced) { mSilenced = silenced; }
+            bool        isSilenced() const { return mSilenced; }
+
 private:
     friend class AudioFlinger;  // for mState
 
@@ -91,6 +94,8 @@
             // used by the record thread to convert frames to proper destination format
             RecordBufferConverter              *mRecordBufferConverter;
             audio_input_flags_t                mFlags;
+
+            bool                               mSilenced;
 };
 
 // playback track, used by PatchPanel
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 3a41ac8..8bf50b1 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -6532,6 +6532,7 @@
         rear = mRsmpInRear += framesRead;
 
         size = activeTracks.size();
+
         // loop over each active track
         for (size_t i = 0; i < size; i++) {
             activeTrack = activeTracks[i];
@@ -6588,6 +6589,11 @@
                 if (activeTrack->mFramesToDrop == 0) {
                     if (framesOut > 0) {
                         activeTrack->mSink.frameCount = framesOut;
+                        // Sanitize before releasing if the track has no access to the source data
+                        // An idle UID receives silence from non virtual devices until active
+                        if (activeTrack->isSilenced()) {
+                            memset(activeTrack->mSink.raw, 0, framesOut * mFrameSize);
+                        }
                         activeTrack->releaseBuffer(&activeTrack->mSink);
                     }
                 } else {
@@ -6927,7 +6933,9 @@
         status_t status = NO_ERROR;
         if (recordTrack->isExternalTrack()) {
             mLock.unlock();
-            status = AudioSystem::startInput(mId, recordTrack->sessionId());
+            bool silenced;
+            status = AudioSystem::startInput(mId, recordTrack->sessionId(),
+                    mInDevice, recordTrack->uid(), &silenced);
             mLock.lock();
             // FIXME should verify that recordTrack is still in mActiveTracks
             if (status != NO_ERROR) {
@@ -6936,6 +6944,7 @@
                 ALOGV("RecordThread::start error %d", status);
                 return status;
             }
+            recordTrack->setSilenced(silenced);
         }
         // Catch up with current buffer indices if thread is already running.
         // This is what makes a new client discard all buffered data.  If the track's mRsmpInFront
@@ -7139,6 +7148,16 @@
     write(fd, result.string(), result.size());
 }
 
+void AudioFlinger::RecordThread::setRecordSilenced(uid_t uid, bool silenced)
+{
+    Mutex::Autolock _l(mLock);
+    for (size_t i = 0; i < mTracks.size() ; i++) {
+        sp<RecordTrack> track = mTracks[i];
+        if (track != 0 && track->uid() == uid) {
+            track->setSilenced(silenced);
+        }
+    }
+}
 
 void AudioFlinger::RecordThread::ResamplerBufferProvider::reset()
 {
@@ -7831,7 +7850,9 @@
     if (isOutput()) {
         ret = AudioSystem::startOutput(mId, streamType(), mSessionId);
     } else {
-        ret = AudioSystem::startInput(mId, mSessionId);
+        // TODO: Block recording for idle UIDs (b/72134552)
+        bool silenced;
+        ret = AudioSystem::startInput(mId, mSessionId, mInDevice, client.clientUid, &silenced);
     }
 
     // abort if start is rejected by audio policy manager
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 17f26c5..41d87a4 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1396,6 +1396,9 @@
 
             void        checkBtNrec();
 
+            // Sets the UID records silence
+            void        setRecordSilenced(uid_t uid, bool silenced);
+
 private:
             // Enter standby if not already in standby, and set mStandby flag
             void    standbyIfNotAlreadyInStandby();
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index f2cb25f..2a8f54d 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -65,15 +65,15 @@
         API_INPUT_TELEPHONY_RX, // used for capture from telephony RX path
     } input_type_t;
 
-   enum {
+    enum {
         API_INPUT_CONCURRENCY_NONE = 0,
         API_INPUT_CONCURRENCY_CALL = (1 << 0),      // Concurrency with a call
         API_INPUT_CONCURRENCY_CAPTURE = (1 << 1),   // Concurrency with another capture
 
         API_INPUT_CONCURRENCY_ALL = (API_INPUT_CONCURRENCY_CALL | API_INPUT_CONCURRENCY_CAPTURE),
-   };
+    };
 
-   typedef uint32_t concurrency_type__mask_t;
+    typedef uint32_t concurrency_type__mask_t;
 
 public:
     virtual ~AudioPolicyInterface() {}
@@ -145,6 +145,7 @@
     // indicates to the audio policy manager that the input starts being used.
     virtual status_t startInput(audio_io_handle_t input,
                                 audio_session_t session,
+                                bool silenced,
                                 concurrency_type__mask_t *concurrency) = 0;
     // indicates to the audio policy manager that the input stops being used.
     virtual status_t stopInput(audio_io_handle_t input,
@@ -239,6 +240,8 @@
 
     virtual float    getStreamVolumeDB(
                 audio_stream_type_t stream, int index, audio_devices_t device) = 0;
+
+    virtual void     setRecordSilenced(uid_t uid, bool silenced);
 };
 
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
index 0d19373..dd5247d 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
@@ -55,6 +55,8 @@
     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; } ;
 
@@ -70,6 +72,7 @@
     const struct audio_config_base mConfig;
     const audio_input_flags_t mFlags;
     bool  mIsSoundTrigger;
+    bool mSilenced;
     uint32_t  mOpenCount;
     uint32_t  mActiveCount;
     AudioMix* mPolicyMix; // non NULL when used by a dynamic policy
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 33f31e0..78a02b2 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1801,10 +1801,15 @@
 
 status_t AudioPolicyManager::startInput(audio_io_handle_t input,
                                         audio_session_t session,
+                                        bool silenced,
                                         concurrency_type__mask_t *concurrency)
 {
-    ALOGV("startInput() input %d", input);
+
+    ALOGV("AudioPolicyManager::startInput(input:%d, session:%d, silenced:%d, concurrency:%d)",
+            input, session, silenced, *concurrency);
+
     *concurrency = API_INPUT_CONCURRENCY_NONE;
+
     ssize_t index = mInputs.indexOfKey(input);
     if (index < 0) {
         ALOGW("startInput() unknown input %d", input);
@@ -1839,12 +1844,33 @@
             return INVALID_OPERATION;
         }
 
-        Vector< sp<AudioInputDescriptor> > activeInputs = mInputs.getActiveInputs();
-        for (const auto& activeDesc : activeInputs) {
-            if (is_virtual_input_device(activeDesc->mDevice)) {
-                continue;
-            }
+        Vector<sp<AudioInputDescriptor>> activeInputs = mInputs.getActiveInputs();
 
+        // If a UID is idle and records silence and another not silenced recording starts
+        // from another UID (idle or active) we stop the current idle UID recording in
+        // 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 &&
+                        activeDesc->getId() == inputDesc->getId()) {
+                     continue;
+                }
+
+                AudioSessionCollection activeSessions = activeDesc->getAudioSessions(
+                        true /*activeOnly*/);
+                sp<AudioSession> activeSession = activeSessions.valueAt(0);
+                if (activeSession->isSilenced()) {
+                    audio_io_handle_t activeInput = activeDesc->mIoHandle;
+                    audio_session_t activeSessionId = activeSession->session();
+                    stopInput(activeInput, activeSessionId);
+                    releaseInput(activeInput, activeSessionId);
+                    ALOGV("startInput(%d) stopping silenced input %d", input, activeInput);
+                    activeInputs = mInputs.getActiveInputs();
+                }
+            }
+        }
+
+        for (const auto& activeDesc : activeInputs) {
             if ((audioSession->flags() & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0 &&
                     activeDesc->getId() == inputDesc->getId()) {
                 continue;
@@ -1881,10 +1907,6 @@
 
         // if capture is allowed, preempt currently active HOTWORD captures
         for (const auto& activeDesc : activeInputs) {
-            if (is_virtual_input_device(activeDesc->mDevice)) {
-                continue;
-            }
-
             if (allowConcurrentWithSoundTrigger && activeDesc->isSoundTrigger()) {
                 continue;
             }
@@ -1907,6 +1929,9 @@
     }
 #endif
 
+    // Make sure we start with the correct silence state
+    audioSession->setSilenced(silenced);
+
     // increment activity count before calling getNewInputDevice() below as only active sessions
     // are considered for device selection
     audioSession->changeActiveCount(1);
@@ -2039,7 +2064,6 @@
 void AudioPolicyManager::releaseInput(audio_io_handle_t input,
                                       audio_session_t session)
 {
-
     ALOGV("releaseInput() %d", input);
     ssize_t index = mInputs.indexOfKey(input);
     if (index < 0) {
@@ -3394,6 +3418,23 @@
     return computeVolume(stream, index, device);
 }
 
+void AudioPolicyManager::setRecordSilenced(uid_t uid, bool silenced)
+{
+    ALOGV("AudioPolicyManager:setRecordSilenced(uid:%d, silenced:%d)", uid, silenced);
+
+    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);
+            }
+        }
+    }
+}
+
 status_t AudioPolicyManager::disconnectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc)
 {
     ALOGV("%s handle %d", __FUNCTION__, sourceDesc->getHandle());
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 611edec..4fd73e6 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -135,6 +135,7 @@
         // indicates to the audio policy manager that the input starts being used.
         virtual status_t startInput(audio_io_handle_t input,
                                     audio_session_t session,
+                                    bool silenced,
                                     concurrency_type__mask_t *concurrency);
 
         // indicates to the audio policy manager that the input stops being used.
@@ -235,6 +236,8 @@
         // return the strategy corresponding to a given stream type
         routing_strategy getStrategy(audio_stream_type_t stream) const;
 
+        virtual void setRecordSilenced(uid_t uid, bool silenced);
+
 protected:
         // A constructor that allows more fine-grained control over initialization process,
         // used in automatic tests.
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 7dd6d70..dc676d0 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -362,14 +362,22 @@
 }
 
 status_t AudioPolicyService::startInput(audio_io_handle_t input,
-                                        audio_session_t session)
+                                        audio_session_t session,
+                                        audio_devices_t device,
+                                        uid_t uid,
+                                        bool *silenced)
 {
+    // If UID inactive it records silence until becoming active
+    *silenced = !mUidPolicy->isUidActive(uid) && !is_virtual_input_device(device);
+
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
+
     Mutex::Autolock _l(mLock);
-    AudioPolicyInterface::concurrency_type__mask_t concurrency;
-    status_t status = mAudioPolicyManager->startInput(input, session, &concurrency);
+    AudioPolicyInterface::concurrency_type__mask_t concurrency =
+            AudioPolicyInterface::API_INPUT_CONCURRENCY_NONE;
+    status_t status = mAudioPolicyManager->startInput(input, session, silenced, &concurrency);
 
     if (status == NO_ERROR) {
         LOG_ALWAYS_FATAL_IF(concurrency & ~AudioPolicyInterface::API_INPUT_CONCURRENCY_ALL,
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index af0c823..e5aed9a 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -28,6 +28,9 @@
 #include <utils/Log.h>
 #include <cutils/properties.h>
 #include <binder/IPCThreadState.h>
+#include <binder/ActivityManager.h>
+#include <binder/PermissionController.h>
+#include <binder/IResultReceiver.h>
 #include <utils/String16.h>
 #include <utils/threads.h>
 #include "AudioPolicyService.h"
@@ -39,6 +42,8 @@
 #include <system/audio.h>
 #include <system/audio_policy.h>
 
+#include <private/android_filesystem_config.h>
+
 namespace android {
 
 static const char kDeadlockedString[] = "AudioPolicyService may be deadlocked\n";
@@ -49,6 +54,7 @@
 
 static const nsecs_t kAudioCommandTimeoutNs = seconds(3); // 3 seconds
 
+static const String16 sManageAudioPolicyPermission("android.permission.MANAGE_AUDIO_POLICY");
 
 // ----------------------------------------------------------------------------
 
@@ -79,6 +85,9 @@
         Mutex::Autolock _l(mLock);
         mAudioPolicyEffects = audioPolicyEffects;
     }
+
+    mUidPolicy = new UidPolicy(this);
+    mUidPolicy->registerSelf();
 }
 
 AudioPolicyService::~AudioPolicyService()
@@ -92,6 +101,9 @@
 
     mNotificationClients.clear();
     mAudioPolicyEffects.clear();
+
+    mUidPolicy->unregisterSelf();
+    mUidPolicy.clear();
 }
 
 // A notification client is always registered by AudioSystem when the client process
@@ -318,6 +330,20 @@
     return NO_ERROR;
 }
 
+void AudioPolicyService::setRecordSilenced(uid_t uid, bool silenced)
+{
+    {
+        Mutex::Autolock _l(mLock);
+        if (mAudioPolicyManager) {
+            mAudioPolicyManager->setRecordSilenced(uid, silenced);
+        }
+    }
+    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+    if (af) {
+        af->setRecordSilenced(uid, silenced);
+    }
+}
+
 status_t AudioPolicyService::dump(int fd, const Vector<String16>& args __unused)
 {
     if (!dumpAllowed()) {
@@ -361,11 +387,210 @@
 }
 
 status_t AudioPolicyService::onTransact(
-        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
+        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+    switch (code) {
+        case SHELL_COMMAND_TRANSACTION: {
+            int in = data.readFileDescriptor();
+            int out = data.readFileDescriptor();
+            int err = data.readFileDescriptor();
+            int argc = data.readInt32();
+            Vector<String16> args;
+            for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
+               args.add(data.readString16());
+            }
+            sp<IBinder> unusedCallback;
+            sp<IResultReceiver> resultReceiver;
+            status_t status;
+            if ((status = data.readNullableStrongBinder(&unusedCallback)) != NO_ERROR) {
+                return status;
+            }
+            if ((status = data.readNullableStrongBinder(&resultReceiver)) != NO_ERROR) {
+                return status;
+            }
+            status = shellCommand(in, out, err, args);
+            if (resultReceiver != nullptr) {
+                resultReceiver->send(status);
+            }
+            return NO_ERROR;
+        }
+    }
+
     return BnAudioPolicyService::onTransact(code, data, reply, flags);
 }
 
+// ------------------- Shell command implementation -------------------
+
+// NOTE: This is a remote API - make sure all args are validated
+status_t AudioPolicyService::shellCommand(int in, int out, int err, Vector<String16>& args) {
+    if (!checkCallingPermission(sManageAudioPolicyPermission, nullptr, nullptr)) {
+        return PERMISSION_DENIED;
+    }
+    if (in == BAD_TYPE || out == BAD_TYPE || err == BAD_TYPE) {
+        return BAD_VALUE;
+    }
+    if (args.size() == 3 && args[0] == String16("set-uid-state")) {
+        return handleSetUidState(args, err);
+    } else if (args.size() == 2 && args[0] == String16("reset-uid-state")) {
+        return handleResetUidState(args, err);
+    } else if (args.size() == 2 && args[0] == String16("get-uid-state")) {
+        return handleGetUidState(args, out, err);
+    } else if (args.size() == 1 && args[0] == String16("help")) {
+        printHelp(out);
+        return NO_ERROR;
+    }
+    printHelp(err);
+    return BAD_VALUE;
+}
+
+status_t AudioPolicyService::handleSetUidState(Vector<String16>& args, int err) {
+    PermissionController pc;
+    int uid = pc.getPackageUid(args[1], 0);
+    if (uid <= 0) {
+        ALOGE("Unknown package: '%s'", String8(args[1]).string());
+        dprintf(err, "Unknown package: '%s'\n", String8(args[1]).string());
+        return BAD_VALUE;
+    }
+    bool active = false;
+    if (args[2] == String16("active")) {
+        active = true;
+    } else if ((args[2] != String16("idle"))) {
+        ALOGE("Expected active or idle but got: '%s'", String8(args[2]).string());
+        return BAD_VALUE;
+    }
+    mUidPolicy->addOverrideUid(uid, active);
+    return NO_ERROR;
+}
+
+status_t AudioPolicyService::handleResetUidState(Vector<String16>& args, int err) {
+    PermissionController pc;
+    int uid = pc.getPackageUid(args[1], 0);
+    if (uid < 0) {
+        ALOGE("Unknown package: '%s'", String8(args[1]).string());
+        dprintf(err, "Unknown package: '%s'\n", String8(args[1]).string());
+        return BAD_VALUE;
+    }
+    mUidPolicy->removeOverrideUid(uid);
+    return NO_ERROR;
+}
+
+status_t AudioPolicyService::handleGetUidState(Vector<String16>& args, int out, int err) {
+    PermissionController pc;
+    int uid = pc.getPackageUid(args[1], 0);
+    if (uid < 0) {
+        ALOGE("Unknown package: '%s'", String8(args[1]).string());
+        dprintf(err, "Unknown package: '%s'\n", String8(args[1]).string());
+        return BAD_VALUE;
+    }
+    if (mUidPolicy->isUidActive(uid)) {
+        return dprintf(out, "active\n");
+    } else {
+        return dprintf(out, "idle\n");
+    }
+}
+
+status_t AudioPolicyService::printHelp(int out) {
+    return dprintf(out, "Audio policy service commands:\n"
+        "  get-uid-state <PACKAGE> gets the uid state\n"
+        "  set-uid-state <PACKAGE> <active|idle> overrides the uid state\n"
+        "  reset-uid-state <PACKAGE> clears the uid state override\n"
+        "  help print this message\n");
+}
+
+// -----------  AudioPolicyService::UidPolicy implementation ----------
+
+void AudioPolicyService::UidPolicy::registerSelf() {
+    ActivityManager am;
+    am.registerUidObserver(this, ActivityManager::UID_OBSERVER_GONE
+            | ActivityManager::UID_OBSERVER_IDLE
+            | ActivityManager::UID_OBSERVER_ACTIVE,
+            ActivityManager::PROCESS_STATE_UNKNOWN,
+            String16("audioserver"));
+}
+
+void AudioPolicyService::UidPolicy::unregisterSelf() {
+    ActivityManager am;
+    am.unregisterUidObserver(this);
+}
+
+void AudioPolicyService::UidPolicy::onUidGone(uid_t uid, __unused bool disabled) {
+    onUidIdle(uid, disabled);
+}
+
+void AudioPolicyService::UidPolicy::onUidActive(uid_t uid) {
+    {
+        Mutex::Autolock _l(mUidLock);
+        mActiveUids.insert(uid);
+    }
+    sp<AudioPolicyService> service = mService.promote();
+    if (service != nullptr) {
+        service->setRecordSilenced(uid, false);
+    }
+}
+
+void AudioPolicyService::UidPolicy::onUidIdle(uid_t uid, __unused bool disabled) {
+    bool deleted = false;
+    {
+        Mutex::Autolock _l(mUidLock);
+        if (mActiveUids.erase(uid) > 0) {
+            deleted = true;
+        }
+    }
+    if (deleted) {
+        sp<AudioPolicyService> service = mService.promote();
+        if (service != nullptr) {
+            service->setRecordSilenced(uid, true);
+        }
+    }
+}
+
+void AudioPolicyService::UidPolicy::addOverrideUid(uid_t uid, bool active) {
+    updateOverrideUid(uid, active, true);
+}
+
+void AudioPolicyService::UidPolicy::removeOverrideUid(uid_t uid) {
+    updateOverrideUid(uid, false, false);
+}
+
+void AudioPolicyService::UidPolicy::updateOverrideUid(uid_t uid, bool active, bool insert) {
+    bool wasActive = false;
+    bool isActive = false;
+    {
+        Mutex::Autolock _l(mUidLock);
+        wasActive = isUidActiveLocked(uid);
+        mOverrideUids.erase(uid);
+        if (insert) {
+            mOverrideUids.insert(std::pair<uid_t, bool>(uid, active));
+        }
+        isActive = isUidActiveLocked(uid);
+    }
+    if (wasActive != isActive) {
+        sp<AudioPolicyService> service = mService.promote();
+        if (service != nullptr) {
+            service->setRecordSilenced(uid, !isActive);
+        }
+    }
+}
+
+bool AudioPolicyService::UidPolicy::isUidActive(uid_t uid) {
+    // Non-app UIDs are considered always active
+    if (uid < FIRST_APPLICATION_UID) {
+        return true;
+    }
+    Mutex::Autolock _l(mUidLock);
+    return isUidActiveLocked(uid);
+}
+
+bool AudioPolicyService::UidPolicy::isUidActiveLocked(uid_t uid) {
+    // Non-app UIDs are considered always active
+    if (uid < FIRST_APPLICATION_UID) {
+        return true;
+    }
+    auto it = mOverrideUids.find(uid);
+    if (it != mOverrideUids.end()) {
+        return it->second;
+    }
+    return mActiveUids.find(uid) != mActiveUids.end();
+}
 
 // -----------  AudioPolicyService::AudioCommandThread implementation ----------
 
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 833a230..9bc13c2 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -24,6 +24,7 @@
 #include <utils/Vector.h>
 #include <utils/SortedVector.h>
 #include <binder/BinderService.h>
+#include <binder/IUidObserver.h>
 #include <system/audio.h>
 #include <system/audio_policy.h>
 #include <media/IAudioPolicyService.h>
@@ -33,9 +34,13 @@
 #include "AudioPolicyEffects.h"
 #include "managerdefault/AudioPolicyManager.h"
 
+#include <unordered_map>
+#include <unordered_set>
 
 namespace android {
 
+using namespace std;
+
 // ----------------------------------------------------------------------------
 
 class AudioPolicyService :
@@ -97,7 +102,10 @@
                                      audio_port_handle_t *selectedDeviceId = NULL,
                                      audio_port_handle_t *portId = NULL);
     virtual status_t startInput(audio_io_handle_t input,
-                                audio_session_t session);
+                                audio_session_t session,
+                                audio_devices_t device,
+                                uid_t uid,
+                                bool *silenced);
     virtual status_t stopInput(audio_io_handle_t input,
                                audio_session_t session);
     virtual void releaseInput(audio_io_handle_t input,
@@ -235,6 +243,57 @@
 
             status_t dumpInternals(int fd);
 
+    // Handles binder shell commands
+    virtual status_t shellCommand(int in, int out, int err, Vector<String16>& args);
+
+    // Sets whether the given UID records only silence
+    virtual void setRecordSilenced(uid_t uid, bool silenced);
+
+    // Overrides the UID state as if it is idle
+    status_t handleSetUidState(Vector<String16>& args, int err);
+
+    // Clears the override for the UID state
+    status_t handleResetUidState(Vector<String16>& args, int err);
+
+    // Gets the UID state
+    status_t handleGetUidState(Vector<String16>& args, int out, int err);
+
+    // Prints the shell command help
+    status_t printHelp(int out);
+
+    // If recording we need to make sure the UID is allowed to do that. If the UID is idle
+    // then it cannot record and gets buffers with zeros - silence. As soon as the UID
+    // transitions to an active state we will start reporting buffers with data. This approach
+    // transparently handles recording while the UID transitions between idle/active state
+    // avoiding to get stuck in a state receiving non-empty buffers while idle or in a state
+    // receiving empty buffers while active.
+    class UidPolicy : public BnUidObserver {
+    public:
+        explicit UidPolicy(wp<AudioPolicyService> service)
+                : mService(service) {}
+
+        void registerSelf();
+        void unregisterSelf();
+
+        bool isUidActive(uid_t uid);
+
+        void onUidGone(uid_t uid, bool disabled);
+        void onUidActive(uid_t uid);
+        void onUidIdle(uid_t uid, bool disabled);
+
+        void addOverrideUid(uid_t uid, bool active);
+        void removeOverrideUid(uid_t uid);
+
+    private:
+        bool isUidActiveLocked(uid_t uid);
+        void updateOverrideUid(uid_t uid, bool active, bool insert);
+
+        Mutex mUidLock;
+        wp<AudioPolicyService> mService;
+        std::unordered_set<uid_t> mActiveUids;
+        std::unordered_map<uid_t, bool> mOverrideUids;
+    };
+
     // Thread used for tone playback and to send audio config commands to audio flinger
     // For tone playback, using a separate thread is necessary to avoid deadlock with mLock because
     // startTone() and stopTone() are normally called with mLock locked and requesting a tone start
@@ -306,7 +365,6 @@
                                                         const audio_config_base_t *deviceConfig,
                                                         audio_patch_handle_t patchHandle);
                     void        insertCommand_l(AudioCommand *command, int delayMs = 0);
-
     private:
         class AudioCommandData;
 
@@ -575,6 +633,8 @@
     // Manage all effects configured in audio_effects.conf
     sp<AudioPolicyEffects> mAudioPolicyEffects;
     audio_mode_t mPhoneState;
+
+    sp<UidPolicy> mUidPolicy;
 };
 
 } // namespace android