3、系统服务框架:SystemServer启动流程、ServiceManager的作用、系统服务注册与获取
好,我们进入第三章。这一章,我打算聊聊车载系统里最核心的骨架——系统服务框架。
你想想看,Android Automotive 为什么能跑起来?为什么你点一下屏幕,空调就能调温,导航就能规划路线?背后就是这一整套服务在支撑。说白了,SystemServer 就是整个系统的“大管家”,ServiceManager 就是“通讯录”。
3.1 SystemServer 启动流程:一切从这里开始
SystemServer 是什么?它是 Android 系统里第一个启动的 Java 进程。Zygote 孵化出它之后,它就负责拉起所有核心服务。
我个人习惯把它的启动流程分成三个阶段:
- Native 层准备:init 进程解析 init.rc,启动 Zygote。Zygote fork 出 SystemServer 进程。
- Java 层初始化:SystemServer.main() 被调用,创建 SystemServer 对象,调用 run() 方法。
- 服务启动三部曲:启动引导服务(如 ActivityManagerService)、启动核心服务(如 PackageManagerService)、启动其他服务(如 CarService)。
嗯,这里要注意。在 Automotive 上,启动顺序比手机更敏感。为什么?因为车载的硬件模块(比如 CAN 总线、域控制器)必须在特定服务就绪后才能访问。
关键代码路径:
// frameworks/base/services/java/com/android/server/SystemServer.java
public static void main(String[] args) {
new SystemServer().run();
}
private void run() {
// 1. 设置系统属性
SystemProperties.set("sys.boot_completed", "0");
// 2. 创建系统上下文
createSystemContext();
// 3. 启动引导服务
startBootstrapServices();
// 4. 启动核心服务
startCoreServices();
// 5. 启动其他服务
startOtherServices();
// 6. 通知系统启动完成
SystemProperties.set("sys.boot_completed", "1");
}
我在项目中遇到过一个问题:某个 Tier1 供应商的空调服务依赖 SensorService,但 SensorService 启动较慢,导致空调控制面板卡死。后来我们加了一个 waitForService 的等待机制才解决。所以,服务间的依赖关系一定要梳理清楚。
3.2 ServiceManager 的作用:系统的“通讯录”
ServiceManager 是什么?你可以把它理解成一本电话簿。每个服务启动后,都会把自己的名字(服务名)和 Binder 句柄登记在 ServiceManager 里。其他进程想用某个服务,就通过名字去查。
为什么需要它?因为 Binder 通信需要知道对方的句柄。如果没有 ServiceManager,每个进程都得硬编码对方的句柄,那系统就乱套了。
ServiceManager 本身也是一个 Binder 服务,它的句柄是固定的(0)。它主要提供三个能力:
- addService:服务注册。服务端调用,把自身暴露出去。
- getService:服务获取。客户端调用,拿到服务端的 Binder 代理。
- checkService:检查服务是否存在。不会阻塞等待。
避坑指南:
我曾经在调试一个 CarService 时,发现 getService 返回了 null。排查了半天,原来是服务注册时用了不同的 Context。记住:ServiceManager.addService() 必须在服务所在进程的主线程或 Binder 线程池中调用,否则会注册失败。
3.3 系统服务注册与获取:手把手教你写一个服务
光说不练假把式。我们来看一个实际的车载服务注册流程。假设我们要写一个 VehicleSpeedService,用来获取车速。
3.3.1 定义 AIDL 接口
// IVehicleSpeedService.aidl
package com.example.automotive;
interface IVehicleSpeedService {
int getCurrentSpeed();
void registerCallback(IVehicleSpeedCallback callback);
}
3.3.2 实现服务端
public class VehicleSpeedService extends IVehicleSpeedService.Stub {
private static final String TAG = "VehicleSpeedService";
@Override
public int getCurrentSpeed() {
// 从 CAN 总线读取车速
return CanBusManager.getInstance().getSpeed();
}
@Override
public void registerCallback(IVehicleSpeedCallback callback) {
// 注册回调,当车速变化时通知客户端
mCallbacks.register(callback);
}
}
3.3.3 注册到 ServiceManager
// 在 SystemServer 的 startOtherServices() 中调用
try {
VehicleSpeedService speedService = new VehicleSpeedService();
ServiceManager.addService("vehicle_speed", speedService);
Slog.i(TAG, "VehicleSpeedService registered successfully");
} catch (Exception e) {
Slog.e(TAG, "Failed to register VehicleSpeedService", e);
}
3.3.4 客户端获取服务
IBinder binder = ServiceManager.getService("vehicle_speed");
if (binder != null) {
IVehicleSpeedService speedService = IVehicleSpeedService.Stub.asInterface(binder);
int speed = speedService.getCurrentSpeed();
Log.d(TAG, "Current speed: " + speed);
} else {
Log.w(TAG, "VehicleSpeedService not available");
}
重要提醒:
在 Automotive 上,服务注册时要注意 SELinux 权限。我曾经在集成第三方导航服务时,因为 SELinux 策略没配好,服务注册成功但客户端无法访问。检查 service_contexts 文件和 te 规则是必修课。
3.4 服务启动的时序问题
你想想看,如果 ServiceManager 还没启动,服务就去注册,会发生什么?答案是:注册失败,进程崩溃。
所以,SystemServer 的启动顺序是严格控制的。我建议你在开发自定义服务时,遵循以下原则:
| 服务类型 | 启动阶段 | 典型服务 |
|---|---|---|
| 引导服务 | startBootstrapServices() | ActivityManagerService, PackageManagerService |
| 核心服务 | startCoreServices() | BatteryService, UsageStatsService |
| 车载服务 | startOtherServices() | CarService, VehicleSpeedService |
| 第三方服务 | 系统启动完成后 | 地图导航、语音助手 |
嗯,这里有个小技巧。如果你的服务依赖另一个服务,不要直接 getService 然后空转等待。用 ServiceManager.waitForService() 会更优雅。这个 API 会阻塞直到目标服务可用。
总结一下:
- SystemServer 是服务的“孵化器”,启动顺序决定系统稳定性。
- ServiceManager 是服务的“通讯录”,没有它,Binder 通信寸步难行。
- 注册服务时注意 SELinux 和 Context,获取服务时注意空指针和超时。
好,这一章就到这里。下一章我们会深入 CarService 的内部架构,看看车载特有的服务是怎么组织起来的。到时候我会分享一个我在某量产车型上遇到的“血泪史”——因为服务注册顺序不对,导致中控屏黑屏的案例。