Compiler des noyaux

Cette page décrit en détail le processus de création de noyaux personnalisés pour les appareils Android. Ces instructions vous guident tout au long du processus de sélection des sources appropriées, de compilation du noyau et d'intégration des résultats dans une image système créée à partir de l'Android Open Source Project (AOSP).

Télécharger les sources et les outils de compilation

Pour les kernels récents, utilisez repo pour télécharger les sources, la chaîne d'outils et les scripts de compilation. Certains noyaux (par exemple, les noyaux Pixel 3) nécessitent des sources provenant de plusieurs dépôts git, tandis que d'autres (par exemple, les noyaux communs) ne nécessitent qu'une seule source. L'approche repo garantit une configuration correcte du répertoire source.

Téléchargez les sources pour la branche appropriée :

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

Pour obtenir la liste des branches de dépôt (BRANCH) pouvant être utilisées avec la commande `repo init` précédente, consultez Branches du noyau et leurs systèmes de compilation.

Pour savoir comment télécharger et compiler des noyaux pour les appareils Pixel, consultez Compiler des noyaux Pixel.

Compiler le noyau

Compiler avec Bazel (Kleaf)

Android 13 a introduit la compilation des noyaux avec Bazel.

Pour créer une distribution pour le noyau GKI pour l'architecture aarch64, consultez une branche Android Common Kernel qui n'est pas antérieure à Android 13, puis exécutez la commande suivante :

tools/bazel run //common:kernel_aarch64_dist [-- --destdir=$DIST_DIR]

Le binaire du noyau, les modules et les images correspondantes se trouvent ensuite dans le répertoire $DIST_DIR. Si --destdir n'est pas spécifié, consultez le résultat de la commande pour connaître l'emplacement des artefacts. Pour en savoir plus, consultez la documentation sur AOSP.

Compiler avec build.sh (ancienne méthode)

Pour les branches Android 12 ou version antérieure, OU les branches sans Kleaf :

build/build.sh

Le fichier binaire du noyau, les modules et l'image correspondante se trouvent dans le répertoire out/BRANCH/dist.

Créer les modules du fournisseur pour l'appareil virtuel

Android 13 a introduit la compilation des noyaux avec Bazel (Kleaf), en remplacement de build.sh.

Pour créer une distribution pour les modules de virtual_device, exécutez la commande suivante :

tools/bazel run //common-modules/virtual-device:virtual_device_x86_64_dist [-- --destdir=$DIST_DIR]

Pour en savoir plus sur la création de noyaux Android avec Bazel, consultez Kleaf : compiler des noyaux Android avec Bazel.

Pour en savoir plus sur la compatibilité de Kleaf avec les architectures individuelles, consultez Compatibilité de Kleaf avec les appareils et les noyaux.

Compiler les modules du fournisseur pour l'appareil virtuel avec build.sh (ancienne méthode)

Dans Android 12, Cuttlefish et Goldfish convergent et partagent donc le même noyau : virtual_device. Pour compiler les modules de ce noyau, utilisez la configuration de compilation suivante :

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

Android 11 a introduit GKI, qui sépare le noyau en une image de noyau gérée par Google et des modules gérés par le fournisseur, qui sont construits séparément.

Cet exemple montre une configuration d'image du noyau :

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

Cet exemple montre une configuration de module (Cuttlefish et Emulator) :

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

Exécuter le noyau

Il existe plusieurs façons d'exécuter un noyau personnalisé. Voici quelques méthodes connues qui conviennent à différents scénarios de développement.

Intégrer à la compilation d'image Android

Copiez Image.lz4-dtb à l'emplacement du binaire du noyau correspondant dans l'arborescence AOSP, puis recréez l'image de démarrage.

Vous pouvez également définir la variable TARGET_PREBUILT_KERNEL lorsque vous utilisez make bootimage (ou toute autre ligne de commande make qui crée une image de démarrage). Cette variable est compatible avec tous les appareils, car elle est configurée via device/common/populate-new-device.sh. Exemple :

export TARGET_PREBUILT_KERNEL=DIST_DIR/Image.lz4-dtb

Flasher et démarrer des noyaux avec fastboot

Les appareils les plus récents disposent d'une extension de bootloader pour simplifier le processus de génération et de démarrage d'une image de démarrage.

Pour démarrer le noyau sans le flasher :

adb reboot bootloader
fastboot boot Image.lz4-dtb

Avec cette méthode, le noyau n'est pas réellement flashé et ne persiste pas après un redémarrage.

Exécuter des kernels sur Cuttlefish

Vous pouvez exécuter des noyaux dans l'architecture de votre choix sur les appareils Cuttlefish.

Pour démarrer un appareil Cuttlefish avec un ensemble particulier d'artefacts du noyau, exécutez la commande cvd create avec les artefacts du noyau cible comme paramètres. L'exemple de commande suivant utilise des artefacts du noyau pour une cible arm64 à partir du fichier manifeste du noyau common-android14-6.1.

cvd create \
    -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

Pour en savoir plus, consultez Développer des noyaux sur Cuttlefish.

Personnaliser la compilation du noyau

Pour personnaliser les compilations du noyau pour les compilations Kleaf, consultez la documentation Kleaf.

Personnaliser la compilation du noyau avec build.sh (ancienne méthode)

