Configurando ART

Esta página discute como configurar o ART e suas opções de compilação. Os tópicos abordados aqui incluem configuração de pré-compilação da imagem do sistema, opções de compilação dex2oat e como negociar o espaço de partição do sistema, espaço de partição de dados e desempenho.

Consulte ART e Dalvik , o formato Dalvik Executable e as páginas restantes em source.android.com para trabalhar com ART. Consulte Verificando o comportamento do aplicativo no Android Runtime (ART) para garantir que seus aplicativos funcionem corretamente.

Como funciona a ART

O ART usa compilação antecipada (AOT) e, a partir do Android 7.0 (Nougat ou N), usa uma combinação híbrida de AOT, compilação just-in-time (JIT) e compilação guiada por perfil. A combinação de todos esses modos de compilação é configurável e será discutida nesta seção. Como exemplo, os dispositivos Pixel são configurados com o seguinte fluxo de compilação:

  1. Um aplicativo é instalado inicialmente sem qualquer compilação AOT. Nas primeiras vezes que o aplicativo for executado, ele será interpretado e os métodos executados com frequência serão compilados em JIT.
  2. Quando o dispositivo está ocioso e carregando, um daemon de compilação é executado para compilar o código usado com frequência AOT com base em um perfil gerado durante as primeiras execuções.
  3. A próxima reinicialização de um aplicativo usará o código guiado por perfil e evitará a compilação JIT em tempo de execução para métodos já compilados. Os métodos que são compilados por JIT durante as novas execuções serão adicionados ao perfil, que será então selecionado pelo daemon de compilação.

ART compreende um compilador (a ferramenta dex2oat ) e um tempo de execução ( libart.so ) que é carregado para iniciar o Zygote. A ferramenta dex2oat pega um arquivo APK e gera um ou mais arquivos de artefato de compilação que o tempo de execução carrega. O número de arquivos, suas extensões e nomes estão sujeitos a alterações entre as versões, mas a partir da versão Android O, os arquivos gerados são:

  • .vdex : contém o código DEX descompactado do APK, com alguns metadados adicionais para acelerar a verificação.
  • .odex : contém código compilado AOT para métodos no APK.
  • .art (optional) : contém representações internas ART de algumas strings e classes listadas no APK, usadas para acelerar a inicialização do aplicativo.

Opções de compilação

As opções de compilação para ART são de duas categorias:

  1. Configuração da ROM do sistema: qual código é compilado por AOT ao construir uma imagem do sistema.
  2. Configuração de tempo de execução: como o ART compila e executa aplicativos em um dispositivo.

Uma opção ART principal para configurar essas duas categorias são os filtros do compilador . Os filtros do compilador determinam como o ART compila o código DEX e é uma opção passada para a ferramenta dex2oat . A partir do Android O, existem quatro filtros oficialmente suportados:

  • verifique : execute apenas a verificação do código DEX.
  • quicken : execute a verificação de código DEX e otimize algumas instruções DEX para obter um melhor desempenho do intérprete.
  • speed : execute a verificação do código DEX e compile todos os métodos AOT.
  • speed-profile : execute a verificação do código DEX e os métodos de compilação AOT listados em um arquivo de perfil.

Configuração da ROM do sistema

Há várias opções de construção ART disponíveis para configurar uma ROM do sistema. Como configurar essas opções depende do espaço de armazenamento disponível para /system e do número de aplicativos pré-instalados. Os JARs/APKs compilados em uma ROM do sistema podem ser divididos em quatro categorias:

  • Código do caminho de classe de inicialização: compilado com o filtro do compilador de velocidade por padrão.
  • Código do servidor do sistema: compilado com o filtro do compilador de velocidade por padrão.
  • Aplicativos principais específicos do produto: compilados com o filtro do compilador de velocidade por padrão.
  • Todos os outros aplicativos: compilados com o filtro do compilador quicken por padrão.

