19、系统服务与框架定制:System Server启动流程、CarService定制、车载应用框架、多用户与配置文件管理

各位同学,今天我们来啃一块硬骨头——系统服务与框架定制。说实话,这部分内容在Android Automotive里属于“牵一发而动全身”的核心地带。我当年第一次接触System Server时,看着那密密麻麻的启动链,心里直犯嘀咕:这玩意儿到底是怎么串起来的?

别急,咱们一步步拆解。你想想看,车载系统和手机系统最大的区别在哪?手机是你一个人用,车是一家人用。这就引出了多用户、配置文件管理这些车载特有的需求。好,咱们正式开始。

19.1 System Server启动流程——从init到CarService的完整链路

System Server是Android框架的心脏。它启动后,所有系统服务才陆续登场。我习惯把它的启动流程分成三个阶段:

  1. init进程启动——解析init.rc,拉起Zygote
  2. Zygote孵化System Server——fork出system_server进程
  3. System Server内部启动链——按优先级启动各类服务

咱们重点看第三步。System Server内部有一个SystemServer.java,它把服务分成了几个启动阶段:

// 伪代码,展示启动顺序
private void startBootstrapServices() {
    // 1. 启动Installer(包管理基础)
    Installer installer = new Installer();
    // 2. 启动ActivityManagerService
    mActivityManagerService = new ActivityManagerService(context);
    // 3. 启动PowerManagerService
    mPowerManagerService = new PowerManagerService(context);
}

private void startCoreServices() {
    // 4. 启动BatteryService、UsageStatsService等
}

private void startOtherServices() {
    // 5. 启动CarService(车载核心)
    // 6. 启动WMS、PMS等
}

这里有个关键点:CarService是在startOtherServices阶段启动的。为什么?因为CarService依赖很多底层服务(比如PowerManager、PackageManager)已经就绪。我在项目中遇到过有人试图把CarService提前到bootstrap阶段启动,结果各种空指针异常,折腾了两天才发现是依赖没准备好。

核心原则:服务启动顺序 = 依赖关系倒序。被依赖的服务先启动,依赖别人的服务后启动。

19.2 CarService定制——车载服务的核心枢纽

CarService是什么?说白了,它就是车载系统的“交通警察”。所有车辆相关的硬件控制(空调、车窗、车门、灯光)都通过它来统一管理。

CarService的架构分三层:

层级 组件 职责
应用层 Car API (android.car.*) 提供Java接口给车载应用调用
服务层 CarService 管理车辆属性、策略控制
硬件抽象层 Vehicle HAL 与车载硬件通信(CAN总线、LIN总线)

定制CarService时,我建议你重点关注两个地方:

  • VehicleMap:车辆属性映射表。比如空调温度对应哪个HAL属性ID,这个表必须和硬件团队对齐。我曾经因为一个属性ID写错,导致空调控制界面死活没反应,查了三天才发现是映射表配错了。
  • CarService的生命周期管理:CarService是一个系统服务,它需要处理用户切换、睡眠唤醒等场景。别忘了在onUserSwitching回调里重置车辆状态。

避坑指南:我曾经在定制CarService时,忘记处理多用户场景下的车辆状态同步。结果主用户调了空调温度,切换到副用户后温度又跳回去了。解决方案是在CarService里维护一个全局状态,用户切换时只更新UI,不重置硬件。

19.3 车载应用框架——从CarApp到多窗口管理

车载应用框架和手机应用框架最大的区别是什么?我总结了两点:

  1. 安全第一:驾驶过程中,应用不能干扰驾驶员。所以车载应用有严格的“驾驶模式”限制。
  2. 多窗口是常态:导航、音乐、空调三个应用同时显示,这在手机上很少见,在车里是标配。

Android Automotive提供了CarApp框架,它封装了车载特有的API:

// 车载应用示例
public class MyCarApp extends CarActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 获取车辆属性管理器
        CarPropertyManager cpm = getCarPropertyManager();
        // 监听车速变化
        cpm.registerCallback(CarPropertyManager.SENSOR_CAR_SPEED, callback);
    }
}

多窗口管理这块,我建议你直接使用CarMultiWindowManager。它提供了预设的布局模板:

  • 全屏模式:导航独占屏幕
  • 分屏模式:导航+音乐各占一半
  • 画中画模式:小窗口显示辅助信息

嗯,这里要注意:不要自己实现窗口管理逻辑。我见过有团队自己写了一套窗口管理,结果和系统原生的多窗口机制冲突,各种崩溃。直接用系统提供的API,省心又稳定。

19.4 多用户与配置文件管理——车载系统的“家庭模式”

车载多用户和手机多用户不太一样。手机多用户是“完全隔离”的,每个用户有自己的应用和数据。车载多用户更灵活:

  • 主用户:车主,拥有所有权限
  • 副用户:家庭成员,可以访问部分功能
  • 访客用户:临时使用,数据用完即焚

配置文件管理是这里的关键。每个用户都有自己的配置文件,里面存储了:

配置项 示例 存储位置
座椅位置 驾驶座前后、靠背角度 /data/system/users/{userId}/car_seat.xml
空调偏好 温度、风量、风向 /data/system/users/{userId}/car_hvac.xml
音频设置 音量、均衡器 /data/system/users/{userId}/car_audio.xml

我建议你在实现多用户时,注意以下几点:

  • 用户切换时保存状态:在onUserSwitching回调里,把当前用户的车辆设置保存到配置文件。
  • 恢复状态时校验合法性:比如副用户不能保存“最高车速限制”这类安全相关的配置。
  • 访客用户的数据清理:访客退出时,记得删除其配置文件,避免隐私泄露。

警告:多用户场景下,千万不要把车辆硬件状态直接和用户绑定。比如空调温度,硬件只有一个实际温度,但每个用户可能有不同的“期望温度”。正确的做法是:用户切换时,只更新UI显示的目标温度,不改变硬件实际温度。等用户确认后,再下发指令给硬件。

19.5 知识体系总览

为了帮你理清思路,我画了一张图,把本章的核心知识点串起来:

系统服务与框架定制知识体系 System Server 启动 CarService 定制 车载应用框架 多用户与配置文件 CarApp API 多窗口管理 用户切换 配置文件管理 安全 · 稳定 · 可定制

这张图把System Server、CarService、车载应用框架、多用户管理串在了一起。你看,底层是System Server启动,中间是CarService这个枢纽,上层分两条线:左边是应用框架,右边是多用户管理。三者共同构成了车载系统的骨架。

好了,这一章的内容就到这里。记住,系统服务定制不是一蹴而就的事,需要你反复调试、验证。我当年做第一个车载项目时,光CarService的启动顺序就调了整整一周。但只要你把基础打牢了,后面的事情就水到渠成了。


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