Costruzione di kernel

Questa pagina descrive in dettaglio il processo di creazione di kernel personalizzati per dispositivi Android. Queste istruzioni ti guidano attraverso il processo di selezione delle fonti corrette, creazione del kernel e incorporamento dei risultati in un'immagine di sistema creata dal progetto Android Open Source (AOSP).

Puoi acquisire sorgenti del kernel più recenti utilizzando Repo ; costruiscili senza ulteriore configurazione eseguendo build/build.sh dalla root del tuo checkout sorgente.

Download di sorgenti e strumenti di creazione

Per i kernel recenti, utilizza repo per scaricare i sorgenti, la toolchain e creare script. Alcuni kernel (ad esempio i kernel Pixel 3) richiedono sorgenti da più repository git, mentre altri (ad esempio i kernel comuni) richiedono solo una singola sorgente. L'utilizzo dell'approccio repo garantisce una corretta configurazione della directory di origine.

Scarica i sorgenti per il ramo appropriato:

mkdir android-kernel && cd android-kernel
repo init -u https://android.googlesource.com/kernel/manifest -b BRANCH
repo sync

Per un elenco dei rami del repository ( BRANCH ) che possono essere utilizzati con il precedente comando "repo init", vedere Rami del kernel e relativi sistemi di compilazione .

Per dettagli sul download e sulla compilazione dei kernel per i dispositivi Pixel, vedere Creazione di kernel Pixel .

Costruire il kernel

Costruire con Bazel (Kleaf)

Android 13 ha introdotto la creazione di kernel con Bazel .

Per creare il kernel GKI per l'architettura aarch64, controlla un ramo Android Common Kernel non prima di Android 13, quindi esegui il comando seguente:

tools/bazel build //common:kernel_aarch64_dist

Per creare una distribuzione, esegui:

tools/bazel run //common:kernel_aarch64_dist -- --dist_dir=$DIST_DIR

Successivamente il binario del kernel, i moduli e le immagini corrispondenti si trovano nella directory $DIST_DIR . Se --dist_dir non è specificato, vedere l'output del comando per la posizione degli artefatti. Per i dettagli, fare riferimento alla documentazione su AOSP .

Costruire con build.sh (legacy)

Per i rami con Android 12 o precedenti o senza Kleaf:

build/build.sh

Il binario del kernel, i moduli e l'immagine corrispondente si trovano nella directory out/ BRANCH /dist .

Creazione dei moduli del fornitore per il dispositivo virtuale

Android 13 ha introdotto la creazione dei kernel con Bazel (Kleaf), sostituendo build.sh .

Per creare i moduli di virtual_device , esegui:

tools/bazel build //common-modules/virtual-device:virtual_device_x86_64_dist

Per creare una distribuzione, esegui:

tools/bazel run //common-modules/virtual-device:virtual_device_x86_64_dist -- --dist_dir=$DIST_DIR

Per maggiori dettagli sulla creazione di kernel Android con Bazel, vedere. Kleaf: creazione di kernel Android con Bazel .

Per dettagli sul supporto Kleaf per le singole architetture, vedere Supporto Kleaf per dispositivi e kernel .

Creazione dei moduli del fornitore per il dispositivo virtuale con build.sh (legacy)

In Android 12 Cuttlefish e Goldfish convergono, quindi condividono lo stesso kernel: virtual_device . Per creare i moduli di quel kernel, usa questa configurazione di build:

BUILD_CONFIG=common-modules/virtual-device/build.config.virtual_device.x86_64 build/build.sh

Android 11 ha introdotto GKI , che separa il kernel in un'immagine del kernel gestita da Google e moduli gestiti dal fornitore, che vengono creati separatamente.

Questo esempio mostra una configurazione dell'immagine del kernel:

BUILD_CONFIG=common/build.config.gki.x86_64 build/build.sh

Questo esempio mostra la configurazione di un modulo (Cuttlefish ed Emulatore):

BUILD_CONFIG=common-modules/virtual-device/build.config.cuttlefish.x86_64 build/build.sh

Esecuzione del kernel

Esistono diversi modi per eseguire un kernel personalizzato. Di seguito sono riportati i modi noti adatti a vari scenari di sviluppo.

