3、车载Android系统定制:AOSP源码下载与编译、车载系统服务定制、系统属性配置
各位同学,今天我们来聊聊车载Android系统定制的硬核部分。说实话,很多做应用层的朋友一听到「源码下载编译」就头大,觉得那是底层工程师的事。但在我做车载座舱系统的这些年里,踩过的坑告诉我——不懂系统定制,你永远只能做「能用」的产品,做不出「好用」的座舱。
这一章,我会带你走一遍AOSP的下载、编译流程,然后深入车载系统服务的定制方法,最后聊聊系统属性配置那些容易被忽略的细节。嗯,都是实战中反复验证过的东西。
3.1 AOSP源码下载与编译:从零搭建你的车载系统基线
先说说源码下载。你可能会问:「不就是git clone吗?有什么好讲的?」
我刚开始也这么想。直到有一次,我在项目里下载了整整两天,结果发现分支选错了,所有车载相关的包都没有……那种感觉,你懂的。
核心要点:车载Android系统定制,必须基于 android-12.0.0_rXX 或更新的版本,因为从Android 12开始,Google正式引入了 car_service 作为系统级服务。
3.1.1 环境准备与Repo初始化
AOSP用的是Repo工具来管理上百个Git仓库。我个人习惯在Ubuntu 20.04 LTS上做开发,内存至少16GB,磁盘建议留出300GB以上——别问我怎么知道的,有一次编译到一半磁盘满了,那叫一个绝望。
# 安装Repo
mkdir ~/bin
PATH=~/bin:$PATH
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo
# 创建工作目录
mkdir ~/aosp_car
cd ~/aosp_car
# 初始化指定分支(以android-12.0.0_r32为例)
repo init -u https://android.googlesource.com/platform/manifest -b android-12.0.0_r32
# 同步源码(-j4表示4线程下载,根据你的网络调整)
repo sync -j4 -c --no-tags
我的经验:国内网络环境下,建议使用清华或中科大的AOSP镜像站。把 manifest 地址换成 https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest,速度能快3-5倍。
3.1.2 车载产品编译配置
源码下载完成后,关键一步是选择正确的编译目标。车载系统不是手机,我们需要的是 car 开头的产品配置。
# 加载编译环境
source build/envsetup.sh
# 查看所有可用的car目标
lunch | grep car
# 选择车载模拟器目标(最常用)
lunch aosp_car_x86_64-userdebug
# 开始编译(-j16根据你的CPU核心数调整)
make -j16
编译时间取决于机器配置。我用的工作站是32核64GB,第一次全编大概40分钟。如果你用笔记本,建议做好过夜的准备。
| 编译目标 | 适用场景 | 说明 |
|---|---|---|
aosp_car_x86_64-userdebug |
模拟器开发调试 | 最常用,带root权限 |
aosp_car_arm64-userdebug |
真机(高通/瑞芯微) | 需要对应BSP支持 |
aosp_car_x86_64-user |
正式发布版本 | 去掉调试功能,性能更优 |
注意:千万不要在 user 版本上做开发调试,没有root权限,很多系统服务改完没法验证。我曾经因为这个浪费了整整一天。
3.2 车载系统服务定制:从CarService到自定义Service
编译完系统,接下来就是重头戏——定制车载系统服务。说白了,车载座舱和手机最大的区别就是:手机是「人机交互」,车载是「人-车-环境」三方交互。
3.2.1 CarService架构解析
CarService是车载Android的核心服务,它管理着车辆的所有硬件抽象。我画了一张图,帮你理清它的层级关系。
3.2.2 自定义车载系统服务实战
假设我们需要一个「驾驶模式管理服务」,用来切换运动、舒适、经济三种模式。这个服务需要同时控制空调、悬架、油门响应等多个子系统。
第一步,定义AIDL接口:
// packages/services/Car/car-lib/src/android/car/IDrivingModeManager.aidl
package android.car;
interface IDrivingModeManager {
int getCurrentMode();
boolean setMode(int mode);
void registerCallback(IDrivingModeCallback callback);
void unregisterCallback(IDrivingModeCallback callback);
}
第二步,实现服务端逻辑:
// packages/services/Car/service/src/android/car/drivingmode/DrivingModeService.java
public class DrivingModeService extends IDrivingModeManager.Stub {
private static final String TAG = "DrivingModeService";
private int mCurrentMode = MODE_COMFORT;
private final VehicleHal mVehicleHal;
public DrivingModeService(VehicleHal hal) {
mVehicleHal = hal;
}
@Override
public boolean setMode(int mode) {
// 检查权限
CarServiceUtils.assertPermission(callingUid, Car.PERMISSION_CONTROL_CAR);
// 通过Vehicle HAL下发到硬件
mVehicleHal.setIntProperty(
VehiclePropertyIds.DRIVING_MODE,
VehicleArea.GLOBAL,
mode
);
mCurrentMode = mode;
notifyModeChanged(mode);
return true;
}
}
避坑指南:我曾经在自定义Service里直接操作硬件,结果发现权限检查没做,任何应用都能切换驾驶模式。记住:所有暴露给应用的接口,必须加 Car.PERMISSION_CONTROL_CAR 级别的权限校验。
3.3 系统属性配置:小配置,大影响
系统属性(System Properties)是Android里最容易被忽视但又极其重要的配置手段。在车载场景下,很多「奇怪的问题」最后都查到了属性配置上。
3.3.1 车载常用系统属性
| 属性名 | 默认值 | 车载推荐值 | 说明 |
|---|---|---|---|
ro.car.ui.headunit |
false | true | 启用车载UI模式 |
persist.car.rotation |
0 | 0或90 | 屏幕旋转方向 |
ro.sf.lcd_density |
320 | 160-240 | DPI密度,影响UI缩放 |
persist.car.wakeup.gesture |
false | true | 支持手势唤醒 |
ro.car.thermal.limit |
无 | 85000 | 温控阈值(毫摄氏度) |
3.3.2 属性配置的最佳实践
属性配置有两种方式:编译时写死和运行时动态设置。我的建议是:
- 编译时属性(ro.开头):用于硬件相关、不可变配置,比如屏幕参数、平台类型
- 持久化属性(persist.开头):用于用户可调、需要重启生效的配置,比如亮度、音量
- 运行时属性(无前缀):用于临时调试,重启后丢失
具体配置方法,在 device/generic/car/ 目录下的 system.prop 文件中添加:
# 车载系统属性配置示例
ro.car.ui.headunit=true
ro.sf.lcd_density=200
persist.car.rotation=0
persist.car.wakeup.gesture=true
# 性能相关
ro.sys.fw.bg_apps_limit=32
ro.vendor.perf.scroll_opt=true
# 音频策略
persist.car.audio.focus=true
ro.car.audio.samplerate=48000
血的教训:有一次我把 ro.sf.lcd_density 设成了120,结果所有车载应用都变得巨大无比,按钮都点不到。后来才发现,这个值必须和屏幕物理尺寸匹配,不能随便改。建议用公式:density = (屏幕宽度像素 / 物理宽度英寸) * 160 来计算。
3.4 编译产物验证与烧录
编译完成后,你会得到一堆镜像文件。车载系统通常需要烧录以下关键镜像:
# 编译产物路径
out/target/product/generic_car/
# 关键镜像文件
- system.img # 系统分区
- vendor.img # 厂商分区(BSP相关)
- boot.img # 内核与ramdisk
- userdata.img # 用户数据分区
- super.img # 动态分区(Android 10+)
验证方法很简单:启动模拟器看看能不能跑起来。
# 启动车载模拟器
emulator -avd CarAVD -wipe-data -no-snapshot
# 或者直接烧录到真机
fastboot flashall -w
我的习惯:每次编译完,先跑一遍CTS(兼容性测试套件)中的车载相关用例,确保基础服务没问题。别等到集成测试才发现CarService起不来,那代价就大了。
好了,这一章的内容就到这里。AOSP下载编译、CarService定制、系统属性配置,这三块是车载Android系统定制的基石。你可能会觉得内容有点多,但相信我——把这些基础打牢了,后面做多屏交互、做HMI优化的时候,你会感谢今天自己的投入。