3. Framework核心服务定制:SystemServer启动流程分析、核心服务(AMS/WMS/PMS)定制、车载场景下的服务优化
各位同学,今天我们来聊聊车载Android系统里最硬核的部分——Framework核心服务的定制。说实话,这部分内容在手机端可能你接触得不多,但在车载场景下,几乎每个项目都要动刀子。我做了这么多年车载系统,可以说,谁掌握了核心服务的定制能力,谁就掌握了系统的灵魂。
3.1 SystemServer启动流程:一切从这里开始
SystemServer,说白了就是Android系统的“大管家”。它负责启动所有核心服务。你想想看,从开机动画结束到Launcher显示,中间发生了什么?全是SystemServer的功劳。
启动流程大致是这样的:
- Zygote进程fork出SystemServer进程
- SystemServer加载本地库,初始化JNI
- 创建SystemServiceManager,开始启动各类服务
- 服务分为三个阶段:引导服务、核心服务、其他服务
- 所有服务启动完成后,通知系统进入就绪状态
嗯,这里要注意一个关键点:服务的启动顺序是写死的。我在项目中遇到过,因为某个第三方服务启动太慢,导致整个开机时间增加了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出发,到三大服务的定制,再到具体的优化策略,最后落到性能指标上。说白了,所有的定制都是为了满足这些指标。
3.4 实战中的几个“坑”
最后,我分享几个实战中遇到的坑,希望能帮大家少走弯路。
| 问题 | 现象 | 根因 | 解决方案 |
|---|---|---|---|
| 开机死锁 | 系统卡在开机动画 | AMS和PMS互相等待 | 调整启动顺序,增加超时机制 |
| 窗口闪烁 | 切换应用时黑屏 | WMS窗口动画未同步 | 使用硬件合成器,预加载窗口 |
| 应用无法安装 | 预装应用被误删 | PMS卸载保护逻辑有bug | 增加白名单校验,修复条件判断 |
| 多屏显示错乱 | 导航显示在副驾屏 | DisplayContent未正确绑定 | 为每个应用指定默认显示屏幕 |
我曾经在调试一个多屏项目时,发现副驾屏总是显示导航界面。查了两天才发现,是WMS中getDefaultDisplay方法返回了错误的屏幕ID。后来我们改成了根据应用包名来分配屏幕,问题才解决。
小技巧:在调试SystemServer相关问题时,建议开启adb logcat -s SystemServer,单独查看SystemServer的日志。这样可以过滤掉大量无关信息,快速定位问题。
好了,这一章的内容就到这里。核心服务的定制是车载Android系统的基石,掌握了这些,你就能真正掌控系统的行为。下一章我们会深入AMS的源码,看看如何实现一个完整的车载应用管理策略。