android - 编译内核模块
本页详细介绍了为 Android 设备构建自定义内核的流程。以下说明会逐步指导您如何选择正确的源代码,构建内核,以及将结果嵌入到根据 Android 开源项目 (AOSP) 构建的系统映像中。
您可以使用 Repo 获取最新的内核源代码;通过在源代码检出的根目录下运行 build/build.sh
可构建这些内核源代码,而无需更多配置。
注意:内核源代码检出的根目录包含
build/build.sh
。Android 树仅包含预构建的内核二进制文件。内核树包含内核源代码和用于构建内核的所有工具,包括此脚本。
安装依赖
Ubuntu/Debian
sudo apt install binutils git ccache automake flex lzop bison gperf build-essential zip curl zlib1g-dev libxml2-utils bzip2 libbz2-dev libbz2-1.0 libghc-bzlib-dev squashfs-tools pngcrush schedtool dpkg-dev liblz4-tool make optipng maven libssl-dev pwgen libswitch-perl policycoreutils minicom libxml-sax-base-perl libxml-simple-perl bc libx11-dev libgl1-mesa-dev xsltproc unzip device-tree-compiler python3 libelf-dev binutils-aarch64-linux-gnu gcc gzip
Deepin
sudo apt install binutils git ccache automake flex lzop bison gperf build-essential zip curl zlib1g-dev libxml2-utils bzip2 libbz2-dev libbz2-1.0 squashfs-tools dpkg-dev liblz4-tool make optipng maven libssl-dev libswitch-perl policycoreutils minicom libxml-sax-base-perl libxml-simple-perl bc libx11-dev libgl1-mesa-dev xsltproc unzip device-tree-compiler python3 libelf-dev binutils-aarch64-linux-gnu gcc gzip
deepin环境下可能需要单独手动编译安装一些依赖库!
安装repo
大部分情况下,apt install repo
都无法找到包,所以说我们进行手动安装!
mkdir -p ~/.bin
PATH="${HOME}/.bin:${PATH}"
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/.bin/repo
chmod a+rx ~/.bin/repo
因为墙的问题(如果您的网络无法访问Google),需要更换源,这里更换为清华源
export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo/'
下载内核编译环境
mkdir android-kernel && cd android-kernel
先创建一个文件夹让我们可以进行repo init
repo init -u https://android.googlesource.com/kernel/manifest -b common-[需要的版本] --repo-rev=v2.16
common-
开头,后面任你选择哦!具体有哪些tag,我们可以看https://android.googlesource.com/kernel/manifest/+refs
repo sync -c -j$(nproc) --no-tags
需要注意的是,这个拉取同步的速度取决于你的网速,
我的网络就很慢很慢!
如需查看可与之前的“repo init”命令搭配使用的 repo 分支 (BRANCH) 列表,请参阅内核分支及其构建系统。
如需详细了解如何为 Pixel 设备下载和编译内核,请参阅构建 Pixel 内核。
将需要编译的内核模块挪动位置
GKI_ROOT=/persistent/home/fuqiuluo/etc/env/android-kernel/android15-6.6
mv [模块路径] $GKI_ROOT/common/drivers/[模块名称]
DRIVER_MAKEFILE=$GKI_ROOT/common/drivers/Makefile
DRIVER_KCONFIG=$GKI_ROOT/common/drivers/Kconfig
grep -q "[模块名称]" "$DRIVER_MAKEFILE" || printf "\nobj-m += [模块名称]/\n" >> "$DRIVER_MAKEFILE"
如果内核模块内有Kconfig文件则还需要执行
grep -q "[模块名称]" "$DRIVER_KCONFIG" || sed -i "/endmenu/i\\source \"drivers/[模块名称]/Kconfig\"" "$DRIVER_KCONFIG"
编译前准备
sudo apt-get install llvm-15 -y
pip install ast-grep-cli
接下来我们需要使用这个ast-grep包,但是你可能安装后无法直接使用请手动设置PATH或者使用cargo包管理器进行安装,cargo install ast-grep --locked
!安装成功后,我们逐行执行以下命令:
ast-grep -U -p '$$$ check_exports($$$) {$$$}' -r '' common/scripts/mod/modpost.c
ast-grep -U -p 'check_exports($$$);' -r '' common/scripts/mod/modpost.c
如果编译的时候报错提示什么和
common/scripts/mod/modpost.c
有关的错误,说明上面的这段命令执行没有效果,需要你手动去对应文件删除和check_exports相关的定义和调用!
检查build/build.sh
文件是否存在,如果不存在则执行以下语句:
sed -i 's/needs unknown symbol/Dont abort when unknown symbol/g' build/kernel/*.sh || echo "No unknown symbol scripts found"
高版本内核添加内核模块(上面的执行完成后,我们继续执行,如果文件build/build.sh
不存在且文件common/modules.bzl
存在则执行以下语句)
sed -i "s/_COMMON_GKI_MODULES_LIST = \[/_COMMON_GKI_MODULES_LIST = \[ \"drivers\/[模块名称]\/[模块名称].ko\",/g" common/modules.bzl
低版本内核去除一些检测(如果build/build.sh
存在的话)
export TARGET_FILE="build/kernel/build.sh"
if [ ! -f "$TARGET_FILE" ]; then
TARGET_FILE="build/build.sh"
fi
sed -i 's/needs unknown symbol/Dont abort when unknown symbol/g' $TARGET_FILE || echo "No unknown symbol in $TARGET_FILE"
sed -i 's/if ! diff -u "\${KERNEL_DIR}\/\${MODULES_ORDER}" "\${OUT_DIR}\/modules\.order"; then/if false; then/g' $TARGET_FILE
sed -i 's@\${ROOT_DIR}/build/abi/compare_to_symbol_list@echo@g' $TARGET_FILE
sed -i 's/needs unknown symbol/Dont abort when unknown symbol/g' build/kernel/*.sh || echo "No unknown symbol scripts found"
我们可以输入repo status
看看修改了哪些文件,同时我们需要执行以下语句删点东西(低版本内核没有这些玩意?):
rm common/android/abi_gki_protected_exports_*
构建编译
使用构建脚本构建内核(如果build/build.sh
存在)
注意:Android 14 及更高版本不支持 build.sh。
对于 Android 12 或更低版本的分支,或者不使用 Kleaf 的分支:
LTO=thin BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh CC="/usr/bin/ccache clang"
后记
在一次编译安卓12的MUMU模拟器的5.4版本的内核的时候,遇到了错误,但是这个版本是用build.sh构建的就找不到错误信息...(被bazel惯坏了),
构建脚本换成LTO=thin BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh V=1 CC="/usr/bin/ccache clang" 2>&1 | tee build.log
然后我们去这个Build.log里面找一下common/drivers/[模块名称]
找一下详细错误信息...
输出目录在
out/android12-5.4/common/drivers/$MODULE_NAME/$MODULE_NAME.ko
使用 Bazel (Kleaf) 构建(不存在则执行)
tools/bazel run --config=fast --lto=thin //common:kernel_aarch64_dist -- --dist_dir=dist
如果你需要编译X64的,可以把
aarch64
改成x86_64
。如果您要构建tag为
android16-6.12
的内核模块,请使用tools/bazel run --disk_cache=/home/runner/.cache/bazel --config=fast --lto=thin //common:kernel_aarch64_dis
Android 13 引入了使用 Bazel 构建内核的功能。
如需为 aarch64 架构构建 GKI 内核,请查看不低于 Android 13 的 Android 通用内核分支,然后运行以下命令:
tools/bazel build //common:kernel_aarch64_dist
如需创建分发版本,请运行以下命令:
tools/bazel run //common:kernel_aarch64_dist -- --dist_dir=$DIST_DIR
之后,内核二进制文件、模块和相应的映像会置于
$DIST_DIR
目录中。如果未指定--dist_dir
,请参阅该命令的输出以了解工件的位置。如需了解详情,请参阅 AOSP 文档。
编译输出的内核模块就在那个叫dist的文件夹里面啦!编译完成的时候,他也会说放到什么地方去的哦!