Criar perfis de referência

Gere perfis automaticamente para cada lançamento usando a biblioteca Macrobenchmark do Jetpack e a BaselineProfileRule. Recomendamos usar o com.android.tools.build:gradle:8.0.0 ou versões mais recentes, que vêm com melhorias de build para o uso de perfis de referência.

Estas são as etapas gerais para criar um novo perfil de referência:

  1. Configure o módulo do perfil de referência.
  2. Defina o teste JUnit que ajuda a gerar perfis de referência.
  3. Adicione as jornadas ideais do usuário (CUJs) que você quer otimizar.
  4. Gere o perfil de referência.

Depois de gerar o perfil de referência, compare-o usando um dispositivo físico para medir as melhorias na velocidade.

Criar um novo perfil de referência com o AGP 8.2 ou mais recente

A maneira mais fácil de criar um novo perfil de referência é usar o modelo de módulo disponível no Android Studio Iguana com o Plug-in do Android para Gradle (AGP) 8.2 e mais recentes.

O modelo de módulo do gerador de perfis de referência do Android Studio automatiza a criação de um novo módulo para gerar e comparar perfis de referência. A execução do modelo gera a maior parte da configuração do build típica, a geração do perfil de referência e o código de verificação. O modelo cria um código para gerar e comparar perfis de referência e avaliar a inicialização do app.

Configurar o módulo do perfil de referência

Para executar o modelo de módulo do perfil de referência, siga estas etapas:

  1. Selecione File > New > New Module.
  2. Selecione o modelo Baseline Profile Generator no painel Templates e configure-o:
    Figura 1. Modelo de módulo do gerador de perfil de referência.

    Estes são os campos do modelo:

    • Target application: define para qual app o perfil de referência será gerado. Quando você só tem um módulo de app no projeto, há apenas um item nessa lista.
    • Module name: o nome que você quer definir para o módulo do perfil de referência que está criando.
    • Package name: o nome do pacote que você quer para o módulo do perfil de referência.
    • Language: se você quer que o código gerado seja em Kotlin ou Java.
    • Build configuration language: para decidir se você vai usar o script Kotlin (KTS) ou o Groovy nos scripts de configuração do build.
    • Use um dispositivo gerenciado pelo Gradle: se você está usando dispositivos gerenciados pelo Gradle para testar seu app.
  3. Clique em Finish para que o novo módulo seja criado. Se você estiver usando o controle de origem, talvez receba uma solicitação para adicionar os arquivos do módulo recém-criado ao controle de origem.

Definir o gerador do perfil de referência

O módulo recém-criado contém testes para gerar e comparar o perfil de referência e testar apenas a inicialização básica do app. Recomendamos que você os aumente para incluir as CUJs e os fluxos de trabalho avançados de inicialização. Verifique se todos os testes relacionados à inicialização do app estão em um bloco rule com includeInStartupProfile definido como true. Por outro lado, para ter o desempenho ideal, verifique se os testes que não estão relacionados à inicialização do app não estão incluídos em um perfil de inicialização. As otimizações de inicialização do app são usadas para definir uma parte especial de um perfil de referência chamado perfil de inicialização.

Isso vai ajudar na manutenção se você abstrair essas CUJs fora do perfil de referência gerado e do código de referência para que elas possam ser usadas para ambos. Isso significa que as alterações nas CUJs são usadas de maneira consistente.

Gerar e instalar o perfil de referência

O modelo de módulo do perfil de referência adiciona uma nova configuração de execução para gerar o perfil de referência. Se você estiver usando variações de produto, o Android Studio vai criar várias configurações de execução para que seja possível gerar perfis de referência separados para cada uma delas.

A configuração de execução "Generate Baseline Profile".
Figura 2. A execução dessa configuração gera o perfil de referência.

Quando a configuração de execução Generate Baseline Profile for concluída, ela vai copiar o perfil de referência gerado para o arquivo src/variant/generated/baselineProfiles/baseline-prof.txt no módulo que está sendo criado. As opções de variantes são o tipo de build de lançamento ou uma variante que o envolva.

