Limites da execução em segundo plano

Sempre que um app é executado em segundo plano, ele consome alguns dos recursos limitados do dispositivo, como a RAM. Isso pode prejudicar a experiência do usuário, principalmente se ele estiver usando um app que consome muitos recursos, como um jogo ou um vídeo. Para melhorar a experiência do usuário, o Android 8.0 (nível 26 da API) impõe limitações ao que os apps podem fazer enquanto são executados em segundo plano. Este documento descreve as mudanças no sistema operacional e como atualizar seu app para que ele funcione bem com as novas limitações.

Visão geral

Muitos aplicativos e serviços do Android podem ser executados simultaneamente. Por exemplo, um usuário pode estar jogando um jogo em uma janela enquanto navega na Web em outra e usa um terceiro app para ouvir música. Quanto mais apps estiverem em execução ao mesmo tempo, maior será a carga no sistema. Se outros apps ou serviços estiverem em execução em segundo plano, isso vai gerar cargas adicionais no sistema, o que pode resultar em uma experiência de usuário ruim. Por exemplo, o app de música pode ser desativado repentinamente.

Para reduzir a chance de esses problemas, o Android 8.0 coloca limitações no que os apps podem fazer enquanto os usuários não estão interagindo diretamente com eles. Os aplicativos são limitados de duas maneiras:

  • Limitações de serviços em segundo plano: enquanto um app está inativo, há limites para o uso de serviços em segundo plano. Isso não se aplica a serviços em primeiro plano, que são mais perceptíveis para o usuário.

  • Limitações de transmissão: com exceções limitadas, os apps não podem usar o manifesto para se registrar para transmissões implícitas. Eles ainda podem se registrar para essas transmissões no momento de execução e usar o manifesto para se registrar para transmissões explícitas e transmissões segmentadas especificamente para o app.

Na maioria dos casos, os apps podem contornar essas limitações usando jobs JobScheduler. Essa abordagem permite que um app se organize para realizar o trabalho quando não estiver em execução, mas ainda oferece ao sistema a liberdade de programar esses trabalhos de uma forma que não afete a experiência do usuário. O Android 8.0 oferece várias melhorias em JobScheduler que facilitam a substituição de serviços e broadcast receivers por jobs programados. Para mais informações, consulte Melhorias no JobScheduler.

Limitações de serviço em segundo plano

Os serviços em execução em segundo plano podem consumir recursos do dispositivo, o que pode resultar em uma experiência do usuário pior. Para atenuar esse problema, o sistema aplica várias limitações aos serviços.

O sistema distingue apps em primeiro plano dos segundo plano. A definição de segundo plano para fins de limitações de serviço é diferente da definição usada pelo gerenciamento de memória. Um app pode estar em segundo plano em relação ao gerenciamento de memória, mas em primeiro plano em relação à capacidade de iniciar serviços. Considera-se que um aplicativo esteja em primeiro plano se alguma das seguintes coisas acontecer:

  • Há uma atividade visível, esteja ela em curso ou pausada.
  • Há um serviço de primeiro plano.
  • Outro app em primeiro plano está conectado ao app, seja vinculado a um dos serviços dele ou fazendo uso de um dos provedores de conteúdo. Por exemplo, o app está em primeiro plano se outro app se vincula ao:
    • IME
    • Serviço de plano de fundo
    • Listener de notificações
    • Serviço de voz ou texto

Se nenhuma dessas condições for verdadeira, será considerado que o app está em segundo plano.

Enquanto um app está em primeiro plano, ele pode criar e executar serviços em primeiro plano e em segundo plano livremente. Quando um app entra em segundo plano, ele tem uma janela de vários minutos em que ainda pode criar e usar serviços. Ao final desse período, o app é considerado inativo. Nesse momento, o sistema interrompe os serviços em segundo plano do app, como se ele tivesse chamado os métodos Service.stopSelf() dos serviços.

Em determinadas circunstâncias, um app em segundo plano é colocado em uma lista de permissões temporária por vários minutos. Enquanto um app está na lista de permissões, ele pode iniciar serviços sem limitação, e os serviços em segundo plano podem ser executados. Um app é colocado na lista de permissões quando processa uma tarefa que é visível para o usuário, como:

  • Processamento de uma mensagem de alta prioridade do Firebase Cloud Messaging (FCM).
  • Receber uma transmissão, como uma mensagem SMS/MMS.
  • Execução de um PendingIntent em uma notificação.
  • Inicie um VpnService antes que o app de VPN seja promovido para o primeiro plano.

Em muitos casos, o app pode substituir os serviços em segundo plano por jobs JobScheduler. Por exemplo, o CoolPhotoApp precisa verificar se o usuário recebeu fotos compartilhadas de amigos, mesmo que o app não esteja em execução em primeiro plano. Anteriormente, o app usava um serviço em segundo plano que verificava o armazenamento em nuvem do app. Para migrar para o Android 8.0 (nível 26 da API), o desenvolvedor substitui o serviço em segundo plano por um job programado, que é iniciado periodicamente, consulta o servidor e é encerrado.

