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