建構核心

本頁詳細介紹了為 Android 裝置建立自訂核心的過程。這些說明將引導您完成選擇正確的來源、建置核心以及將結果嵌入到從 Android 開源專案 (AOSP) 建置的系統映像中的過程。

您可以使用Repo來取得更新的核心原始碼;透過從來源簽出的根目錄執行build/build.sh來建置它們,無需進一步配置。

下載原始碼和建置工具

對於最新的內核,請使用repo下載原始程式碼、工具鍊和建置腳本。某些核心(例如 Pixel 3 核心)需要來自多個 git 儲存庫的來源,而其他核心(例如通用核心)僅需要單一來源。使用repo方法可確保正確的來源目錄設定。

下載對應分支的原始碼:

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

有關可與前面的「repo init」指令一起使用的儲存庫分支 ( BRANCH ) 的列表,請參閱核心分支及其建置系統

有關下載和編譯 Pixel 設備內核的詳細信息,請參閱建置 Pixel Kernels

建構核心

使用 Bazel (Kleaf) 構建

Android 13 引進了使用Bazel建構核心。

要為 aarch64 架構建立 GKI 內核,請查看不早於 Android 13 的 Android Common Kernel 分支,然後執行下列命令:

tools/bazel build //common:kernel_aarch64_dist

若要建立發行版,請執行:

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

此後,內核二進位、模組和相應的映像位於$DIST_DIR目錄中。如果未指定--dist_dir ,請參閱指令的輸出以了解工件的位置。有關詳細信息,請參閱AOSP 上的文檔

使用 build.sh 進行建置(舊版)

對於 Android 12 或更低版本的分支,或沒有 Kleaf 的分支:

build/build.sh

核心二進位檔案、模組和對應的映像位於out/ BRANCH /dist目錄中。

為虛擬設備建置供應商模組

Android 13 引進了使用Bazel (Kleaf) 建立內核,取代了build.sh

若要建置virtual_device的模組,請執行:

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

若要建立發行版,請執行:

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

有關使用 Bazel 構建 Android 內核的更多詳細信息,請參閱。 Kleaf - 使用 Bazel 建立 Android 核心

有關 Kleaf 對各個架構的支援的詳細信息,請參閱Kleaf 對設備和核心的支援

使用 build.sh(舊版)為虛擬設備建立供應商模組

在 Android 12 Cuttlefish 和 Goldfish 中融合,因此它們共享相同的核心: virtual_device 。若要建置該核心的模組,請使用以下建置配置:

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

Android 11 引入了GKI ,它將核心分為 Google 維護的核心映像和供應商維護的模組,它們是單獨建構的。

此範例顯示了核心映像配置:

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

此範例顯示了模組配置(Cuttlefish 和模擬器):

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

運行內核

有多種方法可以運行定制的內核。以下是適合各種開發場景的已知方式。

嵌入到 Android 鏡像建置中

Image.lz4-dtb複製到 AOSP 樹中對應的核心二進位位置並重建啟動映像。

或者,在使用make bootimage (或建立啟動映像的任何其他make命令列)時定義TARGET_PREBUILT_KERNEL變數。所有裝置都支援此變量,因為它是透過device/common/populate-new-device.sh設定的。例如:

export TARGET_PREBUILT_KERNEL=DIST_DIR/Image.lz4-dtb

使用 fastboot 刷新和啟動內核

大多數最新設備都具有引導程式擴展,以簡化生成和引導引導映像的過程。

要啟動核心而不刷新:

adb reboot bootloader
fastboot boot Image.lz4-dtb

使用此方法,核心實際上不會刷新,並且不會在重新引導後持續存在。

在 Cuttlefish 上運行內核

您可以在Cuttlefish 裝置上以您選擇的體系結構執行核心。

若要使用一組特定的核心工件引導 Cuttlefish 設備,請執行cvd start指令並將目標核心工件作為參數。以下範例指令使用common-android14-6.1核心清單中的 arm64 目標的核心工件。

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

有關更多信息,請參閱在 Cuttlefish 上開發內核

客製化內核構建

若要為 Kleaf 建立自訂內核構建,請參閱Kleaf 文件

