Questo documento fornisce indicazioni ai partner per migliorare i tempi di avvio per dispositivi Android specifici. Il tempo di avvio è un componente importante delle prestazioni del sistema poiché gli utenti devono attendere il completamento dell'avvio prima di poter utilizzare il dispositivo. Per dispositivi come le automobili in cui l'avvio a freddo avviene più frequentemente, avere un tempo di avvio rapido è fondamentale (a nessuno piace aspettare decine di secondi solo per inserire una destinazione di navigazione).
Android 8.0 consente tempi di avvio ridotti supportando numerosi miglioramenti in una gamma di componenti. La tabella seguente riassume questi miglioramenti delle prestazioni (misurati sui dispositivi Google Pixel e Pixel XL).
Componente | Miglioramento |
---|---|
Boot loader |
|
Nucleo del dispositivo |
|
Sintonizzazione I/O |
|
init.*.rc |
|
Animazione di avvio |
|
Politica SELinux | Salvato 0,2 secondi da genfscon |
Ottimizza il bootloader
Per ottimizzare il bootloader per migliorare i tempi di avvio:
- Per la registrazione:
- Disabilitare la scrittura del registro su UART poiché può richiedere molto tempo con molte registrazioni. (Sui dispositivi Google Pixel, abbiamo riscontrato che rallenta il bootloader di 1,5 s).
- Registra solo le situazioni di errore e valuta la possibilità di archiviare altre informazioni in memoria con un meccanismo separato per il recupero.
- Per la decompressione del kernel, considerare l'utilizzo di LZ4 per l'hardware contemporaneo invece di GZIP (esempio patch ). Tieni presente che 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.
- Controllare i tempi di attesa non necessari per l'ingresso in modalità antirimbalzo/speciale e ridurli al minimo.
- Passa il tempo di avvio trascorso nel bootloader al kernel come cmdline.
- Controllare l'orologio della CPU e considerare la parallelizzazione (richiede 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 i tempi di avvio e la lettura di tutto ciò che non è necessario dovrebbe essere rinviata a dopo l'avvio (su un Google Pixel, all'avvio vengono letti circa 1,2 GB di dati).
Ottimizza il filesystem
Il kernel Linux read ahead si attiva quando un file viene letto dall'inizio o quando i blocchi vengono letti in sequenza, rendendo necessario ottimizzare i parametri dello scheduler I/O specificatamente per l'avvio (che ha una caratterizzazione del carico di lavoro diversa rispetto alle normali app).
I dispositivi che supportano aggiornamenti continui (A/B) traggono grandi vantaggi dall'ottimizzazione del file system al primo avvio (ad esempio 20s 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 ...
Varie
- Attiva la dimensione di precaricamento dell'hash dm-verity utilizzando la configurazione del kernel DM_VERITY_HASH_PREFETCH_MIN_SIZE (la dimensione predefinita è 128).
- Per una migliore stabilità del file system e un controllo forzato interrotto che si verifica ad ogni avvio, utilizzare il nuovo strumento di generazione ext4 impostando TARGET_USES_MKE2FS in BoardConfig.mk.
Analizzare I/O
Per comprendere le attività I/O durante l'avvio, utilizzare 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, apportare le seguenti modifiche al kernel (solo kernel di sviluppo; 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);
Utilizzare i seguenti script per facilitare l'analisi delle prestazioni di avvio.
-
system/extras/boottime_tools/bootanalyze/bootanalyze.py
Misura il tempo di avvio con una suddivisione dei passaggi importanti nel processo di avvio. -
system/extras/boottime_tools/io_analysis/check_file_read.py boot_trace
Fornisce informazioni di accesso per ciascun file. -
system/extras/boottime_tools/io_analysis/check_io_trace_all.py boot_trace
Fornisce un'analisi a livello di sistema.
Ottimizza init.*.rc
Init è il ponte dal kernel fino alla creazione del framework e i dispositivi solitamente trascorrono alcuni secondi in diverse fasi di inizializzazione.
Esegui attività in parallelo
Sebbene l'attuale init di Android sia più o meno un processo a thread singolo, è comunque possibile eseguire alcune attività in parallelo.
- Esegui comandi lenti in un servizio di script di shell e unisciti a quello in seguito attendendo una proprietà specifica. Android 8.0 supporta questo caso d'uso con un nuovo comando
wait_for_property
. - Identificare 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 registro può indicare opportunità di miglioramento.
- Avviare tempestivamente i servizi e abilitare i dispositivi periferici nel percorso critico. Ad esempio, alcuni SOC richiedono l'avvio di servizi relativi alla sicurezza prima di avviare SurfaceFlinger. Esaminare il registro di sistema quando ServiceManager restituisce "attendere il servizio": in genere questo è un segno che è necessario avviare prima un servizio dipendente.
- Rimuovere eventuali servizi e comandi non utilizzati in init.*.rc. Tutto ciò che non viene utilizzato nella fase iniziale di init dovrebbe essere rimandato al completamento dell'avvio.
Nota: il servizio proprietà fa parte del processo init, quindi chiamare setproperty
durante l'avvio può causare un lungo ritardo se init è occupato nei comandi integrati.
Utilizzare l'ottimizzazione dello scheduler
Utilizza l'ottimizzazione dello scheduler per l'avvio anticipato. Esempio da 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
Alcuni servizi potrebbero richiedere un aumento di 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 ...
Inizia presto lo zigote
I dispositivi con crittografia basata su file possono avviare zygote prima al trigger zygote-start (per impostazione predefinita, zygote viene avviato alla classe main, che è molto più tardi di zygote-start). Quando lo fai, assicurati di consentire l'esecuzione di zygote in tutte le CPU (poiché un'impostazione errata di cpuset potrebbe forzare l'esecuzione di zygote in CPU specifiche).
Disabilita il risparmio energetico
Durante l'avvio del dispositivo, l'impostazione di risparmio energetico per componenti come UFS e/o regolatore della CPU può essere disabilitata.
Attenzione: per ragioni di efficienza, il risparmio energetico deve essere abilitato 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 rinviata a boot_complete
.
on property:sys.boot_completed=1 # Enable ZRAM on boot_complete swapon_all /vendor/etc/fstab.${ro.hardware}
Ottimizza l'animazione di avvio
Utilizzare i seguenti suggerimenti per ottimizzare l'animazione di avvio.
Configura l'avvio anticipato
Android 8.0 consente l'avvio anticipato dell'animazione di avvio, prima del montaggio della partizione dei dati utente. Tuttavia, anche quando si utilizza la nuova catena 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 far sì che la bootanimation venga avviata in anticipo, dividi il montaggio di fstab in due fasi:
- Nella fase iniziale, montare solo le partizioni (come
system/
evendor/
) che non richiedono controlli di esecuzione, quindi avviare i servizi di animazione di avvio e le relative dipendenze (come servicemanager e surfaceflinger). - Nella seconda fase, montare le partizioni (come
data/
) che richiedono controlli di esecuzione.
L'animazione di avvio verrà avviata molto più velocemente (e in tempo costante) indipendentemente da fsck.
Finisci pulito
Dopo aver ricevuto il segnale di uscita, la bootanimation riproduce l'ultima parte, la cui durata può rallentare il tempo di avvio. Un sistema che si avvia rapidamente non ha bisogno di lunghe animazioni che potrebbero effettivamente nascondere eventuali miglioramenti apportati. Ti consigliamo di rendere brevi sia il ciclo ripetuto che il finale.
Ottimizza SELinux
Utilizzare i seguenti suggerimenti per ottimizzare SELinux e migliorare i tempi di avvio.
- Utilizza espressioni regolari pulite (regex) . Una regex mal formata può portare a un sacco di sovraccarico quando si fa corrispondenza con la policy SELinux per
sys/devices
infile_contexts
. Ad esempio, l'espressione regolare/sys/devices/.*abc.*(/.*)?
forza erroneamente una scansione di tutte le sottodirectory/sys/devices
che contengono "abc", abilitando le corrispondenze sia per/sys/devices/abc
che per/sys/devices/xyz/abc
. Migliorare questa espressione regolare in/sys/devices/[^/]*abc[^/]*(/.*)?
abiliterà una corrispondenza solo per/sys/devices/abc
. - Sposta le etichette in genfscon . Questa funzionalità SELinux esistente passa i prefissi di corrispondenza dei file nel kernel nel binario SELinux, dove il kernel li applica ai filesystem generati dal kernel. Ciò aiuta anche a correggere i file creati dal kernel con etichette errate, prevenendo condizioni di competizione che possono verificarsi tra i processi dello spazio utente che tentano di accedere a questi file prima che avvenga la rietichettatura.
Strumenti e metodi
Utilizza i seguenti strumenti per raccogliere dati per gli obiettivi di ottimizzazione.
Grafico di avvio
Bootchart fornisce la ripartizione del carico di CPU e I/O di tutti i processi per l'intero sistema. Non richiede la ricostruzione dell'immagine del sistema e può essere utilizzato come rapido controllo di integrità prima di immergersi in systrace.
Per abilitare il grafico di avvio:
adb shell 'touch /data/bootchart/enabled'
adb reboot
Dopo l'avvio, recupera la tabella di avvio:
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
Al termine, eliminare /data/bootchart/enabled
per evitare di raccogliere i dati ogni volta.
bootchart.png
non esiste, procedi come segue:- 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
(situata in~/Documents/bootchart/pybootchartgui.py
)
Systrace
Systrace consente di raccogliere tracce sia del kernel che di Android durante l'avvio. La visualizzazione di systrace può aiutare ad analizzare problemi specifici durante l'avvio. (Tuttavia, per controllare il numero medio o il numero accumulato durante l'intero avvio, è più semplice esaminare direttamente la traccia del kernel).
Per abilitare systrace durante l'avvio:
- In
frameworks/native/cmds/atrace/atrace.rc
, modificare: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
- 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, aggiungere 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, aggiungere 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
Ciò abilita la traccia (che è disabilitata per impostazione predefinita).
Per un'analisi I/O dettagliata, aggiungi anche block ed ext4 e f2fs.