Mudanças de comportamento: apps destinados ao Android 14 ou mais recente

Como nas versões anteriores, o Android 14 inclui mudanças de comportamento que podem afetar seu app. As seguintes mudanças se aplicam exclusivamente a apps destinados ao Android 14 ou mais recente. Caso seu app seja direcionado ao Android 14 ou a versões mais recentes, faça modificações para oferecer suporte a esses comportamentos de forma adequada, quando aplicável.

Consulte também a lista de mudanças de comportamento que afetam todos os apps executados no Android 14, independente da targetSdkVersion do app.

Principal recurso

Os tipos de serviço em primeiro plano são obrigatórios

Caso o app seja destinado ao Android 14, é necessário especificar pelo menos um tipo de serviço em primeiro plano para cada serviço em primeiro plano. Escolha um tipo que represente o caso de uso do seu app. O sistema espera que serviços em primeiro plano com um tipo específico atendam a um caso de uso específico.

Se um caso de uso no app não estiver associado a nenhum desses tipos, é recomendável migrar a lógica para usar o WorkManager ou jobs de transferência de dados iniciados pelo usuário.

Atualizações do OpenJDK 17

O Android 14 continua o trabalho de atualizar as principais bibliotecas do Android para se alinhar aos recursos das versões mais recentes do LTS do OpenJDK, incluindo atualizações de bibliotecas e suporte à linguagem Java 17 para desenvolvedores de apps e plataformas.

Algumas dessas mudanças podem afetar a compatibilidade do app:

  • Mudanças em expressões regulares: referências inválidas a grupos agora não são permitidas para seguir mais de perto a semântica do OpenJDK. Será possível conferir novos casos em que uma IllegalArgumentException é gerada pela classe java.util.regex.Matcher. Portanto, teste o app para áreas que usam expressões regulares. Para ativar ou desativar essa mudança durante os testes, configure a flag DISALLOW_INVALID_GROUP_REFERENCE usando as ferramentas do framework de compatibilidade.
  • Processamento de UUID: o método java.util.UUID.fromString() agora faz verificações mais rigorosas ao validar o argumento de entrada. Por isso, talvez uma IllegalArgumentException apareça durante desserialização. Para ativar ou desativar essa mudança durante os testes, configure a flag ENABLE_STRICT_VALIDATION usando as ferramentas do framework de compatibilidade.
  • Problemas com o ProGuard: em alguns casos, a adição da classe java.lang.ClassValue causará um problema se você tentar reduzir, ofuscar e otimizar o app usando o ProGuard. O problema se origina em uma biblioteca Kotlin que muda o comportamento no momento de execução, dependendo se Class.forName("java.lang.ClassValue") retorna uma classe ou não. Se o app tiver sido desenvolvido em uma versão mais antiga do ambiente de execução sem a classe java.lang.ClassValue disponível, essas otimizações poderão remover o método computeValue das classes derivadas de java.lang.ClassValue.

Segurança

Restrições a intents implícitas e pendentes

Nos apps destinados ao Android 14, o Android impede que intents implícitas sejam enviadas para componentes internos do app das seguintes maneiras:

  • Intents implícitas são entregues apenas a componentes exportados. Os apps precisam usar uma intent explícita para enviar para componentes não exportados ou marcar o componente como exportado.
  • Se um app criar uma intent pendente mutável com uma intent que não especifica um componente ou pacote, o sistema vai gerar uma exceção.

Essas mudanças impedem que apps maliciosos interceptem intents implícitas destinadas ao uso de componentes internos de um app.

Confira um filtro de intent que pode ser declarado no arquivo de manifesto do app:

<activity
    android:name=".AppActivity"
    android:exported="false">
    <intent-filter>
        <action android:name="com.example.action.APP_ACTION" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

Se o app tentar iniciar essa atividade usando uma intent implícita, uma exceção será gerada:

Kotlin

// Throws an exception when targeting Android 14.
context.startActivity(Intent("com.example.action.APP_ACTION"))

Java

// Throws an exception when targeting Android 14.
context.startActivity(new Intent("com.example.action.APP_ACTION"));

Para iniciar a atividade não exportada, o app precisa usar uma intent explícita:

Kotlin

// This makes the intent explicit.
val explicitIntent =
        Intent("com.example.action.APP_ACTION")
explicitIntent.apply {
    package = context.packageName
}
context.startActivity(explicitIntent)

Java

// This makes the intent explicit.
Intent explicitIntent =
        new Intent("com.example.action.APP_ACTION")
explicitIntent.setPackage(context.getPackageName());
context.startActivity(explicitIntent);

Os broadcast receivers registrados no ambiente de execução precisam especificar o comportamento de exportação

Os apps e serviços direcionados ao Android 14 que usam receptores registrados pelo contexto precisam especificar uma flag para indicar se o receptor precisa ou não ser exportado para todos os outros apps no dispositivo: RECEIVER_EXPORTED ou RECEIVER_NOT_EXPORTED, respectivamente. Esse requisito ajuda a proteger os apps contra vulnerabilidades de segurança usando os recursos desses receptores lançados no Android 13.

