Tạo nhân

Trang này trình bày chi tiết quy trình tạo nhân tuỳ chỉnh cho các thiết bị Android. Các hướng dẫn này sẽ hướng dẫn bạn quy trình chọn nguồn phù hợp, tạo nhân và nhúng kết quả vào một hình ảnh hệ thống được tạo từ Dự án nguồn mở Android (AOSP).

Tải các nguồn và công cụ bản dựng xuống

Đối với các nhân gần đây, hãy sử dụng repo để tải các nguồn, chuỗi công cụ và tập lệnh bản dựng xuống. Một số nhân (ví dụ: nhân Pixel 3) yêu cầu các nguồn từ nhiều kho lưu trữ git, trong khi những nhân khác (ví dụ: nhân chung) chỉ yêu cầu một nguồn duy nhất. Việc sử dụng phương pháp repo đảm bảo thiết lập đúng thư mục nguồn.

Tải các nguồn xuống cho nhánh thích hợp:

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

Để xem danh sách các nhánh repo (BRANCH) có thể dùng với lệnh `repo init` trước đó, hãy xem Các nhánh kernel và hệ thống xây dựng của chúng.

Để biết thông tin chi tiết về cách tải xuống và biên dịch nhân cho thiết bị Pixel, hãy xem phần Tạo nhân Pixel.

Tạo nhân

Tạo bằng Bazel (Kleaf)

Android 13 giới thiệu việc xây dựng các nhân bằng Bazel.

Để tạo bản phân phối cho nhân GKI cho kiến trúc aarch64, hãy kiểm tra một nhánh Nhân chung Android không sớm hơn Android 13 rồi chạy lệnh sau:

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

Sau đó, tệp nhị phân của nhân, các mô-đun và hình ảnh tương ứng sẽ nằm trong thư mục $DIST_DIR. Nếu bạn không chỉ định --destdir, hãy xem đầu ra của lệnh để biết vị trí của cấu phần phần mềm. Để biết thông tin chi tiết, hãy tham khảo tài liệu về AOSP.

Tạo bằng build.sh (phiên bản cũ)

Đối với các nhánh ở Android 12 trở xuống HOẶC các nhánh không có Kleaf:

build/build.sh

Tệp nhị phân nhân, các mô-đun và hình ảnh tương ứng nằm trong thư mục out/BRANCH/dist.

Tạo các mô-đun của nhà cung cấp cho thiết bị ảo

Android 13 giới thiệu việc xây dựng các hạt nhân bằng Bazel (Kleaf), thay thế build.sh.

Để tạo bản phân phối cho các mô-đun của virtual_device, hãy chạy:

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

Để biết thêm thông tin chi tiết về cách tạo các nhân Android bằng Bazel, hãy xem. Kleaf – Xây dựng nhân Android bằng Bazel.

Để biết thông tin chi tiết về hoạt động hỗ trợ Kleaf cho từng cấu trúc, hãy xem phần Kleaf hỗ trợ cho thiết bị và nhân.

Tạo các mô-đun của nhà cung cấp cho thiết bị ảo bằng build.sh (cũ)

Trong Android 12, Cuttlefish và Goldfish hội tụ, vì vậy chúng dùng chung một nhân: virtual_device. Để tạo các mô-đun của nhân đó, hãy sử dụng cấu hình bản dựng này:

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

Android 11 đã giới thiệu GKI, giúp tách nhân thành một hình ảnh nhân do Google duy trì và các mô-đun do nhà cung cấp duy trì, được tạo riêng biệt.

Ví dụ này cho thấy cấu hình hình ảnh của nhân:

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

Ví dụ này cho thấy cấu hình mô-đun (Cuttlefish và Trình mô phỏng):

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

Chạy nhân

Có nhiều cách để chạy một nhân được tạo tuỳ chỉnh. Sau đây là những cách đã biết phù hợp với nhiều trường hợp phát triển.

Nhúng vào bản dựng hình ảnh Android

