Cómo compilar kernels

En esta página, se detalla el proceso de compilación de kernels personalizados para dispositivos Android. Estas instrucciones te guiarán en el proceso de seleccionar las fuentes correctas, compilar el kernel e incorporar los resultados en una imagen del sistema compilada a partir del Proyecto de código abierto de Android (AOSP).

Mediante Repo, puedes adquirir las fuentes de kernel más recientes y compilarlas sin realizar una configuración adicional. Para hacerlo, ejecuta build/build.sh desde la raíz del resultado de tu fuente.

Cómo descargar fuentes y herramientas de compilación

En el caso de los kernels más recientes, usa repo para descargar las fuentes, la cadena de herramientas y las secuencias de comandos de compilación. Algunos kernels (por ejemplo, los de Pixel 3) requieren fuentes de varios repositorios de Git, mientras que otros (por ejemplo, los comunes) solo requieren una fuente. Puedes usar repo para garantizar una configuración correcta del directorio del código fuente.

Descarga las fuentes de la rama correcta:

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

Para obtener una lista de ramas del repo (BRANCH) que puedes usar con el comando “repo init” anterior, consulta Ramas de kernel y sus sistemas de compilación.

Si deseas obtener información detallada para descargar o compilar kernels para dispositivos Pixel, consulta Cómo compilar kernels para Pixel.

Cómo compilar el kernel

Cómo compilar con Bazel (Kleaf)

Android 13 introdujo la compilación de kernels con Bazel.

Para compilar el kernel de GKI para la arquitectura aarch64, consulta una rama de kernel común de Android a partir de Android 13 y, luego, ejecuta el siguiente comando:

tools/bazel build //common:kernel_aarch64_dist

Para crear una distribución, ejecuta el siguiente comando:

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

Luego, los objetos binarios, los módulos y las imágenes correspondientes del kernel se encuentran en el directorio $DIST_DIR. Si no se especifica --dist_dir, consulta el resultado del comando para obtener la ubicación de los artefactos. Para obtener detalles, consulta la documentación sobre AOSP.

Cómo compilar con build.sh (heredado)

Para ramas a partir de Android 12 o versiones anteriores, o ramas sin Kleaf:

build/build.sh

El objeto binario, los módulos y la imagen correspondiente del kernel se encuentran en el directorio out/BRANCH/dist.

Cómo compilar módulos de proveedor para el dispositivo virtual

Android 13 introdujo la compilación de kernels con Bazel (Kleaf) y reemplaza a build.sh.

Para compilar los módulos de virtual_device, ejecuta lo siguiente:

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

Para crear una distribución, ejecuta el siguiente comando:

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

Para obtener más detalles sobre la compilación de kernels de Android con Bazel, consulta Kleaf: Cómo compilar kernels de Android con Bazel.

Si deseas obtener detalles sobre la compatibilidad con Kleaf de arquitecturas individuales, consulta Compatibilidad con Kleaf para dispositivos y kernels.

Cómo compilar módulos de proveedor para el dispositivo virtual con build.sh (heredado)

En Android 12, Cuttlefish y Goldfish convergen, por lo que comparten el mismo kernel: virtual_device. Para compilar los módulos de ese kernel, usa la siguiente configuración de compilación:

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

Android 11 introdujo GKI, que separa el kernel en una imagen de kernel que mantiene Google y los módulos que mantiene el proveedor, compilados por separado.

En este ejemplo, se muestra la configuración de una imagen de kernel:

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

En este ejemplo, se muestra la configuración de un módulo (Cuttlefish y Emulator):

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

Cómo ejecutar el kernel

Hay varias maneras de ejecutar un kernel de compilación personalizada. Los siguientes son métodos conocidos y apropiados de distintos entornos de desarrollo.

Cómo incorporarlo en la compilación de imágenes de Android

Copia Image.lz4-dtb en la ubicación correspondiente del objeto binario del kernel en el árbol de AOSP y vuelve a compilar la imagen de arranque.

También puedes definir la variable TARGET_PREBUILT_KERNEL mientras usas make bootimage (o cualquier otra línea de comandos de make que compile una imagen de arranque). Esta variable es compatible con todos los dispositivos, ya que se configura a través de device/common/populate-new-device.sh. Por ejemplo:

export TARGET_PREBUILT_KERNEL=DIST_DIR/Image.lz4-dtb

Cómo escribir kernels en la memoria flash e iniciarlos con fastboot

Los dispositivos más recientes tienen una extensión de bootloader que optimiza el proceso de generación y de inicio de una imagen de arranque.

Para iniciar el kernel sin escribirlo en la memoria flash, haz lo siguiente:

adb reboot bootloader
fastboot boot Image.lz4-dtb

Mediante este método, el kernel no se escribe en la memoria flash y no persistirá después de un reinicio.

Cómo ejecutar kernels en Cuttlefish

Puedes ejecutar kernels en la arquitectura que elijas en dispositivos Cuttlefish.

Para iniciar un dispositivo Cuttlefish con un conjunto particular de artefactos del kernel, ejecuta el comando cvd start con los artefactos del kernel de destino como parámetros. El siguiente comando de ejemplo usa artefactos del kernel para el destino arm64 desde el manifiesto 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

Para obtener más información, consulta Cómo desarrollar kernels en Cuttlefish.

