Otimizando os tempos de inicialização

Este documento fornece orientação ao parceiro para melhorar os tempos de inicialização para dispositivos Android específicos. O tempo de inicialização é um componente importante do desempenho do sistema, pois os usuários devem aguardar a conclusão da inicialização antes de poderem usar o dispositivo. Para dispositivos como carros onde a inicialização a frio ocorre com mais frequência, ter um tempo de inicialização rápido é crítico (ninguém gosta de esperar dezenas de segundos apenas para inserir um destino de navegação).

O Android 8.0 permite tempos de inicialização reduzidos ao oferecer suporte a várias melhorias em uma variedade de componentes. A tabela a seguir resume essas melhorias de desempenho (medidas em dispositivos Google Pixel e Pixel XL).

Componente Melhoria
Bootloader
  • Economizou 1,6s removendo o log UART
  • Economizou 0,4s ao mudar para LZ4 de GZIP
Kernel do dispositivo
  • Economizou 0,3s removendo configurações de kernel não utilizadas e reduzindo o tamanho do driver
  • Economizou 0,3s com otimização de pré-busca dm-verity
  • Economizou 0,15s para remover espera/teste desnecessário no driver
  • Economizou 0,12s para remover CONFIG_CC_OPTIMIZE_FOR_SIZE
ajuste de E/S
  • Economizou 2s na inicialização normal
  • Economizou 25s na primeira inicialização
init.*.rc
  • Economizou 1,5s ao paralelizar os comandos init
  • Economizou 0,25s iniciando o zigoto mais cedo
  • Economizou 0,22s por ajuste cpuset
Animação de inicialização
  • Começou 2s antes na inicialização sem fsck acionado, muito maior na inicialização com inicialização acionada por fsck
  • Economizou 5s no Pixel XL com desligamento imediato da animação de inicialização
Política do SELinux Economizou 0,2s por genfscon

Otimizando o Bootloader

Para otimizar o bootloader para tempos de inicialização aprimorados:

  • Para registro:
    • Desative a gravação de log no UART, pois pode demorar muito com muitos logs. (Nos dispositivos Google Pixel, descobrimos que ele retarda o bootloader 1,5s).
    • Registre apenas situações de erro e considere armazenar outras informações na memória com um mecanismo separado para recuperação.
  • Para descompactação do kernel, considere o uso de LZ4 para hardware contemporâneo em vez de GZIP (exemplo de patch ). Lembre-se de que diferentes opções de compactação do kernel podem ter diferentes tempos de carregamento e descompactação, e algumas opções podem funcionar melhor do que outras para seu hardware específico.
  • Verifique os tempos de espera desnecessários para entrada no modo debouncing/especial e minimize-os.
  • Passe o tempo de inicialização gasto no bootloader para o kernel como cmdline.
  • Verifique o clock da CPU e considere a paralelização (requer suporte a vários núcleos) para carregar o kernel e inicializar a E/S.

Otimizando a eficiência de E/S

Melhorar a eficiência de E/S é fundamental para tornar o tempo de inicialização mais rápido, e a leitura de qualquer coisa desnecessária deve ser adiada até depois da inicialização (em um Google Pixel, cerca de 1,2 GB de dados são lidos na inicialização).

Ajustando o sistema de arquivos

A leitura antecipada do kernel do Linux entra em ação quando um arquivo é lido desde o início ou quando os blocos são lidos sequencialmente, tornando necessário ajustar os parâmetros do agendador de E/S especificamente para inicialização (que tem uma caracterização de carga de trabalho diferente dos aplicativos normais).

Os dispositivos que oferecem suporte a atualizações contínuas (A/B) se beneficiam muito do ajuste do sistema de arquivos na primeira inicialização (por exemplo, 20s no Google Pixel). Como exemplo, ajustamos os seguintes parâmetros para o Google Pixel:

