En este documento, se proporciona orientación a los socios para mejorar los tiempos de inicio de dispositivos Android específicos. El tiempo de inicio es un componente importante del rendimiento del sistema, ya que los usuarios deben esperar a que se complete el inicio antes de poder usar el dispositivo. En el caso de los dispositivos, como los automóviles, en los que el inicio en frío ocurre con más frecuencia, es fundamental tener un tiempo de inicio rápido (a nadie le gusta esperar decenas de segundos solo para ingresar un destino de navegación).
Android 8.0 permite reducir los tiempos de inicio, ya que admite varias mejoras en una variedad de componentes. En la siguiente tabla, se resumen estas mejoras de rendimiento (medidas en dispositivos Google Pixel y Pixel XL).
Componente | Mejora |
---|---|
Bootloader |
|
Kernel del dispositivo |
|
Ajuste de E/S |
|
init.*.rc |
|
Animación de inicio |
|
Política de SELinux | Se ahorró 0.2 s con genfscon |
Optimiza el bootloader
Para optimizar el bootloader y mejorar los tiempos de inicio, haz lo siguiente:
- Para el registro:
- Inhabilita la escritura de registros en UART, ya que puede tardar mucho tiempo con muchos registros. (en los dispositivos Google Pixel, descubrimos que ralentiza el bootloader 1.5 s).
- Registra solo las situaciones de error y considera almacenar otra información en la memoria con un mecanismo independiente para recuperarla.
- Para la descompresión del kernel, considera usar LZ4 para el hardware contemporáneo en lugar de GZIP (parche de ejemplo). Ten en cuenta que las diferentes opciones de compresión del kernel pueden tener diferentes tiempos de carga y descompresión, y algunas opciones pueden funcionar mejor que otras para tu hardware específico.
- Verifica los tiempos de espera innecesarios para la entrada de depuración o el modo especial y minímalos.
- Pasa el tiempo de inicio que se usó en el bootloader al kernel como cmdline.
- Verifica el reloj de la CPU y considera la paralelización (requiere compatibilidad con varios núcleos) para la carga del kernel y la inicialización de la E/S.
Optimiza la eficiencia de E/S
Mejorar la eficiencia de E/S es fundamental para acelerar el tiempo de inicio, y la lectura de cualquier elemento que no sea necesario debe diferirse hasta después del inicio (en un Google Pixel, se leen alrededor de 1.2 GB de datos durante el inicio).
Ajusta el sistema de archivos
La lectura anticipada del kernel de Linux se activa cuando se lee un archivo desde el principio o cuando se leen bloques de forma secuencial, lo que hace necesario ajustar los parámetros del programador de E/S específicamente para el inicio (que tiene una caracterización de carga de trabajo diferente a la de las apps normales).
Los dispositivos que admiten actualizaciones sin interrupciones (A/B) se benefician en gran medida de la optimización del sistema de archivos durante el primer inicio (p.ej., 20 s en Google Pixel). A modo de ejemplo, ajustamos los siguientes parámetros para el 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 ...
Varios
- Activa el tamaño de la precarga de hash de dm-verity con la configuración del kernel DM_VERITY_HASH_PREFETCH_MIN_SIZE (el tamaño predeterminado es 128).
- Para obtener una mejor estabilidad del sistema de archivos y una verificación forzada que se produce en cada inicio, usa la nueva herramienta de generación de ext4 configurando TARGET_USES_MKE2FS en BoardConfig.mk.
Cómo analizar la E/S
Para comprender las actividades de E/S durante el inicio, usa los datos de ftrace del kernel (que también usa systrace):
trace_event=block,ext4 in BOARD_KERNEL_CMDLINE
Para desglosar el acceso a los archivos de cada archivo, realiza los siguientes cambios en el kernel (solo kernel de desarrollo, no lo uses en kernels de producción):
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);
Usa las siguientes secuencias de comandos para analizar el rendimiento del inicio.
system/extras/boottime_tools/bootanalyze/bootanalyze.py
Mide el tiempo de inicio con un desglose de los pasos importantes del proceso de inicio.system/extras/boottime_tools/io_analysis/check_file_read.py boot_trace
Proporciona información de acceso para cada archivo.system/extras/boottime_tools/io_analysis/check_io_trace_all.py boot_trace
Proporciona un desglose a nivel del sistema.
Optimiza init.*.rc
Init es el puente desde el kernel hasta que se establece el framework, y los dispositivos suelen pasar unos segundos en diferentes etapas de init.
Ejecuta tareas en paralelo
Si bien el inicio de Android actual es más o menos un proceso de subproceso único, aún puedes realizar algunas tareas en paralelo.
- Ejecuta comandos lentos en un servicio de secuencia de comandos de shell y únete a él más adelante esperando una propiedad específica. Android 8.0 admite este caso de uso con un nuevo comando
wait_for_property
. - Identifica las operaciones lentas en init. El sistema registra el comando init exec/wait_for_prop o cualquier acción que tarde mucho tiempo (en Android 8.0, cualquier comando que tarde más de 50 ms). Por ejemplo:
init: Command 'wait_for_coldboot_done' action=wait_for_coldboot_done returned 0 took 585.012ms
Revisar este registro puede indicar oportunidades de mejora.
- Inicia los servicios y habilita los dispositivos periféricos en la ruta crítica con anticipación. Por ejemplo, algunos SOC requieren iniciar servicios relacionados con la seguridad antes de iniciar SurfaceFlinger. Revisa el registro del sistema cuando ServiceManager muestra el mensaje "wait for service". Por lo general, esto es una señal de que primero se debe iniciar un servicio dependiente.
- Quita los servicios y comandos sin usar en init.*.rc. Todo lo que no se use en la inicialización de la etapa inicial se debe aplazar hasta que se complete el inicio.
Nota: El servicio de propiedades forma parte del proceso de init, por lo que llamar a setproperty
durante el inicio puede generar una demora prolongada si init está ocupado en comandos integrados.
Usa el ajuste del programador
Usa el ajuste del programador para el inicio anticipado. Ejemplo de un 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
Es posible que algunos servicios necesiten un aumento de prioridad durante el inicio. Ejemplo:
init.zygote64.rc: service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server class main priority -20 user root ...
Cómo iniciar el zygote antes
Los dispositivos con encriptación basada en archivos pueden iniciar el zygote antes en el activador zygote-start (de forma predeterminada, el zygote se inicia en la clase principal, que es mucho más tarde que zygote-start). Cuando lo hagas, asegúrate de permitir que el zygote se ejecute en todas las CPUs (ya que la configuración incorrecta de cpuset puede forzar al zygote a ejecutarse en CPUs específicas).
Inhabilita el ahorro de energía
Durante el inicio del dispositivo, se puede inhabilitar la configuración de ahorro de energía para componentes como el regulador de UFS o CPU.
Precaución: Para mejorar la eficiencia, se debe habilitar el ahorro de energía en el modo de cargador.
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
Diferir la inicialización no crítica
La inicialización no crítica, como ZRAM, se puede diferir a boot_complete
.
on property:sys.boot_completed=1 # Enable ZRAM on boot_complete swapon_all /vendor/etc/fstab.${ro.hardware}
Cómo optimizar la animación de inicio
Usa las siguientes sugerencias para optimizar la animación de inicio.
Cómo configurar el inicio anticipado
Android 8.0 habilita el inicio de la animación de inicio antes, antes de activar la partición de datos del usuario. Sin embargo, incluso cuando se usa la nueva cadena de herramientas ext4 en Android 8.0, fsck se activa de forma periódica por motivos de seguridad, lo que causa una demora en el inicio del servicio de bootanimation.
Para que bootanimation se inicie antes, divide el montaje de fstab en dos fases:
- En la fase inicial, activa solo las particiones (como
system/
yvendor/
) que no requieran verificaciones de ejecución y, luego, inicia los servicios de animación de inicio y sus dependencias (como servicemanager y surfaceflinger). - En la segunda fase, activa las particiones (como
data/
) que sí requieren verificaciones de ejecución.
La animación de inicio se iniciará mucho más rápido (y en un tiempo constante) independientemente de fsck.
Termina con limpieza
Después de recibir la señal de salida, bootanimation reproduce la última parte, cuya duración puede ralentizar el tiempo de inicio. Un sistema que se inicia rápidamente no necesita animaciones largas que podrían ocultar de manera eficaz cualquier mejora realizada. Te recomendamos que hagas que el bucle de repetición y el final sean breves.
Optimiza SELinux
Usa las siguientes sugerencias para optimizar SELinux y mejorar los tiempos de inicio.
- Usa expresiones regulares (regex) claras. Las regex con el formato incorrecto pueden generar mucha sobrecarga cuando coinciden con la política de SELinux para
sys/devices
enfile_contexts
. Por ejemplo, la regex/sys/devices/.*abc.*(/.*)?
fuerza por error un análisis de todos los subdirectorios/sys/devices
que contienen "abc", lo que habilita las coincidencias para/sys/devices/abc
y/sys/devices/xyz/abc
. Mejorar esta regex a/sys/devices/[^/]*abc[^/]*(/.*)?
habilitará una coincidencia solo para/sys/devices/abc
. - Mueve las etiquetas a genfscon. Esta función existente de SELinux pasa prefijos que coinciden con archivos al kernel en el objeto binario de SELinux, donde el kernel los aplica a los sistemas de archivos generados por el kernel. Esto también ayuda a corregir los archivos creados por el kernel con etiquetas incorrectas, lo que evita las condiciones de carrera que pueden ocurrir entre los procesos del espacio de usuario que intentan acceder a estos archivos antes de que se vuelva a etiquetar.
Herramientas y métodos
Usa las siguientes herramientas para recopilar datos para los objetivos de optimización.
Bootchart
Bootchart proporciona un desglose de la carga de CPU y E/S de todos los procesos del sistema completo. No requiere volver a compilar la imagen del sistema y se puede usar como una verificación rápida antes de comenzar a usar systrace.
Para habilitar bootchart, haz lo siguiente:
adb shell 'touch /data/bootchart/enabled'
adb reboot
Después del inicio, recupera el gráfico de inicio:
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
Cuando termines, borra /data/bootchart/enabled
para evitar que se recopilen los datos cada vez.
bootchart.png
no existe, haz lo siguiente:
- Ejecuta los siguientes 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
- Actualiza
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
para que apunte a la copia local depybootchartgui
(ubicada en~/Documents/bootchart/pybootchartgui.py
).
Systrace
Systrace permite recopilar registros del kernel y de Android durante el inicio. La visualización de systrace puede ayudar a analizar problemas específicos durante el inicio. (Sin embargo, para verificar la cantidad promedio o la cantidad acumulada durante todo el inicio, es más fácil observar el registro del kernel directamente).
Para habilitar systrace durante el inicio, haz lo siguiente:
- En
frameworks/native/cmds/atrace/atrace.rc
, cambia lo siguiente:write /sys/kernel/debug/tracing/tracing_on 0 write /sys/kernel/tracing/tracing_on 0
A:
# write /sys/kernel/debug/tracing/tracing_on 0 # write /sys/kernel/tracing/tracing_on 0
- En el archivo
device.mk
, agrega la siguiente línea:PRODUCT_PROPERTY_OVERRIDES += debug.atrace.tags.enableflags=802922 PRODUCT_PROPERTY_OVERRIDES += persist.traced.enable=0
- En el archivo
BoardConfig.mk
del dispositivo, agrega lo siguiente:BOARD_KERNEL_CMDLINE := ... trace_buf_size=64M trace_event=sched_wakeup,sched_switch,sched_blocked_reason,sched_cpu_hotplug
- En el archivo
init.rc
específico del dispositivo, agrega lo siguiente: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
-
Después del inicio, recupera el seguimiento:
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
Esto habilita el seguimiento (que está inhabilitado de forma predeterminada).
Para obtener un análisis detallado de E/S, también agrega bloque, ext4 y f2fs.