Compilar kernels

Esta página detalha o processo de construção de kernels personalizados para dispositivos Android. Estas instruções orientam você no processo de seleção das fontes corretas, criação do kernel e incorporação dos resultados em uma imagem do sistema criada a partir do Android Open Source Project (AOSP).

Você pode adquirir fontes de kernel mais recentes usando Repo ; construa-os sem configuração adicional executando build/build.sh na raiz do seu checkout de origem.

Baixe fontes e ferramentas de construção

Para kernels recentes, use repo para baixar as fontes, o conjunto de ferramentas e construir scripts. Alguns kernels (por exemplo, os kernels do Pixel 3) requerem fontes de vários repositórios git, enquanto outros (por exemplo, os kernels comuns) requerem apenas uma única fonte. Usar a abordagem repo garante uma configuração correta do diretório de origem.

Baixe as fontes para o branch apropriado:

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

Para obter uma lista de ramificações do repositório ( BRANCH ) que podem ser usadas com o comando `repo init` anterior, consulte ramificações do kernel e seus sistemas de construção .

Para obter detalhes sobre como baixar e compilar kernels para dispositivos Pixel, consulte Construindo Kernels Pixel .

Construa o kernel

Construir com Bazel (Kleaf)

O Android 13 introduziu a construção de kernels com Bazel .

Para construir o kernel GKI para a arquitetura aarch64, verifique uma ramificação do Android Common Kernel não anterior ao Android 13 e execute o seguinte comando:

tools/bazel build //common:kernel_aarch64_dist

Para criar uma distribuição, execute:

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

Depois disso, o binário do kernel, os módulos e as imagens correspondentes estão localizados no diretório $DIST_DIR . Se --dist_dir não for especificado, consulte a saída do comando para obter a localização dos artefatos. Para obter detalhes, consulte a documentação no AOSP .

Construir com build.sh (legado)

Para filiais com Android 12 ou inferior, OU filiais sem Kleaf:

build/build.sh

O binário do kernel, os módulos e a imagem correspondente estão localizados no diretório out/ BRANCH /dist .

Crie os módulos do fornecedor para o dispositivo virtual

O Android 13 introduziu a construção de kernels com Bazel (Kleaf), substituindo build.sh .

Para construir os módulos do virtual_device , execute:

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

Para criar uma distribuição, execute:

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

Para obter mais detalhes sobre a construção de kernels Android com Bazel, consulte. Kleaf - Construindo Kernels Android com Bazel .

Para obter detalhes sobre o suporte do Kleaf para arquiteturas individuais, consulte Suporte do Kleaf para dispositivos e kernels .

Crie os módulos do fornecedor para o dispositivo virtual com build.sh (legado)

No Android 12, Cuttlefish e Goldfish convergem, então compartilham o mesmo kernel: virtual_device . Para construir os módulos desse kernel, use esta configuração de construção:

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

O Android 11 introduziu o GKI , que separa o kernel em uma imagem de kernel mantida pelo Google e módulos mantidos pelo fornecedor, que são construídos separadamente.

Este exemplo mostra uma configuração de imagem do kernel:

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

Este exemplo mostra uma configuração de módulo (Cuttlefish e Emulator):

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

Execute o kernel

Existem várias maneiras de executar um kernel personalizado. A seguir estão formas conhecidas adequadas para vários cenários de desenvolvimento.

Incorporar na construção de imagem do Android

Copie Image.lz4-dtb para o respectivo local binário do kernel na árvore AOSP e reconstrua a imagem de inicialização.

Como alternativa, defina a variável TARGET_PREBUILT_KERNEL ao usar make bootimage (ou qualquer outra linha de comando make que construa uma imagem de inicialização). Esta variável é suportada por todos os dispositivos conforme configurada via device/common/populate-new-device.sh . Por exemplo:

export TARGET_PREBUILT_KERNEL=DIST_DIR/Image.lz4-dtb

Kernels de flash e inicialização com fastboot

Os dispositivos mais recentes possuem uma extensão de bootloader para agilizar o processo de geração e inicialização de uma imagem de inicialização.

Para inicializar o kernel sem piscar:

adb reboot bootloader
fastboot boot Image.lz4-dtb

Usando este método, o kernel não é realmente atualizado e não persistirá durante uma reinicialização.

Execute kernels em Choco

Você pode executar kernels na arquitetura de sua escolha em dispositivos Cuttlefish .

Para inicializar um dispositivo Cuttlefish com um conjunto específico de artefatos do kernel , execute o comando cvd start com os artefatos do kernel de destino como parâmetros. O comando de exemplo a seguir usa artefatos do kernel para um destino arm64 do manifesto do 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 obter mais informações, consulte Desenvolver kernels no Cuttlefish .

Personalize a construção do kernel