on late-fs
  # boot time fs tune
    # boot time fs tune
    write /sys/block/sda/queue/iostats 0
    write /sys/block/sda/queue/scheduler cfq
    write /sys/block/sda/queue/iosched/slice_idle 0
    write /sys/block/sda/queue/read_ahead_kb 2048
    write /sys/block/sda/queue/nr_requests 256
    write /sys/block/dm-0/queue/read_ahead_kb 2048
    write /sys/block/dm-1/queue/read_ahead_kb 2048

on property:sys.boot_completed=1
    # end boot time fs tune
    write /sys/block/sda/queue/read_ahead_kb 512
    ...

Diversos

  • Ative o tamanho de pré-busca de hash dm-verity usando a configuração do kernel DM_VERITY_HASH_PREFETCH_MIN_SIZE (o tamanho padrão é 128).
  • Para obter uma melhor estabilidade do sistema de arquivos e uma verificação forçada descartada que ocorre a cada inicialização, use a nova ferramenta de geração ext4 definindo TARGET_USES_MKE2FS em BoardConfig.mk.

Analisando E/S

Para entender as atividades de E/S durante a inicialização, use os dados ftrace do kernel (também usados ​​pelo systrace):

trace_event=block,ext4 in BOARD_KERNEL_CMDLINE

Para detalhar o acesso a cada arquivo, faça as seguintes alterações no kernel (somente kernel de desenvolvimento; não use em kernels de produção):

diff --git a/fs/open.c b/fs/open.c
index 1651f35..a808093 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -981,6 +981,25 @@
 }
 EXPORT_SYMBOL(file_open_root);
 