Opções de makefile

  • WITH_DEXPREOPT
  • Se dex2oat é invocado no código DEX instalado na imagem do sistema. Ativado por padrão.

  • DONT_DEXPREOPT_PREBUILTS (desde Android L)
  • Habilitar DONT_DEXPREOPT_PREBUILTS impede que os pré-compilados sejam pré-otimizados. Esses são aplicativos que include $(BUILD_PREBUILT) especificados em seu Android.mk , como o Gmail. Ignorar a pré-otimização de aplicativos pré-criados que provavelmente serão atualizados por meio do Google Play economiza /system , mas aumenta o tempo de primeira inicialização.

  • PRODUCT_DEX_PREOPT_DEFAULT_COMPILER_FILTER (desde o Android 9)
  • PRODUCT_DEX_PREOPT_DEFAULT_COMPILER_FILTER especifica o filtro de compilador padrão para aplicativos pré-otimizados. Esses são aplicativos que include $(BUILD_PREBUILT) especificados em seu Android.mk , como o Gmail. Se não especificado, o valor padrão é quicken.

  • WITH_DEXPREOPT_BOOT_IMG_AND_SYSTEM_SERVER_ONLY (novo no Android O MR1)
  • A habilitação de WITH_DEXPREOPT_BOOT_IMG_AND_SYSTEM_SERVER_ONLY pré-otimiza apenas o caminho de classe de inicialização e os jars do servidor do sistema.

  • LOCAL_DEX_PREOPT
  • A pré-otimização também pode ser habilitada ou desabilitada em um aplicativo individual especificando a opção LOCAL_DEX_PREOPT na definição do módulo. Isso pode ser útil para desativar a pré-otimização de aplicativos que podem receber atualizações do Google Play imediatamente, pois as atualizações tornariam o código pré-otimizado na imagem do sistema obsoleto. Isso também é útil para economizar espaço em OTAs de atualização de versão principal, pois os usuários já podem ter versões mais recentes de aplicativos na partição de dados.

    LOCAL_DEX_PREOPT suporta os valores 'true' ou 'false' para habilitar ou desabilitar a pré-otimização, respectivamente. Além disso, 'nostripping' pode ser especificado se a pré-otimização não deve remover o arquivo classes.dex do arquivo APK ou JAR. Normalmente, esse arquivo é removido, pois não é mais necessário após a pré-otimização, mas essa última opção é necessária para permitir que assinaturas de APK de terceiros permaneçam válidas.

  • PRODUCT_DEX_PREOPT_BOOT_FLAGS
  • Passa opções para dex2oat para controlar como a imagem de inicialização é compilada. Ele pode ser usado para especificar listas de classes de imagem personalizadas, listas de classes compiladas e filtros do compilador.

  • PRODUCT_DEX_PREOPT_DEFAULT_FLAGS
  • Passa opções para dex2oat para controlar como tudo além da imagem de inicialização é compilado.

  • PRODUCT_DEX_PREOPT_MODULE_CONFIGS
  • Fornece a capacidade de passar opções dex2oat para um módulo específico e configuração de produto. Ele é definido no arquivo device.mk de um produto por $(call add-product-dex-preopt-module-config,<modules>,<option>) onde <modules> é uma lista de nomes LOCAL_MODULE e LOCAL_PACKAGE para JAR e APK arquivos, respectivamente.

  • PRODUCT_DEXPREOPT_SPEED_APPS (New in Android O)
  • Lista de aplicativos que foram identificados como essenciais para os produtos e que são desejáveis ​​para compilar com o filtro do compilador de velocidade . Por exemplo, aplicativos persistentes como SystemUI têm a chance de usar a compilação guiada por perfil apenas na próxima reinicialização, portanto, pode ser melhor para o produto ter esses aplicativos sempre compilados por AOT.

  • PRODUCT_SYSTEM_SERVER_APPS (New in Android O)
  • Lista de aplicativos que são carregados pelo servidor do sistema. Esses aplicativos serão compilados por padrão com o filtro do compilador de velocidade .

  • PRODUCT_ART_TARGET_INCLUDE_DEBUG_BUILD(Post Android O)
  • Se deve incluir uma versão de depuração do ART no dispositivo. Por padrão, isso é habilitado para builds userdebug e eng. O comportamento pode ser substituído definindo explicitamente a opção como true ou false .

    Por padrão, o dispositivo usará a versão sem depuração ( libart.so ). Para alternar, defina a propriedade do sistema persist.sys.dalvik.vm.lib.2 como libartd.so .

  • WITH_DEXPREOPT_PIC (Removed in Android O)
  • No Android 5.1.0 ao Android 6.0.1, WITH_DEXPREOPT_PIC pode ser especificado para habilitar o código independente de posição (PIC). Com isso, o código compilado da imagem não precisa ser realocado de /system para /data/dalvik-cache, economizando espaço na partição de dados. No entanto, há um pequeno impacto no tempo de execução porque desativa uma otimização que aproveita o código dependente da posição. Normalmente, os dispositivos que desejam economizar espaço em /data devem habilitar a compilação de PIC.

    No Android 7.0, a compilação PIC foi habilitada por padrão.

  • WITH_DEXPREOPT_BOOT_IMG_ONLY (removido no Android O MR1)
  • Essa opção foi substituída por WITH_DEXPREOPT_BOOT_IMG_AND_SYSTEM_SERVER_ONLY que também opta pelos jars do servidor do sistema.

