Proteção de áudio em segundo plano

A partir do Android 17, o framework de áudio impõe restrições às interações de áudio em segundo plano, incluindo reprodução de áudio, solicitações de foco de áudio e APIs de mudança de volume para garantir que essas mudanças sejam iniciadas intencionalmente pelo usuário.

Todos os apps em execução no Android 17 que têm essas interações de áudio em segundo plano precisam ter uma atividade visível ou estar executando um serviço em primeiro plano que não seja do tipo SHORT_SERVICE. Isso se aplica mesmo que o app seja destinado ao nível 37 da API.

Se um app for destinado ao Android 17 (nível da API 37), haverá uma restrição adicional. Se o app estiver em segundo plano, ele precisará executar um serviço em primeiro plano com recursos durante o uso (WIU, na sigla em inglês). Um serviço em primeiro plano recebe recursos de WIU se for iniciado em resposta a uma operação iniciada pelo usuário ou enquanto o app estiver visível para o usuário. No entanto, o requisito de recursos de WIU é dispensado se o app tiver recebido a permissão de alarme exato e estiver fazendo mudanças em fluxos de áudio com o atributo USAGE_ALARM.

Se o app tentar chamar APIs de áudio enquanto não estiver em um ciclo de vida válido, as APIs de reprodução de áudio e mudança de volume vão falhar silenciosamente sem gerar uma exceção ou fornecer uma mensagem de falha. A API de seleção de áudio falha com o código de resultado AUDIOFOCUS_REQUEST_FAILED.

Por que estamos fazendo essa mudança?

O objetivo dessas restrições é reduzir experiências com bugs de áudio em segundo plano não intencionais. Veja alguns exemplos:

  • Os apps que tocam áudio sem um serviço em primeiro plano podem ser congelados. Quando o app é descongelado, ele retoma a reprodução de áudio de forma inesperada, possivelmente horas depois.
  • Os apps que reproduzem áudio sem um serviço em primeiro plano enfrentam várias restrições de execução que resultam em um desempenho de áudio instável.
  • A reprodução foi separada do ciclo de vida da atividade, o que pode resultar em uma sessão de reprodução ou eventos de foco vazados que continuam sem que o usuário possa interromper a reprodução.

Recomendamos que os desenvolvedores testem os apps e enviem feedback sobre a mudança de comportamento se houver casos de uso de áudio intencionais afetados negativamente. Informe qualquer problema usando este rastreador de problemas de compatibilidade de apps do Android 17.

Identificar casos de uso de áudio em segundo plano afetados

Audite a implementação da reprodução de áudio e identifique se o app pretende fornecer funcionalidade de interação de áudio em segundo plano mesmo em circunstâncias condicionais.

Se o app só pretende tocar áudio ou usar APIs de áudio enquanto mostra uma atividade visível para o usuário, incluindo o uso do modo picture-in-picture (PiP), ele não será afetado por nenhuma dessas mudanças.

Se o app oferecer funcionalidade de VoIP, incluindo apps de videochamada, ele já precisa atender aos requisitos de reprodução (normalmente usando as APIs de telecomunicações recomendadas) para gravar áudio. Portanto, é improvável que ele seja afetado.

Se o app pretende continuar a reprodução de áudio com a tela desligada ou enquanto a Activity não está visível, o que é mais comum em apps de streaming de música ou de podcasts, ele é considerado como oferecendo funcionalidade de áudio em segundo plano e precisa atender aos novos requisitos.

Cenários de áudio em segundo plano que provavelmente serão afetados

Se o app não seguir o modelo de continuar uma interação de áudio iniciada enquanto ele estava aberto ou em resposta a um gatilho explícito do usuário, é provável que a funcionalidade do app seja suprimida silenciosamente.

Por exemplo, se o app iniciar um serviço em primeiro plano em resposta a BOOT_COMPLETE e tentar interagir com áudio, ele será suprimido.

Práticas recomendadas para reduzir o impacto do áudio em segundo plano

  • Use o componente MediaSessionService da biblioteca media3 do Jetpack para gerenciar a reprodução de áudio em segundo plano.

    Se você fizer isso, é provável que o app não seja afetado pelo reforço da proteção em segundo plano, já que a biblioteca ajuda a gerenciar o ciclo de vida da reprodução.

  • Se você não estiver usando a biblioteca media3, será necessário iniciar manualmente um FGS mediaPlayback. Sempre inicie um serviço em primeiro plano enquanto o app estiver em primeiro plano se áudio em segundo plano puder ocorrer.

    Por exemplo, se o app for um app de streaming de vídeo, que normalmente é apenas em primeiro plano, mas tiver um recurso para o usuário continuar a reprodução com a tela desligada, quando o gatilho de reprodução iniciado pelo usuário ocorrer, o app ainda precisará iniciar um serviço em primeiro plano.

    Isso garante que o serviço em primeiro plano seja iniciado com recursos de WIU.

  • Mantenha o mediaPlayback FGS ativo durante falhas temporárias de menos de 10 minutos.

    Se o app tiver uma falha temporária, como um problema com o buffer devido à atividade de rede, ou houver uma interrupção temporária esperada, como AUDIOFOCUS_LOSS_TRANSIENT, a intenção de reproduzir deve continuar. Portanto, seu FGS precisa permanecer ativo.

  • Interrompa o serviço em primeiro plano no final da reprodução e reinicie apenas se o usuário retomar explicitamente a reprodução.

    No caso de um sinal permanente para encerrar a reprodução (por exemplo, o conteúdo está completo sem reprodução automática, um AUDIOFOCUS_LOSS, um evento de pausa do UMO ou um evento de tecla de mídia) ou uma falha irrecuperável, o app deve interromper a interação de áudio, parar o serviço em primeiro plano e encerrar a sessão de mídia. Fazer tudo isso corresponde à concepção do usuário de "concluir" a interação de áudio em segundo plano desejada. Depois disso, o app não terá mais recursos de interação de áudio em segundo plano.

    Depois, se o usuário retomar explicitamente a reprodução, por exemplo, pela interface do app ou pelo botão de reprodução do objeto de mídia universal, a intent de iniciar a reprodução de áudio vai retornar, resultando em um novo serviço em primeiro plano.

  • Teste o comportamento de reprodução de áudio com comandos adb shell.

