Google 致力于为黑人社区推动种族平等。查看具体举措
Questa pagina è stata tradotta dall'API Cloud Translation.
Switch to English

Ottimizzazione dei tempi di avvio

Questo documento fornisce indicazioni per i partner per migliorare i tempi di avvio per dispositivi Android specifici. Il tempo di avvio è una 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 auto 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 diversi miglioramenti su una vasta gamma di componenti. La tabella seguente riassume questi miglioramenti delle prestazioni (misurati su dispositivi Google Pixel e Pixel XL).

Componente Miglioramento
Boot loader
  • 1.6 salvati rimuovendo il registro UART
  • Risparmiato 0,4 secondi passando a LZ4 da GZIP
Kernel del dispositivo
  • Risparmiato 0.3s rimuovendo le configurazioni del kernel inutilizzate e riducendo le dimensioni del driver
  • Risparmio di 0,3 secondi con l'ottimizzazione del precaricamento dm-verity
  • Salvati 0.15 secondi per rimuovere l'attesa / test non necessario nel driver
  • 0.12 salvati per rimuovere CONFIG_CC_OPTIMIZE_FOR_SIZE
Sintonizzazione I / O
  • Salvati 2 secondi all'avvio normale
  • 25 salvati al primo avvio
init. *. rc
  • Risparmio di 1,5 secondi mettendo in parallelo i comandi di inizializzazione
  • Hai risparmiato 0,25 secondi avviando zigote presto
  • Salvato 0.22s da cpuset tune
Animazione di avvio
  • Avviato 2 secondi prima all'avvio senza fsck attivato, molto più grande all'avvio con avvio attivato da fsck
  • Salvati 5 secondi su Pixel XL con l'arresto immediato dell'animazione di avvio
Politica di SELinux 0.2s salvati su da genfscon

Ottimizzazione del bootloader

Per ottimizzare il bootloader per tempi di avvio migliori:

  • 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 1.5s).
    • 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 ( patch di esempio). 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'antirimbalzo / immissione in modalità speciale e ridurli al minimo.
  • Passa il tempo di avvio trascorso nel bootloader al kernel come cmdline.
  • Controllare il clock della CPU e considerare la parallelizzazione (richiede il supporto multi-core) per il caricamento del kernel e l'inizializzazione dell'I / O.

Ottimizzazione del kernel

Utilizzare i seguenti suggerimenti per ottimizzare il kernel e migliorare i tempi di avvio.

Riduzione al minimo del dispositivo defconfig

La riduzione al minimo della configurazione del kernel può ridurre le dimensioni del kernel per una decompressione di caricamento più rapida, l'inizializzazione e superfici di attacco più piccole. Per ottimizzare il defconfig del dispositivo:

  • Identifica i driver inutilizzati . Rivedere le /dev e /sys e cercare i nodi con etichette SELinux generali (che indica che quei nodi non sono configurati per essere accessibili dallo spazio utente). Rimuovere tali nodi se trovati.
  • Config inutilizzate non impostate . Rivedere il file .config generato dalla build del kernel per annullare esplicitamente qualsiasi CONFIG inutilizzato attivato per impostazione predefinita. Ad esempio, abbiamo rimosso le seguenti CONFIG non utilizzate da 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
    
  • Rimuovere i CONFIG che portano a test non necessari ad ogni avvio . Sebbene siano utili nello sviluppo, tali configurazioni (cioè CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST) dovrebbero essere rimosse in un kernel di produzione.

Riduzione al minimo delle dimensioni del driver

Alcuni driver nel kernel del dispositivo possono essere rimossi se la funzione non viene utilizzata per ridurre ulteriormente le dimensioni del kernel. Ad esempio, se la WLAN è connessa tramite PCIe, il supporto SDIO non viene utilizzato e deve essere rimosso durante la fase di compilazione. Per i dettagli, fare riferimento al kernel di Google Pixel: net: wireless: cnss: add opzione per disabilitare il supporto SDIO.

Rimozione dell'ottimizzazione del compilatore per le dimensioni

