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;