1 引言
简单记录了这三天来编译Android系统内核、驱动走过的路。遇到了很多坑和不懂的东西,为了下次少走些弯路所以简单总结下。横跨很多天的工作不免记忆模糊,如果参考本博客时遇到问题欢迎大家下方留言和指正。
2 环境
- 宿主机:Windows 11
- 虚拟机:Ubuntu 18 LTS
- 16G或32G的内存
- 1T以上的硬盘空间(推荐使用固态硬盘)
3 准备工作
Android官方文档中推荐使用Ubuntu或者Mac OS系统,这里我们选择了在Windows上使用虚拟机软件(Vmware)运行Ubuntu 18来进行编译。由于Android系统比较庞大,建议大家为虚拟机分配600G及以上的硬盘空间。
3.1 安装工具
首先前往https://source.android.com/source/initializing?hl=zh-cn在Ubuntu中安装必要的软件包。
随后就是安装repo工具,这里我们选择了国内TUNA的镜像,https://mirrors.tuna.tsinghua.edu.cn/help/AOSP/。按照其中的步骤,首先安装git-repo工具;下载TUNA提供的使用每月更新的初始化包,将其解压到虚拟机中并用repo sync
进行同步。
3.2 下载Android源代码并选择分支
在(https://source.android.com/docs/setup/about/build-numbers?hl=zh-cn#source-code-tags-and-builds)[https://source.android.com/docs/setup/about/build-numbers?hl=zh-cn#source-code-tags-and-builds]可以查看所有分支,这里我们选择了Android 13的分支,大家可以根据自己情况进行选择。
4 编译Android源代码
4.1 配置编译选项
首先进入aosp目录,运行:
1 | source build/envsetup.sh |
查看lunch提供的选项(部分):
1 | lunch |
这里建议选择sdk开头的选项。
由于我们想要在x86_64的平台上使用emulator模拟运行,所以使用sdk_x86_64-userdebug
选项。
1 | lunch sdk_x86_64-userdebug |
4.2 编译
接下来可以直接输入:
1 | m |
该命令可以自动识别机器CPU核心数,使用所有核心编译。
同样可以使用make指定核心数:
1 | make -j4 |
5 运行Android系统
这里我们使用AOSP提供的emulator在虚拟机中运行Android系统,直接在aosp目录输入:
1 | emulator |
运行结果:
6 编译Android驱动
6.1 Android驱动——hello_module
Android本身是在Linux内核之上的系统,所以Android驱动也可以理解为Linux驱动。下面是一个Android驱动的代码:
1 | // hello_module.c |
6.2 下载Android-kernel源代码
在Android官方文档https://source.android.com/docs/setup/build/building-kernels?hl=zh-cn中介绍了构建内核的方法。也同样可以使用TUNA镜像进行加速:
1 | $ repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/kernel/manifest -b BRANCH |
这里的BRANCH可以在https://source.android.com/docs/setup/reference/bazel-support?hl=zh-cn选择合适的分支,比如我们这里选择了common-android13-5.15
。
6.3 将加入hello_module驱动内核
源代码Android-kernel中包含common-modules文件夹,由于存放供应商模块。我们在common-modules/virtual-device
目录下创建hello_module
文件夹,其中存放我们的驱动代码hello_module.c,以及下面的Kbuild文件:
1 | # SPDX-License-Identifier: GPL-2.0 |
在hello_module
文件夹的父目录(即common-modules/virtual-device
)下的Kbuild
中加入obj-m += hello_module/
:
1 | obj-m += virtio_gpu/ |
在hello_module
文件夹的父目录(即common-modules/virtual-device
)下的BUILD.bazel
的_virt_common_ext_modules
加入"hello_module/hello-module.ko",
:
1 | # ... |
6.4 编译
编译所有virtual-device(也包括hello-module.ko)
1 | tools/bazel build //common-modules/virtual-device:virtual_device_x86_64_dist |
可以使用dist_dir选项输出到指定文件夹:
1 | $ tools/bazel run //common-modules/virtual-device:virtual_device_x86_6s4_dist -- --dist_dir=out/mydist |
成功编译出:
1 | find ./out/mydist/ -name hello-module.ko |
7 运行Android驱动程序
正常情况下,直接使用adb push将hello-module.ko放入android系统中,使用insmod安装驱动即可成功运行。但是新版Android系统为了安全性,加入了对驱动的检查。
使用dmesg查看:
7.1 Patch驱动程序
根据报错:
1 | [ 3657.631158] hello_module: disagrees about version of symbol module_layout |
我们猜测应该是版本不匹配造成的,那么接下来寻找合法的驱动程序进行比对。这里我们选择aosp中kernel/prebuilts/common-modules/virtual-device/5.15/x86-64/
文件夹下的文件,如zsmalloc.ko
。
我们将hello-module.ko对应的__versions中前四个字节改为相同的即可:
重复第7节最开始的步骤,可以看到成功以及安装并运行了驱动:
参考文献
[1] Android官方文档 https://source.android.com/
[2] Basic android kernel development https://github.com/itewqq/android-kernel-play
[3] TUNA Android 镜像使用帮助 https://mirrors.tuna.tsinghua.edu.cn/help/AOSP/
[4] Linux内核模块常见问题 https://wiki.zohead.com/%E6%8A%80%E6%9C%AF/Linux/kernel/Linux%E5%86%85%E6%A0%B8%E6%A8%A1%E5%9D%97%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98.md
[5] Android系统编写Linux内核驱动 https://github.com/liushui312/notes/blob/master/android/4_android%E7%B3%BB%E7%BB%9F%E7%BC%96%E5%86%99Linux%E5%86%85%E6%A0%B8%E9%A9%B1%E5%8A%A8.txt