diff --git a/media/libaudioclient/AudioEffect.cpp b/media/libaudioclient/AudioEffect.cpp index cb46b93c05..0641b6ead6 100644 --- a/media/libaudioclient/AudioEffect.cpp +++ b/media/libaudioclient/AudioEffect.cpp @@ -447,6 +447,55 @@ status_t AudioEffect::queryDefaultPreProcessing(audio_session_t audioSession, if (aps == 0) return PERMISSION_DENIED; return aps->queryDefaultPreProcessing(audioSession, descriptors, count); } + +status_t AudioEffect::newEffectUniqueId(audio_unique_id_t* id) +{ + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + *id = af->newAudioUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT); + return NO_ERROR; +} + +status_t AudioEffect::addStreamDefaultEffect(const char *typeStr, + const String16& opPackageName, + const char *uuidStr, + int32_t priority, + audio_usage_t usage, + audio_unique_id_t *id) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + + if (typeStr == NULL && uuidStr == NULL) return BAD_VALUE; + + // Convert type & uuid from string to effect_uuid_t. + effect_uuid_t type; + if (typeStr != NULL) { + status_t res = stringToGuid(typeStr, &type); + if (res != OK) return res; + } else { + type = *EFFECT_UUID_NULL; + } + + effect_uuid_t uuid; + if (uuidStr != NULL) { + status_t res = stringToGuid(uuidStr, &uuid); + if (res != OK) return res; + } else { + uuid = *EFFECT_UUID_NULL; + } + + return aps->addStreamDefaultEffect(&type, opPackageName, &uuid, priority, usage, id); +} + +status_t AudioEffect::removeStreamDefaultEffect(audio_unique_id_t id) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + + return aps->removeStreamDefaultEffect(id); +} + // ------------------------------------------------------------------------- status_t AudioEffect::stringToGuid(const char *str, effect_uuid_t *guid) diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp index 73a8b747b4..abf74f80e4 100644 --- a/media/libaudioclient/IAudioPolicyService.cpp +++ b/media/libaudioclient/IAudioPolicyService.cpp @@ -81,7 +81,9 @@ enum { GET_MASTER_MONO, GET_STREAM_VOLUME_DB, GET_SURROUND_FORMATS, - SET_SURROUND_FORMAT_ENABLED + SET_SURROUND_FORMAT_ENABLED, + ADD_STREAM_DEFAULT_EFFECT, + REMOVE_STREAM_DEFAULT_EFFECT }; #define MAX_ITEMS_PER_LIST 1024 @@ -866,6 +868,42 @@ public: } return reply.readInt32(); } + + virtual status_t addStreamDefaultEffect(const effect_uuid_t *type, + const String16& opPackageName, + const effect_uuid_t *uuid, + int32_t priority, + audio_usage_t usage, + audio_unique_id_t* id) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.write(type, sizeof(effect_uuid_t)); + data.writeString16(opPackageName); + data.write(uuid, sizeof(effect_uuid_t)); + data.writeInt32(priority); + data.writeInt32((int32_t) usage); + status_t status = remote()->transact(ADD_STREAM_DEFAULT_EFFECT, data, &reply); + if (status != NO_ERROR) { + return status; + } + status = static_cast (reply.readInt32()); + *id = reply.readInt32(); + return status; + } + + virtual status_t removeStreamDefaultEffect(audio_unique_id_t id) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.writeInt32(id); + status_t status = remote()->transact(REMOVE_STREAM_DEFAULT_EFFECT, data, &reply); + if (status != NO_ERROR) { + return status; + } + return static_cast (reply.readInt32()); + } + }; IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService"); @@ -1561,6 +1599,43 @@ status_t BnAudioPolicyService::onTransact( return NO_ERROR; } + case ADD_STREAM_DEFAULT_EFFECT: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + effect_uuid_t type; + status_t status = data.read(&type, sizeof(effect_uuid_t)); + if (status != NO_ERROR) { + return status; + } + String16 opPackageName; + status = data.readString16(&opPackageName); + if (status != NO_ERROR) { + return status; + } + effect_uuid_t uuid; + status = data.read(&uuid, sizeof(effect_uuid_t)); + if (status != NO_ERROR) { + return status; + } + int32_t priority = data.readInt32(); + audio_usage_t usage = (audio_usage_t) data.readInt32(); + audio_unique_id_t id = 0; + reply->writeInt32(static_cast (addStreamDefaultEffect(&type, + opPackageName, + &uuid, + priority, + usage, + &id))); + reply->writeInt32(id); + return NO_ERROR; + } + + case REMOVE_STREAM_DEFAULT_EFFECT: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + audio_unique_id_t id = static_cast(data.readInt32()); + reply->writeInt32(static_cast (removeStreamDefaultEffect(id))); + return NO_ERROR; + } + default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libaudioclient/include/media/AudioEffect.h b/media/libaudioclient/include/media/AudioEffect.h index ae66e8f2d4..c97f7838a3 100644 --- a/media/libaudioclient/include/media/AudioEffect.h +++ b/media/libaudioclient/include/media/AudioEffect.h @@ -150,6 +150,79 @@ public: effect_descriptor_t *descriptors, uint32_t *count); + /* + * Gets a new system-wide unique effect id. + * + * Parameters: + * id: The address to return the generated id. + * + * Returned status (from utils/Errors.h) can be: + * NO_ERROR successful operation. + * PERMISSION_DENIED could not get AudioFlinger interface + * or caller lacks required permissions. + * Returned value + * *id: The new unique system-wide effect id. + */ + static status_t newEffectUniqueId(audio_unique_id_t* id); + + /* + * Static methods for adding/removing system-wide effects. + */ + + /* + * Adds an effect to the list of default output effects for a given stream type. + * + * If the effect is no longer available when a stream of the given type + * is created, the system will continue without adding it. + * + * Parameters: + * typeStr: Type uuid of effect to be a default: can be null if uuidStr is specified. + * This may correspond to the OpenSL ES interface implemented by this effect, + * or could be some vendor-defined type. + * opPackageName: The package name used for app op checks. + * uuidStr: Uuid of effect to be a default: can be null if type is specified. + * This uuid corresponds to a particular implementation of an effect type. + * Note if both uuidStr and typeStr are specified, typeStr is ignored. + * priority: Requested priority for effect control: the priority level corresponds to the + * value of priority parameter: negative values indicate lower priorities, positive + * values higher priorities, 0 being the normal priority. + * usage: The usage this effect should be a default for. Unrecognized values will be + * treated as AUDIO_USAGE_UNKNOWN. + * id: Address where the system-wide unique id of the default effect should be returned. + * + * Returned status (from utils/Errors.h) can be: + * NO_ERROR successful operation. + * PERMISSION_DENIED could not get AudioFlinger interface + * or caller lacks required permissions. + * NO_INIT effect library failed to initialize. + * BAD_VALUE invalid type uuid or implementation uuid. + * NAME_NOT_FOUND no effect with this uuid or type found. + * + * Returned value + * *id: The system-wide unique id of the added default effect. + */ + static status_t addStreamDefaultEffect(const char* typeStr, + const String16& opPackageName, + const char* uuidStr, + int32_t priority, + audio_usage_t usage, + audio_unique_id_t* id); + + /* + * Removes an effect from the list of default output effects for a given stream type. + * + * Parameters: + * id: The system-wide unique id of the effect that should no longer be a default. + * + * Returned status (from utils/Errors.h) can be: + * NO_ERROR successful operation. + * PERMISSION_DENIED could not get AudioFlinger interface + * or caller lacks required permissions. + * NO_INIT effect library failed to initialize. + * BAD_VALUE invalid id. + */ + static status_t removeStreamDefaultEffect(audio_unique_id_t id); + /* * Events used by callback function (effect_callback_t). */ diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h index cdbb8760c1..c2899f83e0 100644 --- a/media/libaudioclient/include/media/IAudioPolicyService.h +++ b/media/libaudioclient/include/media/IAudioPolicyService.h @@ -109,6 +109,13 @@ public: virtual status_t queryDefaultPreProcessing(audio_session_t audioSession, effect_descriptor_t *descriptors, uint32_t *count) = 0; + virtual status_t addStreamDefaultEffect(const effect_uuid_t *type, + const String16& opPackageName, + const effect_uuid_t *uuid, + int32_t priority, + audio_usage_t usage, + audio_unique_id_t* id) = 0; + virtual status_t removeStreamDefaultEffect(audio_unique_id_t id) = 0; // Check if offload is possible for given format, stream type, sample rate, // bit rate, duration, video and streaming or offload property is enabled virtual bool isOffloadSupported(const audio_offload_info_t& info) = 0; diff --git a/media/utils/Android.bp b/media/utils/Android.bp index 13b66ed950..f5b3f929c2 100644 --- a/media/utils/Android.bp +++ b/media/utils/Android.bp @@ -40,6 +40,12 @@ cc_library { "-Werror", ], + product_variables: { + product_is_iot: { + cflags: ["-DTARGET_ANDROID_THINGS"], + }, + }, + local_include_dirs: ["include"], export_include_dirs: ["include"], } diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp index 0d50be0cb4..1c54aec468 100644 --- a/media/utils/ServiceUtilities.cpp +++ b/media/utils/ServiceUtilities.cpp @@ -158,6 +158,27 @@ bool modifyAudioRoutingAllowed() { return ok; } +bool modifyDefaultAudioEffectsAllowed() { + static const String16 sModifyDefaultAudioEffectsAllowed( + "android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"); + // IMPORTANT: Use PermissionCache - not a runtime permission and may not change. + bool ok = PermissionCache::checkCallingPermission(sModifyDefaultAudioEffectsAllowed); + +#ifdef TARGET_ANDROID_THINGS + if (!ok) { + // Use a secondary permission on Android Things to allow a more lenient level of protection. + static const String16 sModifyDefaultAudioEffectsAndroidThingsAllowed( + "com.google.android.things.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"); + ok = PermissionCache::checkCallingPermission( + sModifyDefaultAudioEffectsAndroidThingsAllowed); + } + if (!ok) ALOGE("com.google.android.things.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"); +#else + if (!ok) ALOGE("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"); +#endif + return ok; +} + bool dumpAllowed() { static const String16 sDump("android.permission.DUMP"); // IMPORTANT: Use PermissionCache - not a runtime permission and may not change. diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h index 0911744fb6..98f54c2b8b 100644 --- a/media/utils/include/mediautils/ServiceUtilities.h +++ b/media/utils/include/mediautils/ServiceUtilities.h @@ -68,6 +68,7 @@ bool captureAudioOutputAllowed(pid_t pid, uid_t uid); bool captureHotwordAllowed(pid_t pid, uid_t uid); bool settingsAllowed(); bool modifyAudioRoutingAllowed(); +bool modifyDefaultAudioEffectsAllowed(); bool dumpAllowed(); bool modifyPhoneStateAllowed(pid_t pid, uid_t uid); status_t checkIMemory(const sp& iMemory); diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp index fdae23b4c9..2858aadb2d 100644 --- a/services/audiopolicy/service/AudioPolicyEffects.cpp +++ b/services/audiopolicy/service/AudioPolicyEffects.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -317,6 +318,102 @@ status_t AudioPolicyEffects::releaseOutputSessionEffects(audio_io_handle_t outpu return status; } +status_t AudioPolicyEffects::addStreamDefaultEffect(const effect_uuid_t *type, + const String16& opPackageName, + const effect_uuid_t *uuid, + int32_t priority, + audio_usage_t usage, + audio_unique_id_t* id) +{ + if (uuid == NULL || type == NULL) { + ALOGE("addStreamDefaultEffect(): Null uuid or type uuid pointer"); + return BAD_VALUE; + } + + audio_stream_type_t stream = audio_usage_to_stream_type(usage); + + if (stream < AUDIO_STREAM_MIN || stream >= AUDIO_STREAM_PUBLIC_CNT) { + ALOGE("addStreamDefaultEffect(): Unsupported stream type %d", stream); + return BAD_VALUE; + } + + // Check that |uuid| or |type| corresponds to an effect on the system. + effect_descriptor_t descriptor = {}; + status_t res = AudioEffect::getEffectDescriptor( + uuid, type, EFFECT_FLAG_TYPE_INSERT, &descriptor); + if (res != OK) { + ALOGE("addStreamDefaultEffect(): Failed to find effect descriptor matching uuid/type."); + return res; + } + + // Only insert effects can be added dynamically as stream defaults. + if ((descriptor.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_INSERT) { + ALOGE("addStreamDefaultEffect(): Desired effect cannot be attached " + "as a stream default effect."); + return BAD_VALUE; + } + + Mutex::Autolock _l(mLock); + + // Find the EffectDescVector for the given stream type, or create a new one if necessary. + ssize_t index = mOutputStreams.indexOfKey(stream); + EffectDescVector *desc = NULL; + if (index < 0) { + // No effects for this stream type yet. + desc = new EffectDescVector(); + mOutputStreams.add(stream, desc); + } else { + desc = mOutputStreams.valueAt(index); + } + + // Create a new effect and add it to the vector. + res = AudioEffect::newEffectUniqueId(id); + if (res != OK) { + ALOGE("addStreamDefaultEffect(): failed to get new unique id."); + return res; + } + EffectDesc *effect = new EffectDesc( + descriptor.name, *type, opPackageName, *uuid, priority, *id); + desc->mEffects.add(effect); + // TODO(b/71813697): Support setting params as well. + + // TODO(b/71814300): Retroactively attach to any existing streams of the given type. + // This requires tracking the stream type of each session id in addition to what is + // already being tracked. + + return NO_ERROR; +} + +status_t AudioPolicyEffects::removeStreamDefaultEffect(audio_unique_id_t id) +{ + if (id == AUDIO_UNIQUE_ID_ALLOCATE) { + // ALLOCATE is not a unique identifier, but rather a reserved value indicating + // a real id has not been assigned. For default effects, this value is only used + // by system-owned defaults from the loaded config, which cannot be removed. + return BAD_VALUE; + } + + Mutex::Autolock _l(mLock); + + // Check each stream type. + size_t numStreams = mOutputStreams.size(); + for (size_t i = 0; i < numStreams; ++i) { + // Check each effect for each stream. + EffectDescVector* descVector = mOutputStreams[i]; + for (auto desc = descVector->mEffects.begin(); desc != descVector->mEffects.end(); ++desc) { + if ((*desc)->mId == id) { + // Found it! + // TODO(b/71814300): Remove from any streams the effect was attached to. + descVector->mEffects.erase(desc); + // Handles are unique; there can only be one match, so return early. + return NO_ERROR; + } + } + } + + // Effect wasn't found, so it's been trivially removed successfully. + return NO_ERROR; +} void AudioPolicyEffects::EffectVector::setProcessorEnabled(bool enabled) { diff --git a/services/audiopolicy/service/AudioPolicyEffects.h b/services/audiopolicy/service/AudioPolicyEffects.h index 623180ea26..69367b1dc0 100644 --- a/services/audiopolicy/service/AudioPolicyEffects.h +++ b/services/audiopolicy/service/AudioPolicyEffects.h @@ -64,7 +64,6 @@ public: status_t releaseInputEffects(audio_io_handle_t input, audio_session_t audioSession); - // Return a list of effect descriptors for default output effects // associated with audioSession status_t queryDefaultOutputSessionEffects(audio_session_t audioSession, @@ -82,18 +81,49 @@ public: audio_stream_type_t stream, audio_session_t audioSession); + // Add the effect to the list of default effects for streams of type |stream|. + status_t addStreamDefaultEffect(const effect_uuid_t *type, + const String16& opPackageName, + const effect_uuid_t *uuid, + int32_t priority, + audio_usage_t usage, + audio_unique_id_t* id); + + // Remove the default stream effect from wherever it's attached. + status_t removeStreamDefaultEffect(audio_unique_id_t id); + private: // class to store the description of an effects and its parameters // as defined in audio_effects.conf class EffectDesc { public: - EffectDesc(const char *name, const effect_uuid_t& uuid) : + EffectDesc(const char *name, + const effect_uuid_t& typeUuid, + const String16& opPackageName, + const effect_uuid_t& uuid, + uint32_t priority, + audio_unique_id_t id) : mName(strdup(name)), - mUuid(uuid) { } + mTypeUuid(typeUuid), + mOpPackageName(opPackageName), + mUuid(uuid), + mPriority(priority), + mId(id) { } + EffectDesc(const char *name, const effect_uuid_t& uuid) : + EffectDesc(name, + *EFFECT_UUID_NULL, + String16(""), + uuid, + 0, + AUDIO_UNIQUE_ID_ALLOCATE) { } EffectDesc(const EffectDesc& orig) : mName(strdup(orig.mName)), - mUuid(orig.mUuid) { + mTypeUuid(orig.mTypeUuid), + mOpPackageName(orig.mOpPackageName), + mUuid(orig.mUuid), + mPriority(orig.mPriority), + mId(orig.mId) { // deep copy mParams for (size_t k = 0; k < orig.mParams.size(); k++) { effect_param_t *origParam = orig.mParams[k]; @@ -116,7 +146,11 @@ private: } } char *mName; + effect_uuid_t mTypeUuid; + String16 mOpPackageName; effect_uuid_t mUuid; + int32_t mPriority; + audio_unique_id_t mId; Vector mParams; }; diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp index dbfda44e5e..d29f637807 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp @@ -859,6 +859,50 @@ status_t AudioPolicyService::queryDefaultPreProcessing(audio_session_t audioSess (audio_session_t)audioSession, descriptors, count); } +status_t AudioPolicyService::addStreamDefaultEffect(const effect_uuid_t *type, + const String16& opPackageName, + const effect_uuid_t *uuid, + int32_t priority, + audio_usage_t usage, + audio_unique_id_t* id) +{ + if (mAudioPolicyManager == NULL) { + return NO_INIT; + } + if (!modifyDefaultAudioEffectsAllowed()) { + return PERMISSION_DENIED; + } + spaudioPolicyEffects; + { + Mutex::Autolock _l(mLock); + audioPolicyEffects = mAudioPolicyEffects; + } + if (audioPolicyEffects == 0) { + return NO_INIT; + } + return audioPolicyEffects->addStreamDefaultEffect( + type, opPackageName, uuid, priority, usage, id); +} + +status_t AudioPolicyService::removeStreamDefaultEffect(audio_unique_id_t id) +{ + if (mAudioPolicyManager == NULL) { + return NO_INIT; + } + if (!modifyDefaultAudioEffectsAllowed()) { + return PERMISSION_DENIED; + } + spaudioPolicyEffects; + { + Mutex::Autolock _l(mLock); + audioPolicyEffects = mAudioPolicyEffects; + } + if (audioPolicyEffects == 0) { + return NO_INIT; + } + return audioPolicyEffects->removeStreamDefaultEffect(id); +} + bool AudioPolicyService::isOffloadSupported(const audio_offload_info_t& info) { if (mAudioPolicyManager == NULL) { diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h index 6a256683ce..44c0347f7f 100644 --- a/services/audiopolicy/service/AudioPolicyService.h +++ b/services/audiopolicy/service/AudioPolicyService.h @@ -126,6 +126,14 @@ public: virtual status_t queryDefaultPreProcessing(audio_session_t audioSession, effect_descriptor_t *descriptors, uint32_t *count); + virtual status_t addStreamDefaultEffect(const effect_uuid_t *type, + const String16& opPackageName, + const effect_uuid_t *uuid, + int32_t priority, + audio_usage_t usage, + audio_unique_id_t* id); + virtual status_t removeStreamDefaultEffect(audio_unique_id_t id); + virtual status_t onTransact( uint32_t code, const Parcel& data,