2. 开发环境搭建:交叉编译工具链配置、Android内核源码下载与编译、模拟器与真机调试环境搭建、ADB与内核日志查看
字符设备驱动开发的第一步,是搭建一个稳定、可复现的编译与调试环境。Android 内核驱动无法在 x86 宿主机上直接运行,必须通过交叉编译工具链生成 ARM64 或 ARM32 目标代码;同时,驱动验证需要内核镜像与运行时环境(模拟器或真机)的配合。本章将按“工具链 → 内核源码 → 编译 → 调试环境 → 日志查看”的顺序,完整搭建开发流水线。
2.1 交叉编译工具链配置
交叉编译工具链负责在 x86_64 宿主机上生成 ARM64 架构的内核与驱动模块。推荐使用 Google 官方提供的 aarch64-linux-android- 预编译工具链,与 AOSP 内核完全兼容。
2.1.1 工具链下载与解压
# 创建工具链目录
mkdir -p ~/android/toolchains
cd ~/android/toolchains
# 下载 Android 官方预编译 GCC 工具链(aarch64)
wget https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/+archive/refs/tags/android-14.0.0_r30.tar.gz
# 解压
tar -xzf aarch64-linux-android-4.9.tar.gz
ls -l bin/aarch64-linux-android-*
2.1.2 环境变量配置
将工具链路径加入 PATH,并设置交叉编译前缀变量,方便后续内核编译时引用。
# 编辑 ~/.bashrc 或 ~/.zshrc,追加以下内容
export TOOLCHAIN_PATH=~/android/toolchains
export CROSS_COMPILE=aarch64-linux-android-
export PATH=$TOOLCHAIN_PATH/bin:$PATH
# 使配置生效
source ~/.bashrc
# 验证工具链
aarch64-linux-android-gcc --version
CROSS_COMPILE 是内核 Makefile 识别交叉编译器的前缀;ARCH=arm64 需在编译时显式指定。如果使用 Clang,还需设置 CC=clang 并下载 LLVM 工具链。
2.1.3 工具链验证清单
| 组件 | 命令 | 预期输出 |
|---|---|---|
| GCC 编译器 | aarch64-linux-android-gcc --version |
显示 4.9.x 版本信息 |
| 汇编器 | aarch64-linux-android-as --version |
GNU assembler 版本 |
| 链接器 | aarch64-linux-android-ld --version |
GNU ld 版本 |
| 目标文件工具 | aarch64-linux-android-objdump --version |
GNU objdump 版本 |
gcc --version 显示的是 x86_64 本地编译器,说明 PATH 未正确覆盖,请检查工具链 bin 目录是否在 $PATH 最前面。
2.2 Android 内核源码下载与编译
Android 内核源码采用 repo 工具管理多 Git 仓库。本课程使用 common-android14-5.15 内核分支,该分支基于 Linux 5.15 LTS,并包含 Android 特有补丁(如 Binder、ashmem、ion 等)。
2.2.1 安装 repo 与初始化
# 安装 repo 工具
mkdir -p ~/bin
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo
export PATH=~/bin:$PATH
# 创建内核源码目录
mkdir -p ~/android/kernel
cd ~/android/kernel
# 初始化 repo(使用清华镜像加速)
repo init -u https://aosp.tuna.tsinghua.edu.cn/kernel/manifest -b common-android14-5.15
# 同步源码(耗时较长,建议使用 -j4 或 -j8)
repo sync -j8
2.2.2 内核编译配置
Android 内核使用 build.config 文件管理编译参数。对于模拟器(goldfish)和真机(Pixel 6/7 等),配置不同。
| 目标环境 | 配置文件路径 | 输出镜像 |
|---|---|---|
| 模拟器 (ARM64) | common/build.config.gki.aarch64 |
out/android14-5.15/dist/Image |
| Pixel 6/7 真机 | private/gs-google/build.config.slider |
out/android14-5.15/dist/Image.lz4 |
2.2.3 执行编译
# 进入内核根目录
cd ~/android/kernel/common
# 设置架构与交叉编译器
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-android-
# 使用 build.sh 脚本编译(模拟器 GKI 内核)
BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh
# 编译完成后,检查内核镜像
ls -lh ../out/android14-5.15/dist/Image
build/build.sh 前设置 export SKIP_MRPROPER=1 可跳过清理步骤;设置 export CC=clang 可使用 LLVM/Clang 编译,生成代码质量更高。
2.3 模拟器与真机调试环境搭建
驱动开发需要快速迭代验证。模拟器适合早期功能测试,真机适合性能与硬件交互验证。两种环境各有优劣,建议开发初期以模拟器为主。
2.3.1 模拟器环境(QEMU + AOSP 模拟器)
使用 AOSP 预编译模拟器镜像,配合自定义内核启动。
# 下载模拟器镜像(ARM64 系统镜像)
sdkmanager "system-images;android-34;google_apis_playstore;arm64-v8a"
# 创建 AVD(使用命令行)
avdmanager create avd -n kernel_test -k "system-images;android-34;google_apis_playstore;arm64-v8a"
# 启动模拟器并指定自定义内核
emulator -avd kernel_test -kernel ~/android/kernel/out/android14-5.15/dist/Image -show-kernel -no-window
-show-kernel 将内核日志输出到终端;-no-window 在无图形界面下运行,节省资源;-kernel 指定编译好的内核镜像,模拟器将使用该内核启动。
2.3.2 真机环境(Pixel 6/7)
真机调试需要解锁 bootloader 并刷入自定义内核。请确保设备已备份数据。
# 1. 解锁 bootloader(仅需一次)
adb reboot bootloader
fastboot flashing unlock
# 2. 刷入自定义内核(boot.img 打包)
# 使用 mkbootimg 工具将 Image.lz4 打包为 boot.img
mkbootimg --kernel Image.lz4 --ramdisk /dev/null --output boot.img
# 3. 刷入设备
fastboot flash boot boot.img
fastboot reboot
# 4. 验证内核版本
adb shell uname -a
| 对比维度 | 模拟器 (QEMU) | 真机 (Pixel 6/7) |
|---|---|---|
| 启动速度 | 快(10-30 秒) | 慢(30-60 秒) |
| 硬件访问 | 受限(虚拟设备) | 完整(GPIO、I2C、SPI 等) |
| 内核日志 | 终端直接输出 | 需 ADB + dmesg |
| 刷机风险 | 无 | 有(变砖风险) |
| 适用阶段 | 功能开发、单元测试 | 集成测试、性能调优 |
2.4 ADB 与内核日志查看
ADB(Android Debug Bridge)是连接宿主机与 Android 设备的通用调试工具。内核日志通过 dmesg 或 logcat -b kernel 获取,是驱动开发中定位问题的第一手资料。
2.4.1 ADB 常用命令速查
| 命令 | 用途 | 示例 |
|---|---|---|
adb devices |
列出已连接的设备 | 显示序列号与状态 |
adb shell |
进入设备 shell | 交互式命令行 |
adb push |
推送文件到设备 | adb push driver.ko /data/local/tmp/ |
adb pull |
从设备拉取文件 | adb pull /proc/kmsg ./ |
adb reboot |
重启设备 | 刷入内核后验证 |
2.4.2 内核日志查看方法
内核日志分为 kmsg(实时流)和 dmesg(环形缓冲区)。驱动开发中推荐使用 dmesg -w 实时监控。
# 方法一:dmesg(查看历史日志 + 实时跟踪)
adb shell dmesg -w | grep "chardev"
# 方法二:logcat 内核日志(Android 特有)
adb logcat -b kernel -v time
# 方法三:直接读取 /proc/kmsg(需要 root)
adb shell su -c "cat /proc/kmsg"
# 方法四:模拟器终端直接查看(-show-kernel 模式)
# 日志会实时打印在启动模拟器的终端窗口中
dmesg 无需 root 即可执行;user 版本受限,建议开发机刷入 userdebug 镜像。/proc/kmsg 始终需要 root 权限。
2.4.3 内核日志格式解析
典型内核日志行包含时间戳、CPU 编号、进程名和日志级别。驱动开发者应重点关注 KERN_ERR (3) 和 KERN_INFO (6) 级别的输出。
[ 12.345678] [0003] [insmod] chardev: major number 240 registered
[ 12.345789] [0003] [insmod] chardev: device class created
[ 13.001234] [0005] [kworker] chardev: open() called by pid 1234
[ 13.001567] [0005] [kworker] chardev: ioctl cmd=0x1234, arg=0x5678
| 字段 | 含义 | 调试价值 |
|---|---|---|
[12.345678] |
系统启动后的秒数 | 定位事件发生顺序 |
[0003] |
CPU 核心编号 | 分析并发问题 |
[insmod] |
进程名 | 区分调用者 |
chardev: |
驱动名称(pr_fmt) | 过滤特定驱动日志 |
major number 240 |
关键事件描述 | 验证驱动初始化 |
2.5 环境验证清单
完成上述步骤后,执行以下验证脚本,确保所有组件正常工作。
#!/bin/bash
# environment_check.sh
echo "=== 1. 交叉编译工具链 ==="
aarch64-linux-android-gcc --version && echo "[OK]" || echo "[FAIL