O Android protege os usuários contra apps maliciosos e oferece uma experiência de interface confiável. O framework de segurança de atividades abrange regras e restrições de plataforma. Essas regras e restrições evitam interrupções indesejadas na interface, roubo de tarefas e outras ameaças à segurança. Essas ameaças se relacionam a quando e como os componentes do app aparecem na tela. Um componente principal desse framework restringe o início de atividades em segundo plano.
Restrições de inicialização de atividades em segundo plano
Uma inicialização de atividade em segundo plano (BAL, na sigla em inglês) ocorre quando um app que não está em primeiro plano, sem atividades visíveis ou um PendingIntent recebido de um app diferente
tenta iniciar uma nova atividade. Esta é uma inicialização de atividade em segundo plano (BAL, na sigla em inglês).
Embora existam casos de uso legítimos, como quando um app de despertador é iniciado, as BALs sem restrições prejudicam a experiência do usuário e criam vulnerabilidades de segurança.
Por que eles são restritos?
Desde o Android 10 (nível 29 da API), a plataforma impõe restrições quanto ao momento em que os apps podem iniciar atividades em segundo plano. Essas proteções ajudam a evitar comportamentos maliciosos de apps e melhoram a experiência do usuário ao reduzir abusos comuns, incluindo:
- Sequestro de interface e anúncios pop-up: um app em segundo plano inicia inesperadamente uma atividade (geralmente um anúncio) sobre o app com que o usuário está interagindo, sequestrando a sessão.
- Phishing e falsificação de identidade: um app em segundo plano inicia uma atividade que se passa por outro app (por exemplo, uma tela de login falsa para um app legítimo) para roubar credenciais de usuário. Isso geralmente é feito por um ataque "Activity Sandwich", em que uma atividade maliciosa é inserida na pilha de tarefas de um app legítimo.
- Tapjacking: um app em segundo plano mostra uma atividade transparente ou obscurecida sobre outro app para interceptar os toques do usuário e enganá-lo para que ele realize ações não intencionais.
- Despertar de apps: um componente em segundo plano de um app desperta os componentes em primeiro plano de outro app para aumentar de forma ilegítima as métricas de usuários ativos por dia.
Serviços em primeiro plano (para tarefas em andamento)
Se o app precisar realizar uma tarefa de longa duração em segundo plano que o usuário precisa conhecer, como tocar música ou monitorar um treino, use um serviço em primeiro plano. Um serviço em primeiro plano precisa mostrar uma notificação persistente que não pode ser dispensada pelo usuário. Essa notificação pode fornecer controles interativos, como botões de reproduzir/pausar para um app de música. Isso mantém o usuário informado e no controle, mas não o interrompe com uma atividade em tela cheia.
Ao seguir essa hierarquia, começando com notificações padrão e só passando para opções mais intrusivas quando necessário, você cria uma experiência melhor e mais previsível para os usuários.
Quando o início de atividades em segundo plano é permitido (exceções)
Um app pode iniciar uma atividade em segundo plano se uma das seguintes condições for atendida:
- O app tem uma janela visível, como uma atividade em primeiro plano.
- O app é o editor de método de entrada (IME, na sigla em inglês) atual.
- A atividade é iniciada por uma
PendingIntentenviada pelo sistema (por exemplo, um toque em uma notificação). - O app tem a permissão
SYSTEM_ALERT_WINDOWconcedida pelo usuário. - O app recebeu a permissão
START_ACTIVITIES_FROM_BACKGROUND. - O app é vinculado por um serviço que recebeu permissão para iniciar atividades em segundo plano.
- O início é feito pelo app de início do dispositivo, como quando um usuário toca no ícone de um app ou interage com um widget.
- O lançamento é de uma parte principal do sistema operacional que precisa ser executada em todos os momentos, como o serviço de telefonia que inicia a tela de chamada recebida.
Novas proteções e ativações obrigatórias
Para aumentar ainda mais a segurança, o Android introduziu regras mais rígidas que exigem
ativações explícitas para apps que usam PendingIntent e IntentSender para
iniciar atividades. Uma inicialização só é permitida se o app que criou a
PendingIntent ou o app que a envia ativar a concessão de privilégios de
inicialização em segundo plano.
Na maioria dos casos, o app que envia o PendingIntent precisa ativar a opção, já que geralmente é o app com que o usuário está interagindo diretamente (por exemplo, tocando em um botão).
Os remetentes precisam ativar o PendingIntent
Quando o app é direcionado ao Android 14 (nível 34 da API) ou versões mais recentes, ele não concede mais privilégios de BAL por padrão ao enviar um PendingIntent. Se você não ativar explicitamente, o início da atividade poderá ser bloqueado, a menos que o criador do PendingIntent já tenha concedido os próprios privilégios.
Para garantir que um lançamento seja bem-sucedido, o remetente precisa ativar a concessão de privilégios chamando ActivityOptions.setPendingIntentBackgroundActivityStartMode() e o modo recomendado é ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE (adicionado no SDK 36).
Esse é um modo mais restrito e seguro. Ele concede permissão somente se o app de envio
estiver visível na tela no momento em que o PendingIntent é enviado. Isso garante mais fortemente que o início da atividade é resultado direto da interação de um usuário com seu app.
Use ActivityOptions.setPendingIntentBackgroundActivityStartMode() para conceder privilégios.
// Sender Side
ActivityOptions options = ActivityOptions.makeBasic()
.setPendingIntentBackgroundActivityStartMode(
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE);
try {
myPendingIntent.send(options.toBundle());
} catch (PendingIntent.CanceledException e) {
Log.e(TAG, "The PendingIntent was canceled", e);
}
// Sender Side
val options = ActivityOptions.makeBasic().apply {
pendingIntentBackgroundActivityStartMode = ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE
}
try {
myPendingIntent.send(options.toBundle())
} catch (e: PendingIntent.CanceledException) {
Log.e(TAG, "The PendingIntent was canceled", e)
}
Os criadores de conteúdo precisam ativar a PendingIntent
Quando o app é direcionado ao Android 15 (nível 35 da API) ou versões mais recentes, um app que
cria um PendingIntent não concede mais privilégios de
início em segundo plano por padrão. Para permitir que o remetente use os privilégios de BAL do seu app, você
precisa ativar essa opção explicitamente.
Use ActivityOptions.setPendingIntentCreatorBackgroundActivityStartMode() para conceder permissões.
// Creator Side
Intent intent = new Intent(context, MyActivity.class);
ActivityOptions options = ActivityOptions.makeBasic().setPendingIntentCreatorBackgroundActivityStartMode(ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
PendingIntent pendingIntent = PendingIntent.getActivity(context, REQUEST_CODE, intent, PendingIntent.FLAG_IMMUTABLE, options.toBundle());
// Creator Side
val intent = Intent(context, MyActivity::class.java)
val options = ActivityOptions.makeBasic().apply {
pendingIntentCreatorBackgroundActivityStartMode = ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
}
val pendingIntent = PendingIntent.getActivity(context, REQUEST_CODE, intent,
PendingIntent.FLAG_IMMUTABLE, options.toBundle())
Início com IntentSender
As mesmas restrições de BAL também se aplicam ao iniciar atividades usando um
IntentSender. Como um IntentSender é obtido via
PendingIntent.getIntentSender, ele está sujeito a requisitos de ativação
semelhantes.
- A partir do Android 14 (API 34), o uso de Context.startIntentSender()
exige uma ativação no lado do remetente. Você também precisa fornecer o pacote
ActivityOptionsaqui.
ActivityOptions options = ActivityOptions.makeBasic()
.setPendingIntentBackgroundActivityStartMode(
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
context.startIntentSender(myIntentSender, fillInIntent, flagsMask,
flagsValues, extraFlags, options.toBundle());
val options = ActivityOptions.makeBasic().apply {
pendingIntentBackgroundActivityStartMode = ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
}
context.startIntentSender(myIntentSender, fillInIntent, flagsMask,
flagsValues, extraFlags, options.toBundle())
- A partir do Android 17 (API 37 ou mais recente), o uso de IntentSender.sendIntent() exige uma ativação no lado do remetente.
ActivityOptions options = ActivityOptions.makeBasic()
.setPendingIntentBackgroundActivityStartMode(
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
myIntentSender.sendIntent(context, code, intent, onFinished, handler,
requiredPermission, options.toBundle());
val options = ActivityOptions.makeBasic().apply {
pendingIntentBackgroundActivityStartMode = ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
}
myIntentSender.sendIntent(context, code, intent, onFinished, handler,
requiredPermission, options.toBundle())
- Usando ActivityResultLauncher<IntentSenderRequest>: essa API do AndroidX usa Context.startIntentSender()internamente e, portanto, é afetada pelas restrições da BAL.
Diagrama de sequência: restrições da BAL
Este diagrama ilustra o processo de iniciar uma atividade com segurança usando uma PendingIntent. Um lançamento bem-sucedido depende de uma cadeia de privilégios válida em que pelo menos um dos apps participantes concede privilégios e tem a capacidade de iniciar uma atividade em segundo plano.
- Criação e delegação (App A: o criador)
- O app Criador cria o
PendingIntent - Se o SDK de destino for a versão 35 ou mais recente, o criador precisará delegar explicitamente os privilégios da BAL usando setPendingIntentCreatorBackgroundActivityStartMode() se quiser que os privilégios sejam usados. Por padrão, nenhum privilégio é delegado.
- O
PendingIntenté entregue a outro app (App B).
- O app Criador cria o
- Lançamento e contribuição (App B: The Sender)
- Mais tarde, o app remetente inicia o lançamento chamando
PendingIntent.send(). - Se o SDK de destino for a versão 34 ou mais recente, o remetente precisará contribuir explicitamente com os próprios privilégios usando setPendingIntentBackgroundActivityStartMode() se quiser que os privilégios sejam usados. Por padrão, nenhum privilégio é delegado.
- Mais tarde, o app remetente inicia o lançamento chamando
- Validação de segurança do sistema Android
- O sistema Android intercepta a solicitação de inicialização e realiza uma verificação de segurança.
- Ele avalia duas condições:
- O criador de conteúdo delegou os privilégios, E o app Creator atualmente atende a uma das exceções gerais da BAL?
- O remetente contribuiu com os privilégios dele? E o app do remetente atualmente atende a uma das exceções gerais da BAL?
- Resultado
- PERMITIDO: se pelo menos uma das duas condições na etapa 3 for atendida, a cadeia de privilégios será validada. O sistema Android inicia a atividade de destino, e o remetente recebe um resultado de sucesso.
- BLOCKED: se nenhuma condição for atendida, o sistema vai bloquear o lançamento. O app remetente não recebe um valor de retorno direto ou uma exceção indicando a falha. Em vez disso, o sistema Android registra internamente uma mensagem "Background activity launch blocked!" no Logcat, que os desenvolvedores precisam verificar para depuração.
Prevenção contra invasão de tarefas
Para evitar ataques de sequestro na tarefa (como o "Activity Sandwich"), o Android 15 introduz novas regras para apps direcionados ao nível 37 da API ou mais recente.
- Regra 1: em uma única tarefa, uma atividade só pode ser iniciada por outra atividade pertencente ao mesmo aplicativo (ou seja, com o mesmo UID) da atividade atual no topo da tarefa.
- Regra 2: somente uma atividade em uma tarefa em primeiro plano que corresponda ao UID da atividade mais alta pode criar uma nova tarefa ou trazer uma tarefa diferente para o primeiro plano.
Ativação de proteções na tarefa para desenvolvedores
Esse comportamento pode ser ativado a partir do SDK de destino 37. É necessário ativar explicitamente. Ele foi projetado para evitar o sequestro de tarefas (ou Activity Sandwiching), em que um app malicioso pode iniciar uma atividade na tarefa do seu app para se passar por ele e roubar dados do usuário.
Ativar proteções
Para ativar o ASM no seu aplicativo, defina o atributo
android:allowCrossUidActivitySwitchFromBelow como "false" no arquivo
AndroidManifest.xml. Essa é uma configuração no nível do aplicativo que protege
todas as atividades no app por padrão.
Como criar exceções para atividades específicas
Se você tiver ativado esse recurso para seu app, mas precisar permitir que uma atividade específica e confiável
seja iniciada por outros apps, crie uma exceção direcionada. Para
eximir uma única atividade dessa proteção, chame
setAllowCrossUidActivitySwitchFromBelow(true) no método
onCreate() dessa atividade. Isso permite que uma atividade seja iniciada enquanto o
restante do app permanece protegido.
Solução de problemas
Filtre o Logcat para encontrar mensagens relevantes usando uma expressão regular. A tag ActivityTaskManager é usada com frequência, e a filtragem por ActivityTaskManager pode ajudar a isolar os registros.
Como entender as principais mensagens de registro
Início bloqueado (erro): essa mensagem indica que o início de uma atividade foi bloqueado.
- Significado: o início de uma atividade foi negado porque a inclusão da PendingIntent necessária estava ausente do remetente (direcionado ao SDK 34 ou mais recente) ou do criador (direcionado ao SDK 35 ou mais recente).
- Ação: atualize seu código para incluir a ativação correta de ActivityOptions.
Ao analisar os registros, verifique estes campos:
- realCallingPackage: o app que enviou o PendingIntent. Este é o remetente.
- callingPackage: o app que criou a PendingIntent. Este é o criador.
Modo restrito
A partir do Android 16, o desenvolvedor de apps pode ativar o modo estrito para receber notificações quando o início de uma atividade é bloqueado (ou corre o risco de ser bloqueado quando o SDK de destino do app é aumentado).
Exemplo de código para ativar no início do método Application.onCreate() do aplicativo, da atividade ou de outro componente do aplicativo:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
StrictMode.setVmPolicy(
StrictMode.VmPolicy.Builder()
.detectBlockedBackgroundActivityLaunch()
.penaltyLog()
.build());
)
}