Configuração do caminho de classe de inicialização

  • Lista de turmas pré-carregadas
  • A lista de classes pré-carregadas é uma lista de classes que o zigoto inicializa na inicialização. Isso evita que cada aplicativo tenha que executar esses inicializadores de classe separadamente, permitindo que eles inicializem mais rapidamente e compartilhem páginas na memória. O arquivo de lista de classes pré-carregadas está localizado em frameworks/base/config/preloaded-classes por padrão e contém uma lista ajustada para uso típico de telefone. Isso pode ser diferente para outros dispositivos, como wearables, e deve ser ajustado de acordo. Tenha cuidado ao ajustar isso; adicionar muitas classes desperdiça memória quando classes não utilizadas são carregadas. Adicionar poucas classes força cada aplicativo a ter sua própria cópia, o que, novamente, desperdiça memória.

    Exemplo de uso (no device.mk do produto):

    PRODUCT_COPY_FILES += <filename>:system/etc/preloaded-classes
    

    Nota: Esta linha deve ser colocada antes de herdar qualquer makefile de configuração do produto que obtenha o padrão de: build/target/product/base.mk

  • Lista de classes de imagens
  • A lista de classes de imagem é uma lista de classes que o dex2oat inicializa antecipadamente e armazena no arquivo boot.art. Isso permite que o zigoto carregue esses resultados do arquivo boot.art na inicialização, em vez de executar os inicializadores para essas classes durante o pré-carregamento. Um recurso importante disso é que as páginas carregadas da imagem e compartilhadas entre os processos podem ser limpas, permitindo que sejam trocadas facilmente em situações de pouca memória. Em L, por padrão, a lista de classes de imagem usa a mesma lista que a lista de classes pré-carregadas. Começando post-L no AOSP, uma lista de classes de imagem personalizada pode ser especificada usando:

    PRODUCT_DEX_PREOPT_BOOT_FLAGS
    

    Exemplo de uso (no device.mk do produto):

    PRODUCT_DEX_PREOPT_BOOT_FLAGS += --image-classes=<filename>
    
  • Lista de Classes Compiladas
  • No pós-L AOSP, um subconjunto de classes do classpath de inicialização pode ser especificado para ser compilado durante a pré-otimização usando a lista de classes compiladas. Essa pode ser uma opção útil para dispositivos com pouco espaço e que não cabem em toda a imagem de inicialização pré-otimizada. No entanto, as classes de nota não especificadas por esta lista não serão compiladas - nem mesmo no dispositivo - e devem ser interpretadas, afetando potencialmente o desempenho do tempo de execução. Por padrão, dex2oat irá procurar por uma lista de classes compiladas em $OUT/system/etc/compiled-classes, então uma customizada pode ser copiada para aquele local pelo device.mk. Um local de arquivo específico também pode ser especificado usando:

    PRODUCT_DEX_PREOPT_BOOT_FLAGS
    

    Exemplo de uso (no device.mk do produto):

    PRODUCT_COPY_FILES += <filename>:system/etc/compiled-classes
    

    Nota: Esta linha deve ser colocada antes de herdar qualquer makefile de configuração do produto que obtenha o padrão de: build/target/product/base.mk

Configuração do ambiente de execução

Opções de Jit

