开发环境搭建:从源码下载到真机调试
说实话,SystemUI 调试的门槛不低,但环境搭好了,后面就顺了。我用过的方案有好几种,今天给你梳理一套我验证过的流程——从 AOSP 源码下载开始,到编译 SystemUI 模块,再到模拟器和真机调试配置。
2.1 AOSP 源码下载——别踩 repo 的坑
AOSP 源码体积巨大,官方推荐用 repo 工具管理。但你想想看,几十个 Git 仓库并行拉取,网络稍不稳定就中断。我早期遇到过 repo sync 三天没跑完的情况……后来总结了一套稳一点的方案。
repo sync -j8,先 repo sync -j1 拉下主要分支,再逐步增加并行数。设置 git config --global core.compression 0 可以避免某些解压崩溃。
具体步骤如下:
- 安装 repo 工具(确保 Python 3 环境)
- 创建工作目录,比如
~/aosp - 初始化 manifest:
repo init -u https://android.googlesource.com/platform/manifest -b android-13.0.0_r35 - 开始同步:
repo sync -c -j4 --no-tags
嗯,这里有个关键点:--no-tags 能省下不少时间。如果你只是编译 SystemUI,不需要看每个仓库的历史 tag。
df -h 先看看你的机器。
2.2 编译 SystemUI 模块——别整全量编译
全量编译 AOSP 动辄两小时,但咱们只关心 SystemUI。用 mmm 或 make SystemUI 可以单独编译这个模块。我个人习惯用 mmm,因为它精准定位目标目录。
先设置环境:
cd ~/aosp
source build/envsetup.sh
lunch aosp_cf_arm64_phone-userdebug
然后编译 SystemUI:
mmm frameworks/base/packages/SystemUI/
输出路径一般在 out/target/product/<设备名>/system/priv-app/SystemUI/。如果你想更快,可以只生成 SystemUI.apk:
make SystemUI -j$(nproc)
make SystemUI 通常两三分钟就好。但如果改了资源文件(比如 layouts),最好 make SystemUI 后 make SystemUI-res 或者直接 mmm 指定 -B 强制重新编译。
2.3 模拟器调试环境——快速迭代的利器
我调试 SystemUI 最常用的环境其实是模拟器。真机有锁屏、模拟器更灵活。Cuttlefish 虚拟设备是官方推荐方案。
启动模拟器前,先确保内核和 ramdisk 编译好:
make -j$(nproc) # 首次需要全量编译(一次痛苦,后面爽)
cvd start # 启动 Cuttlefish 设备
怎么把新编译的 SystemUI 推到模拟器里?用 adb install -r 最简单:
adb install -r out/target/product/vsoc_x86_64/system/priv-app/SystemUI/SystemUI.apk
adb shell am force-stop com.android.systemui
adb shell am start -n com.android.systemui/.SystemUIService
但注意:模拟器里的 SystemUI 是系统应用,直接 install 可能报 INSTALL_FAILED_UPDATE_INCOMPATIBLE。我遇到过这个问题,后来改用 adb push + 重启大法:
adb root
adb remount
adb push out/target/product/vsoc_x86_64/system/priv-app/SystemUI/SystemUI.apk /system/priv-app/SystemUI/
adb reboot
2.4 真机调试环境——直面真实硬件
真机调试能发现模拟器重现不了的 bug,比如按键反馈、低内存状态下的 UI 闪烁。我用 Pixel 系列比较多,因为驱动开源,兼容性好。
真机需要先解锁 bootloader,刷入 userdebug 或 eng 版本的镜像。官方叫法是「刷入工厂镜像」:
fastboot flash boot boot.img
fastboot flash system system.img
fastboot flash vendor vendor.img
fastboot reboot
刷完以后,用 adb 设备列表确认连接:
adb devices
# 看到 "device" 状态就对了
然后和模拟器一样,用 adb push 替换 SystemUI。这里有个坑:直接 push 后 SystemUI 会立即 crash,因为进程还在跑,文件被占用。我建议先杀掉进程再 push:
adb shell stop
adb push ... /system/priv-app/SystemUI/
adb shell start
adb logcat -s SystemUI 是你最好的朋友。SystemUI 崩溃后,logcat 里通常有堆栈和错误码。比如 NullPointerException 或 RemoteException。
另外,真机上 userdebug 版本可以开 adb root,但有些厂商会限制。如果 root 失败,考虑用 adb unroot 再重新授权。
2.5 环境搭建总体流程(一张图看懂)
下面这张图总结了我推荐的从零到真机调试的完整路径。每个节点都标注了关键步骤和常见陷阱。
2.6 开发环境快速参考表
| 组件 | 关键命令 | 常见问题 | 解决思路 |
|---|---|---|---|
| AOSP 下载 | repo sync -c -j4 --no-tags |
网络超时 | 加 --depth=1 或换国内镜像 |
| 编译 SystemUI | make SystemUI -j$(nproc) |
资源未更新 | 先 make SystemUI-res |
| 模拟器启动 | cvd start |
启动失败 | 检查内核是否编译,cvd reset |
| 真机替换 SystemUI | adb push + stop/start |
push 后崩溃 | 确保 adb root 并 stopping |
| 查看崩溃日志 | adb logcat -s SystemUI *:E |
日志太多 | 加 | grep -E "Exception|Error" |
个人忠告:别在第一次就追求完美。我刚开始也贪快,跳过模拟器直接上真机,结果刷了三次都没成功。后来老老实实按流程走,反而省了时间。
2.7 调试环境验证——先跑个 demo
环境搭完后,改一行代码试试。比如在 SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java 里加个 toast:
Toast.makeText(mContext, "Hello SystemUI", Toast.LENGTH_SHORT).show();
编译、push、重启 SystemUI。如果你能在状态栏上方看到这个 toast,说明环境通了一切顺利。如果看不到,先检查 logcat,八成是权限或路径问题了。