Rimuovere la configurazione del kernel per CONFIG_CC_OPTIMIZE_FOR_SIZE. Questo flag è stato originariamente introdotto quando si presumeva che una dimensione del codice più piccola avrebbe prodotto un riscontro nella cache calda (e quindi sarebbe stato più veloce). Tuttavia, questa ipotesi non è più valida poiché i moderni SoC mobili sono diventati più potenti.

Inoltre, la rimozione del flag può abilitare l'avviso del compilatore per le variabili non inizializzate, che viene soppresso nei kernel Linux quando è presente il flag CONFIG_CC_OPTIMIZE_FOR_SIZE (solo questa modifica ci ha aiutato a scoprire molti bug significativi in ​​alcuni driver di dispositivi Android).

Rinviare l'inizializzazione

Molti processi vengono avviati durante l'avvio, ma solo i componenti nel percorso critico (bootloader> kernel> init> montaggio del file system> zygote> server di sistema) influenzano direttamente il tempo di avvio. Profilare l' initcall durante l'avvio del kernel per identificare le periferiche / i componenti lenti e non critici per avviare il processo di inizializzazione, quindi ritardare quelle periferiche / componenti fino a più tardi nel processo di avvio spostandosi nei moduli caricabili del kernel. Il passaggio al probe asincrono del dispositivo / driver può anche aiutare a parallelizzare i componenti lenti nel percorso critico kernel> init.

BoardConfig-common.mk:
    BOARD_KERNEL_CMDLINE += initcall_debug ignore_loglevel

driver:
    .probe_type = PROBE_PREFER_ASYNCHRONOUS,

Nota: le dipendenze dei driver devono essere risolte con attenzione aggiungendo il supporto EPROBEDEFER .

Ottimizzazione dell'efficienza I / O

Migliorare l'efficienza I / O è fondamentale per velocizzare il tempo di avvio e la lettura di tutto ciò che non è necessario dovrebbe essere rimandata fino a dopo l'avvio (su un Google Pixel, vengono letti circa 1,2 GB di dati all'avvio).

Ottimizzazione del filesystem

La lettura anticipata del kernel di Linux si attiva quando un file viene letto dall'inizio o quando i blocchi vengono letti in sequenza, rendendo necessario regolare i parametri dello scheduler I / O specificamente per l'avvio (che ha una caratterizzazione del carico di lavoro diversa rispetto alle normali applicazioni).

I dispositivi che supportano gli aggiornamenti senza interruzioni (A / B) traggono grande vantaggio dall'ottimizzazione del file system al primo avvio (ad esempio 20 secondi su Google Pixel). Un esempio, abbiamo messo a punto 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
    ...

Miscellanea

  • Attiva la dimensione del prefetch 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, usa il nuovo strumento di generazione ext4 impostando TARGET_USES_MKE2FS in BoardConfig.mk.

Analisi dell'I / O

Per comprendere le attività di I / O durante l'avvio, utilizzare i dati ftrace del kernel (usati anche da systrace):

trace_event=block,ext4 in BOARD_KERNEL_CMDLINE

Per suddividere l'accesso ai file per ogni 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 aiutare ad analizzare le 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 ogni file.
  • system/extras/boottime_tools/io_analysis/check_io_trace_all.py boot_trace Fornisce system/extras/boottime_tools/io_analysis/check_io_trace_all.py boot_trace a livello di sistema.

Ottimizzazione di init. *. Rc

Init è il ponte dal kernel fino a quando non viene stabilito il framework, ei dispositivi di solito trascorrono alcuni secondi in diverse fasi di inizializzazione.

Esecuzione di attività in parallelo

Sebbene l'attuale inizializzazione di Android sia più o meno un singolo processo a thread, è comunque possibile eseguire alcune attività in parallelo.

  • Esegui comandi lenti in un servizio di script di shell e unisciti a quello in seguito 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 richiede più di 50 ms). Ad esempio:
    init: Command 'wait_for_coldboot_done' action=wait_for_coldboot_done returned 0 took 585.012ms

    La revisione di questo registro può indicare opportunità di miglioramento.

  • Avvia i servizi e abilita in anticipo 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 "Attendi servizio": in genere questo è un segno che un servizio dipendente deve essere avviato prima.
  • Rimuovere tutti i servizi e comandi inutilizzati in init. *. Rc. Tutto ciò che non è stato utilizzato nella fase iniziale di init dovrebbe essere rimandato all'avvio completato.

