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

To protect user's privacy if a UID is in an idle state we allow
recording but report silence (all zeros in the byte array) and once
the process goes in an active state we report the real mic data.
This avoids the race between the app being notified aboout its
lifecycle and the audio system being notified about the state
of a UID.

Test: Added - AudioRecordTest#testRecordNoDataForIdleUids
      Passing - cts-tradefed run cts-dev -m CtsMediaTestCases
                    -t android.media.cts.AudioRecordTest

bug:63938985

Change-Id: I1442a9dda1553e9ea7a4a654c50555ac1ec06aa0
gugelfrei
Svet Ganov 7 years ago
parent d6be64a3f2
commit f4ddfefc8b

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

@ -987,6 +987,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

@ -6528,6 +6528,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];
@ -6584,6 +6585,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 {
@ -6923,7 +6929,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) {
@ -6932,6 +6940,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
@ -7135,6 +7144,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()
{
@ -7827,7 +7846,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) {
@ -3391,6 +3415,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