Criar kernels

Esta página detalha o processo de criação de kernels personalizados para dispositivos Android. As instruções a seguir oferecem orientação sobre o processo para selecionar as origens certas, criar o kernel e incorporar os resultados em uma imagem do sistema criada usando o Android Open Source Project (AOSP).

Você pode conseguir origens de kernel mais recentes usando o Repo. Crie sem precisar de mais configurações executando build/build.sh pela raiz do checkout da origem.

Baixar origens e ferramentas de build

Para kernels recentes, use o repo para fazer o download de origens, conjuntos de ferramentas e scripts de criação. Alguns kernels (como os do Pixel 3) exigem origens de vários repositórios git, enquanto outros (como os comuns) exigem apenas uma origem. O uso da abordagem repo garante uma configuração correta do diretório de origem.

Baixe as origens para a ramificação adequada:

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

Para conferir uma lista de ramificações do Repo (BRANCH) que podem ser usadas com o comando "repo init" anterior, consulte Ramificações de kernel e sistemas de build delas.

Para mais detalhes sobre como baixar e compilar kernels para dispositivos Pixel, consulte Como criar kernels do Pixel.

Criar o kernel

Criar com o Bazel (Kleaf)

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

Para criar o kernel de GKI para a arquitetura aarch64, faça o checkout de uma ramificação do kernel comum do Android 13 ou mais recente e execute o seguinte comando:

tools/bazel build //common:kernel_aarch64_dist

Para criar uma distribuição, execute o seguinte:

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

Depois disso, o binário, os módulos e as imagens correspondentes do kernel vão estar localizados no diretório $DIST_DIR. Se --dist_dir não estiver especificado, confira a saída do comando para localizar os artefatos. Para mais detalhes, consulte a documentação do AOSP.

Criar com build.sh (legado)

Para ramificações no Android 12 ou em versões anteriores OU ramificações sem Kleaf:

build/build.sh

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

Criar os módulos de fornecedores para o dispositivo virtual

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

Para criar 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 o seguinte:

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

Para saber mais, consulte Kleaf: como criar kernels do Android com o Bazel.

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

Criar os módulos de fornecedores para o dispositivo virtual com build.sh (legado)

No Android 12, o Cuttlefish e o Goldfish convergem, então eles compartilham o mesmo kernel, virtual_device. Para criar os módulos desse kernel, use esta configuração do build:

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

O Android 11 introduziu a GKI, que separa o kernel em uma imagem dele mantida pelo Google e em módulos mantidos pelo fornecedor, que são criados 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

Executar o kernel

Há várias maneiras de executar um kernel personalizado. Abaixo, apresentamos as maneiras conhecidas que são adequadas para vários cenários de desenvolvimento.

Incorporar no build da imagem do Android

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

Outra alternativa é definir a variável TARGET_PREBUILT_KERNEL ao usar make bootimage (ou qualquer outra linha de comando make que crie uma imagem de inicialização). Essa variável é compatível com todos os dispositivos porque é configurada por device/common/populate-new-device.sh. Exemplos:

export TARGET_PREBUILT_KERNEL=DIST_DIR/Image.lz4-dtb

Atualizar e inicializar kernels com fastboot

Os dispositivos mais recentes têm uma extensão do carregador de inicialização para otimizar o processo que gera e inicia uma imagem de inicialização.

Para inicializar o kernel sem realizar uma atualização flash:

adb reboot bootloader
fastboot boot Image.lz4-dtb

Com o uso desse método, uma atualização flash não é realizada no kernel e não persiste durante a reinicialização.

Executar kernels no Cuttlefish

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

Para inicializar um dispositivo Cuttlefish com um conjunto específico de artefatos kernel, execute o comando cvd create com os artefatos kernel alvo como parâmetros. O seguinte exemplo de comando usa artefatos kernel para um arm64 alvo do manifesto do kernel 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

Para mais informações, consulte Desenvolver kernels no Cuttlefish.

Personalizar a criação do kernel

Para personalizar os builds do kernel para builds do Kleaf, consulte a documentação do Kleaf.

Personalizar o build do kernel com build.sh (legado)

Para build/build.sh, o processo de build e o resultado podem ser influenciados por variáveis de ambiente. A maior parte das variáveis é opcional, e cada ramificação do kernel apresenta uma configuração padrão adequada. As mais usadas estão listadas aqui. Para uma lista completa (e atualizada), consulte build/build.sh.

Variável de ambiente Descrição Exemplo
BUILD_CONFIG Cria o arquivo de configuração a partir do qual você inicializa o ambiente de build. O local precisa ser definido em relação ao diretório raiz do Repo. O valor padrão é build.config.
Obrigatório para kernels comuns.
BUILD_CONFIG=common/build.config.gki.aarch64
CC Substitui o compilador a ser usado. Volta para o compilador padrão definido pelo 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 o build do kernel. OUT_DIR=/path/to/my/out
SKIP_DEFCONFIG Pula a make defconfig SKIP_DEFCONFIG=1
SKIP_MRPROPER Pula make mrproper SKIP_MRPROPER=1

Configuração personalizada do kernel para builds locais

No Android 14 e em versões mais recentes, é possível usar fragmentos defconfig para personalizar configurações do kernel. Consulte a documentação do Kleaf sobre fragmentos defconfig.

.

Configuração personalizada do kernel com configuração do build (legado)

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

Se você precisar trocar regularmente uma opção de configuração do kernel, por exemplo, quando estiver trabalhando em um recurso ou se precisar configurar uma opção para fins de desenvolvimento, poderá conseguir essa flexibilidade mantendo uma modificação ou cópia local da configuração de build.

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

Um exemplo comum é desativar a Otimização de tempo de vinculação (LTO, na sigla em inglês) para kernels crosshatch durante o desenvolvimento. Embora a LTO seja benéfica para os kernels lançados, a sobrecarga no tempo de build pode ser significativa. O snippet abaixo, incluído no build.config local, sempre desativa a LTO 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 criar usando duas origens: a árvore AOSP e a imagem do sistema.

Versão do kernel da árvore AOSP

A árvore AOSP contém versões pré-criadas do kernel. 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, consiga-a pela 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

Criar uma imagem de inicialização

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

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

Para dispositivos com a partição init_boot, a imagem de inicialização é criada com o kernel. A imagem initramfs não é incorporada à imagem de inicialização.

Por exemplo, com o Kleaf, é possível criar a imagem de inicialização GKI com:

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

Com build/build.sh (legado), é possível criar a imagem de inicialização GKI com:

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

A imagem de inicialização GKI fica no diretório $DIST_DIR.

Criar 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 do ramdisk, que pode ser acessado fazendo o download e a descompactação de uma imagem de inicialização GKI. Qualquer imagem de inicialização GKI da versão associada do Android vai 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 de kernel (o diretório de trabalho atual).

Se você estiver desenvolvendo com o AOSP principal, faça o download do artefato ramdisk-recovery.img de um build aosp_arm64 em ci.android.com e use-o como seu binário do ramdisk.

Depois de conseguir um binário do ramdisk e copiá-lo para gki-ramdisk.lz4 no diretório raiz do build do kernel, execute o seguinte comando para gerar uma imagem de inicialização:

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ê está trabalhando com uma 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 artefatos $KERNEL_ROOT/out/$KERNEL_VERSION/dist.

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