Antes do Android 8.0, a maneira usual de criar um serviço em primeiro plano era criar um serviço em segundo plano e depois promover esse serviço para o primeiro plano. Com o Android 8.0, há uma complicação: o sistema não permite que um app em segundo plano crie um serviço em segundo plano. Por esse motivo, o Android 8.0 apresenta o novo método startForegroundService() para iniciar um novo serviço em primeiro plano. Depois que o sistema cria o serviço, o app tem cinco segundos para chamar o método [startForeground()](/reference/android/app/Service#startForeground(int, android.app.Notification) do serviço para mostrar a nova notificação visível para o usuário. Se o app não chamar startForeground() dentro do limite de tempo, o sistema vai interromper o serviço e declarar que o app é um ANR.

Limitações de transmissão

Se um app se registrar para receber transmissões, o receptor do app vai consumir recursos sempre que a transmissão for enviada. Isso pode causar problemas se muitos apps se registrarem para receber transmissões com base em eventos do sistema. Um evento do sistema que aciona uma transmissão pode fazer com que todos esses apps consumam recursos em rápida sequência, prejudicando a experiência do usuário. Para atenuar esse problema, o Android 7.0 (nível 24 da API) impôs limitações às transmissões, conforme descrito em Otimização em segundo plano. O Android 8.0 (API de nível 26) torna essas limitações mais rigorosas.

  • Os apps destinados ao Android 8.0 ou mais recente não podem mais registrar broadcast receivers para transmissões implícitas no manifesto, a menos que a transmissão seja restringida especificamente a esse app. Uma transmissão implícita é uma transmissão que não tem como destino um componente específico em um app. Por exemplo, ACTION_PACKAGE_REPLACED é enviada para todos os listeners registrados em todos os apps, informando que alguns pacotes no dispositivo foram substituídos. Como a transmissão é implícita, ela não será entregue a receptores registrados no manifesto em apps destinados ao Android 8.0 ou mais recente. ACTION_MY_PACKAGE_REPLACED também é uma transmissão implícita, mas, como ela é enviada apenas para o app cujo pacote foi substituído, ela será entregue aos receptores registrados no manifesto.
  • Aplicativos podem continuar a se registrar para transmissões explícitas em seus manifestos.
  • Os apps podem usar Context.registerReceiver() no tempo de execução para registrar um receptor para qualquer transmissão, seja implícita ou explícita.
  • As transmissões que exigem uma permissão de assinatura são isentas dessa restrição, já que são enviadas apenas para apps assinados com o mesmo certificado, e não para todos os apps no dispositivo.

Em muitos casos, os apps que já estavam registrados para uma transmissão implícita podem ter uma funcionalidade semelhante usando um job JobScheduler. Por exemplo, um app de fotos de mídia social pode precisar limpar os dados de vez em quando e preferir fazer isso quando o dispositivo estiver conectado a um carregador. Anteriormente, o app registrava um receiver para ACTION_POWER_CONNECTED no manifesto. Quando o app recebia essa transmissão, ele verificava se a limpeza era necessária. Para migrar para o Android 8.0 ou mais recente, o app remove esse receiver do manifest. Em vez disso, o app programa um job de limpeza que é executado quando o dispositivo está inativo e carregando.

Guia de migração

Por padrão, essas mudanças afetam apenas apps destinados ao Android 8.0 (nível 26 da API) ou mais recente. No entanto, os usuários podem ativar essas restrições para qualquer app na tela Configurações, mesmo que o app seja destinado a um nível de API anterior ao 26. Talvez seja necessário atualizar o app para estar em conformidade com as novas limitações.

Verifique como seu aplicativo usa os serviços. Se o app depender de serviços que são executados em segundo plano enquanto ele está inativo, será necessário substituí-los. Possíveis soluções incluem:

  • Se o app precisar criar um serviço em primeiro plano enquanto estiver em segundo plano, use o método startForegroundService() em vez de startService().
  • Se o serviço for perceptível para o usuário, torne-o um serviço de primeiro plano. Por exemplo, um serviço que reproduz áudio precisa ser sempre um serviço em primeiro plano. Crie o serviço usando o método startForegroundService() em vez de startService().
  • Encontre uma maneira de duplicar a funcionalidade do serviço com um job programado. Se o serviço não estiver fazendo algo imediatamente perceptível para o usuário, geralmente será possível usar um job programado.
  • Use o FCM para ativar o app seletivamente quando eventos de rede ocorrerem, em vez de fazer a pesquisa em segundo plano.
  • Adie o trabalho de segundo plano até que o aplicativo esteja naturalmente em primeiro plano.

Revise os broadcast receivers definidos no manifesto do app. Se o manifesto declara um receiver para uma transmissão implícita afetada, substitua-o. Possíveis soluções incluem:

  • Crie o receptor no momento da execução chamando Context.registerReceiver(), em vez de declarar o receptor no manifesto.
  • Use um job programado para verificar a condição que teria acionado a transmissão implícita.