3. Framework核心服务定制:SystemServer启动流程分析、核心服务(AMS/WMS/PMS)定制、车载场景下的服务优化

各位同学,今天我们来聊聊车载Android系统里最硬核的部分——Framework核心服务的定制。说实话,这部分内容在手机端可能你接触得不多,但在车载场景下,几乎每个项目都要动刀子。我做了这么多年车载系统,可以说,谁掌握了核心服务的定制能力,谁就掌握了系统的灵魂。

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

SystemServer,说白了就是Android系统的“大管家”。它负责启动所有核心服务。你想想看,从开机动画结束到Launcher显示,中间发生了什么?全是SystemServer的功劳。

启动流程大致是这样的:

  1. Zygote进程fork出SystemServer进程
  2. SystemServer加载本地库,初始化JNI
  3. 创建SystemServiceManager,开始启动各类服务
  4. 服务分为三个阶段:引导服务、核心服务、其他服务
  5. 所有服务启动完成后,通知系统进入就绪状态

嗯,这里要注意一个关键点:服务的启动顺序是写死的。我在项目中遇到过,因为某个第三方服务启动太慢,导致整个开机时间增加了3秒。后来怎么解决的?我们把它从“核心服务”移到了“其他服务”阶段,延迟加载。

核心思路:车载场景下,开机速度是硬指标。我们要学会“偷懒”——把非关键服务延后启动,优先保证仪表和中控的显示。

来看一段SystemServer中服务启动的核心代码:

// frameworks/base/services/java/com/android/server/SystemServer.java
private void startBootstrapServices() {
    // 启动Installer
    Installer installer = mSystemServiceManager.startService(Installer.class);
    
    // 启动ActivityManagerService
    mActivityManagerService = mSystemServiceManager.startService(
            ActivityManagerService.class);
    
    // 启动PowerManagerService
    mPowerManagerService = mSystemServiceManager.startService(
            PowerManagerService.class);
    
    // 启动PackageManagerService
    mPackageManagerService = mSystemServiceManager.startService(
            PackageManagerService.class);
}

private void startCoreServices() {
    // 启动DisplayManagerService
    mDisplayManagerService = mSystemServiceManager.startService(
            DisplayManagerService.class);
    
    // 启动WindowManagerService
    mWindowManagerService = mSystemServiceManager.startService(
            WindowManagerService.class);
}

这段代码看起来简单,但背后藏着很多坑。比如,AMS和PMS之间有依赖关系,如果顺序搞反了,系统直接崩溃。我曾经调试过一个bug,就是PMS启动时依赖AMS的某个功能,但AMS还没初始化完成,结果死锁了。最后我们加了一个等待机制才解决。

3.2 核心服务定制:AMS/WMS/PMS的“手术刀”

接下来我们一个一个看。这三个服务,是车载定制中最常动刀的地方。

3.2.1 AMS(ActivityManagerService)定制

AMS管什么?管应用的生命周期、任务栈、进程管理。在车载场景下,最头疼的问题是什么?多用户切换前台应用的优先级

举个例子:驾驶员在导航,副驾在看视频。这时候来了一个电话,系统该怎么做?手机的逻辑是直接全屏显示来电界面。但在车上,你不能把导航给切掉啊!

所以,我们需要定制AMS的startActivity流程:

// 伪代码:车载场景下的Activity启动策略
boolean shouldOverrideStartActivity(Intent intent, int userId) {
    // 判断当前前台应用是否属于安全关键应用
    if (isSafetyCriticalApp(getTopApp())) {
        // 如果是导航、仪表等,不允许被普通应用覆盖
        if (!isSafetyCriticalApp(intent)) {
            return true; // 拦截,改为通知或小窗显示
        }
    }
    return false; // 正常启动
}

我个人习惯在AMS中维护一个“安全应用白名单”,只有白名单里的应用才能抢占前台。其他应用,哪怕你调了startActivity,我也只给你弹个通知。

避坑指南:我曾经在定制AMS时,直接修改了startActivityLocked方法,结果导致所有应用的启动都变慢了。后来发现,不能在这个热路径上加太多逻辑。正确的做法是在ActivityStarter层做拦截,而不是在AMS核心方法里。

3.2.2 WMS(WindowManagerService)定制

WMS管窗口的布局、显示、动画。车载场景下,WMS的定制重点在于多屏显示窗口层级管理

现在的车,至少三块屏:仪表屏、中控屏、副驾屏。WMS需要知道每个窗口应该显示在哪块屏上。默认的Android WMS只支持单屏,所以我们需要扩展它。