Incorporamento nella build dell'immagine Android

Copia Image.lz4-dtb nella rispettiva posizione binaria del kernel all'interno dell'albero AOSP e ricostruisci l'immagine di avvio.

In alternativa, definire la variabile TARGET_PREBUILT_KERNEL durante l'utilizzo make bootimage (o qualsiasi altra riga di comando make che crea un'immagine di avvio). Questa variabile è supportata da tutti i dispositivi poiché è configurata tramite device/common/populate-new-device.sh . Per esempio:

export TARGET_PREBUILT_KERNEL=DIST_DIR/Image.lz4-dtb

Lampeggiamento e avvio dei kernel con fastboot

I dispositivi più recenti dispongono di un'estensione del bootloader per semplificare il processo di generazione e avvio di un'immagine di avvio.

Per avviare il kernel senza eseguire il flashing:

adb reboot bootloader
fastboot boot Image.lz4-dtb

Utilizzando questo metodo, il kernel non viene effettivamente aggiornato e non persisterà dopo il riavvio.

Esecuzione di kernel su seppie

Puoi eseguire i kernel nell'architettura che preferisci sui dispositivi Cuttlefish .

Per avviare un dispositivo Cuttlefish con un particolare set di artefatti del kernel , esegui il comando cvd start con gli artefatti del kernel di destinazione come parametri. Il comando di esempio seguente utilizza gli artefatti del kernel per una destinazione arm64 dal manifest del kernel common-android14-6.1 .

cvd start \
    -kernel_path=/$PATH/$TO/common-android14-6.1/out/android14-6.1/dist/Image \
    -initramfs_path=/$PATH/$TO/common-android14-6.1/out/android14-6.1/dist/initramfs.img

Per ulteriori informazioni, vedere Sviluppare kernel su Cuttlefish .

Personalizzazione della build del kernel

Per personalizzare le build del kernel per le build Kleaf, vedere la documentazione di Kleaf .

Personalizzazione della build del kernel con build.sh (legacy)

Per build/build.sh , il processo di compilazione e il risultato possono essere influenzati da variabili di ambiente. La maggior parte di essi sono facoltativi e ogni ramo del kernel dovrebbe avere una configurazione predefinita adeguata. Quelli utilizzati più frequentemente sono elencati qui. Per un elenco completo (e aggiornato), fare riferimento a build/build.sh .

Variabile d'ambiente Descrizione Esempio
BUILD_CONFIG Compila il file di configurazione da cui inizializzi l'ambiente di compilazione. La posizione deve essere definita in relazione alla directory root del repository. Il valore predefinito è build.config .
Obbligatorio per i kernel comuni.
BUILD_CONFIG=common/build.config.gki.aarch64
CC Sostituisci il compilatore da utilizzare. Ritorna al compilatore predefinito definito da build.config . CC=clang
DIST_DIR Directory di output di base per la distribuzione del kernel. DIST_DIR=/path/to/my/dist
OUT_DIR Directory di output di base per la compilazione del kernel. OUT_DIR=/path/to/my/out
SKIP_DEFCONFIG Salta make defconfig SKIP_DEFCONFIG=1
SKIP_MRPROPER Salta make mrproper SKIP_MRPROPER=1

Configurazione del kernel personalizzata per build locali

In Android 14 e versioni successive, puoi utilizzare i frammenti defconfig per personalizzare le configurazioni del kernel. vedere la documentazione di Kleaf sui frammenti di defconfig .

Configurazione del kernel personalizzata per build locali con configurazioni di build (legacy)

In Android 13 e versioni precedenti, vedere quanto segue.

Se è necessario cambiare regolarmente un'opzione di configurazione del kernel, ad esempio, quando si lavora su una funzionalità, o se è necessario impostare un'opzione per scopi di sviluppo, è possibile ottenere tale flessibilità mantenendo una modifica locale o una copia della configurazione di build.

Imposta la variabile POST_DEFCONFIG_CMDS su un'istruzione che viene valutata subito dopo l'esecuzione del consueto passaggio make defconfig . Poiché i file build.config vengono originati nell'ambiente di compilazione, le funzioni definite in build.config possono essere chiamate come parte dei comandi post-defconfig.

