Merge "Don't record audio if UID is idle - media framework"

gugelfrei
TreeHugger Robot 7 years ago committed by Android (Google) Code Review
commit 65a438c642

@ -39,8 +39,7 @@ sp<IAudioFlinger> AudioSystem::gAudioFlinger;
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::getInputForAttr(const audio_attributes_t *attr,
}
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,

@ -48,6 +48,7 @@ enum {
SET_MODE,
SET_MIC_MUTE,
GET_MIC_MUTE,
SET_RECORD_SILENCED,
SET_PARAMETERS,
GET_PARAMETERS,
REGISTER_CLIENT,
@ -306,6 +307,15 @@ public:
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 @@ status_t BnAudioFlinger::onTransact(
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 @@ status_t BnAudioFlinger::onTransact(
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();

@ -330,14 +330,22 @@ public:
}
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 @@ status_t BnAudioPolicyService::onTransact(
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;

@ -244,7 +244,10 @@ public:
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,

@ -368,6 +368,7 @@ public:
// 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;

@ -84,7 +84,10 @@ public:
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,

@ -993,6 +993,21 @@ bool AudioFlinger::getMicMute() const
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();

@ -147,6 +147,8 @@ public:
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;

@ -63,6 +63,9 @@ public:
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 @@ private:
// 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

@ -6532,6 +6532,7 @@ reacquire_wakelock:
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 @@ reacquire_wakelock:
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 AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrac
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 @@ status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrac
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 @@ void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args
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 @@ status_t AudioFlinger::MmapThread::start(const AudioClient& client,
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

@ -1396,6 +1396,9 @@ public:
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();

@ -65,15 +65,15 @@ public:
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 @@ public:
// 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 @@ public:
virtual float getStreamVolumeDB(
audio_stream_type_t stream, int index, audio_devices_t device) = 0;
virtual void setRecordSilenced(uid_t uid, bool silenced);
};

@ -55,6 +55,8 @@ public:
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 @@ private:
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

@ -1801,10 +1801,15 @@ bool AudioPolicyManager::soundTriggerSupportsConcurrentCapture() {
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 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input,
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 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input,
// 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 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input,
}
#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 @@ status_t AudioPolicyManager::stopInput(audio_io_handle_t input,
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 @@ float AudioPolicyManager::getStreamVolumeDB(
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());

@ -135,6 +135,7 @@ public:
// 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 @@ public:
// 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.

@ -362,14 +362,22 @@ status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr,
}
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,

@ -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 int kDumpLockSleepUs = 20000;
static const nsecs_t kAudioCommandTimeoutNs = seconds(3); // 3 seconds
static const String16 sManageAudioPolicyPermission("android.permission.MANAGE_AUDIO_POLICY");
// ----------------------------------------------------------------------------
@ -79,6 +85,9 @@ void AudioPolicyService::onFirstRef()
Mutex::Autolock _l(mLock);
mAudioPolicyEffects = audioPolicyEffects;
}
mUidPolicy = new UidPolicy(this);
mUidPolicy->registerSelf();
}
AudioPolicyService::~AudioPolicyService()
@ -92,6 +101,9 @@ AudioPolicyService::~AudioPolicyService()
mNotificationClients.clear();
mAudioPolicyEffects.clear();
mUidPolicy->unregisterSelf();
mUidPolicy.clear();
}
// A notification client is always registered by AudioSystem when the client process
@ -318,6 +330,20 @@ status_t AudioPolicyService::dumpInternals(int fd)
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::dumpPermissionDenial(int fd)
}
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 ----------

@ -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 @@ public:
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 @@ private:
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 @@ private:
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 @@ private:
// Manage all effects configured in audio_effects.conf
sp<AudioPolicyEffects> mAudioPolicyEffects;
audio_mode_t mPhoneState;
sp<UidPolicy> mUidPolicy;
};
} // namespace android

Loading…
Cancel
Save