Cómo personalizar la compilación del kernel

Si quieres personalizar las compilaciones del kernel para las compilaciones de Kleaf, consulta la documentación de Kleaf.

Cómo personalizar la compilación del kernel con build.sh (heredado)

Para build/build.sh, el proceso de compilación y el resultado pueden verse influenciados por las variables de entorno. La mayoría son opcionales y cada rama de kernel debería incluir una configuración predeterminada apropiada. Las más utilizadas se incluyen en esta lista. Para ver la lista completa (y actualizada), consulta build/build.sh.

Variable de entorno Descripción Ejemplo
BUILD_CONFIG Archivo de configuración de compilación desde donde se inicializa el entorno de compilación. La ubicación debe definirse según el directorio raíz del repositorio. La configuración predeterminada es build.config.
Es obligatorio para kernels comunes.
BUILD_CONFIG=common/build.config.gki.aarch64
CC Anula el compilador que se utilizará. Recurre al compilador predeterminado definido por build.config. CC=clang
DIST_DIR Directorio de salida base para la distribución de kernel DIST_DIR=/path/to/my/dist
OUT_DIR Directorio de salida base para la compilación de kernel OUT_DIR=/path/to/my/out
SKIP_DEFCONFIG Omitir make defconfig SKIP_DEFCONFIG=1
SKIP_MRPROPER Omitir make mrproper SKIP_MRPROPER=1

Cómo configurar el kernel de forma personalizada para compilaciones locales

En Android 14 y versiones posteriores, puedes usar fragmentos de defconfig para personalizar las configuraciones del kernel. Consulta la documentación de Kleaf sobre los fragmentos de defconfig.

Cómo configurar el kernel de forma personalizada para configuraciones de compilación (heredado)

En Android 13 y versiones anteriores, consulta lo siguiente.

Si necesitas cambiar una opción de la configuración de kernel con frecuencia (por ejemplo, cuando trabajas en una función) o si precisas que se configure una opción con fines de desarrollo, puedes mantener una versión local o copiar la configuración de la compilación para lograr esa flexibilidad.

Establece la variable POST_DEFCONFIG_CMDS en una afirmación que se evalúe una vez que termine el paso make defconfig habitual. Como los archivos build.config se originan en el entorno de compilación, se puede llamar a las funciones definidas en build.config como parte de los comandos posteriores a la desconfiguración.

Un ejemplo común consiste en inhabilitar la optimización del tiempo de vinculación (LTO) para kernels de crosshatch durante el desarrollo. Aunque LTO ofrece ventajas para los kernels lanzados, el tiempo de compilación puede ser considerable. Si agregas el siguiente fragmento al build.config local, se inhabilitará LTO de manera persistente cuando uses 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)
}

Cómo identificar las versiones de kernel

Puedes identificar la versión correcta para compilar a partir de dos fuentes: el árbol de AOSP y la imagen del sistema.

Versión de kernel del árbol de AOSP

El árbol de AOSP incluye versiones de kernel compiladas previamente. El registro de Git muestra la versión correcta como parte del mensaje de confirmación:

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

Si la versión de kernel no aparece en el registro de Git, obtenla desde la imagen del sistema, como se describe a continuación.

Versión de kernel de la imagen del sistema

Para determinar la versión de kernel que se usa en una imagen del sistema, ejecuta el siguiente comando en el archivo de kernel:

file kernel

En el caso de los archivos Image.lz4-dtb, ejecuta lo siguiente:

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

Cómo compilar una imagen de arranque

Es posible compilar una imagen de arranque usando el entorno de compilación del kernel.

Cómo compilar una imagen de arranque para dispositivos con init_boot

Para dispositivos con la partición init_boot, la imagen de arranque se compila junto con el kernel. La imagen initramfs no está incorporada a la imagen de arranque.

Por ejemplo, con Kleaf, puedes compilar la imagen de arranque de GKI con lo siguiente:

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

Con build/build.sh (heredado), puedes compilar la imagen de arranque de GKI con lo siguiente:

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

La imagen de arranque de GKI se encuentra en $DIST_DIR.

Cómo compilar una imagen de arranque para dispositivos sin init_boot (heredado)

Para dispositivos sin la partición init_boot, necesitas un objeto binario ramdisk, que puedes obtener si descargas una imagen de arranque de GKI y la desempaquetas. Cualquier imagen de arranque de GKI de la versión de Android asociada funcionará.

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

La carpeta de destino es el directorio de nivel superior del árbol del kernel (directorio de trabajo actual).

Si estás desarrollando con la rama principal de AOSP, puedes descargar el artefacto de compilación ramdisk-recovery.img de una compilación aosp_arm64 en ci.android.com y usarlo como objeto binario de ramdisk.

Si tienes un objeto binario de ramdisk y lo copias en gki-ramdisk.lz4, en el directorio raíz de la compilación del kernel, puedes generar una imagen de arranque ejecutando lo siguiente:

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 estás trabajando con una arquitectura que se basa en x86, reemplaza Image por bzImage y aarch64 por 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

Ese archivo se encuentra en el directorio de artefactos $KERNEL_ROOT/out/$KERNEL_VERSION/dist.

La imagen de arranque se encuentra en out/<kernel branch>/dist/boot.img.