核心思路是:为每个物理屏幕创建一个独立的DisplayContent,然后为每个屏幕定义不同的窗口层级策略。

// 伪代码:车载多屏WMS配置
class CarWindowManagerService extends WindowManagerService {
    // 为每个屏幕定义独立的窗口层级
    void configureDisplayForCar() {
        // 仪表屏:只允许系统窗口和导航应用
        DisplayContent instrumentDisplay = getDisplay(Display.TYPE_INSTRUMENT);
        instrumentDisplay.setWindowPolicy(new InstrumentPanelPolicy());
        
        // 中控屏:允许所有应用,但限制悬浮窗
        DisplayContent centerDisplay = getDisplay(Display.TYPE_CENTER);
        centerDisplay.setWindowPolicy(new CenterConsolePolicy());
        
        // 副驾屏:允许视频、游戏等娱乐应用
        DisplayContent passengerDisplay = getDisplay(Display.TYPE_PASSENGER);
        passengerDisplay.setWindowPolicy(new PassengerEntertainmentPolicy());
    }
}

嗯,这里要注意,不同屏幕的刷新率可能不一样。仪表屏通常是60Hz,中控屏可能是120Hz。WMS需要根据屏幕的刷新率来调整动画帧率,否则会出现画面撕裂。

3.2.3 PMS(PackageManagerService)定制

PMS管应用的安装、卸载、权限。车载场景下,PMS的定制重点在于预装应用管理权限策略

车厂通常有大量的预装应用,而且这些应用不能随便被卸载。默认的PMS允许用户卸载预装应用,但在车上,你不能让用户把导航给卸了吧?

所以,我们需要定制PMS的卸载逻辑:

// 伪代码:车载PMS卸载保护
boolean canUninstallPackage(String packageName, int userId) {
    // 检查是否在保护名单中
    if (isProtectedPackage(packageName)) {
        return false; // 不允许卸载
    }
    // 检查是否是系统关键应用
    if (isSystemCriticalApp(packageName)) {
        return false;
    }
    return super.canUninstallPackage(packageName, userId);
}

另外,权限管理也是个坑。车载应用需要的权限和手机不一样。比如,导航应用需要访问CAN总线数据,这在手机上是没有的。所以我们需要在PMS中扩展自定义权限。

警告:千万不要在PMS的scanPackageLI方法中做太多定制。这个方法在开机时会被调用数百次,任何额外的逻辑都会显著拖慢开机速度。我见过一个项目,因为在这个方法里加了数据库查询,开机时间从15秒变成了40秒。

3.3 车载场景下的服务优化:实战经验

好了,理论讲完了,我们来点实战的。下面这张图是我总结的车载核心服务优化框架:

车载核心服务优化框架 SystemServer AMS定制 WMS定制 PMS定制 AMS优化策略 • 安全应用白名单 • 延迟启动非关键应用 WMS优化策略 • 多屏独立DisplayContent • 按屏幕调整刷新率 PMS优化策略 • 预装应用卸载保护 • 自定义车载权限 核心性能指标 开机时间 ≤ 15s | 应用启动 ≤ 500ms | 窗口切换无黑屏 | 多屏同步 ≤ 16ms

这张图展示了我们优化的整体思路。从SystemServer出发,到三大服务的定制,再到具体的优化策略,最后落到性能指标上。说白了,所有的定制都是为了满足这些指标。

3.4 实战中的几个“坑”

最后,我分享几个实战中遇到的坑,希望能帮大家少走弯路。

问题 现象 根因 解决方案
开机死锁 系统卡在开机动画 AMS和PMS互相等待 调整启动顺序,增加超时机制
窗口闪烁 切换应用时黑屏 WMS窗口动画未同步 使用硬件合成器,预加载窗口
应用无法安装 预装应用被误删 PMS卸载保护逻辑有bug 增加白名单校验,修复条件判断
多屏显示错乱 导航显示在副驾屏 DisplayContent未正确绑定 为每个应用指定默认显示屏幕

我曾经在调试一个多屏项目时,发现副驾屏总是显示导航界面。查了两天才发现,是WMS中getDefaultDisplay方法返回了错误的屏幕ID。后来我们改成了根据应用包名来分配屏幕,问题才解决。

小技巧:在调试SystemServer相关问题时,建议开启adb logcat -s SystemServer,单独查看SystemServer的日志。这样可以过滤掉大量无关信息,快速定位问题。

好了,这一章的内容就到这里。核心服务的定制是车载Android系统的基石,掌握了这些,你就能真正掌控系统的行为。下一章我们会深入AMS的源码,看看如何实现一个完整的车载应用管理策略。


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