O perfil de referência gerado é criado originalmente em build/outputs. O caminho completo é determinado pela variante ou variação do app para o qual um perfil está sendo criado e pelo uso de um dispositivo gerenciado pelo Gradle ou um dispositivo conectado para criar um perfil. Se você usar os nomes utilizados pelo código e as configurações de build geradas pelo modelo, o perfil de referência será criado no arquivo build/outputs/managed_device_android_test_additional_output/nonminifiedrelease/pixel6Api31/BaselineProfileGenerator_generate-baseline-prof.txt. Você provavelmente não vai precisar interagir diretamente com essa versão do perfil de referência gerado, a menos que a copie manualmente para os módulos de destino, o que não é recomendado.

Criar um novo perfil de referência com o AGP 8.1

Caso não seja possível usar o modelo de módulo do perfil de referência, use o modelo de módulo da biblioteca Macrobenchmark e o plug-in do perfil de referência para Gradle para criar um novo perfil. Recomendamos usar essas ferramentas no Android Studio Giraffe e com o AGP 8.1 e versões mais recentes.

Confira as etapas para criar um novo perfil de referência usando o modelo de módulo da biblioteca Macrobenchmark e o plug-in do perfil de referência para Gradle:

  1. Configure um módulo da Macrobenchmark no seu projeto do Gradle.
  2. Defina uma nova classe com o nome BaselineProfileGenerator:
    class BaselineProfileGenerator {
        @get:Rule
        val baselineProfileRule = BaselineProfileRule()
    
        @Test
        fun startup() = baselineProfileRule.collect(
            packageName = "com.example.app",
            profileBlock = {
                startActivityAndWait()
            }
        )
    }

    O gerador pode incluir interações com o app além da inicialização. Isso permite otimizar o desempenho de execução do app, como listas de rolagem, execução de animações e navegação em uma Activity. Confira outros exemplos de testes que usam @BaselineProfileRule para melhorar jornadas ideais do usuário.

  3. Adicione o plug-in do perfil de referência para Gradle (libs.plugins.androidx.baselineprofile). Ele facilita a geração e manutenção de perfis de referência.

  4. Para gerar o perfil de referência, execute as tarefas do Gradle :app:generateBaselineProfile ou :app:generateVariantBaselineProfile no terminal.

    Execute o gerador como um teste de instrumentação em um dispositivo físico, emulador ou dispositivo gerenciado pelo Gradle com acesso root. Se você usa um dispositivo gerenciado pelo Gradle, defina aosp como systemImageSource, já que o gerador de perfis de referência precisa de acesso root.

    No final da tarefa de geração, o perfil de referência será copiado para app/src/variant/generated/baselineProfiles.

Criar um novo perfil de referência sem modelos

Recomendamos criar um perfil de referência usando o modelo de módulo de perfil de referência do Android Studio (preferencial) ou o modelo da biblioteca Macrobenchmark, mas você também pode usar o plug-in do perfil de referência para Gradle sozinho. Para saber mais sobre o plug-in do perfil de referência para Gradle, consulte Configurar a geração do perfil de referência.

