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
gugelfrei
Eric Laurent 6 years ago
parent 9fc25229e0
commit a2f478ca0b

@ -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

@ -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<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);
}
}

@ -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 &timestamp);
pid_t mPid;
bool mSilenced; // protected by MMapThread::mLock
bool mSilencedNotified; // protected by MMapThread::mLock
}; // end of Track

@ -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<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 @@ 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<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 @@ status_t AudioFlinger::MmapThread::stop(audio_port_handle_t handle)
return NO_ERROR;
}
Mutex::Autolock _l(mLock);
sp<MmapTrack> track;
for (const sp<MmapTrack> &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<EffectChain> chain = getEffectChain_l(track->sessionId());
if (chain != 0) {
@ -8518,9 +8544,11 @@ void AudioFlinger::MmapThread::checkInvalidTracks_l()
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 @@ 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<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 @@ 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

@ -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<String16>& args);
virtual void dumpInternals(int fd, const Vector<String16>& args);
void dumpTracks(int fd, const Vector<String16>& args);
@ -1637,6 +1641,9 @@ class MmapThread : public ThreadBase
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 @@ 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<String16>& 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:

@ -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)
{
}

@ -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;

@ -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();
};

@ -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<float> values) override;

Loading…
Cancel
Save