Os perfis de referência são uma lista de classes e métodos incluídos em um APK usado pelo Android Runtime (ART) durante a instalação para pré-compilar caminhos essenciais para o código de máquina. Essa é uma forma de otimização guiada por perfil (PGO, na sigla em inglês) que permite aos apps otimizar a inicialização, reduzir a instabilidade e melhorar a performance para os usuários finais.
Como funcionam os perfis de referência
As regras de perfil são compiladas em um formato binário no APK, em
assets/dexopt/baseline.prof
.
Durante a instalação, o ART realiza a compilação antecipada (AOT, na sigla em inglês) de métodos no perfil, resultando em uma execução mais rápida deles. Se o perfil tiver métodos usados na inicialização do app ou durante a renderização do frame, o tempo para a inicialização vai ser mais rápido e a instabilidade do app será reduzida.
Ao desenvolver seu app ou biblioteca, defina perfis de referência para cobrir caminhos específicos durante jornadas ideais do usuário em que a latência ou o tempo de renderização são importantes, como inicialização, transições ou rolagem.
Os perfis de referência vão ser enviados diretamente aos usuários (pelo Google Play) junto ao APK, como mostrado na Figura 1:

Motivos para usar perfis de referência
O tempo de inicialização é um componente essencial para melhorar o engajamento do usuário com seu aplicativo. O aumento da velocidade e capacidade de resposta de um app leva a mais usuários ativos por dia e uma taxa média de visitas mais alta.
Os perfis na nuvem também otimizam essas interações, mas ficam disponíveis para os usuários somente um dia ou mais após o lançamento de uma atualização, além de não terem suporte do Android 7 (API 24) ao Android 8 (API 26).
Comportamento de compilação nas versões do Android
As versões da Plataforma Android usaram diferentes abordagens de compilação de apps, cada uma com vantagens específicas. Os perfis de referência melhoram os métodos de compilação anteriores fornecendo um perfil para todas as instalações.
Versão do Android | Método de compilação | Abordagem de otimização |
---|---|---|
Android 5 (nível 21 da API) ao Android 6 (nível 23 da API) | Antecipação completa | O app todo é otimizado durante a instalação, resultando em longos tempos de espera para o uso, aumento no uso de RAM e espaço em disco e tempos mais longos de carregamento do código do disco, o que pode aumentar os tempos de inicialização a frio. |
Android 7 (nível 24 da API) ao Android 8.1 (nível 27 da API) | Antecipação parcial (perfil de referência) | Os perfis de referência são
instalados por
androidx.profileinstaller
na primeira execução, quando o
módulo do app define essa
dependência. O ART pode melhorar
ainda mais o processo adicionando
outras regras de perfil
durante o uso do app e
as compilando quando o
dispositivo estiver inativo. Isso
otimiza o espaço em disco
e o tempo para carregar o código do
disco, reduzindo
o tempo de espera do app. |
Android 9 (nível 28 da API) e versões mais recentes | Antecipação parcial (perfil de referência + da nuvem) | O Play usa perfis de referência durante a instalação do app para otimizar os perfis de APK e da nuvem (se disponíveis). Após a instalação, é feito o upload dos perfis do ART para o Play e eles são agregados e depois fornecidos como perfis de nuvem para outros usuários na instalação/atualização do app. |
Criar perfis de referência
Criar regras de perfil automaticamente usando BaselineProfileRule
Como desenvolvedor de apps, você pode gerar perfis automaticamente para cada lançamento usando a biblioteca Macrobenchmark do Jetpack.
Para criar perfis de referência usando a biblioteca Macrobenchmark, siga estas etapas:
Adicione uma dependência à biblioteca ProfileInstaller no arquivo
build.gradle
do seu app para ativar a compilação de perfis de referência locais e da Play Store. Essa é a única maneira de transferir por sideload um perfil de referência localmente.dependencies { implementation("androidx.profileinstaller:profileinstaller:1.2.0-beta01") }
Configure um módulo da Macrobenchmark no seu projeto do Gradle.
Defina um novo teste com o nome
BaselineProfileGenerator
parecido com este:@ExperimentalBaselineProfilesApi @RunWith(AndroidJUnit4::class) class BaselineProfileGenerator { @get:Rule val baselineProfileRule = BaselineProfileRule() @Test fun startup() = baselineProfileRule.collectBaselineProfile(packageName = "com.example.app") { pressHome() // This block defines the app's critical user journey. Here we are interested in // optimizing for app startup. But you can also navigate and scroll // through your most important UI. startActivityAndWait() } }
Conecte um
userdebug
ou emulador do Android Open Source Project (AOSP) com acesso root usando Android 9 ou uma versão mais recente.Execute o comando
adb root
no terminal para garantir que o daemon do adb esteja em execução com permissões de acesso root.Execute o teste e aguarde a conclusão.
Encontre o local do perfil gerado no logcat. Pesquise a tag de registro
Benchmark
.com.example.app D/Benchmark: Usable output directory: /storage/emulated/0/Android/media/com.example.app
# List the output baseline profile ls /storage/emulated/0/Android/media/com.example.app SampleStartupBenchmark_startup-baseline-prof.txt
Extraia o arquivo gerado do dispositivo.
adb pull storage/emulated/0/Android/media/com.example.app/SampleStartupBenchmark_startup-baseline-prof.txt .
Renomeie o arquivo gerado como
baseline-prof.txt
e o copie para o diretóriosrc/main
do módulo do app.
Definir regras de perfil manualmente
Para definir as regras de perfil manualmente em um app ou módulo de biblioteca, crie
um arquivo chamado baseline-prof.txt
no diretório src/main
. Essa é a
mesma pasta que contém o arquivo AndroidManifest.xml
.
O arquivo especifica uma regra por linha. Cada regra representa um padrão de métodos ou classes de correspondência que precisa ser otimizado no app ou na biblioteca.
A sintaxe dessas regras é um superconjunto do formato de perfil do ART legível por humanos
(HRF, na sigla em inglês) ao usar adb shell profman --dump-classes-and-methods
. Ela
é muito semelhante à
sintaxe para descritores e assinaturas,
mas também permite o uso de caracteres curinga para simplificar o processo de criação de regras.
Os exemplos abaixo mostram algumas regras de perfil de referência incluídas na biblioteca do Jetpack Compose:
HSPLandroidx/compose/runtime/ComposerImpl;->updateValue(Ljava/lang/Object;)V
HSPLandroidx/compose/runtime/ComposerImpl;->updatedNodeCount(I)I
HLandroidx/compose/runtime/ComposerImpl;->validateNodeExpected()V
PLandroidx/compose/runtime/CompositionImpl;->applyChanges()V
HLandroidx/compose/runtime/ComposerKt;->findLocation(Ljava/util/List;I)I
Landroidx/compose/runtime/ComposerImpl;
Sintaxe de regras
Essas regras podem ter uma de duas formas destinadas a métodos ou classes:
[FLAGS][CLASS_DESCRIPTOR]->[METHOD_SIGNATURE]
Uma regra de classe usa o seguinte padrão:
[CLASS_DESCRIPTOR]
Sintaxe | Descrição |
---|---|
FLAGS |
Representa um ou mais dos caracteres H , S e P para indicar se esse método será sinalizado como Hot , Startup ou Post Startup em relação ao tipo de inicialização. Um método com a sinalização H indica que ele é "quente", ou seja, chamado várias vezes durante a vida útil do app. Um método com a sinalização S indica que ele é chamado na inicialização. Um método com a sinalização P indica que ele é quente e não tem relação com a inicialização. Uma classe presente nesse arquivo indica que ela é usada durante a inicialização e precisa ser pré-alocada no heap para evitar o custo do carregamento. O compilador do ART emprega várias estratégias de otimização, como a compilação antecipada desses métodos e otimizações de layout no arquivo gerado antecipadamente. |
CLASS_DESCRIPTOR |
Descritor da classe do método. Por exemplo, androidx.compose.runtime.SlotTable teria um descritor de Landroidx/compose/runtime/SlotTable; . Observação: aqui, L é anexado ao formato Dalvik Executable (DEX). |
METHOD_SIGNATURE |
Assinatura do método, incluindo o nome, os tipos de parâmetro e os tipos de retorno. Por exemplo, o método // LayoutNode.kt fun isPlaced():Boolean { // ... } em LayoutNode tem a assinatura isPlaced()Z . |
Esses padrões podem ter caracteres curinga para que uma única regra inclua vários métodos ou classes. Para receber assistência guiada ao programar usando a sintaxe de regra no Android Studio, consulte o plug-in Android Baseline Profiles (link em inglês).
Este é um exemplo de regra de caractere curinga:
HSPLandroidx/compose/ui/layout/**->**(**)**
Tipos com suporte nas regras de perfil de referência
As regras de perfil de referência oferecem suporte aos seguintes tipos: Para conferir detalhes sobre esses tipos, consulte o formato Dalvik Executable (DEX).
Caractere | Tipo | Descrição |
---|---|---|
B |
byte | Byte assinado |
C |
char | Ponto de código de caractere Unicode codificado em UTF-16 |
D |
double | Valor de ponto flutuante de precisão dupla |
F |
float | Valor de ponto flutuante de precisão única |
I |
int | Número inteiro |
J |
long | Número inteiro longo |
S |
short | Número inteiro curto assinado |
V |
void | Vazio |
Z |
boolean | Verdadeiro ou falso |
L (nome da classe) |
reference | Uma instância de um nome de classe |
Além disso, as bibliotecas podem definir regras que são empacotadas em artefatos do AAR. Ao criar um APK para incluir esses artefatos, as regras são mescladas (de maneira semelhante à mesclagem de manifestos) e compiladas em um perfil ART binário compacto específico para o APK.
O ART aproveita esse perfil quando o APK é usado em dispositivos para compilar antecipadamente um subconjunto específico do aplicativo durante a instalação no Android 9 (nível 28 da API) ou Android 7 (nível 24 da API) com o ProfileInstaller.
Outras observações
Ao criar perfis de referência, considere alguns outros detalhes:
As versões do Android 5 ao Android 6 (níveis 21 a 23 da API) já compilam o APK antecipadamente no momento da instalação.
Os aplicativos depuráveis nunca são compilados antecipadamente para ajudar na solução de problemas.
Os arquivos de regras precisam ser nomeados como
baseline-prof.txt
e colocados no diretório raiz do conjunto de origem principal. Ele precisa ser um arquivo irmão doAndroidManifest.xml
.Esses arquivos vão ser utilizados apenas se você estiver usando o Plug-in do Android para Gradle
7.1.0-alpha05
ou uma versão mais recente (Android Studio Bumblebee Canary 5).No momento, o Bazel não oferece suporte à leitura e mesclagem de perfis de referência em um APK.
Perfis de referência compactados não podem ter mais de 1,5 MB. As bibliotecas e os aplicativos precisam definir um pequeno conjunto de regras de perfil que maximizem o impacto.
Regras abrangentes que compilem grande parte do aplicativo podem atrasar a inicialização devido ao aumento do acesso ao disco. Você precisa testar a performance dos perfis de referência.
Medir as melhorias
Automatizar a medição com a biblioteca Macrobenchmark
Macrobenchmarks permitem controlar a compilação de pré-medição usando a API
CompilationMode,
incluindo o uso de BaselineProfile
.
Se você já tiver configurado um teste de BaselineProfileRule
em um módulo da Macrobenchmark, vai poder definir um novo teste nesse módulo para avaliar a performance dele:
@RunWith(AndroidJUnit4::class)
class BaselineProfileBenchmark {
@get:Rule
val benchmarkRule = MacrobenchmarkRule()
@Test
fun startupNoCompilation() {
startup(CompilationMode.None())
}
@Test
fun startupBaselineProfile() {
startup(CompilationMode.Partial(
baselineProfileMode = BaselineProfileMode.Require
))
}
private fun startup(compilationMode: CompilationMode) {
benchmarkRule.measureRepeated(
packageName = "com.example.app",
metrics = listOf(StartupTimingMetric()),
iterations = 10,
startupMode = StartupMode.COLD,
compilationMode = compilationMode
) { // this = MacrobenchmarkScope
pressHome()
startActivityAndWait()
}
}
}
A Figura 2 mostra um exemplo de resultados de testes aprovados:

O exemplo acima analisa StartupTimingMetric
, mas existem outras
métricas importantes que precisam ser consideradas, como a
instabilidade (métricas de frame),
que podem ser medidas com a biblioteca Macrobenchmark do Jetpack.
Avaliar manualmente as melhorias do app
Para referência, primeiro vamos medir a inicialização do app não otimizada.
PACKAGE_NAME=com.example.app
# Force Stop App adb shell am force-stop $PACKAGE_NAME # Reset compiled state adb shell cmd package compile --reset $PACKAGE_NAME
# Measure App startup # This corresponds to `Time to initial display` metric # For additional info https://developer.android.com/topic/performance/vitals/launch-time#time-initial adb shell am start-activity -W -n $PACKAGE_NAME/.ExampleActivity \ | grep "TotalTime"
A próxima etapa é carregar o perfil de referência.
# Unzip the Release APK first unzip release.apk
# Create a ZIP archive # Note: The name should match the name of the APK # Note: Copy baseline.prof{m} and rename it to primary.prof{m} cp assets/dexopt/baseline.prof primary.prof cp assets/dexopt/baseline.profm primary.profm
# Create an archive zip -r release.dm primary.prof primary.profm
# Confirm that release.dm only contains the two profile files: unzip -l release.dm # Archive: release.dm # Length Date Time Name # --------- ---------- ----- ---- # 3885 1980-12-31 17:01 primary.prof # 1024 1980-12-31 17:01 primary.profm # --------- ------- # 2 files
# Install APK + Profile together adb install-multiple release.apk release.dm
Para verificar se o pacote foi otimizado na instalação, execute o comando abaixo:
# Check dexopt state
adb shell dumpsys package dexopt | grep -A 1 $PACKAGE_NAME
A saída precisa declarar que o pacote foi compilado.
[com.example.app]
path: /data/app/~~YvNxUxuP2e5xA6EGtM5i9A==/com.example.app-zQ0tkJN8tDrEZXTlrDUSBg==/base.apk
arm64: [status=speed-profile] [reason=install-dm]
Agora, é possível medir a performance da inicialização do app como anteriormente, mas sem redefinir o estado compilado.
# Force Stop App adb shell am force-stop $PACKAGE_NAME
# Measure App startup adb shell am start-activity -W -n $PACKAGE_NAME/.ExampleActivity \ | grep "TotalTime"
Problemas conhecidos
Atualmente, o uso de perfis de referência tem vários problemas conhecidos:
Os perfis de referência não são empacotados corretamente ao criar o APK de um pacote de apps. Para resolver esse problema, aplique
com.android.tools.build:gradle:7.3.0-beta02
e versões mais recentes (problema).Os perfis de referência são empacotados corretamente apenas para o arquivo
classes.dex
principal. Isso afeta apps com mais de um arquivo.dex
. Para resolver esse problema, apliquecom.android.tools.build:gradle:7.3.0-beta02
e versões mais recentes (problema).A Macrobenchmark é incompatível com perfis de referência no Android 12L (API 32) (problema) e o Android 13 (API 33) (problema).
Não é permitido redefinir os caches de perfil do ART em builds
user
(sem acesso root). Para contornar isso,androidx.benchmark:benchmark-macro-junit4:1.1.0-rc02
inclui uma correção que reinstala o app durante a comparação (problema).Os criadores de perfil do Android Studio não instalam perfis de referência ao criar o perfil do app (problema).
Atualmente, os sistemas de compilação que não são do Gradle (Bazel, Buck, etc.) não oferecem suporte à compilação de perfis de referência em APKs de saída.
A Play Store atualmente leva de 10 a 14 horas após o upload do AAB para disponibilizar os perfis de referência na instalação. Os usuários que fizerem o download do app durante esse período não vão aproveitar os benefícios desses perfis até que o dexopt seja executado em segundo plano, provavelmente durante a madrugada. Estamos trabalhando ativamente para melhorar isso.
Os canais de distribuição de apps que não são da Play Store podem não oferecer suporte ao uso de perfis de referência na instalação. Os usuários do app que usam esses canais não vão poder aproveitar os benefícios desses perfis até que o dexopt seja executado em segundo plano, provavelmente durante a madrugada.