Questo documento fornisce ai partner indicazioni per migliorare i tempi di avvio di dispositivi Android specifici. Il tempo di avvio è un componente importante delle prestazioni del sistema, in quanto gli utenti devono attendere il completamento dell'avvio prima di poter utilizzare il dispositivo. Per i dispositivi come le auto, in cui l'avvio a freddo si verifica più di frequente, è fondamentale avere un tempo di avvio rapido (a nessuno piace attendere decine di secondi solo per inserire una destinazione di navigazione).
Android 8.0 consente di ridurre i tempi di avvio supportando diversi miglioramenti su una serie di componenti. La seguente tabella riassume questi miglioramenti delle prestazioni (misurati su dispositivi Google Pixel e Pixel XL).
Componente | Miglioramento |
---|---|
Bootloader |
|
Kernel del dispositivo |
|
Ottimizzazione I/O |
|
init.*.rc |
|
Animazione di avvio |
|
Norme SELinux | Risparmiato 0,2 secondi da genfscon |
Ottimizza il bootloader
Per ottimizzare il bootloader per migliorare i tempi di avvio:
- Per il logging:
- Disattiva la scrittura dei log in UART, in quanto può richiedere molto tempo con un volume elevato di logging. (sui dispositivi Google Pixel abbiamo riscontrato che rallenta il bootloader di 1, 5 secondi).
- Registra solo le situazioni di errore e valuta la possibilità di memorizzare altre informazioni in memoria con un meccanismo di recupero separato.
- Per la decompressione del kernel, valuta la possibilità di utilizzare LZ4 per l'hardware contemporaneo anziché GZIP (patch di esempio). Tieni presente che le diverse opzioni di compressione del kernel possono avere tempi di caricamento e decompressione diversi e alcune opzioni potrebbero funzionare meglio di altre per il tuo hardware specifico.
- Controlla i tempi di attesa non necessari per il debouncing/l'ingresso in modalità speciale e riducili al minimo.
- Passa il tempo di avvio trascorso nel bootloader al kernel come cmdline.
- Controlla la frequenza della CPU e valuta la parallelizzazione (richiede il supporto multi-core) per il caricamento del kernel e l'inizializzazione dell'I/O.
Ottimizza l'efficienza I/O
Migliorare l'efficienza I/O è fondamentale per velocizzare il tempo di avvio e la lettura di qualsiasi elemento non necessario deve essere posticipata al termine dell'avvio (su Google Pixel vengono letti circa 1,2 GB di dati all'avvio).
Ottimizza il file system
La lettura anticipata del kernel di Linux viene attivata quando un file viene letto dall'inizio o quando i blocchi vengono letti in sequenza, rendendo necessario ottimizzare i parametri di pianificazione I/O specificamente per l'avvio (che ha una caratterizzazione del carico di lavoro diversa rispetto alle normali app).
I dispositivi che supportano gli aggiornamenti seamless (A/B) traggono grande vantaggio dalla ottimizzazione del filesystem al primo avvio (ad es. 20 secondi su Google Pixel). Ad esempio, abbiamo ottimizzato i seguenti parametri per 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 ...
Vari
- Attiva la dimensione del prefetch dell'hash dm-verity utilizzando la configurazione del kernel DM_VERITY_HASH_PREFETCH_MIN_SIZE (la dimensione predefinita è 128).
- Per una maggiore stabilità del file system e un controllo forzato interrotto che si verifica su ogni avvio, utilizza il nuovo strumento di generazione ext4 impostando TARGET_USES_MKE2FS in BoardConfig.mk.
Analizza l'I/O
Per comprendere le attività di I/O durante l'avvio, utilizza i dati ftrace del kernel (utilizzati anche da systrace):
trace_event=block,ext4 in BOARD_KERNEL_CMDLINE
Per suddividere l'accesso ai file per ciascun file, apporta le seguenti modifiche al kernel (solo kernel di sviluppo; da non utilizzare nei kernel di produzione):
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);
Utilizza i seguenti script per analizzare il rendimento del boot.
system/extras/boottime_tools/bootanalyze/bootanalyze.py
Misura il tempo di avvio con un'analisi dettagliata dei passaggi importanti del processo di avvio.system/extras/boottime_tools/io_analysis/check_file_read.py boot_trace
Fornisce informazioni di accesso per ogni file.system/extras/boottime_tools/io_analysis/check_io_trace_all.py boot_trace
Fornisce un'analisi dettagliata a livello di sistema.
Ottimizza init.*.rc
L'inizializzazione è il ponte dal kernel fino all'impostazione del framework e solitamente i dispositivi impiegano alcuni secondi in diverse fasi di inizializzazione.
Eseguire attività in parallelo
Sebbene l'attuale init di Android sia più o meno un processo a thread singolo, puoi comunque eseguire alcune attività in parallelo.
- Esegui comandi lenti in un servizio di script shell e uniscili in un secondo momento aspettando una proprietà specifica. Android 8.0 supporta questo caso d'uso con un nuovo comando
wait_for_property
. - Identifica le operazioni lente in init. Il sistema registra il comando init
exec/wait_for_prop o qualsiasi azione che richiede molto tempo (in Android 8.0, qualsiasi comando
che richiede più di 50 ms). Ad esempio:
init: Command 'wait_for_coldboot_done' action=wait_for_coldboot_done returned 0 took 585.012ms
L'esame di questo log potrebbe indicare opportunità di miglioramento.
- Avvia in anticipo i servizi e abilita i dispositivi periferici nel percorso critico. Ad esempio, alcuni SOC richiedono l'avvio di servizi correlati alla sicurezza prima di avviare SurfaceFlinger. Esamina il log di sistema quando ServiceManager restituisce "wait for service" (attendi servizio). In genere, questo è un segno che è necessario avviare prima un servizio dipendente.
- Rimuovi i servizi e i comandi inutilizzati in init.*.rc. Qualsiasi elemento non utilizzato nell'inizializzazione iniziale deve essere posticipato al completamento dell'avvio.
Nota: il servizio Property fa parte della procedura di inizializzazione, pertanto l'uso di setproperty
durante l'avvio può comportare un lungo ritardo se init è occupato nei comandi di sistema.
Utilizzare l'ottimizzazione dell'scheduler
Utilizza l'ottimizzazione dell'organizzatore per l'avvio anticipato. Esempio da 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
Alcuni servizi potrebbero richiedere un aumento della priorità durante l'avvio. Esempio:
init.zygote64.rc: service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server class main priority -20 user root ...
Avvia zygote in anticipo
I dispositivi con crittografia basata su file possono avviare zygote prima all'attivatore zygote-start (per impostazione predefinita, zygote viene avviato in class main, molto più tardi rispetto a zygote-start). Quando esegui questa operazione, assicurati di consentire l'esecuzione di zygote su tutte le CPU (poiché l'impostazione errata di cpuset potrebbe forzare l'esecuzione di zygote su CPU specifiche).
Disattivare il risparmio energetico
Durante l'avvio del dispositivo, l'impostazione di risparmio energetico per componenti come UFS e/o il governatore della CPU può essere disattivata.
Attenzione: per motivi di efficienza, il risparmio energetico deve essere attivato in modalità caricabatterie.
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
Rimandare l'inizializzazione non critica
L'inizializzazione non critica, come ZRAM, può essere differita a boot_complete
.
on property:sys.boot_completed=1 # Enable ZRAM on boot_complete swapon_all /vendor/etc/fstab.${ro.hardware}
Ottimizzare l'animazione di avvio
Segui i suggerimenti riportati di seguito per ottimizzare l'animazione di avvio.
Configurare l'avvio anticipato
Android 8.0 consente di avviare l'animazione di avvio in anticipo, prima del montaggio della partizione userdata. Tuttavia, anche se utilizzi la nuova suite di strumenti ext4 in Android 8.0, fsck viene comunque attivato periodicamente per motivi di sicurezza, causando un ritardo nell'avvio del servizio bootanimation.
Per avviare bootanimation in anticipo, suddividi il montaggio fstab in due fasi:
- Nella fase iniziale, monta solo le partizioni (ad esempio
system/
evendor/
) che non richiedono controlli di esecuzione, quindi avvia i servizi di animazione all'avvio e le relative dipendenze (ad esempio servicemanager e surfaceflinger). - Nella seconda fase, monta le partizioni (ad esempio
data/
) che richiedono l'esecuzione di controlli.
L'animazione di avvio verrà avviata molto più velocemente (e in tempo costante) indipendentemente da fsck.
Pulizia finale
Dopo aver ricevuto l'indicatore di uscita, l'animazione di avvio riproduce l'ultima parte, la cui durata può rallentare il tempo di avvio. Un sistema che si avvia rapidamente non ha bisogno di animazioni lunghe che potrebbero nascondere efficacemente eventuali miglioramenti apportati. Ti consigliamo di mantenere brevi sia il loop ripetuto sia la parte finale.
Ottimizza SELinux
Segui questi suggerimenti per ottimizzare SELinux in modo da migliorare i tempi di avvio.
- Utilizza espressioni regolari (regex) chiare. Le espressioni regolari con formattazione non corretta possono comportare un notevole overhead durante la corrispondenza del criterio SELinux per
sys/devices
infile_contexts
. Ad esempio, la regex/sys/devices/.*abc.*(/.*)?
forza erroneamente la scansione di tutte/sys/devices
le sottodirectory contenenti "abc", attivando le corrispondenze sia per/sys/devices/abc
sia per/sys/devices/xyz/abc
. Migliorando questa regex in/sys/devices/[^/]*abc[^/]*(/.*)?
, verrà attivata una corrispondenza solo per/sys/devices/abc
. - Sposta le etichette in genfscon. Questa funzionalità SELinux esistente passa i prefissi di corrispondenza dei file al kernel nel file binario SELinux, dove il kernel li applica ai filesystem generati dal kernel. Ciò contribuisce anche a correggere i file creati dal kernel con etichette errate, impedendo condizioni di gara che possono verificarsi tra i processi dello spazio utente che tentano di accedere a questi file prima che venga eseguita la ridesignazione.
Strumenti e metodi
Utilizza i seguenti strumenti per raccogliere i dati per i target di ottimizzazione.
Bootchart
Bootchart fornisce un'analisi dettagliata del carico della CPU e dell'I/O di tutti i processi per l'intero sistema. Non richiede la ricostruzione dell'immagine di sistema e può essere utilizzato come rapido controllo di conformità prima di iniziare a utilizzare systrace.
Per attivare il grafico di avvio:
adb shell 'touch /data/bootchart/enabled'
adb reboot
Dopo l'avvio, recupera il grafico di avvio:
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
Al termine, elimina /data/bootchart/enabled
per evitare di raccogliere
i dati ogni volta.
bootchart.png
non esiste, procedi nel seguente modo:
- Esegui i seguenti comandi:
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
- Aggiorna
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
in modo che punti alla copia locale dipybootchartgui
(in~/Documents/bootchart/pybootchartgui.py
)
Systrace
Systrace consente di raccogliere sia le tracce del kernel che quelle di Android durante l'avvio. La visualizzazione di systrace può essere utile per analizzare un problema specifico durante l'avvio. Tuttavia, per controllare il numero medio o accumulato durante l'intero avvio, è più facile esaminare direttamente la traccia del kernel.
Per attivare systrace durante l'avvio:
- In
frameworks/native/cmds/atrace/atrace.rc
, modifica:write /sys/kernel/debug/tracing/tracing_on 0 write /sys/kernel/tracing/tracing_on 0
Segui le istruzioni per eseguire le operazioni indicate:
# write /sys/kernel/debug/tracing/tracing_on 0 # write /sys/kernel/tracing/tracing_on 0
- Nel file
device.mk
, aggiungi la seguente riga:PRODUCT_PROPERTY_OVERRIDES += debug.atrace.tags.enableflags=802922 PRODUCT_PROPERTY_OVERRIDES += persist.traced.enable=0
- Nel file
BoardConfig.mk
del dispositivo, aggiungi quanto segue:BOARD_KERNEL_CMDLINE := ... trace_buf_size=64M trace_event=sched_wakeup,sched_switch,sched_blocked_reason,sched_cpu_hotplug
- Nel file
init.rc
specifico del dispositivo, aggiungi quanto segue: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
-
Dopo l'avvio, recupera la traccia:
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
Viene attivata la tracciatura (disattivata per impostazione predefinita).
Per un'analisi dettagliata dell'I/O, aggiungi anche block, ext4 e f2fs.