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) impõe limitações sobre 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.

Informações gerais

Muitos aplicativos e serviços do Android podem ser executados simultaneamente. Por exemplo, um usuário pode jogar em uma janela enquanto navega na Web em outra e usar um terceiro app para tocar música. Quanto mais aplicativos são executados ao mesmo tempo, mais carga é colocada no sistema. Se outros apps ou serviços estiverem em execução em segundo plano, isso sobrecarregará 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 estabelece limitações sobre 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ço em segundo plano: enquanto um 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 pelo usuário.

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

Na maioria dos casos, os apps podem contornar essas limitações usando jobs de JobScheduler. Essa abordagem permite que um app realize o trabalho quando não estiver em execução ativamente, mas ainda dá ao sistema liberdade 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 o 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 executados em segundo plano podem consumir recursos do dispositivo, possivelmente resultando em uma experiência pior para o usuário. 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 está em 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 a ele, seja vinculado a um dos serviços dele ou usando um dos provedores de conteúdo. Por exemplo, o app vai estar em primeiro plano se outro app se vincular ao seguinte:
    • 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 entra 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 da janela, 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 visível para o usuário, por exemplo:

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

Em muitos casos, seu 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 para o primeiro plano. No Android 8.0, há um problema: 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 ao usuário do novo serviço. Se o app não chamar startForeground() dentro do limite de tempo, o sistema interromperá o serviço e declarará o app como 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 atenuar esse problema, o Android 7.0 (nível 24 da API) colocou limitações em 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.

  • 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 é enviada 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. A 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 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 elas 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 receber 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 recebeva essa transmissão, ele verificava se a limpeza era necessária. Ao 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 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 o app seja direcionado a um nível de API anterior ao 26. Talvez seja necessário atualizar o app para atender às novas limitações.

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

  • Caso seu app precise 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 no momento da execução chamando Context.registerReceiver(), em vez de declará-lo no manifesto.
  • Use um job programado para verificar a condição que acionaria a transmissão implícita.