Android Kernel 编译与调试指北
上一篇文章介绍了在wsl2环境下编译AOSP并将其运转到Cuttlefish中,本篇文章依赖于上文Cuttlefish,请依照顺序食用本指北
环境
本指北根据以下代码和环境编写
OS : Ubuntu 22.04.2 LTS
AOSP : master
kernel : 根据编译方针决议
target : aosp_cf_x86_64_phone-userdebug
设备 : Cuttlefish
在前一篇文章说过,因为工具链的原因,AOSP的代码不宜太旧,自上一篇文章以来Cuttlefish的功能和文档逐渐健全,足以见得google对其的投入程度,所以假如版别不一样会遇见无此参数等这样那样的问题,本文在master上测试经过。
Android Kernel Repo的源码下载
Linux Kernel是Android体系运转的基础,而Linux Kernel的源码在AOSP中并不存在,一般存在的是预构建的内核映像,假如想对内核做一些定制化的修正,就需求下载代码并构建,Linux Kernel像AOSP有各种各样的分支,并不是随意选择一个分支构建就能够正常运转。编译AOSP对应的Linux Kernel版别才干防止构建进程走许多弯路。每一个AOSP构建方针都预置了预编译的内核映像,能够从内核印象中获取相应版别的蛛丝马迹。
需求阐明的是Android的内核项目同样是由repo(android.googlesource.com/kernel/mani…) 办理的,其间Linux Kernel的源码存在于kernel/common(android.googlesource.com/kernel/comm…) 目录下,其他目录是与构建相关的工具链或许脚本等,在之前旧版别Linux Kernel构建中能够直接下载kernel/common的代码运用make直接编译出内核镜像,可是随着Android GKI的推出,这套办法就行不通了。读者最好运用repo供给的编译脚本等进行构建。
下面以
aosp_cf_x86_64_phone-userdebug
target为例,讲述怎么一步步找到对应的分支
查找Linux Kernel的version和commitId
从Android设置界面查找
假如你编译的体系已经成功运转到虚拟机,你能够翻开Settings – About Phone – Android Version -Kernel Version 能够看到对应的Kernel信息,Linux的版别号依照major.minor.patch-build.desc的格式,经过匹配屏幕输出能够得出内核版别为6.1,从附加描述中提取g开头的连续字符能够得知对应的commitId为963667856ef1
从AOSP树中查找
假如只要一个构建方针(aosp_cf_x86_64_phone-userdebug)并没有运转成功虚拟机,能够遵循以下过程获取。
- 索引到device/google/cuttlefish目录,device目录下存放了芯片和硬件厂商的相关产品装备,其间cuttlefish作为一款虚拟器,也被增加到了该目录下。
- 经过
mgrep ":kernel"
检查装备文件(该办法不是很通用,能够经过“增加新设备”了解相关常识),最终检查查找到的装备文件,经过下图能够看到该方针链接的kernel映像文件位于kernel/prebuilts/6.1/x86_64/kernel-6.1
- 对该文件执行
file kernel-6.1
得到以下输出,同样能够得到commmitId为963667856ef1
kernel-6.1: Linux kernel x86 boot executable bzImage, version 6.1.25-android14-7-00377-g963667856ef1-ab10271074 (build-user@build-host) #1 SMP PREEMPT Tue Jun 6 23:03:20 UTC 2023, RO-rootFS, swap_dev 0X10, Normal VGA
根据分支拉取Kernel代码
经过上面的操作得到了Linux Kernel的版别和commitId,准备就绪就能够着手拉取代码了,需求注意上文获取的commitId是指android.googlesource.com/kernel/comm… 仓库的相应提交。
根据kernel/common的commitId找到对应repo分支
直接访问android.googlesource.com/kernel/comm… (注意依照实际输出更改commitId) 就能够得到对应的changeId,经过点击changeId链接就能够看到对应gerrit 地址,如下所示,该页面同时标注了Linux kernel的分支[android14-6.1], 这里的branch仍是Linux Kernel的分支,那么怎么得到repo的分支内,只要猜了,经过在
android.googlesource.com/kernel/mani… 中查找6.1找到了多个成果,经过依次检查该分支下的default.xml文件,发现common-android14-6.1分支下指向了Linux Kernel的android14-6.1分支,代码如下<project path="common" name="kernel/common" revision="android14-6.1" />
拉取Kernel代码
运用从上文得到的kernel的repo分支,运用repo下载Linux Kernel的源码和脚本等
mkdir android-kernel && cd android-kernel
repo init -u https://android.googlesource.com/kernel/manifest -b common-android14-6.1
repo sync
假如一切OK,代码就下载好了,假如你遇见了任何网络问题,能够参照上一篇文章设置镜像源下载。
Bazel编译Kernel
Android11引入了GKI的特性,用于将内核拆分为由 Google 保护的内核映像和由供应商保护的模块,两个模块别离构建。Android13开始运用Bazel进行编译,因为构建的分支是master分支,所以内核的编译需求运用bazel进行构建,而且需求别离构建两个内核。
//通用内核镜像的构建
$ tools/bazel run //common:kernel_x86_64_dist -- --dist_dir=out
//因为是虚拟机,所以是虚拟的设备GKI virtual_device
$ tools/bazel run //common-modules/virtual-device:virtual_device_x86_64_dist -- --dist_dir=out
以上假如构建没有问题,在out目录下会生成bzImage
和initramfs.img
文件,请记住他们的方位,之后会用到
Cuttlefish 使用新内核
运用kernel_path和initramfs_path即可对Cuttlefish使用新内核,十分便利,需求注意launch_cvd的运转根据上一篇文章编译成功,在AOSP根目录下运转
source build/envsetup.sh
lunch aosp_cf_x86_64_phone-userdebug
launch_cvd -kernel_path /home/prosixe/ssd/Android/android-kernel/out/bzImage -initramfs_path /home/prosixe/ssd/Android/android-kernel/out/initramfs.img
经过检查体系信息,内核已经发生了改动,体系能够正常开机
运用GDB调试Kernel
运用下面指令使内核可调试,读者实操时注意要区别aosp和android-kernel的目录。
//注意在aosp根目录
source build/envsetup.sh
lunch aosp_cf_x86_64_phone-userdebug
launch_cvd -kernel_path /home/prosixe/ssd/Android/android-kernel/out/bzImage -initramfs_path /home/prosixe/ssd/Android/android-kernel/out/initramfs.img -gdb_port 1234 -cpus=1 -extra_kernel_cmdline nokaslr
然后在另一个终端索引到android-kernel/common便利gdb索引到符号
//切换android-kernel根目录
cd common
gdb ../out/vmlinux
(gdb) target remote :1234
(gdb) hbreak start_kernel
(gdb) c
能够看到内核在start_kernel时停止了,而且能够正常显现对应的源代码。
总结
经过一步步的探索,将Linux内核成功运转到了Cuttlefish中,在Cuttlefish的环境下,能够调试内核,调试Native代码,调试Framework代码,也能够当作你的常用“开发机”运用。
该文章是笔者学习中的一个总结,因为常识面的狭窄总有知道不到的过错产生,请大家不吝赐教。假如大家学习中遇见问题,也欢迎大家交流交流。