3、系统服务框架:SystemServer启动流程、ServiceManager的作用、系统服务注册与获取

好,我们进入第三章。这一章,我打算聊聊车载系统里最核心的骨架——系统服务框架。

你想想看,Android Automotive 为什么能跑起来?为什么你点一下屏幕,空调就能调温,导航就能规划路线?背后就是这一整套服务在支撑。说白了,SystemServer 就是整个系统的“大管家”,ServiceManager 就是“通讯录”。

3.1 SystemServer 启动流程:一切从这里开始

SystemServer 是什么?它是 Android 系统里第一个启动的 Java 进程。Zygote 孵化出它之后,它就负责拉起所有核心服务。

我个人习惯把它的启动流程分成三个阶段:

  1. Native 层准备:init 进程解析 init.rc,启动 Zygote。Zygote fork 出 SystemServer 进程。
  2. Java 层初始化:SystemServer.main() 被调用,创建 SystemServer 对象,调用 run() 方法。
  3. 服务启动三部曲:启动引导服务(如 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 的内部架构,看看车载特有的服务是怎么组织起来的。到时候我会分享一个我在某量产车型上遇到的“血泪史”——因为服务注册顺序不对,导致中控屏黑屏的案例。