第二章:开发环境搭建与源码编译

开发SystemUI,环境是第一步。很多人觉得这步就是个机械操作,照着文档敲命令就行。但我个人的经验是——环境搭不好,后面八成的坑都从这里来。今天我们就聊聊怎么高效配置AOSP、按需编译SystemUI模块,还有怎么把代码塞进IDE里看得舒服。

2.1 AOSP源码获取与配置

先说说repo。我知道很多人一上来就用repo init -u ... --depth=1想省空间,但这个参数会砍掉所有历史commit,后面你想git log看谁改了什么就抓瞎了。我建议还是拉完整分支,至少保留最近一年的提交记录。

# 初始化AOSP主分支(如果你在搞Android 13/14)
mkdir ~/aosp && cd ~/aosp
repo init -u https://android.googlesource.com/platform/manifest -b android-14.0.0_r30
repo sync -c -j8  # -c只同步当前分支,省带宽
个人习惯:我会先跑 repo sync -c -j8 --force-sync --no-clone-bundle 2>&1 | tee sync.log,这样能在日志里快速定位哪些仓库失败了。记得留至少150GB磁盘空间,我遇到过编译到一半磁盘满的惨案。

为什么我用-j8?因为8个并行repo同步线程对普通网络比较友好,太多会被GitHub限速。如果你内网有镜像,可以调到16。

2.2 模块编译命令精讲

全量编译AOSP动辄一两个小时,我们搞SystemUI的只需要编译目标模块就行。记住这套心法:分步骤、只编改过的东西。

2.2.1 编译框架层(framework/base)

SystemUI在frameworks/base/packages/SystemUI,但它依赖framework.jar。每次改完SystemUI代码,我一般先只编译framework-res和SystemUI两个目标:

source build/envsetup.sh
lunch aosp_husky-userdebug  # 选你的设备

# 只编译framework资源(避免全量编framework.jar)
make framework-res -j16

# 编译SystemUI模块
make SystemUI -j16

# 或者更精细:单独编译systemui的静态jar
make services -j16 && make SystemUI -j16
避坑指南:我曾经忘记先编译Resource,直接改res/文件后执行make SystemUI,结果资源id没对齐,导致运行时崩溃。现在我的标准流程:改资源 → make framework-res → 改代码 → make SystemUI。

2.2.2 增量编译与热替换

如果只改了Kotlin或Java源文件,可以用mm命令在模块目录下直接编译:

cd frameworks/base/packages/SystemUI
mm -j16
# 输出文件在 out/target/product/xxx/system_ext/priv-app/SystemUI/SystemUI.apk

你想想看,mm只编译当前目录及其依赖,比make快3倍不止。我一般开着两个终端:一个终端做mm,另一个终端用adb sync推送。

# 推送到设备
adb root && adb remount
adb sync system_ext/priv-app/SystemUI
adb reboot  # 或者重启SystemUI: adb shell pkill -f com.android.systemui

记住,adb sync system_ext/priv-app/SystemUI只推送SystemUI的apk和oat,秒级完成。

2.2.3 编译产物的常见问题

有时候改了代码后mm还是会报错,说某些类找不到。别慌,可能是之前的obj文件没清除干净。我习惯先运行make clean-SystemUI清理专门模块,再重新 mm。

场景推荐命令耗时(参考)
第一次全量编译make -j$(nproc)40~120分钟
只改Java/Kotlinmm -j1630秒~3分钟
改资源文件make framework-res && make SystemUI1~5分钟
改了framework APImake -j16 framework SystemUI5~15分钟

2.3 IDE导入技巧:IntelliJ与Android Studio

AOSP代码结构特殊,直接打开根目录会卡死。我摸索出一套比较顺手的导入方式。

2.3.1 生成IDE项目文件

AOSP自带了一个工具development/tools/idegen,能生成IntelliJ的项目配置文件:

cd ~/aosp
source build/envsetup.sh
lunch aosp_husky-userdebug
make idegen  # 编译idegen工具
development/tools/idegen/idegen.sh   # 生成android.ipr和android.iml

生成后,用IntelliJ直接打开android.ipr。第一次加载会扫描所有源码,大概5~10分钟。嗯,这里要注意:生成的iml默认会把所有模块都include,我一般在iml里把不相关的模块exclude掉,只保留frameworks/base、packages、libcore。

2.3.2 手动配置依赖与源码路径

如果用Android Studio直接打开frameworks/base目录,能更快加载。我常用这个方式:

  1. File → New → Project from Existing Sources → 选择 frameworks/base/packages/SystemUI
  2. 选择Gradle构建系统(如果提示没有build.gradle,选None)
  3. 打开工程后,手动添加依赖:File → Project Structure → Modules → 添加 frameworks/base/core/java、frameworks/base/packages 等源码根目录
  4. 注意把 out/soong/.intermediates/frameworks/base/framework/android_common/gen 路径加进去,否则找不到R.java和AIDL生成的类
个人小技巧:我写了一个shell脚本,每次mm后自动把最新生成的R.java和AIDL拷贝到IDE的对应目录,这样代码不报红。脚本大概20行,有需要的可以抄我的:
cp -r $OUT/../gen/R.java $PROJECT_ROOT/gen/

2.3.3 调试环境:直接Attach到SystemUI进程

IDE配置好之后,调试就简单了:启动模拟器或真机,执行adb root && adb shell setprop debug.debuggable 1(或直接在userdebug版本上),然后在Android Studio里选择Attach Debugger to Android Process,选com.android.systemui。断点就可以打在任何SystemUI代码里。

为什么我推荐Attach而不是Run?因为SystemUI是系统核心进程,直接重启会导致系统重绘,而Attach调试不会中断SystemUI的正常运行。

2.4 环境搭建的整体流程

下面这张图总结了开发环境搭建的核心流程和关键节点,方便你把前面的知识点串起来。

SystemUI开发环境搭建流程 ① 硬件/磁盘准备 CPU 8核+, RAM 16G+, 磁盘200G+ ② repo sync源码 分支 android-14.0.0_r30 ③ lunch选择目标 aosp_husky-userdebug ④ 选择编译方式 全量 make vs 增量 mm / 框架资源编译 framework-res ⑤ 生成IDE项目 idegen.sh 或手动导入 添加R.java/AIDL路径 ⑥ 推送与验证 adb sync + 重启SystemUI 或 adb install -r SystemUI.apk ⑦ Attach调试 Android Studio Attach to Process 断点调试SystemUI代码 ⑧ 定位问题 & 修复代码 回到步骤④~⑦循环 关键原则 优先增量编译 → 优先模块编译 → 避免全量编译 → 频繁推送验证

核心要点回顾

  • 拉源码时别偷懒省depth,否则查commit历史时会哭
  • 编译SystemUI首选mm,配合adb sync实现秒级推送
  • 改资源必须先编framework-res,否则运行时资源ID错乱
  • IDE里把out/.../gen加进去就不报红
  • Attach调试比Run调试更方便,不会重启SystemUI

环境搭好了,后面写代码才能跑得起来。你想想看,如果每次改一行都要全量编译40分钟,谁还有心思优化卡顿?所以这一章就是你的“加速器”。