Exceção para receptores que recebem apenas transmissões do sistema

Se o app estiver registrando um receptor apenas paratransmissões do sistema usando métodos Context#registerReceiver, como Context#registerReceiver(), ele não precisará especificar uma flag.

Carregamento mais seguro de código dinâmico

Se o app for direcionado ao Android 14 e usar o carregamento de código dinâmico (DCL, na sigla em inglês), todos os arquivos carregados dinamicamente precisarão ser marcados como somente leitura. Caso contrário, o sistema gerará uma exceção. Recomendamos que os apps evitem carregar código dinamicamente sempre que possível, porque isso aumenta muito o risco de comprometimento do app por injeção ou adulteração de código.

Se você precisar carregar código dinamicamente, use a seguinte abordagem para definir o arquivo carregado dessa forma (como um arquivo DEX, JAR ou APK) como somente leitura assim que ele for aberto e antes de qualquer conteúdo ser programado:

Kotlin

val jar = File("DYNAMICALLY_LOADED_FILE.jar")
val os = FileOutputStream(jar)
os.use {
    // Set the file to read-only first to prevent race conditions
    jar.setReadOnly()
    // Then write the actual file content
}
val cl = PathClassLoader(jar, parentClassLoader)

Java

File jar = new File("DYNAMICALLY_LOADED_FILE.jar");
try (FileOutputStream os = new FileOutputStream(jar)) {
    // Set the file to read-only first to prevent race conditions
    jar.setReadOnly();
    // Then write the actual file content
} catch (IOException e) { ... }
PathClassLoader cl = new PathClassLoader(jar, parentClassLoader);

Processar arquivos carregados dinamicamente que já existem

Para evitar que exceções sejam geradas para arquivos carregados dinamicamente já existentes, recomendamos excluir e recriar os arquivos antes de tentar carregá-los dessa forma no app. Ao recriar os arquivos, siga as orientações anteriores para marcá-los como somente leitura no momento da gravação. Como alternativa, rotule novamente os arquivos existentes como somente leitura, mas, nesse caso, recomendamos verificar a integridade dos arquivos primeiro, comparando a assinatura do arquivo com um valor confiável, por exemplo, para ajudar a proteger seu app contra ações maliciosas.

Travessia de caminhos de arquivo ZIP

Em apps destinados ao Android 14, o Android evita a vulnerabilidade da travessia de caminhos de arquivo ZIP da seguinte forma: ZipFile(String) e ZipInputStream.getNextEntry() geram uma ZipException quando os nomes dos arquivos ZIP têm ".." ou começam com "/".

Os apps podem desativar essa validação chamando dalvik.system.ZipPathValidator.clearCallback().

Mais restrições para o início de atividades em segundo plano

Para apps destinados ao Android 14, o sistema restringe ainda mais a permissão para que os apps iniciem atividades em segundo plano:

  • Quando um app envia uma PendingIntent usando PendingIntent#send() ou métodos semelhantes, ele agora precisa ativar um recurso para conceder à própria atividade em segundo plano os privilégios de inicialização para iniciar a intent pendente. Para ativar o recurso, o app precisa transmitir um pacote ActivityOptions com setPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED).
  • Quando um app visível vincula um serviço de outro app que está em segundo plano usando o método bindService(), ele precisa ativar um recurso para conceder às próprias atividades em segundo plano os privilégios de inicialização do serviço vinculado. Para isso, o app precisa incluir a flag BIND_ALLOW_ACTIVITY_STARTS ao chamar o método bindService().

Essas mudanças ampliam o conjunto existente de restrições para proteger os usuários. Elas impedem que apps maliciosos usem APIs para iniciar atividades que causam interrupções em segundo plano.

Atualização das restrições não SDK

O Android 14 inclui listas atualizadas de interfaces não SDK restritas com base na colaboração com desenvolvedores Android e nos testes internos mais recentes. Antes de restringirmos interfaces não SDK, sempre que possível, garantimos que haja alternativas públicas disponíveis.

Caso seu app não seja destinado ao Android 14, é possível que algumas dessas mudanças não afetem você imediatamente. No entanto, embora atualmente seja possível usar algumas interfaces não SDK (dependendo do nível da API de destino do app), o uso de qualquer método ou campo não SDK sempre apresenta um alto risco de corromper o app.

Se você não sabe se o app usa interfaces não SDK, é possível testá-lo para descobrir. Se ele depende de interfaces não SDK, planeje uma migração para alternativas SDK. No entanto, entendemos que alguns apps têm casos de uso válidos para interfaces não SDK. Se você não encontrar uma alternativa para deixar de usar uma interface não SDK em um recurso no app, solicite uma nova API pública.

Para saber mais sobre as mudanças dessa versão do Android, consulte Atualizações para restrições de interfaces não SDK no Android 14. Para saber mais sobre interfaces não SDK em geral, consulte Restrições para interfaces não SDK.