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 resultar em uma experiência do usuário prejudicada, especialmente se o usuário 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) limita o que os apps podem fazer durante a execução em segundo plano. Este documento descreve as mudanças no sistema operacional e como você pode 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 em uma janela enquanto navega na Web em outra e usando um terceiro app para tocar música. Quanto mais apps são executados ao mesmo tempo, mais carga é colocada no sistema. Caso outros apps ou serviços estejam em execução em segundo plano, isso sobrecarrega o sistema, o que pode resultar em uma experiência ruim para o usuário. Por exemplo, o app de música pode ser desligado de repente.

Para reduzir a chance desses problemas, o Android 8.0 limita o 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 o app está inativo, há limites para o uso de serviços em segundo plano. Isso não se aplica aos 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 nessas transmissões durante a execução e usar o manifesto para registrar transmissões explícitas e direcionadas especificamente ao app.

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

Limitações de serviços em segundo plano

Os serviços executados em segundo plano podem consumir recursos do dispositivo, possivelmente resultando 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 entre apps em primeiro plano e em 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 no que diz respeito ao gerenciamento de memória, mas no primeiro plano no que diz respeito à 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 vai estar em primeiro plano se outro app se vincular a:
    • 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 e segundo plano livremente. Quando um app fica em segundo plano, ele tem uma janela de vários minutos em que ainda tem permissão para criar e usar serviços. No final dessa janela, o app será 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 visível para o usuário, por exemplo:

  • Processamento de mensagens 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.
  • Iniciar um VpnService antes que o app de VPN se promova para o primeiro plano.

Em muitos casos, o app pode substituir serviços em segundo plano por jobs do 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 normal de criar um serviço em primeiro plano era criar um serviço em segundo plano e promovê-lo ao primeiro plano. No 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 introduz o novo método startForegroundService() para iniciar um novo serviço em primeiro plano. Depois que o sistema criar o serviço, o app terá cinco segundos para chamar o método [startForeground()](/reference/android/app/Service#startForeground(int, android.app.Notification) do serviço para mostrar a notificação visível do novo serviço. Se o app não chamar startForeground() dentro do limite de tempo, o sistema vai interromper o serviço e declarar que o app é ANR.

Limitações da transmissão

Se um app se registrar para receber transmissões, o receptor dele 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 sucessão, prejudicando a experiência do usuário. Para mitigar esse problema, o Android 7.0 (API de nível 24) estabeleceu limitações para 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 direcionados ao Android 8.0 ou versões mais recentes não podem mais registrar broadcast receivers para transmissões implícitas no manifesto, a menos que a transmissão seja restrita especificamente a esse app. Uma transmissão implícita é uma transmissão que não tem como alvo um componente específico em um app. Por exemplo, ACTION_PACKAGE_REPLACED é enviado a todos os listeners registrados em todos os apps, informando que algum pacote no dispositivo foi substituído. Como a transmissão é implícita, ela não será entregue a receptores registrados pelo manifesto em apps direcionados ao Android 8.0 ou versões mais recentes. ACTION_MY_PACKAGE_REPLACED também é uma transmissão implícita, mas, como ele é enviado apenas ao app cujo pacote foi substituído, ele será entregue aos receptores registrados pelo manifesto.
  • Aplicativos podem continuar a se registrar para transmissões explícitas em seus manifestos.
  • Os apps podem usar o Context.registerReceiver() durante a 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 estão isentas dessa restrição, já que são enviadas apenas para apps assinados com o mesmo certificado, não para todos os apps no dispositivo.

Em muitos casos, os apps que foram registrados anteriormente para uma transmissão implícita podem ter uma funcionalidade semelhante usando um job JobScheduler. Por exemplo, um app social de fotos 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 receptor 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 versões mais recentes, o app remove esse receptor do manifesto. 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 os apps destinados ao Android 8.0 (nível 26 da API) ou versões mais recentes. No entanto, os usuários podem ativar essas restrições para qualquer app na tela Configurações, mesmo que ele seja direcionado a um nível de API anterior ao 26. Talvez seja necessário atualizar seu app para atender às novas limitações.

Verifique como seu aplicativo usa os serviços. Se seu app depende de serviços que são executados em segundo plano enquanto ele está ocioso, 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 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 é possível usar um job programado.
  • Use o FCM para ativar seu aplicativo seletivamente quando ocorrerem eventos de rede, em vez de realizar pesquisas 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 declarar um receptor para uma transmissão implícita afetada, ele precisa ser substituído. Possíveis soluções incluem:

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