30、项目实战:从零搭建 AAOS 车载信息娱乐系统、常见问题排查、性能调优案例
说实话,前面讲了那么多理论,今天终于到了我最喜欢的环节——动手干。
这一章,我会带你从零开始,搭建一个完整的 AAOS 车载信息娱乐系统。不是那种 Hello World 的玩具,而是一个能跑在模拟器上、有真实交互、能排查问题的工程。
我会把我在几个量产项目中踩过的坑、调优的经验,一股脑倒给你。你跟着走一遍,基本就能应付大部分车载开发的日常了。
30.1 搭建前的准备工作
别急着敲代码。先看看你的环境够不够硬。
| 项目 | 最低要求 | 推荐配置 |
|---|---|---|
| CPU | 8 核 | 16 核以上 |
| 内存 | 16 GB | 32 GB 或更高 |
| 磁盘 | 250 GB 空闲 | 500 GB SSD |
| 操作系统 | Ubuntu 20.04 | Ubuntu 22.04 |
我个人习惯用 Ubuntu 22.04 + 32GB 内存。你想想看,一次完整编译要跑 40 分钟,如果内存不够,直接 OOM 崩溃,那才叫崩溃。
30.2 创建项目骨架
我们基于 AAOS 官方分支 android-14.0.0_r30 来搭建。先拉代码:
mkdir aaos-project && cd aaos-project
repo init -u https://android.googlesource.com/platform/manifest -b android-14.0.0_r30
repo sync -j8
嗯,这里要注意。同步时间取决于你的网络。我在国内项目时,通常用清华或中科大的镜像,速度能快 3 倍。
同步完成后,我们创建一个新的设备配置。假设我们的车载设备叫 my_car:
mkdir -p device/mycompany/my_car
cd device/mycompany/my_car
然后创建核心文件:
AndroidProducts.mk—— 定义产品名称和编译目标BoardConfig.mk—— 硬件板级配置device.mk—— 包含哪些模块、应用system.prop—— 系统属性
举个例子,AndroidProducts.mk 长这样:
PRODUCT_MAKEFILES := \
$(LOCAL_DIR)/my_car.mk
而 my_car.mk 里,我会这样写:
$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
$(call inherit-product, packages/services/Car/car_product/build/car.mk)
PRODUCT_NAME := my_car
PRODUCT_DEVICE := my_car
PRODUCT_BRAND := Android
PRODUCT_MODEL := AAOS Car Demo
# 加入车载特有模块
PRODUCT_PACKAGES += \
CarLauncher \
CarSettings \
CarSystemUI
30.3 核心架构图
下面这张图,是我自己总结的 AAOS 信息娱乐系统核心分层。你看一眼,后面所有代码都围绕这个结构展开。
说白了,上层应用只管 UI 和交互,中间 Car Service 负责跟车打交道,底层 HAL 跟硬件通信。每一层都有自己该干的事,别越界。
30.4 编译与烧录
配置写好了,开始编译:
source build/envsetup.sh
lunch my_car-userdebug
make -j16
我第一次编译时,等了 40 分钟,结果报了个错:No rule to make target 'vendor/xxx'。查了半天,发现是 device.mk 里引用了一个不存在的模块路径。
PRODUCT_PACKAGES 里的模块名对不对,再看 BoardConfig.mk 里的 TARGET_BOARD_PLATFORM 是否匹配。
编译成功后,生成的目标文件在 out/target/product/my_car/ 下。用模拟器跑的话:
emulator -avd my_car_avd -wipe-data
嗯,第一次启动会比较慢。别急,等个两三分钟,看到 CarLauncher 界面出来,就说明成了。
30.5 常见问题排查
这里我列几个我在项目中遇到的高频问题,你八成也会碰到。
30.5.1 CarService 起不来
症状:模拟器启动后黑屏,logcat 里看到 CarService: failed to start。
原因:多半是 Vehicle HAL 没有正确实现。AAOS 默认需要一个 Vehicle HAL 服务,如果没有,CarService 会直接罢工。
解决方法:在 device.mk 里加上默认的模拟 HAL:
PRODUCT_PACKAGES += \
android.hardware.automotive.vehicle@2.0-service
30.5.2 音频没声音
症状:界面正常,但播放音乐没声音。
排查:先看 dumpsys audio 里有没有输出设备。我遇到过是 audio_policy_configuration.xml 里缺少车载音频策略。
解决:在 device.mk 中引入车载音频配置:
PRODUCT_COPY_FILES += \
device/mycompany/my_car/audio/audio_policy_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_configuration.xml
30.5.3 触摸屏没反应
症状:模拟器里鼠标点击没反应。
原因:模拟器默认没有启用触摸事件转发。需要加启动参数:
emulator -avd my_car_avd -no-audio -no-window -gpu swiftshader_indirect
BoardConfig.mk 里加了 BOARD_TOUCH_SCREEN_ROTATION := 180 才解决。真机调试时,先确认坐标映射。
30.6 性能调优案例
系统跑起来了,但卡顿、掉帧、启动慢,这些都是家常便饭。我分享两个真实调优案例。
30.6.1 启动速度优化
项目里有个需求:从上电到 CarLauncher 显示,不能超过 8 秒。一开始测出来是 14 秒。
我排查后发现,瓶颈在 SystemServer 里加载了太多不必要的服务。比如车载根本用不到 Telephony 和 Bluetooth 的某些模块。
优化方法:在 system.prop 里禁用非必要服务:
ro.car.startup.disable_telephony=true
ro.car.startup.disable_bluetooth_profile=true
配合 zygote 预加载优化,最终启动时间降到了 7.2 秒。
30.6.2 界面掉帧问题
另一个项目,导航地图滑动时掉帧严重。我用 systrace 抓了一下,发现是 SurfaceFlinger 的 vsync 周期被音频线程打断了。
说白了,就是音频 HAL 占用了太多 CPU 时间,导致 UI 渲染线程抢不到时间片。
解决方案:把音频处理线程绑定到小核上,UI 线程绑定到大核:
# 在 init.rc 中设置
on boot
write /dev/cpuset/foreground/cpus 4-7
write /dev/cpuset/audio/cpus 0-3
调完后,掉帧率从 15% 降到了 2% 以下。
systrace 看整体,再用 perf 定位热点函数。别一上来就瞎猜,数据说话。
30.7 小结
这一章,我们从零搭了一个 AAOS 信息娱乐系统。你经历了环境准备、项目创建、编译烧录、问题排查、性能调优的全流程。
说实话,车载开发跟手机开发最大的区别,就是你要跟硬件、跟车打交道。很多问题在模拟器上跑得好好的,一上真车就翻车。但别怕,只要掌握了排查思路和调优方法,大部分坑都能填平。
嗯,今天就到这里。你动手试试,有问题随时翻回来看。