From a2f478ca0b2bda8db9b321f0cfa9e9d3cf6130f9 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Tue, 10 Apr 2018 19:09:40 -0700 Subject: [PATCH] audioflinger: implement silenced capture for mmap Implement silencing of audio capture for idle UIDs for MMAP streams. Use audio HAL setMicGain() API to silence the mmap buffer for exclusive mode and when only one client is active in shared mode. Add new MmapStreamCallback method onStreamSilenced() for AAudio service to selectively silence streams from silenced UIDs in shared mode. Bug: 72134552 Test: manual Change-Id: I7c92ba0002bc5ba003c1a3c887edddf9ae53b538 --- include/media/MmapStreamCallback.h | 3 +- services/audioflinger/AudioFlinger.cpp | 10 +- services/audioflinger/MmapTracks.h | 11 ++ services/audioflinger/Threads.cpp | 100 +++++++++++++++--- services/audioflinger/Threads.h | 14 ++- services/audioflinger/Tracks.cpp | 2 +- .../managerdefault/AudioPolicyManager.cpp | 15 ++- .../oboeservice/AAudioServiceEndpointMMAP.cpp | 3 +- .../oboeservice/AAudioServiceEndpointMMAP.h | 2 +- 9 files changed, 128 insertions(+), 32 deletions(-) diff --git a/include/media/MmapStreamCallback.h b/include/media/MmapStreamCallback.h index 8098e79109..31b8eb54c4 100644 --- a/include/media/MmapStreamCallback.h +++ b/include/media/MmapStreamCallback.h @@ -31,8 +31,9 @@ class MmapStreamCallback : public virtual RefBase { * The mmap stream should be torn down because conditions that permitted its creation with * the requested parameters have changed and do not allow it to operate with the requested * constraints any more. + * \param[in] handle handle for the client stream to tear down. */ - virtual void onTearDown() = 0; + virtual void onTearDown(audio_port_handle_t handle) = 0; /** * The volume to be applied to the use case specified when opening the stream has changed diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index b38d37fac2..54121cd94a 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -1000,14 +1000,12 @@ 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 thread = mRecordThreads.valueAt(i); - if (thread != 0) { - thread->setRecordSilenced(uid, silenced); - } + mRecordThreads[i]->setRecordSilenced(uid, silenced); + } + for (size_t i = 0; i < mMmapThreads.size(); i++) { + mMmapThreads[i]->setRecordSilenced(uid, silenced); } } diff --git a/services/audioflinger/MmapTracks.h b/services/audioflinger/MmapTracks.h index a210a1bd22..6f546c3add 100644 --- a/services/audioflinger/MmapTracks.h +++ b/services/audioflinger/MmapTracks.h @@ -43,6 +43,15 @@ public: static void appendDumpHeader(String8& result); void appendDump(String8& result, bool active); + // protected by MMapThread::mLock + void setSilenced_l(bool silenced) { mSilenced = silenced; + mSilencedNotified = false;} + // protected by MMapThread::mLock + bool isSilenced_l() const { return mSilenced; } + // protected by MMapThread::mLock + bool getAndSetSilencedNotified_l() { bool silencedNotified = mSilencedNotified; + mSilencedNotified = true; + return silencedNotified; } private: friend class MmapThread; @@ -58,5 +67,7 @@ private: virtual void onTimestamp(const ExtendedTimestamp ×tamp); pid_t mPid; + bool mSilenced; // protected by MMapThread::mLock + bool mSilencedNotified; // protected by MMapThread::mLock }; // end of Track diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 43a8b50ae4..f9c287ae8b 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -7886,7 +7886,7 @@ AudioFlinger::MmapThread::MmapThread( mSessionId(AUDIO_SESSION_NONE), mDeviceId(AUDIO_PORT_HANDLE_NONE), mPortId(AUDIO_PORT_HANDLE_NONE), mHalStream(stream), mHalDevice(hwDev->hwDevice()), mAudioHwDev(hwDev), - mActiveTracks(&this->mLocalLog) + mActiveTracks(&this->mLocalLog), mNoCallbackWarningCount(0) { mStandby = true; readHalParameters_l(); @@ -7904,7 +7904,14 @@ void AudioFlinger::MmapThread::onFirstRef() void AudioFlinger::MmapThread::disconnect() { - for (const sp &t : mActiveTracks) { + ActiveTracks activeTracks; + { + Mutex::Autolock _l(mLock); + for (const sp &t : mActiveTracks) { + activeTracks.add(t); + } + } + for (const sp &t : activeTracks) { stop(t->portId()); } // This will decrement references and may cause the destruction of this thread. @@ -7949,6 +7956,17 @@ status_t AudioFlinger::MmapThread::getMmapPosition(struct audio_mmap_position *p return mHalStream->getMmapPosition(position); } +status_t AudioFlinger::MmapThread::exitStandby() +{ + status_t ret = mHalStream->start(); + if (ret != NO_ERROR) { + ALOGE("%s: error mHalStream->start() = %d for first track", __FUNCTION__, ret); + return ret; + } + mStandby = false; + return NO_ERROR; +} + status_t AudioFlinger::MmapThread::start(const AudioClient& client, audio_port_handle_t *handle) { @@ -7962,13 +7980,7 @@ status_t AudioFlinger::MmapThread::start(const AudioClient& client, if (*handle == mPortId) { // for the first track, reuse portId and session allocated when the stream was opened - ret = mHalStream->start(); - if (ret != NO_ERROR) { - ALOGE("%s: error mHalStream->start() = %d for first track", __FUNCTION__, ret); - return ret; - } - mStandby = false; - return NO_ERROR; + return exitStandby(); } audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE; @@ -8016,33 +8028,43 @@ status_t AudioFlinger::MmapThread::start(const AudioClient& client, return BAD_VALUE; } + bool silenced = false; if (isOutput()) { ret = AudioSystem::startOutput(mId, streamType(), mSessionId); } else { - // TODO: Block recording for idle UIDs (b/72134552) - bool silenced; ret = AudioSystem::startInput(portId, &silenced); } + Mutex::Autolock _l(mLock); // abort if start is rejected by audio policy manager if (ret != NO_ERROR) { ALOGE("%s: error start rejected by AudioPolicyManager = %d", __FUNCTION__, ret); if (mActiveTracks.size() != 0) { + mLock.unlock(); if (isOutput()) { AudioSystem::releaseOutput(mId, streamType(), mSessionId); } else { AudioSystem::releaseInput(portId); } + mLock.lock(); } else { mHalStream->stop(); } return PERMISSION_DENIED; } + if (!isOutput() && !silenced) { + for (const sp &track : mActiveTracks) { + if (track->isSilenced_l() && track->uid() != client.clientUid) + track->invalidate(); + } + } + // Given that MmapThread::mAttr is mutable, should a MmapTrack have attributes ? sp track = new MmapTrack(this, mAttr, mSampleRate, mFormat, mChannelMask, mSessionId, client.clientUid, client.clientPid, portId); + track->setSilenced_l(silenced); mActiveTracks.add(track); sp chain = getEffectChain_l(mSessionId); if (chain != 0) { @@ -8072,6 +8094,8 @@ status_t AudioFlinger::MmapThread::stop(audio_port_handle_t handle) return NO_ERROR; } + Mutex::Autolock _l(mLock); + sp track; for (const sp &t : mActiveTracks) { if (handle == t->portId()) { @@ -8085,6 +8109,7 @@ status_t AudioFlinger::MmapThread::stop(audio_port_handle_t handle) mActiveTracks.remove(track); + mLock.unlock(); if (isOutput()) { AudioSystem::stopOutput(mId, streamType(), track->sessionId()); AudioSystem::releaseOutput(mId, streamType(), track->sessionId()); @@ -8092,6 +8117,7 @@ status_t AudioFlinger::MmapThread::stop(audio_port_handle_t handle) AudioSystem::stopInput(track->portId()); AudioSystem::releaseInput(track->portId()); } + mLock.lock(); sp chain = getEffectChain_l(track->sessionId()); if (chain != 0) { @@ -8518,9 +8544,11 @@ void AudioFlinger::MmapThread::checkInvalidTracks_l() if (track->isInvalid()) { sp callback = mCallback.promote(); if (callback != 0) { - callback->onTearDown(); + callback->onTearDown(track->portId()); + } else if (mNoCallbackWarningCount < kMaxNoCallbackWarnings) { + ALOGW("Could not notify MMAP stream tear down: no onTearDown callback!"); + mNoCallbackWarningCount++; } - break; } } } @@ -8575,7 +8603,6 @@ AudioFlinger::MmapPlaybackThread::MmapPlaybackThread( mStreamVolume(1.0), mStreamMute(false), mHalVolFloat(-1.0f), // Initialize to illegal value so it always gets set properly later. - mNoCallbackWarningCount(0), mOutput(output) { snprintf(mThreadName, kThreadNameLength, "AudioMmapOut_%X", id); @@ -8780,6 +8807,12 @@ AudioFlinger::MmapCaptureThread::MmapCaptureThread( mChannelCount = audio_channel_count_from_in_mask(mChannelMask); } +status_t AudioFlinger::MmapCaptureThread::exitStandby() +{ + mInput->stream->setGain(1.0f); + return MmapThread::exitStandby(); +} + AudioFlinger::AudioStreamIn* AudioFlinger::MmapCaptureThread::clearInput() { Mutex::Autolock _l(mLock); @@ -8788,6 +8821,34 @@ AudioFlinger::AudioStreamIn* AudioFlinger::MmapCaptureThread::clearInput() return input; } + +void AudioFlinger::MmapCaptureThread::processVolume_l() +{ + bool changed = false; + bool silenced = false; + + sp callback = mCallback.promote(); + if (callback == 0) { + if (mNoCallbackWarningCount < kMaxNoCallbackWarnings) { + ALOGW("Could not set MMAP stream silenced: no onStreamSilenced callback!"); + mNoCallbackWarningCount++; + } + } + + // After a change occurred in track silenced state, mute capture in audio DSP if at least one + // track is silenced and unmute otherwise + for (size_t i = 0; i < mActiveTracks.size() && !silenced; i++) { + if (!mActiveTracks[i]->getAndSetSilencedNotified_l()) { + changed = true; + silenced = mActiveTracks[i]->isSilenced_l(); + } + } + + if (changed) { + mInput->stream->setGain(silenced ? 0.0f: 1.0f); + } +} + void AudioFlinger::MmapCaptureThread::updateMetadata_l() { if (mInput == nullptr || mInput->stream == nullptr || @@ -8805,4 +8866,15 @@ void AudioFlinger::MmapCaptureThread::updateMetadata_l() mInput->stream->updateSinkMetadata(metadata); } +void AudioFlinger::MmapCaptureThread::setRecordSilenced(uid_t uid, bool silenced) +{ + Mutex::Autolock _l(mLock); + for (size_t i = 0; i < mActiveTracks.size() ; i++) { + if (mActiveTracks[i]->uid() == uid) { + mActiveTracks[i]->setSilenced_l(silenced); + broadcast_l(); + } + } +} + } // namespace android diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index 5a5961a989..bc4a534743 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -1589,6 +1589,7 @@ class MmapThread : public ThreadBase virtual void threadLoop_exit(); virtual void threadLoop_standby(); virtual bool shouldStandby_l() { return false; } + virtual status_t exitStandby(); virtual status_t initCheck() const { return (mHalStream == 0) ? NO_INIT : NO_ERROR; } virtual size_t frameCount() const { return mFrameCount; } @@ -1621,6 +1622,9 @@ class MmapThread : public ThreadBase virtual void invalidateTracks(audio_stream_type_t streamType __unused) {} + // Sets the UID records silence + virtual void setRecordSilenced(uid_t uid __unused, bool silenced __unused) {} + void dump(int fd, const Vector& args); virtual void dumpInternals(int fd, const Vector& args); void dumpTracks(int fd, const Vector& args); @@ -1637,6 +1641,9 @@ class MmapThread : public ThreadBase sp mHalDevice; AudioHwDevice* const mAudioHwDev; ActiveTracks mActiveTracks; + + int32_t mNoCallbackWarningCount; + static constexpr int32_t kMaxNoCallbackWarnings = 5; }; class MmapPlaybackThread : public MmapThread, public VolumeInterface @@ -1670,7 +1677,7 @@ public: virtual audio_stream_type_t streamType() { return mStreamType; } virtual void checkSilentMode_l(); - virtual void processVolume_l(); + void processVolume_l() override; virtual void dumpInternals(int fd, const Vector& args); @@ -1686,8 +1693,6 @@ protected: bool mMasterMute; bool mStreamMute; float mHalVolFloat; - int32_t mNoCallbackWarningCount; - static constexpr int32_t kMaxNoCallbackWarnings = 5; AudioStreamOut* mOutput; }; @@ -1702,9 +1707,12 @@ public: AudioStreamIn* clearInput(); + status_t exitStandby() override; virtual bool isOutput() const override { return false; } void updateMetadata_l() override; + void processVolume_l() override; + void setRecordSilenced(uid_t uid, bool silenced) override; protected: diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index ee9ce84bca..47fe6ecaab 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -1945,7 +1945,7 @@ AudioFlinger::MmapThread::MmapTrack::MmapTrack(ThreadBase *thread, sessionId, uid, false /* isOut */, ALLOC_NONE, TYPE_DEFAULT, portId), - mPid(pid) + mPid(pid), mSilenced(false), mSilencedNotified(false) { } diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index 29ec961d6b..1cd5e09dc9 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -1468,14 +1468,19 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, } // For MMAP mode, the first call to getInputForAttr() is made on behalf of audioflinger. // 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. + // 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) { - ALOGW("getInputForAttr() bad uid %d for session %d uid %d", - uid, session, audioSession->uid()); - status = INVALID_OPERATION; - goto error; + if (!audioSession->isSilenced()) { + ALOGW("getInputForAttr() bad uid %d for session %d uid %d", + uid, session, audioSession->uid()); + status = INVALID_OPERATION; + goto error; + } + audioSession->setUid(uid); + audioSession->setSilenced(false); } audioSession->changeOpenCount(1); *inputType = API_INPUT_LEGACY; diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp index 52990da180..713ce60c2d 100644 --- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp +++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp @@ -343,8 +343,9 @@ aaudio_result_t AAudioServiceEndpointMMAP::getTimestamp(int64_t *positionFrames, } -void AAudioServiceEndpointMMAP::onTearDown() { +void AAudioServiceEndpointMMAP::onTearDown(audio_port_handle_t handle __unused) { ALOGD("%s(%p) called", __func__, this); + //TODO: disconnect only stream corresponding to handle received disconnectRegisteredStreams(); }; diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.h b/services/oboeservice/AAudioServiceEndpointMMAP.h index 16b62694c5..c4c943d4af 100644 --- a/services/oboeservice/AAudioServiceEndpointMMAP.h +++ b/services/oboeservice/AAudioServiceEndpointMMAP.h @@ -68,7 +68,7 @@ public: aaudio_result_t getTimestamp(int64_t *positionFrames, int64_t *timeNanos) override; // -------------- Callback functions for MmapStreamCallback --------------------- - void onTearDown() override; + void onTearDown(audio_port_handle_t handle) override; void onVolumeChanged(audio_channel_mask_t channels, android::Vector values) override;