Este documento fornece orientação aos parceiros para melhorar os tempos de inicialização de dispositivos Android específicos. O tempo de inicialização é um componente importante do desempenho do sistema, já que os usuários precisam esperar a inicialização ser concluída antes de usar o dispositivo. Para dispositivos como carros, em que a inicialização a frio acontece com mais frequência, ter um tempo de inicialização rápido é fundamental. Ninguém gosta de esperar dezenas de segundos apenas para inserir um destino de navegação.
O Android 8.0 reduz o tempo de inicialização com suporte a várias melhorias em vários componentes. A tabela a seguir resume essas melhorias de desempenho (como medido em dispositivos Google Pixel e Pixel XL).
Componente | Melhoria |
---|---|
Carregador de inicialização |
|
Kernel do dispositivo |
|
Ajuste de E/S |
|
init.*.rc |
|
Animação de inicialização |
|
Política do SELinux | 0,2s foram salvos por genfscon |
Otimizar o carregador de inicialização
Para otimizar o carregador de inicialização e melhorar os tempos de inicialização:
- Para registro:
- Desative a gravação de registro no UART, porque isso pode levar muito tempo com muita geração de registros. Em dispositivos Google Pixel, descobrimos que ele retarda o bootloader em 1,5s.
- Registre apenas situações de erro e considere armazenar outras informações na memória com um mecanismo separado para extrair.
- Para descompactação do kernel, considere usar LZ4 para hardware contemporâneo em vez de GZIP (exemplo de patch). Tenha em mente que diferentes opções de compactação do kernel podem ter tempos de carregamento e descompactação diferentes, e algumas opções podem funcionar melhor que outras para seu hardware específico.
- Verifique tempos de espera desnecessários para a entrada de debouncing/modo especial e minimize eles.
- O tempo de inicialização gasto no carregador de inicialização é transmitido ao 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.
Otimizar a eficiência de E/S
Melhorar a eficiência de E/S é fundamental para acelerar o tempo de inicialização, e a leitura de qualquer coisa que não seja necessá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.
Ajustar o sistema de arquivos
A leitura antecipada do kernel do Linux é ativada quando um arquivo é lido desde o início ou quando os blocos são lidos sequencialmente, tornando necessário ajustar os parâmetros do programador de E/S especificamente para a inicialização, que tem uma caracterização de carga de trabalho diferente dos apps normais.
Os dispositivos compatíveis com atualizações contínuas (A/B) se beneficiam muito do ajuste do sistema de arquivos na primeira inicialização (por exemplo, 20 segundos 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é-carregamento de hash dm-verity usando a configuração do kernel DM_VERITY_HASH_PREFETCH_MIN_SIZE (o tamanho padrão é 128).
- Para melhorar a estabilidade do sistema de arquivos e uma verificação forçada descartada que ocorre em cada inicialização, use a nova ferramenta de geração ext4 definindo TARGET_USES_MKE2FS em BoardConfig.mk.
Analisar E/S
Para entender as atividades de E/S durante a inicialização, use os dados de ftrace do kernel (também usados pelo systrace):
trace_event=block,ext4 in BOARD_KERNEL_CMDLINE
Para detalhar o acesso a arquivos para 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 abaixo para analisar o desempenho de inicialização.
system/extras/boottime_tools/bootanalyze/bootanalyze.py
Meça o tempo de inicialização com uma análise detalhada das etapas importantes do 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 detalhes no nível do sistema.
Otimizar init.*.rc
O init é a ponte entre o kernel e o framework, e os dispositivos geralmente passam alguns segundos em diferentes estágios de inicialização.
Executar tarefas em paralelo
Embora o init atual do Android seja mais ou menos um processo de linha de execução única, ainda é possível realizar algumas tarefas em paralelo.
- Execute comandos lentos em um serviço de script de shell e faça a associação mais tarde
esperando por 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 de inicialização
exec/wait_for_prop ou qualquer ação que leva muito tempo (no Android 8.0, qualquer comando
leva mais de 50 ms). Exemplo:
init: Command 'wait_for_coldboot_done' action=wait_for_coldboot_done returned 0 took 585.012ms
A análise desse registro pode indicar oportunidades de melhoria.
- Inicie os serviços e ative os dispositivos periféricos no caminho crítico com antecedência. Por exemplo, alguns SOCs exigem a inicialização de serviços relacionados à segurança antes de iniciar o SurfaceFlinger. Analise o registro do sistema quando o ServiceManager retornar "wait for service". Isso geralmente é um sinal de que um serviço dependente precisa ser iniciado primeiro.
- Remova todos os serviços e comandos não utilizados em init.*.rc. Qualquer coisa que não seja usada na iniciação inicial precisa ser adiada até a inicialização ser concluída.
Observação:o serviço de propriedade faz parte do processo de inicialização. Portanto, chamar
setproperty
durante a inicialização pode causar um longo atraso se a inicialização estiver ocupada em
comandos integrados.
Usar o ajuste do programador
Use o ajuste do programador 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 ...
Iniciar o Zygote antecipadamente
Dispositivos com criptografia baseada em arquivos podem iniciar o zygote mais cedo no acionador zygote-start. Por padrão, o zygote é iniciado na classe principal, muito depois de zygote-start. Ao fazer isso, permita que o zygote seja executado em todas as CPUs, já que a configuração incorreta de cpuset pode forçar o zygote a ser executado em CPUs específicas.
Desativar a economia de energia
Durante a inicialização do dispositivo, a configuração de economia de energia para componentes como o controlador de CPU e/ou UFS pode ser desativada.
Cuidado:a economia de energia precisa estar ativada no modo de carregador para 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 a inicialização não crítica
A inicialização não crítica, como a 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}
Otimizar a animação de inicialização
Use as dicas a seguir para otimizar a animação de inicialização.
Configurar a inicialização antecipada
O Android 8.0 permite iniciar a animação de inicialização mais cedo, antes de montar a partição userdata. No entanto, mesmo usando a nova cadeia de ferramentas ext4 no Android 8.0, o fsck ainda é acionado periodicamente por motivos de segurança, causando um atraso na inicialização do serviço de bootanimation.
Para iniciar a bootanimation mais cedo, divida a montagem do fstab em duas fases:
- Na fase inicial, monte apenas as partições (como
system/
evendor/
) que não exigem verificações de execução e inicie os serviços de animação de inicialização e as dependências dele, como servicemanager e surfaceflinger. - Na segunda fase, monte partições (como
data/
) que exigem verificações de execução.
A animação de inicialização será iniciada muito mais rápido (e em tempo constante), independentemente do fsck.
Limpar a tela
Depois de receber o sinal de saída, a bootanimation reproduz a última parte, cuja duração pode retardar o tempo de inicialização. Um sistema que inicializa rapidamente não precisa de animações longas, que podem ocultar as melhorias feitas. Recomendamos que você faça o ciclo de repetição e a finalização curtos.
Otimizar o SELinux
Use as dicas a seguir para otimizar o SELinux e melhorar os tempos de inicialização.
- Use expressões regulares (regex) limpas. Uma regex malformada
pode causar muita sobrecarga ao corresponder à política do SELinux para
sys/devices
emfile_contexts
. Por exemplo, o regex/sys/devices/.*abc.*(/.*)?
força erroneamente 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
. Melhorar esse regex para/sys/devices/[^/]*abc[^/]*(/.*)?
vai permitir uma correspondência apenas para/sys/devices/abc
. - Mover os marcadores para genfscon. Esse recurso do SELinux transmite prefixos de correspondência de arquivos para o kernel no binário do 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 processos do espaço do usuário que tentam acessar esses arquivos antes da nova marcação.
Ferramentas e métodos
Use as ferramentas a seguir para coletar dados para as metas de otimização.
Bootchart
O Bootchart fornece um detalhamento da carga de CPU e E/S de todos os processos do sistema. Ele não requer a reconstrução da imagem do sistema e pode ser usado como uma verificação rápida antes de mergulhar no systrace.
Para ativar o bootchart:
adb shell 'touch /data/bootchart/enabled'
adb reboot
Depois da 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
dos dados sempre.
bootchart.png
não existe, faça
o seguinte:
- 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
- Atualize
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
para apontar para a cópia local depybootchartgui
(localizada em~/Documents/bootchart/pybootchartgui.py
)
Systrace
O Systrace permite coletar rastros 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 acumulado durante toda a inicialização, é mais fácil analisar o rastreamento do kernel diretamente.
Para ativar o systrace durante a inicialização:
- Em
frameworks/native/cmds/atrace/atrace.rc
, mude: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
- No arquivo
device.mk
, adicione esta 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
- 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
-
Depois da inicialização, busque o rastro:
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
Isso ativa o rastreamento, que fica desativado por padrão.
Para uma análise detalhada de E/S, adicione também o bloco e ext4 e f2fs.