Pour build/build.sh, le processus et le résultat de la compilation peuvent être influencés par des variables d'environnement. La plupart d'entre eux sont facultatifs et chaque branche du noyau doit être fournie avec une configuration par défaut appropriée. Les plus fréquemment utilisés sont listés ici. Pour obtenir une liste complète et à jour, consultez build/build.sh.

Variable d'environnement Description Exemple
BUILD_CONFIG Fichier de configuration de compilation à partir duquel vous initialisez l'environnement de compilation. L'emplacement doit être défini par rapport au répertoire racine du dépôt. La valeur par défaut est build.config.
Obligatoire pour les noyaux courants.
BUILD_CONFIG=common/build.config.gki.aarch64
CC Remplace le compilateur à utiliser. Utilise le compilateur par défaut défini par build.config. CC=clang
DIST_DIR Répertoire de sortie de base pour la distribution du noyau. DIST_DIR=/path/to/my/dist
OUT_DIR Répertoire de sortie de base pour la compilation du noyau. OUT_DIR=/path/to/my/out
SKIP_DEFCONFIG Ignorer make defconfig SKIP_DEFCONFIG=1
SKIP_MRPROPER Ignorer make mrproper SKIP_MRPROPER=1

Configuration du noyau personnalisée pour les compilations locales

Dans Android 14 et versions ultérieures, vous pouvez utiliser des fragments defconfig pour personnaliser les configurations du noyau. Consultez la documentation Kleaf sur les fragments defconfig.

Configuration du noyau personnalisée pour les compilations locales avec des configurations de compilation (ancienne version)

Pour Android 13 et versions antérieures, consultez les informations suivantes.

Si vous devez modifier régulièrement une option de configuration du noyau, par exemple lorsque vous travaillez sur une fonctionnalité, ou si vous avez besoin qu'une option soit définie à des fins de développement, vous pouvez obtenir cette flexibilité en conservant une modification ou une copie locale de la configuration de compilation.

Définissez la variable POST_DEFCONFIG_CMDS sur une instruction qui est évaluée juste après l'étape make defconfig habituelle. Étant donné que les fichiers build.config sont intégrés à l'environnement de compilation, les fonctions définies dans build.config peuvent être appelées dans le cadre des commandes post-defconfig.

Un exemple courant consiste à désactiver l'optimisation au moment de l'édition des liens (LTO) pour les noyaux crosshatch pendant le développement. Bien que l'optimisation LTO soit bénéfique pour les noyaux publiés, la surcharge au moment de la compilation peut être importante. L'extrait suivant ajouté au build.config local désactive LTO de manière persistante lors de l'utilisation de 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)
}

Identifier les versions du noyau

Vous pouvez identifier la version correcte à partir de laquelle compiler à l'aide de deux sources : l'arborescence AOSP et l'image système.

Version du noyau à partir de l'arborescence AOSP

L'arborescence AOSP contient des versions de noyau précompilées. Le journal Git révèle la version correcte dans le message de commit :

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

Si la version du noyau n'est pas listée dans le journal Git, obtenez-la à partir de l'image système, comme décrit ci-dessous.

Version du noyau de l'image système

Pour déterminer la version du noyau utilisée dans une image système, exécutez la commande suivante sur le fichier du noyau :

file kernel

Pour les fichiers Image.lz4-dtb, exécutez :

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

Créer une image de démarrage

Il est possible de créer une image de démarrage à l'aide de l'environnement de compilation du noyau.

Créer une image de démarrage pour les appareils avec init_boot

Pour les appareils avec la partition init_boot, l'image de démarrage est créée avec le noyau. L'image initramfs n'est pas intégrée à l'image de démarrage.

Par exemple, avec Kleaf, vous pouvez créer l'image de démarrage GKI avec :

tools/bazel run //common:kernel_aarch64_dist [-- --destdir=$DIST_DIR]

Avec build/build.sh (ancienne version), vous pouvez créer l'image de démarrage GKI avec :

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

L'image de démarrage GKI se trouve dans $DIST_DIR.

Créer une image de démarrage pour les appareils sans init_boot (ancienne méthode)

Pour les appareils sans partition init_boot, vous avez besoin d'un binaire ramdisk, que vous pouvez obtenir en téléchargeant une image de démarrage GKI et en la décompressant. N'importe quelle image de démarrage GKI de la version Android associée fonctionnera.

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

Le dossier cible est le répertoire de premier niveau de l'arborescence du noyau (le répertoire de travail actuel).

Si vous développez avec la dernière branche de version AOSP, vous pouvez télécharger l'artefact de compilation ramdisk-recovery.img à partir d'une compilation aosp_arm64 sur ci.android.com et l'utiliser comme binaire ramdisk.

Une fois que vous disposez d'un binaire ramdisk et que vous l'avez copié dans gki-ramdisk.lz4 dans le répertoire racine de la compilation du noyau, vous pouvez générer une image de démarrage en exécutant la commande suivante :

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

Si vous utilisez une architecture basée sur x86, remplacez Image par bzImage et aarch64 par 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

Ce fichier se trouve dans le répertoire d'artefacts $KERNEL_ROOT/out/$KERNEL_VERSION/dist.

L'image de démarrage se trouve à l'emplacement out/<kernel branch>/dist/boot.img.