Este documento fornece orientações 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, 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, é fundamental ter um tempo de inicialização rápido (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 diversas melhorias em vários componentes. A tabela a seguir resume essas melhorias de desempenho (medidas 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 SELinux | Salvo 0,2s por genfscon |
Otimize o bootloader
Para otimizar o bootloader para melhorar os tempos de inicialização:
- Para registro:
- Desative a gravação de log no UART, pois pode levar muito tempo com muitos registros. (Nos dispositivos Google Pixel, descobrimos que o bootloader fica lento em 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 usar LZ4 para hardware contemporâneo em vez de GZIP (exemplo patch ). Tenha em mente 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 que outras para o seu hardware específico.
- Verifique os tempos de espera desnecessários para entrada no modo especial/debouncing 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 multi-core) para carregamento do kernel e inicialização de E/S.
Otimize 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é após a inicialização (em um Google Pixel, cerca de 1,2 GB de dados são lidos na inicialização).
Ajuste o sistema de arquivos
A leitura antecipada do kernel 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).
Dispositivos que suportam 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). Por 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 melhor estabilidade do sistema de arquivos e uma verificação forçada 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 do kernel ftrace (também usados pelo systrace):
trace_event=block,ext4 in BOARD_KERNEL_CMDLINE
Para dividir 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 de inicialização.
-
system/extras/boottime_tools/bootanalyze/bootanalyze.py
Mede o tempo de inicialização com uma análise 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 por cada arquivo. -
system/extras/boottime_tools/io_analysis/check_io_trace_all.py boot_trace
Fornece detalhamento no nível do sistema.
Otimize init.*.rc
Init é a ponte entre o kernel até que a estrutura seja estabelecida, e os dispositivos geralmente passam alguns segundos em diferentes estágios de inicialização.
Execute tarefas em paralelo
Embora o init atual do Android seja mais ou menos um processo de thread único, 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 que leve muito tempo (no Android 8.0, qualquer comando que leve 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 deste registro pode indicar oportunidades de melhorias.
- Inicie serviços e habilite dispositivos periféricos em caminhos críticos antecipadamente. 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 "aguardar serviço" — isso geralmente é um sinal de que um serviço dependente deve ser iniciado primeiro.
- Remova quaisquer serviços e comandos não utilizados em init.*.rc. Qualquer coisa não usada no estágio inicial de inicialização deve ser adiada para a inicialização ser 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 o init estiver ocupado nos comandos internos.
Usar 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 ...
Comece o zigoto cedo
Dispositivos com criptografia baseada em arquivo podem iniciar o zigoto mais cedo no gatilho de início do zigoto (por padrão, o zigoto é iniciado na classe principal, que é muito mais tarde do que o início do zigoto). Ao fazer isso, certifique-se de permitir que o zigoto seja executado em todas as CPUs (pois a configuração incorreta do cpuset pode forçar o zigoto a ser executado 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 de CPU pode ser desativada.
Cuidado: A economia de energia deve ser ativada no modo carregador 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}
Otimize a animação de inicialização
Use as dicas a seguir para otimizar a animação de inicialização.
Configurar início antecipado
O Android 8.0 permite iniciar a animação de inicialização antecipadamente, antes de montar a partição userdata. 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 com que a bootanimation comece 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, em seguida, inicie os serviços de animação de inicialização e suas dependências (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.
Termine limpo
Depois de receber o sinal de saída, o bootanimation desempenha 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 possam efetivamente ocultar quaisquer melhorias feitas. Recomendamos fazer o loop de repetição e o final curtos.
Otimize o SELinux
Use as dicas a seguir para otimizar o SELinux para melhorar os tempos de inicialização.
- Use expressões regulares limpas (regex) . Regex mal formada pode levar a muita sobrecarga ao combinar a política SELinux para
sys/devices
emfile_contexts
. Por exemplo, a 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
. Melhorando este regex para/sys/devices/[^/]*abc[^/]*(/.*)?
ativará uma correspondência apenas para/sys/devices/abc
. - Mova os rótulos para genfscon . Este recurso existente do SELinux passa prefixos de correspondência de arquivo para o kernel no binário SELinux, onde o kernel os aplica aos 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 que ocorra a reetiquetagem.
Ferramentas e métodos
Use as ferramentas a seguir para ajudá-lo a coletar dados para metas de otimização.
Gráfico de inicialização
Bootchart fornece detalhamento de carga de CPU e E/S de todos os processos para todo o sistema. Não requer reconstrução da imagem do sistema e pode ser usado como uma verificação rápida de integridade antes de mergulhar no systrace.
Para ativar o gráfico de inicialização:
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.
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 dopybootchartgui
(localizada 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 acumulado durante toda a inicialização, é mais fácil examinar diretamente o rastreamento do kernel).
Para ativar 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
- 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
- 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
Isso habilita o rastreamento (que está desabilitado por padrão).
Para análise detalhada de E/S, adicione também block e ext4 e f2fs.