Sao chép Image.lz4-dtb vào vị trí nhị phân nhân tương ứng trong cây AOSP và tạo lại hình ảnh khởi động.

Ngoài ra, hãy xác định biến TARGET_PREBUILT_KERNEL trong khi sử dụng make bootimage (hoặc bất kỳ dòng lệnh make nào khác tạo ra một hình ảnh khởi động). Tất cả các thiết bị đều hỗ trợ biến này vì biến này được thiết lập thông qua device/common/populate-new-device.sh. Ví dụ:

export TARGET_PREBUILT_KERNEL=DIST_DIR/Image.lz4-dtb

Nạp và khởi động nhân bằng fastboot

Hầu hết các thiết bị gần đây đều có một tiện ích trình tải khởi động để đơn giản hoá quy trình tạo và khởi động một hình ảnh khởi động.

Cách khởi động nhân mà không cần flash:

adb reboot bootloader
fastboot boot Image.lz4-dtb

Khi sử dụng phương thức này, nhân thực tế sẽ không được flash và sẽ không duy trì sau khi khởi động lại.

Chạy các nhân trên Cuttlefish

Bạn có thể chạy các nhân trong cấu trúc mà bạn chọn trên thiết bị Cuttlefish.

Để khởi động một thiết bị Cuttlefish bằng một nhóm hiện vật hạt nhân cụ thể, hãy chạy lệnh cvd create với hiện vật hạt nhân mục tiêu làm tham số. Lệnh ví dụ sau đây sử dụng các cấu phần phần mềm của nhân cho mục tiêu arm64 từ tệp kê khai nhân 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

Để biết thêm thông tin, hãy xem phần Phát triển nhân trên Cuttlefish.

Tuỳ chỉnh bản dựng kernel

Để tuỳ chỉnh bản dựng kernel cho bản dựng Kleaf, hãy xem tài liệu về Kleaf.

Tuỳ chỉnh bản dựng kernel bằng build.sh (phiên bản cũ)

Đối với build/build.sh, quy trình và kết quả của bản dựng có thể chịu ảnh hưởng của các biến môi trường. Hầu hết các nhánh này đều không bắt buộc và mỗi nhánh kernel đều phải có một cấu hình mặc định phù hợp. Những phím tắt thường dùng nhất được liệt kê ở đây. Để xem danh sách đầy đủ (và mới nhất), hãy tham khảo build/build.sh.

Biến môi trường Mô tả Ví dụ
BUILD_CONFIG Tạo tệp cấu hình bản dựng từ nơi bạn khởi động môi trường bản dựng. Vị trí phải được xác định tương ứng với thư mục gốc Repo. Giá trị mặc định là build.config.
Bắt buộc đối với các nhân chung.
BUILD_CONFIG=common/build.config.gki.aarch64
CC Ghi đè trình biên dịch sẽ được dùng. Quay lại trình biên dịch mặc định do build.config xác định. CC=clang
DIST_DIR Thư mục đầu ra cơ sở cho bản phân phối hạt nhân. DIST_DIR=/path/to/my/dist
OUT_DIR Thư mục đầu ra cơ sở cho bản dựng hạt nhân. OUT_DIR=/path/to/my/out
SKIP_DEFCONFIG Bỏ qua make defconfig SKIP_DEFCONFIG=1
SKIP_MRPROPER Bỏ qua make mrproper SKIP_MRPROPER=1

Cấu hình kernel tuỳ chỉnh cho các bản dựng cục bộ

Trong Android 14 trở lên, bạn có thể dùng các mảnh defconfig để tuỳ chỉnh cấu hình hạt nhân. Hãy xem tài liệu Kleaf về các mảnh defconfig.

Cấu hình kernel tuỳ chỉnh cho các bản dựng cục bộ bằng cấu hình bản dựng (cũ)

Trong Android 13 trở xuống, hãy xem phần sau.