使用 build.sh 自訂核心建置(舊版)

對於build/build.sh ,建置過程和結果可能會受到環境變數的影響。其中大多數是可選的,每個核心分支都應該帶有適當的預設配置。這裡列出了最常用的。有關完整(且最新)的列表,請參閱build/build.sh

環境變數描述例子
BUILD_CONFIG從初始化建置環境的位置建置設定檔。該位置必須相對於 Repo 根目錄進行定義。預設為build.config
對於通用核心是必需的。
BUILD_CONFIG=common/build.config.gki.aarch64
CC覆寫要使用的編譯器。回退到build.config定義的預設編譯器。 CC=clang
DIST_DIR核心發行版的基本輸出目錄。 DIST_DIR=/path/to/my/dist
OUT_DIR內核建構的基本輸出目錄。 OUT_DIR=/path/to/my/out
SKIP_DEFCONFIG跳過make defconfig SKIP_DEFCONFIG=1
SKIP_MRPROPER跳過make mrproper SKIP_MRPROPER=1

用於本地建置的自訂內核配置

在 Android 14 及更高版本中,您可以使用 defconfig 片段來自訂核心配置。請參閱有關 defconfig 片段的 Kleaf 文件

使用建置配置(舊版)進行本地建置的自訂內核配置

在 Android 13 及更低版本中,請參閱以下內容。

如果您需要定期切換內核配置選項,例如,在處理某個功能時,或者如果您需要為開發目的設定選項,則可以透過維護建置配置的本機修改或副本來實現這種靈活性。

將變數POST_DEFCONFIG_CMDS設定為在通常的make defconfig步驟完成後立即評估的語句。由於build.config檔源自於建置環境,因此可以將build.config中定義的函數作為 post-defconfig 命令的一部分進行呼叫。

一個常見的範例是在開發過程中停用交叉影線核心的連結時間最佳化 (LTO)。雖然 LTO 對已發布的核心有益,但建置時的開銷可能很大。新增至本機build.config下列程式碼片段在使用build/build.sh時永久停用 LTO。

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)
}

識別核心版本

您可以從兩個來源確定要建置的正確版本:AOSP 樹和系統映像。

AOSP 樹的核心版本

AOSP 樹包含預先建置的核心版本。 git 日誌顯示正確的版本作為提交訊息的一部分:

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

如果 git 日誌中未列出核心版本,請從系統映像中取得它,如下所述。

系統映像中的核心版本

若要確定係統映像中使用的核心版本,請針對核心檔案執行以下命令:

file kernel

對於Image.lz4-dtb文件,運行:

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

建立啟動映像

可以使用核心建構環境建構啟動映像。

使用init_boot為裝置建立啟動映像

對於具有init_boot分割區的設備,啟動映像與核心一起建置。 initramfs映像未嵌入到啟動映像中。

例如,使用 Kleaf,您可以使用下列命令建立 GKI 啟動映像:

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

使用build/build.sh (舊版),您可以使用以下命令建立 GKI 啟動映像:

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

GKI 啟動映像位於$DIST_DIR中。

為沒有init_boot的裝置建立啟動映像(舊版)

對於沒有init_boot分割區的設備,您需要一個 ramdisk 二進位文件,您可以透過下載 GKI 啟動映像並解壓縮它來取得它。相關 Android 版本中的任何 GKI 啟動映像檔都可以使用。

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

目標資料夾是內核樹的頂級目錄(當前工作目錄)。

如果您使用 AOSP main 進行開發,則可以從ci.android.com上的 aosp_arm64 建置下載ramdisk-recovery.img建置工件,並將其用作 ramdisk 二進位檔案。

當您擁有 ramdisk 二進位檔案並將其複製到核心建置根目錄中的gki-ramdisk.lz4時,您可以透過執行以下命令來產生引導映像:

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

如果您使用基於 x86 的架構,請將Image替換為bzImage ,將aarch64替換為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

檔案位於工件目錄$KERNEL_ROOT/out/$KERNEL_VERSION/dist中。

啟動映像位於out/<kernel branch>/dist/boot.img