Un esempio comune è la disabilitazione dell'ottimizzazione del tempo di collegamento (LTO) per i kernel crosshatch durante lo sviluppo. Sebbene LTO sia vantaggioso per i kernel rilasciati, il sovraccarico in fase di compilazione può essere significativo. Il seguente frammento aggiunto al build.config locale disabilita LTO in modo persistente quando si utilizza build/build.sh .

POST_DEFCONFIG_CMDS="check_defconfig && update_debug_config"
function update_debug_config() {
    ${KERNEL_DIR}/scripts/config --file ${OUT_DIR}/.config \
         -d LTO \
         -d LTO_CLANG \
         -d CFI \
         -d CFI_PERMISSIVE \
         -d CFI_CLANG
    (cd ${OUT_DIR} && \
     make O=${OUT_DIR} $archsubarch CC=${CC} CROSS_COMPILE=${CROSS_COMPILE} olddefconfig)
}

Identificazione delle versioni del kernel

È possibile identificare la versione corretta da compilare da due fonti: l'albero AOSP e l'immagine di sistema.

Versione del kernel dall'albero AOSP

L'albero AOSP contiene versioni del kernel predefinite. Il log git rivela la versione corretta come parte del messaggio di commit:

cd $AOSP/device/VENDOR/NAME
git log --max-count=1

Se la versione del kernel non è elencata nel log git, ottienila dall'immagine di sistema, come descritto di seguito.

Versione del kernel dall'immagine di sistema

Per determinare la versione del kernel utilizzata in un'immagine di sistema, eseguire il comando seguente sul file del kernel:

file kernel

Per i file Image.lz4-dtb , esegui:

grep -a 'Linux version' Image.lz4-dtb

Creazione di un'immagine di avvio

È possibile creare un'immagine di avvio utilizzando l'ambiente di compilazione del kernel.

Creazione di un'immagine di avvio per dispositivi con init_boot

Per i dispositivi con la partizione init_boot , l'immagine di avvio viene creata insieme al kernel. L'immagine initramfs non è incorporata nell'immagine di avvio.

Ad esempio, con Kleaf, puoi creare l'immagine di avvio GKI con:

tools/bazel run //common:kernel_aarch64_dist -- --dist_dir=$DIST_DIR

Con build/build.sh (legacy), puoi creare l'immagine di avvio GKI con:

BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh

L'immagine di avvio GKI si trova in $DIST_DIR .

Creazione di un'immagine di avvio per dispositivi senza init_boot (legacy)

Per i dispositivi senza la partizione init_boot , è necessario un file binario ramdisk, che puoi ottenere scaricando un'immagine di avvio GKI e decomprimendola. Funzionerà qualsiasi immagine di avvio GKI della versione Android associata.

tools/mkbootimg/unpack_bootimg.py --boot_img=boot-5.4-gz.img
mv $KERNEL_ROOT/out/ramdisk gki-ramdisk.lz4

La cartella di destinazione è la directory di primo livello dell'albero del kernel (la directory di lavoro corrente).

Se stai sviluppando con AOSP main, puoi invece scaricare l'artefatto di build ramdisk-recovery.img da una build aosp_arm64 su ci.android.com e utilizzarlo come binario ramdisk.

Quando hai un binario ramdisk e lo hai copiato su gki-ramdisk.lz4 nella directory root della build del kernel, puoi generare un'immagine di avvio eseguendo:

BUILD_BOOT_IMG=1 SKIP_VENDOR_BOOT=1 KERNEL_BINARY=Image GKI_RAMDISK_PREBUILT_BINARY=gki-ramdisk.lz4 BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh

Se stai lavorando con un'architettura basata su x86, sostituisci Image con bzImage e aarch64 con x86_64 :

BUILD_BOOT_IMG=1 SKIP_VENDOR_BOOT=1 KERNEL_BINARY=bzImage GKI_RAMDISK_PREBUILT_BINARY=gki-ramdisk.lz4 BUILD_CONFIG=common/build.config.gki.x86_64 build/build.sh

Quel file si trova nella directory degli artefatti $KERNEL_ROOT/out/$KERNEL_VERSION/dist .

L'immagine di avvio si trova in out/<kernel branch>/dist/boot.img .