Este documento fornece orientação aos parceiros para melhorar os tempos de inicialização de aplicativos Dispositivos Android. O tempo de inicialização é um componente importante do desempenho do sistema, pois os usuários precisam aguardar a conclusão da inicialização para usar o dispositivo. Para dispositivos como carros com inicialização a frio que ocorre com mais frequência, tempo é crítico (ninguém gosta de esperar dezenas de segundos só para inserir um destino da navegação).
O Android 8.0 permite tempos de inicialização reduzidos por ser compatível com várias melhorias em uma variedade de componentes. A tabela a seguir resume esses desempenhos Melhorias (conforme medido em um dispositivo 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 | Salvo 0,2 s por genfscon |
Otimizar o carregador de inicialização
Para otimizar o carregador de inicialização a fim de melhorar os tempos de inicialização:
- Para geração de registros:
- Desative a gravação de registros no UART, porque isso pode levar muito tempo com muitas geração de registros. Nos dispositivos Google Pixel, descobrimos que ele deixa o carregador de inicialização 1.5s lento.
- Registrar apenas situações de erro e 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 de patch). Lembre-se de que diferentes opções de compactação de kernel podem ter cargas de descompressão, e algumas opções podem funcionar melhor do que outras para seu hardware específico.
- Verifique tempos de espera desnecessários para dedução/entrada no modo especial e minimize para resolvê-los com rapidez.
- Passar o tempo de inicialização gasto no carregador de inicialização para o kernel como cmdline.
- Verifique o relógio da CPU e considere usar o carregamento em paralelo (requer suporte a vários núcleos) para carregamento do kernel e inicialização de E/S.
Otimize a eficiência de E/S
Melhorar a eficiência de E/S é essencial para agilizar o tempo de inicialização, e a leitura tudo o que não for necessário deve ser adiado 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
O kernel de leitura antecipada do Linux é iniciado quando um arquivo é lido desde o início ou quando os blocos são lidos sequencialmente, tornando necessário ajustar o programador de E/S específicos para a inicialização (que tem uma carga de trabalho diferente do que os apps normais).
Dispositivos compatíveis com atualizações contínuas (A/B) se beneficiam muito do sistema de arquivos Ajuste na primeira inicialização (por exemplo, 20 segundos no Google Pixel). Um exemplo que 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
- Ativar 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 no toda inicialização, use a nova ferramenta de geração ext4 configurando TARGET_USES_MKE2FS no BoardConfig.mk.
Analisar 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 (apenas 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 analisar o desempenho da inicialização.
system/extras/boottime_tools/bootanalyze/bootanalyze.py
Mede o tempo de inicialização com um detalhamento 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 a cada arquivo.system/extras/boottime_tools/io_analysis/check_io_trace_all.py boot_trace
Fornece um detalhamento no nível do sistema.
Otimizar o arquivo init.*.rc
Ele é a ponte do kernel até que o framework seja estabelecido. 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, você ainda podem executar algumas tarefas em paralelo.
- Executar comandos lentos em um serviço de script de shell e mesclar isso depois
aguardando uma propriedade específica. O Android 8.0 oferece suporte a esse caso de uso
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
levando mais de 50 ms). Por 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 melhorias.
- Inicie os serviços e ative os dispositivos periféricos no caminho crítico antecipadamente. Para exemplo, alguns SOCs exigem a inicialização de serviços relacionados à segurança antes de iniciar com o SurfaceFlinger. Revise o registro do sistema quando o ServiceManager retornar "wait for 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 de init.*.rc. Qualquer item não usado em o init no estágio inicial deve ser adiado para que a inicialização seja concluída.
Observação:o serviço de propriedade faz parte do processo init. Por isso, chamar
setproperty
durante a inicialização pode causar um longo atraso se o init estiver ocupado
comandos integrados.
Usar o ajuste do programador
Usar o ajuste do programador para a 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 zigoto precoce
Dispositivos com criptografia baseada em arquivos podem iniciar o zigoto mais cedo no início do zigoto (por padrão, o zigoto é iniciado na classe main, que é muito mais recente início-zigoto). Ao fazer isso, certifique-se de permitir que o zigoto seja executado em todas as CPUs (como a configuração de cpuset errada pode forçar a execução do zigoto 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 UFS e/ou CPU o governador pode ser desativado.
Cuidado:a economia de energia deve estar ativada em carregador para ter 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 o início antecipado
O Android 8.0 permite iniciar a animação de inicialização antecipadamente, antes de montar dados do usuário partição. No entanto, mesmo ao usar a nova cadeia de ferramentas ext4 no Android 8.0, o fsck ainda é acionada periodicamente por motivos de segurança, causando um atraso no iniciando o serviço bootAnimation.
Para que a "bootAnimation" comece mais cedo, divida a montagem do fstab em duas fases:
- Na fase inicial, monte somente as partições (como
system/
evendor/
) que não exigem execução e iniciar os serviços de animação de inicialização e as dependências deles (como servicemanager eSurfaceflinger). - Na segunda fase, ative partições (como
data/
) que exigem verificações de execução.
A animação de inicialização será iniciada muito mais rapidamente (e em tempo constante), independentemente do fsck.
Concluir limpeza
Depois de receber o sinal de saída, a função "bootAnimation" reproduz a última parte, a duração o que pode tornar o tempo de inicialização mais lento. Um sistema com inicialização rápida não precisa de tempo animações que poderiam esconder efetivamente quaisquer melhorias feitas. Recomendamos deixando o loop repetido e o final curtos.
Otimizar o SELinux
Use as dicas a seguir para otimizar o SELinux e aumentar os tempos de inicialização.
- Use expressões regulares limpas (regex). regex mal formado
pode gerar muita sobrecarga ao fazer a correspondência da política SELinux para
sys/devices
emfile_contexts
. Por exemplo, o regex/sys/devices/.*abc.*(/.*)?
força erroneamente a verificação de todos Subdiretórios/sys/devices
que contêm "abc", ativando correspondências para/sys/devices/abc
e/sys/devices/xyz/abc
. Melhorar essa regex para/sys/devices/[^/]*abc[^/]*(/.*)?
vai ativar uma correspondência apenas para/sys/devices/abc
. - Mova rótulos para genfscon. Esse recurso SELinux existente passa prefixos de correspondência de arquivos para o kernel em no binário do SELinux, em que o kernel os aplica aos nós gerados pelo kernel, nos sistemas de arquivos. Isso também ajuda a corrigir arquivos criados pelo kernel mal rotulados, impedindo condições de corrida que podem ocorrer entre processos do espaço do usuário que tentam acessar esses arquivos antes da nova rotulagem.
Ferramentas e métodos
Use as ferramentas a seguir para coletar dados para metas de otimização.
Gráfico de inicialização
O gráfico de inicialização fornece detalhamento da carga de CPU e E/S de todos os processos para todo sistema. Ele não exige a recriação da imagem do sistema e pode ser usado de integridade antes de começar a usar o 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
nos dados todas as vezes.
bootchart.png
não existe, faça o seguinte:
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 o
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
para apontar para a cópia local depybootchartgui
(localizada~/Documents/bootchart/pybootchartgui.py
)
Systrace
O Systrace permite a coleta de rastros do kernel e do Android durante a inicialização. A visualização do Systrace pode ajudar na análise de um problema específico durante a inicialização. (No entanto, para verificar o número médio ou acumulado durante o toda a inicialização, é mais fácil analisar diretamente o trace do kernel).
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 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 trace:
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 está desativado por padrão).
Para uma análise detalhada de E/S, adicione também block, ext4 e f2fs.