3. 开发环境搭建
Native Service 开发与普通 App 开发最大的区别在于:你写的 C/C++ 代码最终要跑在 Android 系统镜像里,而不是安装成一个 APK。因此开发环境不只是“装个 IDE”,而是要同时具备系统源码编译能力、NDK 交叉编译能力和设备调试能力三条链路。本节按这三条链路展开,并给出可复用的命令与配置。
一、核心原理:三条链路各司其职
AOSP 源码编译负责把 Native Service 编进 system 分区,产出可刷写的镜像;NDK 负责在 Android Studio 中快速验证 C/C++ 逻辑与 JNI 接口;adb/fastboot 负责把产物送到设备并观察运行状态。三者关系可以用下面的结构图表示。
二、AOSP 源码下载与编译流程
AOSP 体积大、依赖多,建议使用 Ubuntu 20.04/22.04,至少 16 核 CPU、32GB 内存、400GB 以上 SSD。首次同步耗时较长,务必先配置好 Git 身份与代理。
# 1. 安装 repo
mkdir ~/bin && curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo && export PATH=~/bin:$PATH
# 2. 初始化并同步(以 Android 13 为例)
mkdir aosp && cd aosp
repo init -u https://android.googlesource.com/platform/manifest -b android-13.0.0_r1
repo sync -c -j8 --no-tags
# 3. 编译环境
source build/envsetup.sh
lunch aosp_arm64-userdebug
m -j16 # 全量编译
mm # 编译当前目录模块
mmm frameworks/base/services/core/jni # 编译指定路径模块
只改一个 Native Service 时,优先使用
mm 或 mmm,再 adb push 对应产物到设备,比全量 m 快一个数量级。全量编译仅在首次或改动系统公共库时使用。三、Android Studio NDK 配置
NDK 链路用于快速验证 C/C++ 逻辑、JNI 接口和第三方库移植,不必每次都刷机。在 local.properties 或 build.gradle 中固定 NDK 版本,避免团队间版本漂移。
android {
ndkVersion "25.2.9519653"
defaultConfig {
externalNativeBuild {
cmake { cppFlags "-std=c++17 -fno-exceptions" }
}
ndk { abiFilters "arm64-v8a", "x86_64" }
}
externalNativeBuild {
cmake { path file("src/main/cpp/CMakeLists.txt") }
}
}
若需脱离 Gradle 单独交叉编译,可直接调用 NDK 工具链:
$NDK/build/tools/make_standalone_toolchain.py \
--arch arm64 --api 33 --install-dir /opt/ndk-arm64
/opt/ndk-arm64/bin/aarch64-linux-android33-clang++ \
-shared -fPIC -o libdemo.so demo.cpp -llog
四、adb 与 fastboot 调试工具
adb 面向运行中的系统,fastboot 面向未启动的引导阶段,两者配合完成“编译—推送—验证—刷写”闭环。
| 工具 | 典型命令 | 使用场景 |
|---|---|---|
| adb | adb devices -l | 确认设备连接与序列号 |
| adb | adb push out/.../xxx_service /system/bin/ | 推送单个 Native 可执行文件 |
| adb | adb shell setenforce 0 | 临时关闭 SELinux 排查权限问题 |
| adb | adb logcat -s xxx_service:V | 按 TAG 过滤服务日志 |
| fastboot | fastboot flash system system.img | 刷写 system 分区 |
| fastboot | fastboot reboot | 刷写后重启进入系统 |
修改
/system 分区前需执行 adb remount 或 adb disable-verity 后重启,否则会因 dm-verity 校验失败导致写入无效。生产设备还需解锁 bootloader,注意数据会被清空。五、案例场景:新增一个 Native Service 的完整闭环
- 在
frameworks/base/services/下新建模块目录,编写Android.bp,声明cc_binary与依赖的libbinder、libutils。 - 编写
xxx_service.rc,定义service、class core、user system与oneshot等属性。 - 执行
mmm frameworks/base/services/xxx编译,确认out/target/product/.../system/bin/xxx_service生成。 adb push可执行文件与 rc 文件,adb shell start xxx_service启动。- 用
adb logcat与adb shell dumpsys验证服务注册与接口调用。 - 验证通过后,将模块加入系统编译配置,全量
m并fastboot flash system固化。
六、误区与复盘
- 只配 NDK 不配 AOSP:NDK 编出的 .so 无法直接作为系统服务常驻,最终仍需 AOSP 编译进镜像。
- 忽略 SELinux:服务启动失败常因
avc: denied,应先用setenforce 0定位,再补te规则,而不是长期关闭。 - NDK 版本漂移:不同 NDK 的 libc++ ABI 可能不兼容,务必在构建脚本中锁定版本。
- 直接改 system 分区不刷机:临时 push 只适合调试,正式验证必须走镜像刷写,否则环境不可复现。
环境搭建的验收标准:能独立完成一次 AOSP 全量编译、能用 NDK 编出一个可执行程序、能通过 adb 推送并看到 Native Service 日志、能用 fastboot 刷写 system 镜像并正常启动。四条全部打通,才具备后续 Native Service 开发的基础条件。