3、CarService 核心服务:启动流程、核心API与硬件交互

各位同学,今天我们来聊聊 CarService。这是 Android Automotive 里最核心的一个服务,没有之一。我当年第一次接触 Automotive 项目时,就被 CarService 的启动流程绕晕过——它不像普通 App 那样简单 start,而是经历了好几层初始化。今天我就把这块掰开揉碎了讲清楚。

3.1 CarService 的启动流程

CarService 本质上是一个系统服务,但它不是通过 SystemServer 直接启动的。它走了一条「曲线救国」的路径。

启动流程大致分三步:

  1. SystemServer 启动 CarServiceHelperService——这是一个轻量级的辅助服务,负责拉起 CarService 的进程。
  2. CarServiceHelperService 通过 bindService 启动 CarService——CarService 运行在独立的进程中(android.car),与 SystemServer 隔离。
  3. CarService 初始化所有子服务——比如 CarPropertyService、CarAudioService、CarNavigationService 等。

我画了一张流程图,方便你理解:

CarService 启动流程图 SystemServer 启动 CarServiceHelperService bindService → CarService CarService.init() CarPropertyService CarAudioService 其他子服务...

嗯,这里要注意:CarService 是运行在 android.car 进程中的。为什么要单独一个进程?说白了就是为了隔离——万一 CarService 崩了,不会拖垮整个系统。我在项目中遇到过好几次 CarService 因硬件通信超时导致 ANR,但因为进程隔离,SystemServer 和 Launcher 都还活着,用户体验好很多。

3.2 核心 API 设计

CarService 暴露给上层应用的 API,主要通过 Car 这个入口类。你想想看,一个车载应用要获取车速、控制空调、切换音源,总不能直接跟硬件打交道吧?CarService 就是中间人。

核心 API 分为几大类:

API 类别 Manager 类 典型功能
车辆属性 CarPropertyManager 读取车速、里程、油量、车门状态
音频 CarAudioManager 音区控制、音量调节、音源切换
导航 CarNavigationManager 导航指令、仪表盘投射
传感器 CarSensorManager 加速度、陀螺仪、GPS 融合数据
诊断 CarDiagnosticManager OBD 故障码读取

每个 Manager 都对应一个子服务。比如 CarPropertyManager 背后是 CarPropertyService,它通过 Vehicle HAL 与硬件通信。我建议你重点看 CarPropertyManager,因为它覆盖了 80% 的车载数据场景。

重要提示:CarService 的 API 设计遵循「订阅-发布」模式。你调用 registerCallback() 后,当车辆状态变化(比如车门打开),CarService 会主动推给你。不要用轮询——我在项目中见过有人每秒读一次车速,结果 CPU 占用飙到 15%,被架构师狠批了一顿。

3.3 与车载硬件的交互方式

CarService 怎么跟硬件打交道?答案是 Vehicle HAL。这是 Android Automotive 最巧妙的设计之一。

交互链路是这样的:

App → CarService → Vehicle HAL → 硬件(CAN 总线 / LIN 总线 / 以太网)

Vehicle HAL 定义了标准的接口,比如 getProperty()setProperty()subscribe()。CarService 通过 JNI 调用 HAL 的 C++ 实现,HAL 再通过 Socket 或共享内存与硬件通信。

我举个例子,读取当前车速:

// App 端
Car car = Car.createCar(context);
CarPropertyManager pm = (CarPropertyManager) car.getManager(Car.PROPERTY_SERVICE);
float speed = pm.getFloatProperty(VehicleProperty.PERF_VEHICLE_SPEED, 0);

这段代码背后发生了什么?

  1. App 通过 Binder 调用 CarPropertyService
  2. CarPropertyService 调用 Vehicle HAL 的 get() 方法
  3. HAL 从 CAN 总线读取车速传感器的原始数据
  4. 数据一路返回给 App

整个过程大约 5-15 毫秒。你可能会问:为什么不用更快的通信方式?嗯,这里有个现实问题——车载硬件的响应速度本身就不快。CAN 总线的典型波特率是 500kbps,一条报文也就 8 字节数据。所以 CarService 的设计哲学是「够用就好」,而不是追求极致性能。

避坑指南:我曾经在调试空调控制时,发现 setProperty() 调用后硬件没有反应。排查了半天,结果是 HAL 层没有实现 set() 方法——它只实现了 get()。所以你在对接硬件时,一定要先确认 HAL 实现了哪些属性,哪些是只读的,哪些是可写的。别想当然。

3.4 属性订阅机制

CarService 支持属性变化主动通知。你不需要反复查询,只需要注册监听:

pm.registerCallback(callback, VehicleProperty.PERF_VEHICLE_SPEED,
    CarPropertyManager.SENSOR_RATE_NORMAL);

当车速变化时,CarService 会回调 onPropertyEvent()。这个机制底层依赖 Vehicle HAL 的 subscribe() 接口。HAL 会监听 CAN 总线上的特定报文,一旦有变化就上报。

我个人习惯把订阅逻辑封装在 ViewModel 里,配合 Lifecycle 管理。这样 Activity 销毁时自动取消订阅,避免内存泄漏。你想想看,如果忘记取消订阅,CarService 会一直持有你的回调引用——这在车载系统里是致命问题,因为 CarService 是常驻服务,永远不会重启。

警告:不要在 onPropertyEvent() 中做耗时操作。这个回调运行在 CarService 的 Binder 线程池中,阻塞它会影响其他应用获取车辆数据。如果你需要处理数据,请切换到自己的工作线程。

3.5 总结

CarService 是 Android Automotive 的中枢神经。它通过 Vehicle HAL 与硬件解耦,通过 Binder 与上层应用通信。启动流程虽然绕,但保证了进程隔离和稳定性。核心 API 以 Manager 形式暴露,覆盖了车辆属性、音频、导航等关键领域。

最后说一句:理解 CarService 的关键,在于理解「分层」和「隔离」这两个设计思想。你搞懂了这两点,后面学 CarAudioService、CarNavigationService 就会轻松很多。


公众号:蓝海资料掘金营,微信 deep3321