Testando mudanças

Para testar a conformidade do app em apps com o Android 17 ou versões mais recentes (a partir do Beta 3), execute o seguinte comando ADB:

adb shell cmd audio set-enable-hardening <enable|disable|throw>

Esse comando tem as seguintes opções:

  • enable: ativa todas as restrições de reforço da proteção de áudio para todos os apps. O requisito para serviços em primeiro plano do WIU é aplicado se um app é destinado ao Android 17 (nível 37 da API) ou não. Além disso, o requisito é aplicado mesmo que o app esteja fazendo mudanças nos fluxos de alarmes e tenha a permissão exata de alarme.

  • disable: desativa todas as restrições de proteção de áudio.

  • throw: ativa todas as restrições de reforço da proteção de áudio para todos os apps, como enable. Além disso, essa flag ativa falhas graves, gerando IllegalStateException para interações de volume e foco. Para reprodução de áudio, o método de gravação retorna um código de erro de forma persistente. Para modos de reprodução sem gravações explícitas, o app falha.

Use adb dumpsys audio ou logcat para identificar se o app encontrou falhas silenciosas devido à aplicação do reforço de áudio. Se sim, haverá uma entrada com o prefixo AudioHardening e o nome do pacote. Se a mensagem contiver level: full, o app estará executando um serviço em primeiro plano, mas ele não terá capacidade de uso durante o uso. Se a mensagem contiver level: partial, seu app não estará executando um serviço em primeiro plano.

Entender o FGS com capacidade de uso durante o uso

Em geral, os serviços em primeiro plano (FGS, na sigla em inglês) precisam ser iniciados enquanto um app está em primeiro plano para estender as operações iniciadas pelo usuário. Em alguns casos específicos, os apps podem iniciar um serviço em primeiro plano enquanto estão em segundo plano. No entanto, esses serviços em primeiro plano geralmente não recebem recursos de uso durante o uso (WIU, na sigla em inglês).

O WIU funciona como um portão de segurança. Ele impede que o SPP iniciado em segundo plano se envolva em determinados comportamentos sensíveis quando o usuário não tem conhecimento da atividade do app. Ele impede que o app acesse dados sensíveis, como localização, câmera ou microfone. Além disso, a partir do Android 17, ele também bloqueia APIs de áudio que normalmente exigem um contexto de interface visível.

Confira uma referência útil:

  • SPP padrão: os serviços iniciados enquanto o app está visível ou com capacidade de iniciar atividades em segundo plano recebem acesso ao WIU.
  • FGS iniciado em segundo plano (BFSL): a maioria não concede acesso ao WIU. As exceções principais que concedem o WIU são interações que envolvem a intenção explícita do usuário, por exemplo, cliques em notificações, interações com widgets ou eventos de teclas de mídia de um dispositivo externo.
  • O sistema iniciou o FGS: os serviços em primeiro plano recebem acesso ao WIU se forem iniciados por delegação do system-server (por exemplo, da biblioteca Telecom jetpack) ou por vinculações do sistema que representam um estado em primeiro plano elevado para realizar funcionalidades dedicadas (como para um VoiceInteractionService).

Leia mais em Restrições para iniciar um serviço em primeiro plano do segundo plano.

Lista completa das APIs de áudio afetadas

Função de áudio

Resultado

APIs afetadas

Reprodução de áudio

A reprodução é silenciada

Nenhuma exceção, nenhuma mensagem de falha fornecida por qualquer API

AudioTrack.write()

(NDK) AAudioStream_write

OpenSL ES para Android

Qualquer biblioteca de mídia do lado do cliente que gerencie a reprodução, como media3, Exoplayer e Oboe, também pode ser afetada.

Solicitação de seleção de áudio

Retorna AUDIOFOCUS_REQUEST_FAILED

Nenhum efeito na reprodução de áudio de outros apps, nenhum foco adquirido

AudioManager.requestAudioFocus()

APIs de volume e modo de toque

Nenhum efeito no modo ou volume da campainha (a chamada de método é ignorada silenciosamente)

Nenhuma exceção, nenhuma mensagem de falha fornecida por qualquer API

AudioManager.setStreamVolume()

AudioManager.setStreamMute()

AudioManager.adjustStreamVolume()

AudioManager.adjustVolume()

AudioManager.adjustSuggestedStreamVolume()

AudioManager.setRingerMode()