Nếu cần chuyển đổi thường xuyên một lựa chọn cấu hình nhân, chẳng hạn như khi làm việc trên một tính năng, hoặc nếu cần đặt một lựa chọn cho mục đích phát triển, bạn có thể đạt được sự linh hoạt đó bằng cách duy trì một bản sao hoặc bản sửa đổi cục bộ của cấu hình bản dựng.

Đặt biến POST_DEFCONFIG_CMDS thành một câu lệnh được đánh giá ngay sau khi bước make defconfig thông thường hoàn tất. Vì các tệp build.config được đưa vào môi trường xây dựng, nên các hàm được xác định trong build.config có thể được gọi trong các lệnh sau defconfig.

Một ví dụ phổ biến là tắt tính năng tối ưu hoá thời gian liên kết (LTO) cho các hạt nhân crosshatch trong quá trình phát triển. Mặc dù LTO có lợi cho các nhân đã phát hành, nhưng chi phí phát sinh tại thời điểm tạo có thể đáng kể. Đoạn mã sau đây được thêm vào build.config cục bộ sẽ vô hiệu hoá LTO một cách liên tục khi sử dụng 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)
}

Xác định phiên bản nhân

Bạn có thể xác định phiên bản chính xác để tạo từ 2 nguồn: cây AOSP và hình ảnh hệ thống.

Phiên bản kernel trong cây AOSP

Cây AOSP chứa các phiên bản hạt nhân được tạo sẵn. Nhật ký git cho thấy phiên bản chính xác trong phần thông báo cam kết:

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

Nếu phiên bản kernel không có trong nhật ký git, hãy lấy phiên bản đó từ hình ảnh hệ thống, như mô tả bên dưới.

Phiên bản kernel trong hình ảnh hệ thống

Để xác định phiên bản kernel được dùng trong một hình ảnh hệ thống, hãy chạy lệnh sau đối với tệp kernel:

file kernel

Đối với tệp Image.lz4-dtb, hãy chạy:

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

Tạo một hình ảnh khởi động

Bạn có thể tạo một hình ảnh khởi động bằng môi trường tạo kernel.

Tạo hình ảnh khởi động cho các thiết bị có init_boot

Đối với các thiết bị có phân vùng init_boot, hình ảnh khởi động được tạo cùng với nhân. Hình ảnh initramfs không được nhúng trong hình ảnh khởi động.

Ví dụ: với Kleaf, bạn có thể tạo hình ảnh khởi động GKI bằng cách:

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

Với build/build.sh (cũ), bạn có thể tạo hình ảnh khởi động GKI bằng cách:

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

Hình ảnh khởi động GKI nằm trong $DIST_DIR.

Tạo hình ảnh khởi động cho các thiết bị không có init_boot (phiên bản cũ)

Đối với các thiết bị không có phân vùng init_boot, bạn cần một tệp nhị phân ramdisk. Bạn có thể lấy tệp này bằng cách tải một hình ảnh khởi động GKI xuống rồi giải nén. Mọi hình ảnh khởi động GKI từ bản phát hành Android được liên kết đều sẽ hoạt động.

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

Thư mục đích là thư mục cấp cao nhất của cây nhân (thư mục đang hoạt động).

Nếu đang phát triển bằng nhánh phát hành AOSP mới nhất, bạn có thể tải ramdisk-recovery.img tạo tác bản dựng xuống từ bản dựng aosp_arm64 trên ci.android.com và sử dụng tạo tác đó làm tệp nhị phân ramdisk.

Khi có tệp nhị phân ramdisk và đã sao chép tệp đó vào gki-ramdisk.lz4 trong thư mục gốc của bản dựng kernel, bạn có thể tạo một hình ảnh khởi động bằng cách thực thi:

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

Nếu bạn đang sử dụng kiến trúc dựa trên x86, hãy thay thế Image bằng bzImageaarch64 bằng 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

Tệp đó nằm trong thư mục cấu phần phần mềm $KERNEL_ROOT/out/$KERNEL_VERSION/dist.

Hình ảnh khởi động nằm ở out/<kernel branch>/dist/boot.img.