As opções a seguir afetam as versões do Android somente onde o compilador ART JIT está disponível.

  • dalvik.vm.usejit: se o JIT está ou não habilitado.
  • dalvik.vm.jitinitialsize (padrão 64K): a capacidade inicial do cache de código. O cache de código fará GC regularmente e aumentará, se necessário.
  • dalvik.vm.jitmaxsize (padrão 64M): a capacidade máxima do cache de código.
  • dalvik.vm.jitthreshold: (padrão 10000) - Este é o limite que o contador "hotness" de um método precisa passar para que o método seja compilado JIT. O contador "hotness" é uma métrica interna ao tempo de execução. Inclui o número de chamadas, ramificações para trás e outros fatores.
  • dalvik.vm.usejitprofiles: se os perfis JIT estão habilitados ou não; isso pode ser usado mesmo se dalvik.vm.usejit for falso. Observe que, se for falso, o perfil de velocidade do filtro do compilador não compila AOT nenhum método e é equivalente a quicken .
  • dalvik.vm.jitprithreadweight (padrão para dalvik.vm.jitthreshold / 20) - O peso das "amostras" JIT (consulte jitthreshold) para o thread de interface do usuário do aplicativo. Use para acelerar a compilação de métodos que afetam diretamente a experiência dos usuários ao interagir com o aplicativo.
  • dalvik.vm.jittransitionweight: (padrão para dalvik.vm.jitthreshold / 10) o peso da invocação do método que transita entre o código de compilação e o interpretador. Isso ajuda a garantir que os métodos envolvidos sejam compilados para minimizar as transições (que são caras).

Opções do gerenciador de pacotes

Desde o Android 7.0, existe uma maneira genérica de especificar o nível de compilação/verificação que aconteceu em vários estágios. Os níveis de compilação podem ser configurados através das propriedades do sistema com os padrões sendo:

  • pm.dexopt.install=speed-profile
  • Este é o filtro de compilação usado na instalação de aplicativos por meio do Google Play. Recomendamos que o filtro de instalação seja definido como speed-profile para permitir o uso de perfis dos arquivos de metadados dex. Observe que se um perfil não for fornecido ou se estiver vazio, speed-profile é equivalente a quicken.

  • pm.dexopt.bg-dexopt=speed-profile
  • Este é o filtro de compilação usado quando o dispositivo está ocioso, carregando e totalmente carregado. Experimente o filtro do compilador de perfil de velocidade para aproveitar a compilação guiada por perfil e economizar no armazenamento.

  • pm.dexopt.boot=verify
  • O filtro de compilação usado após uma atualização sem fio. Recomendamos fortemente o filtro do compilador de verificação para esta opção para evitar tempos de inicialização muito longos.

  • pm.dexopt.first-boot=quicken
  • O filtro de compilação pela primeira vez que o dispositivo é inicializado. O filtro usado aqui só afetará o tempo de inicialização após a fábrica. Recomendamos que o filtro seja rápido para evitar longos períodos de tempo antes de um usuário usar o telefone pela primeira vez. Observe que se todos os aplicativos em /system já estiverem compilados com o filtro do compilador quicken ou forem compilados com o filtro do compilador speed ou speed-profile , o pm.dexopt.first-boot não terá efeito.

Opções de Dex2oat

Observe que essas opções afetam dex2oat durante a compilação no dispositivo, bem como durante a pré-otimização, enquanto a maioria das opções discutidas acima afeta apenas a pré-otimização.

Para controlar o dex2oat enquanto compila a imagem de inicialização:

  • dalvik.vm.image-dex2oat-Xms: tamanho de heap inicial
  • dalvik.vm.image-dex2oat-Xmx: tamanho máximo de heap
  • dalvik.vm.image-dex2oat-filter: opção de filtro do compilador
  • dalvik.vm.image-dex2oat-threads: número de threads a serem usados

Para controlar o dex2oat enquanto ele está compilando tudo além da imagem de inicialização:

  • dalvik.vm.dex2oat-Xms: tamanho de heap inicial
  • dalvik.vm.dex2oat-Xmx: tamanho máximo de heap
  • dalvik.vm.dex2oat-filter: opção de filtro do compilador

