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
diff --git a/include/media/MmapStreamCallback.h b/include/media/MmapStreamCallback.h
index 8098e79..31b8eb5 100644
--- a/include/media/MmapStreamCallback.h
+++ b/include/media/MmapStreamCallback.h
@@ -31,8 +31,9 @@
* 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 b38d37f..54121cd 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1000,14 +1000,12 @@
{
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);
- }
+ 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 a210a1b..6f546c3 100644
--- a/services/audioflinger/MmapTracks.h
+++ b/services/audioflinger/MmapTracks.h
@@ -43,6 +43,15 @@
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 @@
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 43a8b50..f9c287a 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -7886,7 +7886,7 @@
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::disconnect()
{
- for (const sp<MmapTrack> &t : mActiveTracks) {
+ ActiveTracks<MmapTrack> activeTracks;
+ {
+ Mutex::Autolock _l(mLock);
+ for (const sp<MmapTrack> &t : mActiveTracks) {
+ activeTracks.add(t);
+ }
+ }
+ for (const sp<MmapTrack> &t : activeTracks) {
stop(t->portId());
}
// This will decrement references and may cause the destruction of this thread.
@@ -7949,6 +7956,17 @@
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 @@
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 @@
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<MmapTrack> &track : mActiveTracks) {
+ if (track->isSilenced_l() && track->uid() != client.clientUid)
+ track->invalidate();
+ }
+ }
+
// Given that MmapThread::mAttr is mutable, should a MmapTrack have attributes ?
sp<MmapTrack> track = new MmapTrack(this, mAttr, mSampleRate, mFormat, mChannelMask, mSessionId,
client.clientUid, client.clientPid, portId);
+ track->setSilenced_l(silenced);
mActiveTracks.add(track);
sp<EffectChain> chain = getEffectChain_l(mSessionId);
if (chain != 0) {
@@ -8072,6 +8094,8 @@
return NO_ERROR;
}
+ Mutex::Autolock _l(mLock);
+
sp<MmapTrack> track;
for (const sp<MmapTrack> &t : mActiveTracks) {
if (handle == t->portId()) {
@@ -8085,6 +8109,7 @@
mActiveTracks.remove(track);
+ mLock.unlock();
if (isOutput()) {
AudioSystem::stopOutput(mId, streamType(), track->sessionId());
AudioSystem::releaseOutput(mId, streamType(), track->sessionId());
@@ -8092,6 +8117,7 @@
AudioSystem::stopInput(track->portId());
AudioSystem::releaseInput(track->portId());
}
+ mLock.lock();
sp<EffectChain> chain = getEffectChain_l(track->sessionId());
if (chain != 0) {
@@ -8518,9 +8544,11 @@
if (track->isInvalid()) {
sp<MmapStreamCallback> 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 @@
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 @@
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 @@
return input;
}
+
+void AudioFlinger::MmapCaptureThread::processVolume_l()
+{
+ bool changed = false;
+ bool silenced = false;
+
+ sp<MmapStreamCallback> 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 @@
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 5a5961a..bc4a534 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1589,6 +1589,7 @@
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 @@
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<String16>& args);
virtual void dumpInternals(int fd, const Vector<String16>& args);
void dumpTracks(int fd, const Vector<String16>& args);
@@ -1637,6 +1641,9 @@
sp<DeviceHalInterface> mHalDevice;
AudioHwDevice* const mAudioHwDev;
ActiveTracks<MmapTrack> mActiveTracks;
+
+ int32_t mNoCallbackWarningCount;
+ static constexpr int32_t kMaxNoCallbackWarnings = 5;
};
class MmapPlaybackThread : public MmapThread, public VolumeInterface
@@ -1670,7 +1677,7 @@
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<String16>& args);
@@ -1686,8 +1693,6 @@
bool mMasterMute;
bool mStreamMute;
float mHalVolFloat;
- int32_t mNoCallbackWarningCount;
- static constexpr int32_t kMaxNoCallbackWarnings = 5;
AudioStreamOut* mOutput;
};
@@ -1702,9 +1707,12 @@
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 ee9ce84..47fe6ec 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1945,7 +1945,7 @@
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 29ec961..1cd5e09 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1468,14 +1468,19 @@
}
// 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 52990da..713ce60 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -343,8 +343,9 @@
}
-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 16b6269..c4c943d 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.h
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.h
@@ -68,7 +68,7 @@
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<float> values) override;