+static void _trace_do_sys_open(struct file *filp, int flags, int mode, long fd)
+{
+       char *buf;
+       char *fname;
+
+       buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!buf)
+               return;
+       fname = d_path(&filp-<f_path, buf, PAGE_SIZE);
+
+       if (IS_ERR(fname))
+               goto out;
+
+       trace_printk("%s: open(\"%s\", %d, %d) fd = %ld, inode = %ld\n",
+                     current-<comm, fname, flags, mode, fd, filp-<f_inode-<i_ino);
+out:
+       kfree(buf);
+}
+
long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
 {
 	struct open_flags op;
@@ -1003,6 +1022,7 @@
 		} else {
 			fsnotify_open(f);
 			fd_install(fd, f);
+			_trace_do_sys_open(f, flags, mode, fd);

Use os scripts a seguir para ajudar na análise do desempenho da inicialização.

  • system/extras/boottime_tools/bootanalyze/bootanalyze.py Mede o tempo de inicialização com uma divisão de etapas importantes no processo de inicialização.
  • system/extras/boottime_tools/io_analysis/check_file_read.py boot_trace Fornece informações de acesso para cada arquivo.
  • system/extras/boottime_tools/io_analysis/check_io_trace_all.py boot_trace Fornece detalhamento no nível do sistema.

Otimizando init.*.rc

O init é a ponte do kernel até que a estrutura seja estabelecida, e os dispositivos geralmente passam alguns segundos em diferentes estágios de inicialização.

Executando tarefas em paralelo

Embora o init atual do Android seja mais ou menos um único processo encadeado, você ainda pode executar algumas tarefas em paralelo.

  • Execute comandos lentos em um serviço de script de shell e junte-se a ele mais tarde, aguardando uma propriedade específica. O Android 8.0 oferece suporte a esse caso de uso com um novo comando wait_for_property .
  • Identifique operações lentas no init. O sistema registra o comando init exec/wait_for_prop ou qualquer ação demorada (no Android 8.0, qualquer comando demorando mais de 50 ms). Por exemplo:
    init: Command 'wait_for_coldboot_done' action=wait_for_coldboot_done returned 0 took 585.012ms

    A revisão desse log pode indicar oportunidades de melhorias.

  • Inicie os serviços e habilite os dispositivos periféricos no caminho crítico com antecedência. Por exemplo, alguns SOCs exigem o início de serviços relacionados à segurança antes de iniciar o SurfaceFlinger. Revise o log do sistema quando o ServiceManager retornar "esperar pelo serviço" — isso geralmente é um sinal de que um serviço dependente deve ser iniciado primeiro.
  • Remova todos os serviços e comandos não utilizados em init.*.rc. Qualquer coisa não usada no init de estágio inicial deve ser adiada para inicialização concluída.

Nota: O serviço de propriedade faz parte do processo init, portanto, chamar setproperty durante a inicialização pode levar a um longo atraso se init estiver ocupado em comandos integrados.

Usando o ajuste do agendador

Use o ajuste do agendador para inicialização antecipada. Exemplo de um Google Pixel:

on init
    # boottime stune
    write /dev/stune/schedtune.prefer_idle 1
    write /dev/stune/schedtune.boost 100
    on property:sys.boot_completed=1
    # reset stune
    write /dev/stune/schedtune.prefer_idle 0
    write /dev/stune/schedtune.boost 0

    # or just disable EAS during boot
    on init
    write /sys/kernel/debug/sched_features NO_ENERGY_AWARE
    on property:sys.boot_completed=1
    write /sys/kernel/debug/sched_features ENERGY_AWARE

Alguns serviços podem precisar de um aumento de prioridade durante a inicialização. Exemplo:

init.zygote64.rc:
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
...

Iniciando o zigoto cedo

Dispositivos com criptografia baseada em arquivo podem iniciar o zygote mais cedo no gatilho zygote-start (por padrão, o zygote é iniciado na classe principal, que é muito posterior ao zygote-start). Ao fazer isso, certifique-se de permitir que o zygote seja executado em todas as CPUs (já que a configuração incorreta do cpuset pode forçar a execução do zygote em CPUs específicas).

Desativar economia de energia

Durante a inicialização do dispositivo, a configuração de economia de energia para componentes como UFS e/ou governador da CPU pode ser desativada.

Cuidado: a economia de energia deve ser habilitada no modo de carregamento para maior eficiência.

on init
    # Disable UFS powersaving
    write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 0
    write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 0
    write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 0
    write /sys/module/lpm_levels/parameters/sleep_disabled Y
on property:sys.boot_completed=1
    # Enable UFS powersaving
    write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 1
    write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 1
    write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 1
    write /sys/module/lpm_levels/parameters/sleep_disabled N
on charger
    # Enable UFS powersaving
    write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 1
    write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 1
    write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 1
    write /sys/class/typec/port0/port_type sink
    write /sys/module/lpm_levels/parameters/sleep_disabled N

Adiar inicialização não crítica

A inicialização não crítica, como ZRAM, pode ser adiada para boot_complete.

on property:sys.boot_completed=1
   # Enable ZRAM on boot_complete
   swapon_all /vendor/etc/fstab.${ro.hardware}

Otimizando a animação de inicialização

Use as dicas a seguir para otimizar a animação de inicialização.

Configurando início antecipado

O Android 8.0 permite iniciar a animação de inicialização antecipadamente, antes de montar a partição de dados do usuário. No entanto, mesmo ao usar a nova cadeia de ferramentas ext4 no Android 8.0, o fsck ainda é acionado periodicamente por motivos de segurança, causando um atraso no início do serviço bootanimation.

Para fazer o bootanimation começar cedo, divida a montagem do fstab em duas fases:

  • Na fase inicial, monte apenas as partições (como system/ e vendor/ ) que não requerem verificações de execução e, em seguida, inicie os serviços de animação de inicialização e suas dependências (como servicemanager e surfaceflinger).
  • Na segunda fase, monte as partições (como data/ ) que requerem verificações de execução.

A animação de inicialização será iniciada muito mais rapidamente (e em tempo constante), independentemente do fsck.

Acabamento limpo

Depois de receber o sinal de saída, o bootanimation reproduz a última parte, cuja duração pode retardar o tempo de inicialização. Um sistema que inicializa rapidamente não precisa de longas animações que poderiam efetivamente esconder quaisquer melhorias feitas. Recomendamos que o loop de repetição e o final sejam curtos.

Otimizando o SELinux

Use as dicas a seguir para otimizar o SELinux para tempos de inicialização aprimorados.

  • Use expressões regulares limpas (regex) . Regex mal formado pode levar a muita sobrecarga ao corresponder à política SELinux para sys/devices em file_contexts . Por exemplo, o regex /sys/devices/.*abc.*(/.*)? força por engano uma verificação de todos os subdiretórios /sys/devices que contêm "abc", permitindo correspondências para /sys/devices/abc e /sys/devices/xyz/abc . Melhorando este regex para /sys/devices/[^/]*abc[^/]*(/.*)? habilitará uma correspondência apenas para /sys/devices/abc .
  • Mova os rótulos para genfscon . Esse recurso SELinux existente passa prefixos de correspondência de arquivo para o kernel no binário SELinux, onde o kernel os aplica a sistemas de arquivos gerados pelo kernel. Isso também ajuda a corrigir arquivos criados pelo kernel com rótulos incorretos, evitando condições de corrida que podem ocorrer entre os processos do espaço do usuário que tentam acessar esses arquivos antes que ocorra a reetiquetagem.

Ferramenta e métodos

Use as ferramentas a seguir para ajudá-lo a coletar dados para metas de otimização.

Bootchart

O Bootchart fornece análise de carga de CPU e E/S de todos os processos para todo o sistema. Ele não requer a reconstrução da imagem do sistema e pode ser usado como uma verificação rápida de sanidade antes de mergulhar no systrace.

Para habilitar o bootchart:

adb shell 'touch /data/bootchart/enabled'
adb reboot

Após a inicialização, busque o gráfico de inicialização:

$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh

Quando terminar, exclua /data/bootchart/enabled para evitar a coleta de dados todas as vezes.

Se o bootchart não funcionar e você receber um erro informando que bootchart.png não existe, faça o seguinte:
  1. Execute os seguintes comandos:
          sudo apt install python-is-python3
          cd ~/Documents
          git clone https://github.com/xrmx/bootchart.git
          cd bootchart/pybootchartgui
          mv main.py.in main.py
        
  2. Atualize $ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh para apontar para a cópia local de pybootchartgui (localizado em ~/Documents/bootchart/pybootchartgui.py )

Systrace

O Systrace permite coletar rastreamentos do kernel e do Android durante a inicialização. A visualização do systrace pode ajudar na análise de problemas específicos durante a inicialização. (No entanto, para verificar o número médio ou o número acumulado durante toda a inicialização, é mais fácil examinar diretamente o rastreamento do kernel).

Para habilitar o systrace durante a inicialização:

  • Em frameworks/native/cmds/atrace/atrace.rc , altere:
      write /sys/kernel/debug/tracing/tracing_on 0
      write /sys/kernel/tracing/tracing_on 0

    Para:

      #    write /sys/kernel/debug/tracing/tracing_on 0
      #    write /sys/kernel/tracing/tracing_on 0
  • Isso habilita o rastreamento (que é desabilitado por padrão).

  • No arquivo device.mk , adicione a seguinte linha:
    PRODUCT_PROPERTY_OVERRIDES +=    debug.atrace.tags.enableflags=802922
    PRODUCT_PROPERTY_OVERRIDES +=    persist.traced.enable=0
  • No arquivo BoardConfig.mk do dispositivo, adicione o seguinte:
    BOARD_KERNEL_CMDLINE := ... trace_buf_size=64M trace_event=sched_wakeup,sched_switch,sched_blocked_reason,sched_cpu_hotplug
  • Para análise detalhada de E/S, adicione também block e ext4 e f2fs.

  • No arquivo init.rc específico do dispositivo, adicione o seguinte:
    on property:sys.boot_completed=1          // This stops tracing on boot complete
    write /d/tracing/tracing_on 0
    write /d/tracing/events/ext4/enable 0
    write /d/tracing/events/f2fs/enable 0
    write /d/tracing/events/block/enable 0
    
  • Após a inicialização, busque o rastreamento:

    adb root && adb shell atrace --async_stop -z -c -o /data/local/tmp/boot_trace
    adb pull /data/local/tmp/boot_trace
    $ANDROID_BUILD_TOP/external/chromium-trace/systrace.py --from-file=boot_trace
    
,

Este documento fornece orientação ao parceiro para melhorar os tempos de inicialização para dispositivos Android específicos. O tempo de inicialização é um componente importante do desempenho do sistema, pois os usuários devem aguardar a conclusão da inicialização antes de poderem usar o dispositivo. Para dispositivos como carros onde a inicialização a frio ocorre com mais frequência, ter um tempo de inicialização rápido é crítico (ninguém gosta de esperar dezenas de segundos apenas para inserir um destino de navegação).

O Android 8.0 permite tempos de inicialização reduzidos ao oferecer suporte a várias melhorias em uma variedade de componentes. A tabela a seguir resume essas melhorias de desempenho (medidas em dispositivos Google Pixel e Pixel XL).

Componente Melhoria
Bootloader
  • Economizou 1,6s removendo o log UART
  • Economizou 0,4s ao mudar para LZ4 de GZIP
Kernel do dispositivo
  • Economizou 0,3s removendo configurações de kernel não utilizadas e reduzindo o tamanho do driver
  • Economizou 0,3s com otimização de pré-busca dm-verity
  • Economizou 0,15s para remover espera/teste desnecessário no driver
  • Economizou 0,12s para remover CONFIG_CC_OPTIMIZE_FOR_SIZE
ajuste de E/S
  • Economizou 2s na inicialização normal
  • Economizou 25s na primeira inicialização
init.*.rc
  • Economizou 1,5s ao paralelizar os comandos init
  • Economizou 0,25s iniciando o zigoto mais cedo
  • Economizou 0,22s por ajuste cpuset
Animação de inicialização
  • Começou 2s antes na inicialização sem fsck acionado, muito maior na inicialização com inicialização acionada por fsck
  • Economizou 5s no Pixel XL com desligamento imediato da animação de inicialização
Política do SELinux Economizou 0,2s por genfscon

Otimizando o Bootloader

Para otimizar o bootloader para tempos de inicialização aprimorados:

  • Para registro:
    • Desative a gravação de log no UART, pois pode demorar muito com muitos logs. (Nos dispositivos Google Pixel, descobrimos que ele retarda o bootloader 1,5s).
    • Registre apenas situações de erro e considere armazenar outras informações na memória com um mecanismo separado para recuperação.
  • Para descompactação do kernel, considere o uso de LZ4 para hardware contemporâneo em vez de GZIP (exemplo de patch ). Lembre-se de que diferentes opções de compactação do kernel podem ter diferentes tempos de carregamento e descompactação, e algumas opções podem funcionar melhor do que outras para seu hardware específico.
  • Verifique os tempos de espera desnecessários para entrada no modo debouncing/especial e minimize-os.
  • Passe o tempo de inicialização gasto no bootloader para o kernel como cmdline.
  • Verifique o clock da CPU e considere a paralelização (requer suporte a vários núcleos) para carregar o kernel e inicializar a E/S.

Otimizando a eficiência de E/S

Melhorar a eficiência de E/S é fundamental para tornar o tempo de inicialização mais rápido, e a leitura de qualquer coisa desnecessária deve ser adiada até depois da inicialização (em um Google Pixel, cerca de 1,2 GB de dados são lidos na inicialização).

Ajustando o sistema de arquivos

A leitura antecipada do kernel do Linux entra em ação quando um arquivo é lido desde o início ou quando os blocos são lidos sequencialmente, tornando necessário ajustar os parâmetros do agendador de E/S especificamente para inicialização (que tem uma caracterização de carga de trabalho diferente dos aplicativos normais).

Os dispositivos que oferecem suporte a atualizações contínuas (A/B) se beneficiam muito do ajuste do sistema de arquivos na primeira inicialização (por exemplo, 20s no Google Pixel). Como exemplo, ajustamos os seguintes parâmetros para o Google Pixel:

on late-fs
  # boot time fs tune
    # boot time fs tune
    write /sys/block/sda/queue/iostats 0
    write /sys/block/sda/queue/scheduler cfq
    write /sys/block/sda/queue/iosched/slice_idle 0
    write /sys/block/sda/queue/read_ahead_kb 2048
    write /sys/block/sda/queue/nr_requests 256
    write /sys/block/dm-0/queue/read_ahead_kb 2048
    write /sys/block/dm-1/queue/read_ahead_kb 2048

on property:sys.boot_completed=1
    # end boot time fs tune
    write /sys/block/sda/queue/read_ahead_kb 512
    ...

Diversos

  • Ative o tamanho de pré-busca de hash dm-verity usando a configuração do kernel DM_VERITY_HASH_PREFETCH_MIN_SIZE (o tamanho padrão é 128).
  • Para obter uma melhor estabilidade do sistema de arquivos e uma verificação forçada descartada que ocorre a cada inicialização, use a nova ferramenta de geração ext4 definindo TARGET_USES_MKE2FS em BoardConfig.mk.

Analisando E/S

Para entender as atividades de E/S durante a inicialização, use os dados ftrace do kernel (também usados ​​pelo systrace):

trace_event=block,ext4 in BOARD_KERNEL_CMDLINE

Para detalhar o acesso a cada arquivo, faça as seguintes alterações no kernel (somente kernel de desenvolvimento; não use em kernels de produção):

diff --git a/fs/open.c b/fs/open.c
index 1651f35..a808093 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -981,6 +981,25 @@
 }
 EXPORT_SYMBOL(file_open_root);
 