Nota: il servizio di proprietà fa parte del processo di inizializzazione, quindi chiamare setproperty durante l'avvio può comportare un lungo ritardo se init è occupato nei comandi incorporati.

Utilizzo dell'ottimizzazione dello scheduler

Usa 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 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
...

Avvio dello zigote presto

I dispositivi con crittografia basata su file possono avviare zygote prima all'avvio di zygote (per impostazione predefinita, zygote viene avviato alla classe principale, che è molto più tardi di zygote-start). Quando si esegue questa operazione, assicurarsi 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).

Disabilita il risparmio energetico

Durante l'avvio del dispositivo, è possibile disabilitare l'impostazione del risparmio energetico per componenti come UFS e / o CPU governor.

Attenzione: il risparmio energetico dovrebbe essere abilitato in modalità caricatore per efficienza.

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

Rimanda l'inizializzazione non critica

L'inizializzazione non critica come ZRAM può essere rimandata a boot_complete.

on property:sys.boot_completed=1
   # Enable ZRAM on boot_complete
   swapon_all /vendor/etc/fstab.${ro.hardware}

Ottimizzazione dell'animazione di avvio

Utilizzare i seguenti suggerimenti per ottimizzare l'animazione di avvio.

Configurazione dell'avvio anticipato

Android 8.0 consente di avviare l'animazione di avvio in anticipo, prima di montare la 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 di bootanimazione.

Per fare in modo che la bootanimazione inizi presto, dividi il montaggio fstab in due fasi:

  • Nella fase iniziale, monta solo le partizioni (come system/ e vendor/ ) che non richiedono controlli di esecuzione, quindi avvia i servizi di animazione di avvio e le relative dipendenze (come servicemanager e surfaceflinger).
  • Nella seconda fase, monta 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.

Finitura pulita

Dopo aver ricevuto il segnale di uscita, 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 nascondere efficacemente i miglioramenti apportati. Consigliamo di abbreviare sia il ciclo ripetuto che il finale.

Ottimizzazione di SELinux

Usa i seguenti suggerimenti per ottimizzare SELinux per tempi di avvio migliori.

  • Usa espressioni regolari pulite (regex) . L' file_contexts formata può portare a un sacco di overhead quando si abbina la policy SELinux per sys/devices in file_contexts . Ad esempio, la regex /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 regex in /sys/devices/[^/]*abc[^/]*(/.*)? abiliterà una corrispondenza solo per /sys/devices/abc .
  • Sposta le etichette in genfscon . Questa caratteristica SELinux esistente passa i prefissi di corrispondenza dei file al kernel nel binario SELinux, dove il kernel li applica ai filesystem generati dal kernel. Questo 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.

Strumento e metodi

Utilizza i seguenti strumenti per raccogliere dati per gli obiettivi di ottimizzazione.

Bootchart

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 un rapido controllo di integrità prima di immergersi in systrace.

Per abilitare il bootchart:

adb shell 'touch /data/bootchart/enabled'
adb reboot

Dopo l'avvio, scarica il grafico di avvio:

$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh

Al termine, elimina /data/bootchart/enabled per impedire la raccolta dei dati ogni volta.

Systrace

Systrace consente di raccogliere sia le tracce del kernel che quelle di Android durante l'avvio. La visualizzazione di systrace può aiutare nell'analisi di 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/atrace/atrace.rc , modificare:
    write /sys/kernel/debug/tracing/tracing_on 0

    Per:

    #write /sys/kernel/debug/tracing/tracing_on 0
  • Ciò abilita la traccia (che è disabilitata per impostazione predefinita).

  • 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
  • Per un'analisi I / O dettagliata, aggiungi anche block, ext4 e f2fs.

  • Nel file init.rc specifico del dispositivo, apporta le seguenti modifiche:
    • on property:sys.boot_completed=1 (interrompe la traccia al completamento dell'avvio)
    • 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

Nota: Chrome non è in grado di gestire file troppo grandi. Considera l' boot_trace tagliare il file boot_trace usando tail , head o grep per le parti necessarie. E l'analisi I / O spesso richiede l'analisi diretta del boot_trace acquisito, poiché sono presenti troppi eventi.