Merge "Don't record audio if UID is idle - media framework"
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 50fe385..16150f6 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -39,8 +39,7 @@
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::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,
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 56ddd4f..6507a5c 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -48,6 +48,7 @@
SET_MODE,
SET_MIC_MUTE,
GET_MIC_MUTE,
+ SET_RECORD_SILENCED,
SET_PARAMETERS,
GET_PARAMETERS,
REGISTER_CLIENT,
@@ -306,6 +307,15 @@
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 @@
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 @@
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();
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index 53bc1b7..c0e53b3 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -330,14 +330,22 @@
}
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 @@
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;
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 24a6e22..d6cc37a 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -244,7 +244,10 @@
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,
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 57d9778..472a3da 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -368,6 +368,7 @@
// 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;
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index 5558b77..7e9413d 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -84,7 +84,10 @@
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,
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 2a2f6fc..a9d0054 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -993,6 +993,21 @@
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();
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 5a64f0b..a1c3f36 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -147,6 +147,8 @@
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;
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index f8da780..63a3d98 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -63,6 +63,9 @@
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 @@
// 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
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 3a41ac8..8bf50b1 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -6532,6 +6532,7 @@
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 @@
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 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 @@
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 @@
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 @@
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
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 17f26c5..41d87a4 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1396,6 +1396,9 @@
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();
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index f2cb25f..2a8f54d 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -65,15 +65,15 @@
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 @@
// 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 @@
virtual float getStreamVolumeDB(
audio_stream_type_t stream, int index, audio_devices_t device) = 0;
+
+ virtual void setRecordSilenced(uid_t uid, bool silenced);
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
index 0d19373..dd5247d 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
@@ -55,6 +55,8 @@
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 @@
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
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 33f31e0..78a02b2 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1801,10 +1801,15 @@
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 @@
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 @@
// 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 @@
}
#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 @@
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 @@
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());
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 611edec..4fd73e6 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -135,6 +135,7 @@
// 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 @@
// 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.
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 7dd6d70..dc676d0 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -362,14 +362,22 @@
}
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,
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index af0c823..e5aed9a 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -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 nsecs_t kAudioCommandTimeoutNs = seconds(3); // 3 seconds
+static const String16 sManageAudioPolicyPermission("android.permission.MANAGE_AUDIO_POLICY");
// ----------------------------------------------------------------------------
@@ -79,6 +85,9 @@
Mutex::Autolock _l(mLock);
mAudioPolicyEffects = audioPolicyEffects;
}
+
+ mUidPolicy = new UidPolicy(this);
+ mUidPolicy->registerSelf();
}
AudioPolicyService::~AudioPolicyService()
@@ -92,6 +101,9 @@
mNotificationClients.clear();
mAudioPolicyEffects.clear();
+
+ mUidPolicy->unregisterSelf();
+ mUidPolicy.clear();
}
// A notification client is always registered by AudioSystem when the client process
@@ -318,6 +330,20 @@
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::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 ----------
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 833a230..9bc13c2 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -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 @@
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 @@
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 @@
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 @@
// Manage all effects configured in audio_effects.conf
sp<AudioPolicyEffects> mAudioPolicyEffects;
audio_mode_t mPhoneState;
+
+ sp<UidPolicy> mUidPolicy;
};
} // namespace android