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 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 permite tempos de inicialização reduzidos ao oferecer suporte a várias melhorias em vários componentes. A tabela a seguir resume essas melhorias de desempenho (conforme medidas em dispositivos Google Pixel e Pixel XL).
Componente | Melhoria |
---|---|
Bootloader |
|
Kernel do dispositivo |
|
Ajuste de E/S |
|
init.*.rc |
|
Animação de inicialização |
|
Política SELinux | Salvo 0,2s por genfscon |
Otimizando o Bootloader
Para otimizar o bootloader para tempos de inicialização aprimorados:
- Para logar:
- Desative a gravação de log no UART, pois pode levar muito tempo com muitos logs. (Nos dispositivos Google Pixel, descobrimos que diminui a velocidade do 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 descompressã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 do kernel podem ter tempos de carregamento e descompactação diferentes, e algumas opções podem funcionar melhor do que outras para seu hardware específico.
- Verifique os tempos de espera desnecessários para entrada de 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 carregar o kernel e inicializar a E/S.
Otimizando Kernel
Use as dicas a seguir para otimizar o kernel para tempos de inicialização aprimorados.
Minimizando o defconfig do dispositivo
Minimizar a configuração do kernel pode reduzir o tamanho do kernel para descompressão de carregamento mais rápida, inicialização e superfícies de ataque menores. Para otimizar o defconfig do dispositivo:
- Identifique drivers não utilizados . Revise os
/dev
e/sys
e procure por nós com rótulos SELinux gerais (o que indica que esses nós não estão configurados para serem acessíveis pelo espaço do usuário). Remova esses nós, se encontrados. - Desativar CONFIGs não utilizados . Revise o arquivo .config gerado pela compilação do kernel para desmarcar explicitamente qualquer CONFIG não utilizado que foi ativado por padrão. Por exemplo, removemos os seguintes CONFIGs não utilizados do Google Pixel:
CONFIG_ANDROID_LOGGER=y
CONFIG_IMX134=y
CONFIG_IMX132=y
CONFIG_OV9724=y
CONFIG_OV5648=y
CONFIG_GC0339=y
CONFIG_OV8825=y
CONFIG_OV8865=y
CONFIG_s5k4e1=y
CONFIG_OV12830=y
CONFIG_USB_EHCI_HCD=y
CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST=y
CONFIG_IKCONFIG=y
CONFIG_RD_BZIP2=y
CONFIG_RD_LZMA=y
CONFIG_TI_DRV2667=y
CONFIG_CHR_DEV_SCH=y
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
CONFIG_MMC_CLKGATE=y
CONFIG_MMC_PARANOID_SD_INIT=y
CONFIG_MMC_BLOCK_MINORS=32
CONFIG_MMC_TEST=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_MSM=y
CONFIG_MMC_SDHCI_MSM_ICE=y
CONFIG_MMC_CQ_HCI=y
CONFIG_MSDOS_FS=y
# CONFIG_SYSFS_SYSCALL is not set
CONFIG_EEPROM_AT24=y
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
CONFIG_INPUT_HBTP_INPUT=y
# CONFIG_VGA_ARB is not set
CONFIG_USB_MON=y
CONFIG_USB_STORAGE_DATAFAB=y
CONFIG_USB_STORAGE_FREECOM=y
CONFIG_USB_STORAGE_ISD200=y
CONFIG_USB_STORAGE_USBAT=y
CONFIG_USB_STORAGE_SDDR09=y
CONFIG_USB_STORAGE_SDDR55=y
CONFIG_USB_STORAGE_JUMPSHOT=y
CONFIG_USB_STORAGE_ALAUDA=y
CONFIG_USB_STORAGE_KARMA=y
CONFIG_USB_STORAGE_CYPRESS_ATACB=y
CONFIG_SW_SYNC_USER=y
CONFIG_SEEMP_CORE=y
CONFIG_MSM_SMEM_LOGGING=y
CONFIG_IOMMU_DEBUG=y
CONFIG_IOMMU_DEBUG_TRACKING=y
CONFIG_IOMMU_TESTS=y
CONFIG_MOBICORE_DRIVER=y
# CONFIG_DEBUG_PREEMPT is not set
- Remova CONFIGs que levam a execuções de teste desnecessárias em cada inicialização . Embora útil no desenvolvimento, tais configurações (ou seja, CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST) devem ser removidas em um kernel de produção.
Minimizando o tamanho do driver
Alguns drivers no kernel do dispositivo podem ser removidos se a função não for usada para reduzir ainda mais o tamanho do kernel. Por exemplo, se a WLAN estiver conectada por meio de PCIe, o suporte SDIO não será usado e deverá ser removido durante o tempo de compilação. Para obter detalhes, consulte o kernel do Google Pixel: net: wireless: cnss: add opção para desabilitar o suporte SDIO.
Removendo a otimização do compilador para tamanho
Remova a configuração do kernel para CONFIG_CC_OPTIMIZE_FOR_SIZE. Esse sinalizador foi originalmente introduzido quando a suposição era de que um tamanho de código menor geraria hit de hot cache (e, portanto, seria mais rápido). No entanto, essa suposição não é mais válida, pois os SoCs móveis modernos se tornaram mais poderosos.
Além disso, remover o sinalizador pode habilitar o aviso do compilador para variáveis não inicializadas, que é suprimido em kernels Linux quando o sinalizador CONFIG_CC_OPTIMIZE_FOR_SIZE está presente (fazer essa alteração sozinha nos ajudou a descobrir muitos bugs significativos em alguns drivers de dispositivos Android).
Adiando a inicialização
Muitos processos são iniciados durante a inicialização, mas apenas os componentes no caminho crítico (bootloader > kernel > init > montagem do sistema de arquivos > zygote > servidor do sistema) afetam diretamente o tempo de inicialização. Perfil initcall durante a inicialização do kernel para identificar periféricos/componentes que são lentos e não críticos para iniciar o processo de inicialização e, em seguida, atrase esses periféricos/componentes até mais tarde no processo de inicialização, movendo-se para módulos de kernel carregáveis. Mover para o probe dispositivo/driver assíncrono também pode ajudar a colocar em paralelo componentes lentos no kernel > init caminho crítico.
BoardConfig-common.mk:
BOARD_KERNEL_CMDLINE += initcall_debug ignore_loglevel
driver:
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
Nota: As dependências do driver devem ser resolvidas com cuidado adicionando o suporte EPROBEDEFER
.
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 das aplicações normais).
Os 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). 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 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 configurando TARGET_USES_MKE2FS em BoardConfig.mk.
Analisando 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 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 a analisar o desempenho da inicialização.
-
system/extras/boottime_tools/bootanalyze/bootanalyze.py
Mede o tempo de inicialização com um detalhamento 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 o 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 isso 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 deste log pode indicar oportunidades de melhorias.
- Inicie serviços e habilite dispositivos periféricos no caminho crítico antecipadamente. Por exemplo, alguns SOCs exigem iniciar 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 init do estágio inicial deve ser adiada para inicialização concluída.
Nota: O serviço de propriedade faz parte do processo de inicialização, portanto, chamar setproperty
durante a inicialização pode levar a um longo atraso se o init estiver ocupado em comandos internos.
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 main, 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 o zygote 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 controlador de CPU pode ser desabilitada.
Cuidado: A economia de energia deve ser ativada no modo de 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 a 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 o 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 na inicialização do serviço bootanimation.
Para fazer bootanimation começar cedo, divida a montagem 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.
Acabamento limpo
Depois de receber o sinal de saída, o bootanimation desempenha a última parte, cuja duração pode diminuir o tempo de inicialização. Um sistema que inicializa rapidamente não precisa de animações longas que possam ocultar efetivamente quaisquer melhorias feitas. Recomendamos fazer o loop de repetição e o final 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) . O regex mal formado pode levar a muita sobrecarga ao corresponder à 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", habilitando 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 existente do SELinux passa prefixos de correspondência de arquivos para o kernel no binário do SELinux, onde o kernel os aplica aos sistemas de arquivos gerados pelo kernel. Isso também ajuda a corrigir arquivos criados pelo kernel mal rotulados, 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 nova rotulagem.
Ferramenta e métodos
Use as ferramentas a seguir para ajudá-lo a coletar dados para destinos de otimização.
Bootchart
Bootchart fornece quebra 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 rápida verificação 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 sempre.
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 0Para:
# 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.