Confira como criar um perfil de referência usando o plug-in para Gradle:

  1. Crie um novo módulo com.android.test (por exemplo, :baseline-profile).
  2. Configure o arquivo build.gradle.kts para :baseline-profile:

    1. Aplique o plug-in androidx.baselineprofile.
    2. Confira se targetProjectPath aponta para o módulo :app.
    3. Se quiser, adicione um dispositivo gerenciado pelo Gradle (GMD, na sigla em inglês). No exemplo abaixo, é pixel6Api31. Se não for especificado, o plug-in vai usar um dispositivo conectado, seja ele emulado ou físico.
    4. Aplique a configuração desejada, conforme mostrado no exemplo abaixo.

    Kotlin

    plugins {
        id("com.android.test")
        id("androidx.baselineprofile")
    }
    
    android {
        defaultConfig {
            ...
        }
    
        // Point to the app module, the module that you're generating the Baseline Profile for.
        targetProjectPath = ":app"
        // Configure a GMD (optional).
        testOptions.managedDevices.devices {
            pixel6Api31(com.android.build.api.dsl.ManagedVirtualDevice) {
                device = "Pixel 6"
                apiLevel = 31
                systemImageSource = "aosp"
            }
        }
    }
    
    dependencies { ... }
    
    // Baseline Profile Gradle plugin configuration. Everything is optional. This
    // example uses the GMD added earlier and disables connected devices.
    baselineProfile {
        // Specifies the GMDs to run the tests on. The default is none.
        managedDevices += "pixel6Api31"
        // Enables using connected devices to generate profiles. The default is
        // `true`. When using connected devices, they must be rooted or API 33 and
        // higher.
        useConnectedDevices = false
    }

    Groovy

    plugins {
        id 'com.android.test'
        id 'androidx.baselineprofile'
    }
    
    android {
        defaultConfig {
            ...
        }
    
        // Point to the app module, the module that you're generating the Baseline Profile for.
        targetProjectPath ':app'
        // Configure a GMD (optional).
        testOptions.managedDevices.devices {
            pixel6Api31(com.android.build.api.dsl.ManagedVirtualDevice) {
                device 'Pixel 6'
                apiLevel 31
                systemImageSource 'aosp'
            }
        }
    }
    
    dependencies { ... }
    
    // Baseline Profile Gradle plugin configuration. Everything is optional. This
    // example uses the GMD added earlier and disables connected devices.
    baselineProfile {
        // Specifies the GMDs to run the tests on. The default is none.
        managedDevices ['pixel6Api31']
        // Enables using connected devices to generate profiles. The default is
        // `true`. When using connected devices, they must be rooted or API 33 and
        // higher.
        useConnectedDevices false
    }
  3. Crie um teste do perfil de referência no módulo de teste :baseline-profile. O exemplo abaixo é um teste que inicia o app e aguarda a inatividade.

    Kotlin

    class BaselineProfileGenerator {
    
        @get:Rule
        val baselineRule = BaselineProfileRule()
    
        @Test
        fun startupBaselineProfile() {
            baselineRule.collect("com.myapp") {
                startActivityAndWait()
            }
        }
    }

    Java

    public class BaselineProfileGenerator {
    
        @Rule
        Public BaselineProfileRule baselineRule = new BaselineProfileRule();
    
        @Test
        Public void startupBaselineProfile() {
            baselineRule.collect(
                "com.myapp",
                (scope -> {
                    scope.startActivityAndWait();
                    Return Unit.INSTANCE;
                })
            )
        }
    }
  4. Atualize o arquivo build.gradle.kts no módulo do app (por exemplo, :app).

    1. Aplique o plug-in androidx.baselineprofile.
    2. Adicione uma dependência do baselineProfile ao módulo :baseline-profile.

    Kotlin

    plugins {
        id("com.android.application")
        id("androidx.baselineprofile")
    }
    
    android {
        // There are no changes to the `android` block.
        ...
    }
    
    dependencies {
        ...
        // Add a `baselineProfile` dependency on the `:baseline-profile` module.
        baselineProfile(project(":baseline-profile"))
    }

    Groovy

    plugins {
        id 'com.android.application'
        id 'androidx.baselineprofile'
    }
    
    android {
        // No changes to the `android` block.
        ...
    }
    
    dependencies {
        ...
        // Add a `baselineProfile` dependency on the `:baseline-profile` module.
        baselineProfile ':baseline-profile'
    }
  5. Gere o perfil executando as tarefas :app:generateBaselineProfile ou :app:generateVariantBaselineProfile do Gradle.

  6. No final da tarefa de geração, o perfil de referência será copiado para app/src/variant/generated/baselineProfiles.

Criar um novo perfil de referência com o AGP 7.3 ou 7.4

É possível gerar perfis de referência com o AGP 7.3 ou 7.4, mas recomendamos fazer upgrade para pelo menos o AGP 8.1 para que você possa usar o plug-in do perfil de referência para Gradle e os recursos mais recentes.

Caso você precise criar perfis de referência com o AGP 7.3 ou 7.4, as etapas são as mesmas do AGP 8.1, com estas exceções:

Aplicar manualmente as regras geradas

