Ubuntu 下编译goldfish内核并使用模拟器运行
Ubuntu 下编译goldfish内核并使用模拟器运行
前言
要学习Android Framework开发,通常需要下载AOSP(Android Open Source Project)项目。AOSP包含了Android操作系统的全部源代码,但并不包含内核部分。若需进一步学习驱动开发,则需另行下载内核源码。
需要特别说明的是,Android系统使用的内核并非原生Linux Kernel,而是基于Linux内核进行了深度定制,加入了进程间通信(Binder)、低内存管理等Android专属特性。内核有很多版本,我们可以选择谷歌官方维护的Android通用内核(Android Common Kernel, ACK),也可根据实际设备情况选用厂商开源的内核(需注意部分设备可能要求解锁Bootloader)。
简单起见,本文选用goldfish内核作为学习对象。该内核是Android模拟器专用版本,特别适合在虚拟环境中进行驱动开发测试。
值得注意的是,虽然Android基于Linux内核构建,但是AOSP是不需要和内核编译到一起的,而是在设备启动时,Bootloader 负责选择并加载内核,然后再启动 AOSP。
本文所用环境
- VMware + Ubuntu 22.04
- Android ndk 16
1 下载及编译
1.1 内核下载
AOSP项目比较大,我们这里只获取 Goldfish 内核,而不下载整个 AOSP,clone完成需要手动checkout 出源码分支。
Android模拟器内核更新的比较慢,通常用的都是相对稳定、较老的内核:
- 3.18:长期使用的老版本(早期 AOSP)
- 4.4 / 4.9:主流 LTS 支持版本(支持 Android 9/10)
- 4.14:进入 Android 10/11 时期
- 5.4:对应 Android 12/13(只维护了一个分支)
1 | git clone https://android.googlesource.com/kernel/goldfish |
1.2 环境配置
安装gcc
内核构建过程分为两个部分,ndk中的交叉编译工具链(x86_64-linux-android-gcc)负责内核本体的交叉编译,同时内核构建脚本还需要一个本地主机的 gcc 来编译 host 工具(如 fixdep 等),因此需要安装gcc。
1 | sudo apt install gcc |
下载交叉编译器
goldfish内核默认使用 GCC 编译,较高的版本才支持clang编译,可以通过goldfish/Documentation/process/changes.rst
查看要求编译器的最低版本。
这里我们使用Android ndk提供的编译器来编译,打开Android studio 下载ndk,由于
goldfish 默认使用gcc编译器,而自 NDK r18 版本起,Android 官方推荐使用 Clang 作为默认的编译器,gcc被移除,因此我们选择下载r18以下的旧版本。
1.3编译
配置编译脚本
使用touch
命令新建build.sh
配置编译脚本文件,输入以下内容:
1 |
|
开始编译
执行 sh build.sh
开始编译。编译过程比较简单,以下是一些可能出现的报错:
secclass_map 需要更新
错误信息:
1 | In file included from scripts/selinux/mdp/mdp.c:49: |
解决方法:打开security/selinux/include/classmap.h
在secclass_map
结构体增加 添加新的地址族对应项。
或者临时解决:执行 grep -r "PF_MAX" /usr/include/
查找PF_MAX的值,修改if语句:
1 |
报错 multiple definition of ‘yylloc’重复定义
错误信息:
1 | /usr/bin/ld: scripts/dtc/dtc-parser.tab.o:(.bss+0x10): multiple definition of yylloc'; scripts/dtc/dtc-lexer.lex.o:(.bss+0x0): first defined here |
解决方法:使用grep -rw "YYLTYPE yylloc;"
命令搜索这个变量,找出到除了dtc-lexer.lex.c 外的(scripts/dtc/dtc-lexer.l
、dtc-lexer.lex.c_shipped
)所有YYLTYPE yylloc
改成extern YYLTYPE yylloc
完成
当终端输出以下信息代表内核映像 bzImage 已成功构建。表示bzImage已经生成,位于arch/x86/boot/bzImage。bzImage 是经过压缩的内核映像文件,用于启动系统。
1 | Kernel: arch/x86/boot/bzImage is ready (#1) |
2 使用avd启动加载内核
启动内核映像通常依赖于使用模拟器或在物理硬件。以上编译的goldfish内核镜像bzImage可以用模拟器( Android Emulator)来运行。
2.1 创建模拟器
运行Android Stuido并打开Virtual Device Manager
创建一个模拟器,由于我们编译的Goldfish 内核是针对 x86_64 架构的,因此模拟器镜像也选择x86_64的,Android版本也要与内核版本兼容,我们前面选择的是内核版本 4.14,与之对应的是Android10(android-29)。具体可以从这里(Which Android runs which Linux kernel?)和AOSP官网查到Android内核支持表。
如果提示Your CPU does not support required features (VT-x or SVM).
,则需要启用虚拟化技术,打开VMware的虚拟化的设置:
- 关闭当前虚拟机,依次选择虚拟机->设置->硬件tab下的处理器选项,勾选右侧的
虚拟化Intel VT-x/EPT或AMD-V/RVI
。 - 如果仍然报错:关闭有冲突的windows虚拟化功能,打开Windows主机的“启用或关闭windows功能”,关闭所有有关的功能:包括Hyper-V、Windows虚拟机监控程序平台、适用于Linux的Windows子系统、虚拟机平台等。
2.2 使用命令运行模拟器
为了能在终端使用模拟器的命令,需要配置Android sdk环境变量:
1 | export ANDROID_HOME=//home/zhg/Workplace/Android/Sdk |
启动 AVD,<avd_name>
是上面在Android studio中创建avd时的名称。
1 | # 通过 -kernel 命令行参数指定内核 |
执行命令后,可能会出现在虚拟机上运行模拟器(禁止套娃)导致性能下降之类的风险提示,可以忽略。
2.3 查看模拟器内核版本
等模拟器运行起来后,在模拟器的设置->关于模拟器页面->Android版本
中可以看到内核版本信息,也可以使用命令adb shell uname -a
查看,根据版本号和时间可以确定运行的是我们刚才编译的内核。
2.4 查看内核日志
查看内核控件日志,logcat只能查看用户空间的日志,dmesg可以查看全部日志。
Android 8.0(Oreo)及以上版本,访问 dmesg需要root权限
1 | adb root # 获取 root 权限 |
以上就是关于goldfish内核的编译及运行,下一篇我们将使用goldfish内核来编写一个简单的驱动来学习相关知识。