+static void _trace_do_sys_open(struct file *filp, int flags, int mode, long fd)
+{
+       char *buf;
+       char *fname;
+
+       buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!buf)
+               return;
+       fname = d_path(&filp-<f_path, buf, PAGE_SIZE);
+
+       if (IS_ERR(fname))
+               goto out;
+
+       trace_printk("%s: open(\"%s\", %d, %d) fd = %ld, inode = %ld\n",
+                     current-<comm, fname, flags, mode, fd, filp-<f_inode-<i_ino);
+out:
+       kfree(buf);
+}
+
long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
 {
 	struct open_flags op;
@@ -1003,6 +1022,7 @@
 		} else {
 			fsnotify_open(f);
 			fd_install(fd, f);
+			_trace_do_sys_open(f, flags, mode, fd);

Use os scripts a seguir para ajudar na análise do desempenho da inicialização.

  • system/extras/boottime_tools/bootanalyze/bootanalyze.py Mede o tempo de inicialização com uma divisão de etapas importantes no processo de inicialização.
  • system/extras/boottime_tools/io_analysis/check_file_read.py boot_trace Fornece informações de acesso para cada arquivo.
  • system/extras/boottime_tools/io_analysis/check_io_trace_all.py boot_trace Fornece detalhamento no nível do sistema.

Otimizando init.*.rc

O init é a ponte do kernel até que a estrutura seja estabelecida, e os dispositivos geralmente passam alguns segundos em diferentes estágios de inicialização.

Executando tarefas em paralelo

Embora o init atual do Android seja mais ou menos um único processo encadeado, você ainda pode executar algumas tarefas em paralelo.

  • Execute comandos lentos em um serviço de script de shell e junte-se a ele mais tarde, aguardando uma propriedade específica. O Android 8.0 oferece suporte a esse caso de uso com um novo comando wait_for_property .
  • Identifique operações lentas no init. O sistema registra o comando init exec/wait_for_prop ou qualquer ação demorada (no Android 8.0, qualquer comando demorando mais de 50 ms). Por exemplo:
    init: Command 'wait_for_coldboot_done' action=wait_for_coldboot_done returned 0 took 585.012ms

    A revisão desse log pode indicar oportunidades de melhorias.

  • Inicie os serviços e habilite os dispositivos periféricos no caminho crítico com antecedência. Por exemplo, alguns SOCs exigem o início de serviços relacionados à segurança antes de iniciar o SurfaceFlinger. Revise o log do sistema quando o ServiceManager retornar "esperar pelo serviço" — isso geralmente é um sinal de que um serviço dependente deve ser iniciado primeiro.
  • Remova todos os serviços e comandos não utilizados em init.*.rc. Qualquer coisa não usada no init de estágio inicial deve ser adiada para inicialização concluída.

Nota: O serviço de propriedade faz parte do processo init, portanto, chamar setproperty durante a inicialização pode levar a um longo atraso se init estiver ocupado em comandos integrados.

Usando o ajuste do agendador

Use o ajuste do agendador para inicialização antecipada. Exemplo de um Google Pixel:

on init
    # boottime stune
    write /dev/stune/schedtune.prefer_idle 1
    write /dev/stune/schedtune.boost 100
    on property:sys.boot_completed=1
    # reset stune
    write /dev/stune/schedtune.prefer_idle 0
    write /dev/stune/schedtune.boost 0

    # or just disable EAS during boot
    on init
    write /sys/kernel/debug/sched_features NO_ENERGY_AWARE
    on property:sys.boot_completed=1
    write /sys/kernel/debug/sched_features ENERGY_AWARE

Alguns serviços podem precisar de um aumento de prioridade durante a inicialização. Exemplo:

init.zygote64.rc:
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
...

Iniciando o zigoto cedo

Dispositivos com criptografia baseada em arquivo podem iniciar o zygote mais cedo no gatilho zygote-start (por padrão, o zygote é iniciado na classe principal, que é muito posterior ao zygote-start). Ao fazer isso, certifique-se de permitir que o zygote seja executado em todas as CPUs (já que a configuração incorreta do cpuset pode forçar a execução do zygote em CPUs específicas).

Desativar economia de energia

Durante a inicialização do dispositivo, a configuração de economia de energia para componentes como UFS e/ou governador da CPU pode ser desativada.

Cuidado: a economia de energia deve ser habilitada no modo de carregamento para maior eficiência.

on init
    # Disable UFS powersaving
    write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 0
    write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 0
    write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 0
    write /sys/module/lpm_levels/parameters/sleep_disabled Y
on property:sys.boot_completed=1
    # Enable UFS powersaving
    write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 1
    write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 1
    write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 1
    write /sys/module/lpm_levels/parameters/sleep_disabled N
on charger
    # Enable UFS powersaving
    write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 1
    write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 1
    write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 1
    write /sys/class/typec/port0/port_type sink
    write /sys/module/lpm_levels/parameters/sleep_disabled N

Adiar inicialização não crítica

A inicialização não crítica, como ZRAM, pode ser adiada para boot_complete.

on property:sys.boot_completed=1
   # Enable ZRAM on boot_complete
   swapon_all /vendor/etc/fstab.${ro.hardware}

Otimizando a animação de inicialização

Use as dicas a seguir para otimizar a animação de inicialização.

Configurando início antecipado

O Android 8.0 permite iniciar a animação de inicialização antecipadamente, antes de montar a partição de dados do usuário. No entanto, mesmo ao usar a nova cadeia de ferramentas ext4 no Android 8.0, o fsck ainda é acionado periodicamente por motivos de segurança, causando um atraso no início do serviço bootanimation.

Para fazer o bootanimation começar cedo, divida a montagem do fstab em duas fases:

  • Na fase inicial, monte apenas as partições (como system/ e vendor/ ) que não requerem verificações de execução e, em seguida, inicie os serviços de animação de inicialização e suas dependências (como servicemanager e surfaceflinger).
  • Na segunda fase, monte as partições (como data/ ) que requerem verificações de execução.

A animação de inicialização será iniciada muito mais rapidamente (e em tempo constante), independentemente do fsck.

Acabamento limpo

Depois de receber o sinal de saída, o bootanimation reproduz a última parte, cuja duração pode retardar o tempo de inicialização. Um sistema que inicializa rapidamente não precisa de longas animações que poderiam efetivamente esconder quaisquer melhorias feitas. Recomendamos que o loop de repetição e o final sejam curtos.

Otimizando o SELinux

Use as dicas a seguir para otimizar o SELinux para tempos de inicialização aprimorados.

  • Use expressões regulares limpas (regex) . Regex mal formado pode levar a muita sobrecarga ao corresponder à política SELinux para sys/devices em file_contexts . Por exemplo, o regex /sys/devices/.*abc.*(/.*)? força por engano uma verificação de todos os subdiretórios /sys/devices que contêm "abc", permitindo correspondências para /sys/devices/abc e /sys/devices/xyz/abc . Melhorando este regex para /sys/devices/[^/]*abc[^/]*(/.*)? habilitará uma correspondência apenas para /sys/devices/abc .
  • Mova os rótulos para genfscon . Esse recurso SELinux existente passa prefixos de correspondência de arquivo para o kernel no binário SELinux, onde o kernel os aplica a sistemas de arquivos gerados pelo kernel. Isso também ajuda a corrigir arquivos criados pelo kernel com rótulos incorretos, evitando condições de corrida que podem ocorrer entre os processos do espaço do usuário que tentam acessar esses arquivos antes que ocorra a reetiquetagem.

Ferramenta e métodos

Use as ferramentas a seguir para ajudá-lo a coletar dados para metas de otimização.

Bootchart

O Bootchart fornece análise de carga de CPU e E/S de todos os processos para todo o sistema. Ele não requer a reconstrução da imagem do sistema e pode ser usado como uma verificação rápida de sanidade antes de mergulhar no systrace.

Para habilitar o bootchart:

adb shell 'touch /data/bootchart/enabled'
adb reboot

Após a inicialização, busque o gráfico de inicialização:

$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh

Quando terminar, exclua /data/bootchart/enabled para evitar a coleta de dados todas as vezes.

Se o bootchart não funcionar e você receber um erro informando que bootchart.png não existe, faça o seguinte:
  1. Execute os seguintes comandos:
          sudo apt install python-is-python3
          cd ~/Documents
          git clone https://github.com/xrmx/bootchart.git
          cd bootchart/pybootchartgui
          mv main.py.in main.py
        
  2. Atualize $ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh para apontar para a cópia local de pybootchartgui (localizado em ~/Documents/bootchart/pybootchartgui.py )

Systrace

O Systrace permite coletar rastreamentos do kernel e do Android durante a inicialização. A visualização do systrace pode ajudar na análise de problemas específicos durante a inicialização. (No entanto, para verificar o número médio ou o número acumulado durante toda a inicialização, é mais fácil examinar diretamente o rastreamento do kernel).

Para habilitar o systrace durante a inicialização:

  • Em frameworks/native/cmds/atrace/atrace.rc , altere:
      write /sys/kernel/debug/tracing/tracing_on 0
      write /sys/kernel/tracing/tracing_on 0

    Para:

      #    write /sys/kernel/debug/tracing/tracing_on 0
      #    write /sys/kernel/tracing/tracing_on 0
  • Isso habilita o rastreamento (que é desabilitado por padrão).

  • No arquivo device.mk , adicione a seguinte linha:
    PRODUCT_PROPERTY_OVERRIDES +=    debug.atrace.tags.enableflags=802922
    PRODUCT_PROPERTY_OVERRIDES +=    persist.traced.enable=0
  • No arquivo BoardConfig.mk do dispositivo, adicione o seguinte:
    BOARD_KERNEL_CMDLINE := ... trace_buf_size=64M trace_event=sched_wakeup,sched_switch,sched_blocked_reason,sched_cpu_hotplug
  • Para análise detalhada de E/S, adicione também block e ext4 e f2fs.

  • No arquivo init.rc específico do dispositivo, adicione o seguinte:
    on property:sys.boot_completed=1          // This stops tracing on boot complete
    write /d/tracing/tracing_on 0
    write /d/tracing/events/ext4/enable 0
    write /d/tracing/events/f2fs/enable 0
    write /d/tracing/events/block/enable 0
    
  • Após a inicialização, busque o rastreamento:

    adb root && adb shell atrace --async_stop -z -c -o /data/local/tmp/boot_trace
    adb pull /data/local/tmp/boot_trace
    $ANDROID_BUILD_TOP/external/chromium-trace/systrace.py --from-file=boot_trace