Nas versões até o Android 6.0, uma opção adicional é fornecida para compilar tudo além da imagem de inicialização:

  • dalvik.vm.dex2oat-threads: número de threads a serem usados

A partir do Android 6.1, isso se torna duas opções adicionais para compilar tudo além da imagem de inicialização:

  • dalvik.vm.boot-dex2oat-threads: número de threads a serem usados ​​durante o boot
  • dalvik.vm.dex2oat-threads: número de threads a serem usados ​​após o tempo de inicialização

A partir do Android 7.1, duas opções são fornecidas para controlar como a memória é usada ao compilar tudo além da imagem de inicialização:

  • dalvik.vm.dex2oat-very-large: tamanho mínimo total do arquivo dex em bytes para desabilitar a compilação AOT
  • dalvik.vm.dex2oat-swap: use o arquivo de troca dex2oat (para dispositivos com pouca memória)

As opções que controlam o tamanho de heap inicial e máximo para dex2oat não devem ser reduzidas, pois podem limitar quais aplicativos podem ser compilados.

A partir do Android 11, três opções de afinidade de CPU são fornecidas para permitir que os threads do compilador sejam restritos a um grupo específico de CPUs:

  • dalvik.vm.boot-dex2oat-cpu-set: CPUs executando threads dex2oat durante o tempo de inicialização
  • dalvik.vm.image-dex2oat-cpu-set: CPUs executando dex2oat ao compilar a imagem de inicialização
  • dalvik.vm.dex2oat-cpu-set: CPUs executando threads dex2oat após o tempo de inicialização

As CPUs devem ser especificadas como uma lista separada por vírgulas de IDs de CPU. Por exemplo, para rodar em dex2oat nas CPUs 0-3, defina:

dalvik.vm.dex2oat-cpu-set=0,1,2,3

Ao definir as propriedades de afinidade de CPU, recomendamos combinar a propriedade correspondente para o número de threads dex2oat para corresponder ao número de CPUs selecionadas para evitar memória desnecessária e contenção de E/S:

dalvik.vm.dex2oat-cpu-set=0,1,2,3
dalvik.vm.dex2oat-threads=4

A partir do Android 12, as seguintes opções foram adicionadas:

  • dalvik.vm.ps-min-first-save-ms: o tempo de espera para que o tempo de execução gere um perfil do aplicativo, na primeira vez que o aplicativo é iniciado
  • dalvik.vm.ps-min-save-period-ms: o tempo mínimo de espera antes de atualizar o perfil de um aplicativo
  • dalvik.vm.systemservercompilerfilter: o filtro do compilador que o dispositivo usará ao recompilar o servidor do sistema

Configuração específica A/B

configuração ROM

A partir do Android 7.0, os dispositivos podem usar duas partições do sistema para ativar as atualizações do sistema A/B . Para economizar no tamanho da partição do sistema, os arquivos pré-optados podem ser instalados na segunda partição do sistema não utilizada. Eles são então copiados para a partição de dados na primeira inicialização.

Exemplo de uso (em device-common.mk ):

PRODUCT_PACKAGES += \
     cppreopts.sh
PRODUCT_PROPERTY_OVERRIDES += \
     ro.cp_system_other_odex=1

E no BoardConfig.mk do dispositivo:

BOARD_USES_SYSTEM_OTHER_ODEX := true

Observe que o código do caminho de classe de inicialização, o código do servidor do sistema e os aplicativos principais específicos do produto sempre compilam na partição do sistema. Por padrão, todos os outros aplicativos são compilados na segunda partição do sistema não utilizada. Isso pode ser controlado com o SYSTEM_OTHER_ODEX_FILTER , que tem um valor padrão de:

SYSTEM_OTHER_ODEX_FILTER ?= app/% priv-app/%

OTA de dexopt em segundo plano

Com dispositivos habilitados para A/B, os aplicativos podem ser compilados em segundo plano para atualização para a nova imagem do sistema. Consulte Compilação de aplicativos em segundo plano para incluir opcionalmente o script de compilação e os binários na imagem do sistema. O filtro de compilação usado para esta compilação é controlado com:

pm.dexopt.ab-ota=speed-profile

Recomendamos usar o perfil de velocidade para aproveitar a compilação guiada por perfil e economizar no armazenamento.