Ce document fournit des conseils aux partenaires pour améliorer les temps de démarrage de certains appareils Android. Le temps de démarrage est un élément important des performances du système, car les utilisateurs doivent attendre la fin du démarrage avant de pouvoir utiliser le périphérique. Pour les appareils tels que les voitures où les démarrages à froid sont plus fréquents, il est essentiel d'avoir un temps de démarrage rapide (personne n'aime attendre des dizaines de secondes juste pour saisir une destination de navigation).
Android 8.0 permet de réduire les temps de démarrage en prenant en charge plusieurs améliorations sur une gamme de composants. Le tableau suivant résume ces améliorations de performances (telles que mesurées sur les appareils Google Pixel et Pixel XL).
Composant | Amélioration |
---|---|
Chargeur de démarrage |
|
Noyau de l'appareil |
|
Réglage des E/S |
|
init.*.rc |
|
Animation de démarrage |
|
Politique SELinux | Économisé 0,2 seconde par genfscon |
Optimiser le chargeur de démarrage
Pour optimiser le chargeur de démarrage afin d'améliorer les temps de démarrage :
- Pour la journalisation :
- Désactivez l'écriture du journal sur UART car cela peut prendre beaucoup de temps avec beaucoup de journalisation. (Sur les appareils Google Pixel, nous avons constaté que cela ralentissait le chargeur de démarrage de 1,5 seconde).
- Enregistrez uniquement les situations d'erreur et envisagez de stocker d'autres informations en mémoire avec un mécanisme distinct à récupérer.
- Pour la décompression du noyau, envisagez d'utiliser LZ4 pour le matériel contemporain au lieu de GZIP (exemple patch ). Gardez à l’esprit que différentes options de compression du noyau peuvent avoir des temps de chargement et de décompression différents, et que certaines options peuvent mieux fonctionner que d’autres pour votre matériel spécifique.
- Vérifiez les temps d’attente inutiles pour l’entrée en mode anti-rebond/spécial et minimisez-les.
- Transmettez le temps de démarrage passé dans le chargeur de démarrage au noyau en tant que ligne de commande.
- Vérifiez l'horloge du processeur et envisagez la parallélisation (nécessite une prise en charge multicœur) pour le chargement du noyau et l'initialisation des E/S.
Optimiser l'efficacité des E/S
L'amélioration de l'efficacité des E/S est essentielle pour accélérer le temps de démarrage, et la lecture de tout ce qui n'est pas nécessaire doit être différée jusqu'après le démarrage (sur un Google Pixel, environ 1,2 Go de données sont lues au démarrage).
Ajuster le système de fichiers
La lecture anticipée du noyau Linux intervient lorsqu'un fichier est lu depuis le début ou lorsque des blocs sont lus séquentiellement, ce qui nécessite de régler les paramètres du planificateur d'E/S spécifiquement pour le démarrage (qui a une caractérisation de charge de travail différente de celle des applications normales).
Les appareils prenant en charge les mises à jour transparentes (A/B) bénéficient grandement du réglage du système de fichiers au premier démarrage (par exemple, 20 s sur Google Pixel). À titre d'exemple, nous avons ajusté les paramètres suivants pour le 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 ...
Divers
- Activez la taille de prélecture du hachage dm-verity à l'aide de la configuration du noyau DM_VERITY_HASH_PREFETCH_MIN_SIZE (la taille par défaut est 128).
- Pour une meilleure stabilité du système de fichiers et une vérification forcée abandonnée qui se produit à chaque démarrage, utilisez le nouvel outil de génération ext4 en définissant TARGET_USES_MKE2FS dans BoardConfig.mk.
Analyser les E/S
Pour comprendre les activités d'E/S pendant le démarrage, utilisez les données ftrace du noyau (également utilisées par systrace) :
trace_event=block,ext4 in BOARD_KERNEL_CMDLINE
Pour répartir l'accès aux fichiers pour chaque fichier, apportez les modifications suivantes au noyau (noyau de développement uniquement ; ne pas utiliser dans les noyaux de production) :
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);
Utilisez les scripts suivants pour vous aider à analyser les performances de démarrage.
-
system/extras/boottime_tools/bootanalyze/bootanalyze.py
Mesure le temps de démarrage avec une répartition des étapes importantes du processus de démarrage. -
system/extras/boottime_tools/io_analysis/check_file_read.py boot_trace
Fournit des informations d'accès pour chaque fichier. -
system/extras/boottime_tools/io_analysis/check_io_trace_all.py boot_trace
Donne une ventilation au niveau du système.
Optimiser init.*.rc
Init est le pont entre le noyau et l'établissement du framework, et les appareils passent généralement quelques secondes à différentes étapes d'initialisation.
Exécuter des tâches en parallèle
Bien que l'initialisation Android actuelle soit plus ou moins un processus à thread unique, vous pouvez toujours effectuer certaines tâches en parallèle.
- Exécutez des commandes lentes dans un service de script shell et rejoignez-le plus tard en attendant une propriété spécifique. Android 8.0 prend en charge ce cas d'utilisation avec une nouvelle commande
wait_for_property
. - Identifiez les opérations lentes dans init. Le système enregistre la commande init exec/wait_for_prop ou toute action prenant beaucoup de temps (sous Android 8.0, toute commande prenant plus de 50 ms). Par exemple :
init: Command 'wait_for_coldboot_done' action=wait_for_coldboot_done returned 0 took 585.012ms
L'examen de ce journal peut indiquer des opportunités d'amélioration.
- Démarrez les services et activez les périphériques dans le chemin critique le plus tôt possible. Par exemple, certains SOC nécessitent le démarrage de services liés à la sécurité avant de démarrer SurfaceFlinger. Consultez le journal système lorsque ServiceManager renvoie « attendre le service » : il s'agit généralement d'un signe qu'un service dépendant doit être démarré en premier.
- Supprimez tous les services et commandes inutilisés dans init.*.rc. Tout ce qui n'est pas utilisé au début de l'initialisation doit être différé jusqu'à la fin du démarrage.
Remarque : le service de propriété fait partie du processus d'initialisation, donc appeler setproperty
pendant le démarrage peut entraîner un long délai si init est occupé dans les commandes intégrées.
Utiliser le réglage du planificateur
Utilisez le réglage du planificateur pour un démarrage anticipé. Exemple d'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
Certains services peuvent nécessiter une priorité lors du démarrage. Exemple:
init.zygote64.rc: service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server class main priority -20 user root ...
Commencez le zygote tôt
Les appareils dotés d'un chiffrement basé sur les fichiers peuvent démarrer zygote plus tôt au niveau du déclencheur zygote-start (par défaut, zygote est lancé au niveau de la classe principale, ce qui est bien plus tard que zygote-start). Ce faisant, assurez-vous d'autoriser zygote à s'exécuter sur tous les processeurs (car un mauvais paramètre cpuset peut forcer zygote à s'exécuter sur des processeurs spécifiques).
Désactiver l'économie d'énergie
Pendant le démarrage de l'appareil, les paramètres d'économie d'énergie pour les composants tels que l'UFS et/ou le gouverneur du processeur peuvent être désactivés.
Attention : L'économie d'énergie doit être activée en mode chargeur pour plus d'efficacité.
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
Différer l'initialisation non critique
L'initialisation non critique telle que ZRAM peut être différée vers boot_complete
.
on property:sys.boot_completed=1 # Enable ZRAM on boot_complete swapon_all /vendor/etc/fstab.${ro.hardware}
Optimiser l'animation de démarrage
Utilisez les conseils suivants pour optimiser l’animation de démarrage.
Configurer le démarrage anticipé
Android 8.0 permet de démarrer l'animation de démarrage plus tôt, avant de monter la partition de données utilisateur. Cependant, même lors de l'utilisation de la nouvelle chaîne d'outils ext4 dans Android 8.0, fsck est toujours déclenché périodiquement pour des raisons de sécurité, entraînant un retard dans le démarrage du service d'animation de démarrage.
Pour que l'animation de démarrage démarre plus tôt, divisez le montage fstab en deux phases :
- Au début, montez uniquement les partitions (telles que
system/
etvendor/
) qui ne nécessitent pas d'exécution de vérifications, puis démarrez les services d'animation de démarrage et ses dépendances (telles que servicemanager et surfaceflinger). - Dans la deuxième phase, montez les partitions (telles que
data/
) qui nécessitent des vérifications d'exécution.
L'animation de démarrage sera lancée beaucoup plus rapidement (et en temps constant), quel que soit fsck.
Terminer propre
Après avoir reçu le signal de sortie, bootanimation joue la dernière partie, dont la durée peut ralentir le temps de démarrage. Un système qui démarre rapidement n’a pas besoin de longues animations qui pourraient effectivement masquer les améliorations apportées. Nous vous recommandons de rendre la boucle répétitive et la finale courtes.
Optimiser SELinux
Utilisez les conseils suivants pour optimiser SELinux afin d'améliorer les temps de démarrage.
- Utilisez des expressions régulières propres (regex) . Une expression régulière mal formée peut entraîner beaucoup de surcharge lors de la mise en correspondance de la politique SELinux pour
sys/devices
dansfile_contexts
. Par exemple, l'expression régulière/sys/devices/.*abc.*(/.*)?
force par erreur une analyse de tous les sous-répertoires/sys/devices
qui contiennent "abc", permettant des correspondances pour/sys/devices/abc
et/sys/devices/xyz/abc
. Améliorer cette expression régulière en/sys/devices/[^/]*abc[^/]*(/.*)?
permettra une correspondance uniquement pour/sys/devices/abc
. - Déplacez les étiquettes vers genfscon . Cette fonctionnalité SELinux existante transmet les préfixes de correspondance de fichiers au noyau dans le binaire SELinux, où le noyau les applique aux systèmes de fichiers générés par le noyau. Cela permet également de corriger les fichiers mal étiquetés créés par le noyau, évitant ainsi les conditions de concurrence qui peuvent survenir entre les processus de l'espace utilisateur tentant d'accéder à ces fichiers avant que le réétiquetage ne se produise.
Outils et méthodes
Utilisez les outils suivants pour vous aider à collecter des données pour les objectifs d'optimisation.
Tableau de démarrage
Bootchart fournit une répartition de la charge CPU et E/S de tous les processus pour l'ensemble du système. Il ne nécessite pas de reconstruction de l'image système et peut être utilisé comme un contrôle rapide de l'intégrité avant de plonger dans Systrace.
Pour activer le diagramme de démarrage :
adb shell 'touch /data/bootchart/enabled'
adb reboot
Après le démarrage, récupérez le graphique de démarrage :
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
Une fois terminé, supprimez /data/bootchart/enabled
pour éviter de collecter les données à chaque fois.
bootchart.png
n'existe pas, procédez comme suit :- Exécutez les commandes suivantes :
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
- Mettez à jour
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
pour pointer vers la copie locale depybootchartgui
(située dans~/Documents/bootchart/pybootchartgui.py
)
Systrace
Systrace permet de collecter les traces du noyau et d'Android lors du démarrage. La visualisation de systrace peut aider à analyser un problème spécifique lors du démarrage. (Cependant, pour vérifier le nombre moyen ou le nombre accumulé pendant tout le démarrage, il est plus facile de consulter directement la trace du noyau).
Pour activer Systrace lors du démarrage :
- Dans
frameworks/native/cmds/atrace/atrace.rc
, modifiez :write /sys/kernel/debug/tracing/tracing_on 0 write /sys/kernel/tracing/tracing_on 0
À:
# write /sys/kernel/debug/tracing/tracing_on 0 # write /sys/kernel/tracing/tracing_on 0
- Dans le fichier
device.mk
, ajoutez la ligne suivante :PRODUCT_PROPERTY_OVERRIDES += debug.atrace.tags.enableflags=802922 PRODUCT_PROPERTY_OVERRIDES += persist.traced.enable=0
- Dans le fichier
BoardConfig.mk
du périphérique, ajoutez ce qui suit :BOARD_KERNEL_CMDLINE := ... trace_buf_size=64M trace_event=sched_wakeup,sched_switch,sched_blocked_reason,sched_cpu_hotplug
- Dans le fichier
init.rc
spécifique au périphérique, ajoutez ce qui suit :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
Après le démarrage, récupérez la 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
Cela active le traçage (qui est désactivé par défaut).
Pour une analyse détaillée des E/S, ajoutez également block et ext4 et f2fs.