O gerador do perfil de referência cria um arquivo de texto em formato legível por humanos (HRF, na sigla em inglês) no dispositivo e o copia para a máquina host. Para aplicar o perfil gerado ao código, siga estas etapas:

  1. Localize o arquivo HRF na pasta de build do módulo em que você gera o perfil: [module]/build/outputs/managed_device_android_test_additional_output/[device].

    Os perfis seguem o padrão de nomenclatura [class name]-[test method name]-baseline-prof.txt e têm esta aparência: BaselineProfileGenerator-startup-baseline-prof.txt.

  2. Copie o perfil gerado para src/main/ e renomeie o arquivo como baseline-prof.txt.

  3. Adicione uma dependência à biblioteca ProfileInstaller no arquivo build.gradle.kts do app para ativar a compilação de perfis de referência locais quando os perfis do Cloud não estiverem disponíveis. Essa é a única maneira de transferir um perfil de referência localmente por sideload.

    dependencies {
         implementation("androidx.profileinstaller:profileinstaller:1.4.1")
    }
    
  4. Crie a versão de produção do app, em que as regras de HRF aplicadas são compiladas no formato binário e incluídas no APK ou AAB. Em seguida, distribua o app normalmente.

Comparar o perfil de referência

Para comparar seu perfil de referência, crie uma configuração de execução de teste instrumentado do Android com base na ação de gutter que executa as comparações definidas no arquivo StartupBenchmarks.kt ou StartupBencharks.java. Para saber mais sobre os testes de comparação, consulte Criar uma classe Macrobenchmark e Automatizar a medição com a biblioteca Macrobenchmark.

Figura 3. Execute os testes do Android na ação de gutter.

Quando essa execução é feita no Android Studio, a saída do build contém detalhes das melhorias de velocidade oferecidas pelo perfil de referência:

StartupBenchmarks_startupCompilationBaselineProfiles
timeToInitialDisplayMs   min 161.8,   median 178.9,   max 194.6
StartupBenchmarks_startupCompilationNone
timeToInitialDisplayMs   min 184.7,   median 196.9,   max 202.9

Capturar todos os caminhos de código necessários

Confira as duas métricas principais para medir os tempos de inicialização do app:

Tempo para exibição inicial (TTID, na sigla em inglês)
O tempo necessário para mostrar o primeiro frame da interface do aplicativo.
Tempo para exibição total (TTFD, na sigla em inglês)
O TTID somado ao tempo para mostrar conteúdo que seja carregado de forma assíncrona após a exibição do frame inicial.

O TTFD é informado quando o método reportFullyDrawn() da ComponentActivity é chamado. Se o método reportFullyDrawn() nunca for chamado, o TTID será informado. Talvez seja necessário atrasar a chamada do reportFullyDrawn() até que o carregamento assíncrono seja concluído. Por exemplo, se a interface contém uma lista dinâmica, como RecyclerView ou uma lista lenta, talvez ela seja preenchida por uma tarefa em segundo plano que será concluída depois que a lista for renderizada e, portanto, depois que a interface estiver marcada como totalmente renderizada. Nesses casos, o código executado depois que a interface atinge o estado totalmente renderizado não é incluído no perfil de referência.

Para incluir o preenchimento da lista como parte do perfil de referência, acesse o FullyDrawnReporter usando getFullyDrawnReporter() e adicione um informante no código do app. Libere o informante depois que a tarefa em segundo plano terminar de preencher a lista. O FullyDrawnReporter não chama o método reportFullyDrawn() até que todos os informantes sejam liberados. Ao fazer isso, o perfil de referência inclui os caminhos de código necessários para preencher a lista. Isso não muda o comportamento do app para o usuário, mas permite que o perfil de referência inclua todos os caminhos de código necessários.

Se o app usar o Jetpack Compose, utilize as APIs abaixo para indicar o estado totalmente renderizado:

  • ReportDrawn indica que o elemento combinável está pronto para interação.
  • ReportDrawnWhen usa um predicado, por exemplo, list.count > 0, para indicar quando o elemento combinável está pronto para interação.
  • ReportDrawnAfter usa um método de suspensão que, quando concluído, indica que o elemento combinável está pronto para interação.