Para personalizar as compilações do kernel para compilações do Kleaf, consulte a documentação do Kleaf .

Personalize a construção do kernel com build.sh (legado)

Para build/build.sh , o processo de construção e o resultado podem ser influenciados por variáveis ​​de ambiente. A maioria deles é opcional e cada ramificação do kernel deve vir com uma configuração padrão adequada. Os mais usados ​​estão listados aqui. Para obter uma lista completa (e atualizada), consulte build/build.sh .

Variável de ambiente Descrição Exemplo
BUILD_CONFIG Arquivo de configuração de compilação de onde você inicializa o ambiente de compilação. O local deve ser definido em relação ao diretório raiz do Repo. O padrão é build.config .
Obrigatório para kernels comuns.
BUILD_CONFIG=common/build.config.gki.aarch64
CC Substitua o compilador a ser usado. Volta para o compilador padrão definido por build.config . CC=clang
DIST_DIR Diretório de saída base para a distribuição do kernel. DIST_DIR=/path/to/my/dist
OUT_DIR Diretório de saída base para a construção do kernel. OUT_DIR=/path/to/my/out
SKIP_DEFCONFIG Ignorar make defconfig SKIP_DEFCONFIG=1
SKIP_MRPROPER Pular make mrproper SKIP_MRPROPER=1

Configuração personalizada do kernel para compilações locais

No Android 14 e superior, você pode usar fragmentos defconfig para personalizar as configurações do kernel. veja a documentação do Kleaf sobre fragmentos defconfig .

Configuração personalizada do kernel para compilações locais com configurações de compilação (legado)

No Android 13 e versões anteriores, consulte o seguinte.

Se você precisar alternar uma opção de configuração do kernel regularmente, por exemplo, ao trabalhar em um recurso, ou se precisar que uma opção seja definida para fins de desenvolvimento, você poderá obter essa flexibilidade mantendo uma modificação local ou cópia da configuração de compilação.

Defina a variável POST_DEFCONFIG_CMDS como uma instrução que é avaliada logo após a conclusão da etapa usual make defconfig . Como os arquivos build.config são originados no ambiente de construção, as funções definidas em build.config podem ser chamadas como parte dos comandos pós-defconfig.

Um exemplo comum é desabilitar a otimização de tempo de link (LTO) para kernels hachurados durante o desenvolvimento. Embora o LTO seja benéfico para kernels lançados, a sobrecarga no momento da construção pode ser significativa. O trecho a seguir adicionado ao build.config local desativa o LTO persistentemente ao usar 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)
}

Identificar versões do kernel

Você pode identificar a versão correta para construir a partir de duas fontes: a árvore AOSP e a imagem do sistema.

Versão do kernel da árvore AOSP

A árvore AOSP contém versões de kernel pré-construídas. O log do git revela a versão correta como parte da mensagem de commit:

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

Se a versão do kernel não estiver listada no log do git, obtenha-a na imagem do sistema, conforme descrito abaixo.

Versão do kernel da imagem do sistema

Para determinar a versão do kernel usada em uma imagem do sistema, execute o seguinte comando no arquivo do kernel:

file kernel

Para arquivos Image.lz4-dtb , execute:

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

Crie uma imagem de inicialização

É possível construir uma imagem de inicialização usando o ambiente de construção do kernel.

Crie uma imagem de inicialização para dispositivos com init_boot

Para dispositivos com a partição init_boot , a imagem de inicialização é construída junto com o kernel. A imagem initramfs não está incorporada na imagem de inicialização.

Por exemplo, com o Kleaf, você pode criar a imagem de inicialização do GKI com:

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

Com build/build.sh (legado), você pode construir a imagem de inicialização do GKI com:

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

A imagem de inicialização do GKI está localizada em $DIST_DIR .

Crie uma imagem de inicialização para dispositivos sem init_boot (legado)

Para dispositivos sem a partição init_boot , você precisa de um binário ramdisk, que pode ser obtido baixando uma imagem de inicialização GKI e descompactando-a. Qualquer imagem de inicialização GKI da versão Android associada funcionará.

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

A pasta de destino é o diretório de nível superior da árvore do kernel (o diretório de trabalho atual).

Se você estiver desenvolvendo com AOSP principal, poderá baixar o artefato de compilação ramdisk-recovery.img de uma compilação aosp_arm64 em ci.android.com e usá-lo como seu binário ramdisk.

Quando você tem um binário ramdisk e o copiou para gki-ramdisk.lz4 no diretório raiz da compilação do kernel, você pode gerar uma imagem de inicialização executando:

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 você estiver trabalhando com arquitetura baseada em x86, substitua Image por bzImage e 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

Esse arquivo está localizado no diretório de artefato $KERNEL_ROOT/out/$KERNEL_VERSION/dist .

A imagem de inicialização está localizada em out/<kernel branch>/dist/boot.img .