1. 课程导入
在 Android 系统开发中,Service 是一个被频繁提及却容易被混淆的概念。应用开发者熟悉的 Service 是四大组件之一,运行在应用进程内,由 ActivityManagerService 调度;而系统开发者口中的 Native Service,则是运行在 system_server 之外、以 C/C++ 编写、通过 Binder 驱动直接向内核注册节点的系统级服务。本课程讨论的是后者——它是 Android 系统能力的“地基”,负责音频、相机、显示、传感器、电源、存储等几乎所有硬件相关能力的对外暴露。
.rc 脚本拉起,以 service 关键字声明,并注册到 ServiceManager 中供全局查询。
一、从 Java Service 到 Native Service:为什么需要两套体系
Android 早期(1.0~2.x)大量系统能力直接以 Java Service 形式实现在 frameworks/base/services/java 中,例如早期的 ActivityManagerService、WindowManagerService。但随着硬件抽象层(HAL)和多媒体、图形栈的复杂化,Java 层暴露出三个难以回避的问题:
- 性能与实时性:音频混音、相机帧回调、传感器采样对延迟敏感,JVM 的 GC 停顿和 JNI 边界开销不可接受。
- 复用既有 C/C++ 库:Stagefright、Skia、libhardware、Vulkan 等本身就是 Native 库,用 Java 重写成本极高。
- 进程隔离与稳定性:把相机、音频等易崩溃模块放进独立 Native 进程,可避免拖垮 system_server。
于是从 Android 4.x 开始,Google 逐步将 MediaPlayerService、CameraService、AudioFlinger、SurfaceFlinger、SensorService 等迁移为 Native Service,形成“Java Service 管策略、Native Service 管执行”的分层格局。到 Android 8.0 引入 Treble 与 HIDL,Android 10 引入 AIDL HAL,Native Service 的边界进一步下沉到 vendor 分区,成为连接 framework 与 HAL 的关键枢纽。
二、Java Service 与 Native Service 的核心差异
理解两者差异,是后续所有调试与开发工作的前提。下表从语言、进程、注册方式、接口描述、生命周期等维度做对照:
| 对比维度 | Java Service | Native Service |
|---|---|---|
| 实现语言 | Java / Kotlin | C / C++ |
| 运行位置 | system_server 或应用进程 | 独立 Native 进程(如 audioserver、cameraserver) |
| 启动方式 | SystemServer 中 addService | init 解析 .rc 脚本 fork/exec |
| 注册中心 | ServiceManager(Java 代理) | ServiceManager(Binder 驱动 /dev/binder) |
| 接口描述 | AIDL(.aidl 文件) | AIDL(NDK backend)或 HIDL |
| 典型代表 | ActivityManagerService、PackageManagerService | AudioFlinger、CameraService、SurfaceFlinger |
| 调试手段 | dumpsys、am、logcat | dumpsys、binder 节点、strace、perfetto |
需要特别强调的是:两者并非替代关系,而是协作关系。例如应用调用 AudioManager,实际链路是 AudioManager(Java) → AudioService(Java, system_server) → AudioFlinger(Native) → Audio HAL。Java 层负责权限、策略与状态机,Native 层负责数据通路与硬件交互。
三、整体知识框架与学习路径
本课程围绕“能看懂、能调试、能新增、能优化”四个目标展开,知识框架可归纳为五层:
- 基础层:Binder 驱动、ServiceManager、IPCThreadState、Parcel 序列化。
- 框架层:BnInterface/BpInterface、AIDL NDK 生成规则、
defaultServiceManager()与addService。 - 启动层:init.rc 语法、service/on 段、SELinux 域与
service_contexts。 - 实现层:典型服务剖析(AudioFlinger、CameraService、SensorService)与 HAL 对接。
- 工程层:Android.bp 编译、dumpsys 调试、binder 泄漏排查、性能与稳定性优化。
下图给出 Native Service 在 Android 系统中的位置与一次跨进程调用的完整信号链,帮助建立全局视角:
四、典型场景:一次录音请求的完整链路
以应用调用 AudioRecord 录音为例,可清晰看到 Java 与 Native 的分工:
App: AudioRecord.startRecording()
→ AudioRecord (JNI) → android_media_AudioRecord_start
→ AudioSystem::startInput (Native)
→ BpAudioFlinger → Binder 驱动 → BnAudioFlinger::onTransact
→ AudioFlinger::startInput → AudioStreamIn::start
→ Audio HAL (AIDL) → ALSA / 驱动
这条链路中,AudioService 负责判断录音权限、焦点与并发策略;AudioFlinger 负责创建输入流、混音与缓冲区管理;HAL 负责真正打开 PCM 设备。任何一环出错,都会在 dumpsys media.audio_flinger 或 logcat -b all 中留下痕迹。
service list | grep hello 验证注册成功,再逐步加入 AIDL 接口、SELinux 策略与 dumpsys 输出。有了可运行的“活体”,再回头看 Binder 原理会事半功倍。
五、常见误区与复盘
- 误区一:把 Native Service 等同于 HAL。HAL 是硬件抽象接口,Native Service 是系统服务实现,二者是调用方与被调用方的关系,一个 Native Service 可对接多个 HAL。
- 误区二:认为 Native Service 一定在独立进程。部分服务(如
SurfaceFlinger的某些线程)可运行在 system_server 的 native 线程中,判断依据是ps -A与dumpsys -l的实际输出。 - 误区三:忽略 SELinux。服务注册成功但调用失败,十有八九是
avc: denied,需检查service_contexts与te规则。 - 误区四:只改代码不验证。每次修改后应执行
adb shell dumpsys <service>与adb shell service list,确认服务存活与接口可见。