在TI AM57xx/AM65x开发板上构建Android Automotive OS完整指南
1. 项目概述与核心价值
如果你手头有一块德州仪器(TI)的AM57xx或AM65x系列开发板,并且一直在琢磨如何让它跑起来一套真正为汽车座舱优化的操作系统,那么这篇文章就是为你准备的。我最近花了相当长的时间,在TI的BeagleBoard-X15和AM65x EVM上折腾Android Automotive OS,从环境搭建、源码修改到烧录测试,把整个流程完整地走了一遍。Android Automotive OS(AAOS)和我们手机上的Android或者车机上的Android Auto(手机投屏)有本质区别,它是一个完整的、深度定制的、直接运行在车载硬件上的操作系统。这意味着你可以像在手机上一样,在车机里直接安装和运行专为驾驶场景优化的应用,比如集成的气候控制界面、车辆状态通知面板、以及符合车载安全规范的地图和音乐应用。
这个项目的核心价值在于,它提供了一个在嵌入式硬件上验证和开发车载信息娱乐系统(IVI)的绝佳平台。对于嵌入式工程师、车载系统开发者,或者任何对汽车电子和Android底层感兴趣的朋友来说,通过在一块实际的开发板上亲手构建并运行AAOS,你能深刻理解从硬件抽象层(HAL)到上层应用服务的整个车载软件栈是如何协同工作的。这不仅仅是跑通一个Demo,更是为未来开发真正的数字座舱产品打下坚实的技术基础。接下来,我会把整个过程中涉及的环境准备、代码修改、构建部署、测试验证等所有关键步骤和踩过的坑,毫无保留地分享出来。
2. 环境准备与前期工作
在开始修改代码和构建系统之前,一个稳定、合规的构建环境是成功的基石。这一步如果没做好,后续会冒出各种稀奇古怪的错误,让人无从下手。
2.1 硬件与软件基础要求
首先,你需要一块支持的TI开发板。本文主要基于AM57xx BeagleBoard-X15,这是目前TI在Android开源项目(AOSP)中官方支持的主要平台。同时,我也会提及如何将同样的工作迁移到AM65x EVM上。除了开发板,你还需要一台性能足够强劲的Linux构建主机。根据Google官方的建议,构建Android系统推荐至少16GB内存和250GB以上的可用磁盘空间(SSD最佳)。我个人的经验是,内存越大越好,32GB或以上可以显著减少构建时间,避免因内存不足导致的构建失败。
软件层面,你需要一个64位的Ubuntu LTS发行版(如18.04或20.04)。确保你的系统已经安装了必要的依赖包。除了AOSP常规的构建依赖(如git,curl,python等),针对TI的平台,你还需要TI提供的Processor SDK for Android。这个SDK包含了针对TI芯片优化的内核源码、U-Boot引导程序、以及一些预编译的二进制文件和工具链,是成功构建的必备条件。你需要从TI官网下载对应你开发板型号和Android版本的SDK安装包。
2.2 源码获取与仓库初始化
AAOS的源码基于AOSP。TI维护了自己的AOSP manifest仓库,其中包含了针对其硬件平台的特定配置和补丁。因此,你不能直接从Google的AOSP仓库拉取代码,而必须使用TI提供的manifest。
第一步是安装repo工具,这是Google为管理AOSP这种超大型多仓库项目而开发的工具。然后,你需要为你的构建创建一个工作目录,并初始化repo客户端,指定TI的manifest仓库和对应的分支。例如,对于Android Pie版本,你可能需要使用pie-core-release分支。这个过程可能会花费一些时间,因为它需要同步数十个Git仓库,总体积超过100GB,请确保网络通畅且有足够的磁盘空间。
在同步完源码后,紧接着就需要设置构建环境。这包括导入一系列环境变量和构建命令。你需要进入源码根目录,执行source build/envsetup.sh脚本。这个脚本会为你提供后续关键的lunch和make等命令。lunch命令用于选择你要构建的目标设备(target product)和变体(variant),例如beagle_x15-userdebug就是为BeagleBoard-X15构建一个带调试功能的用户版本。
2.3 工具链与内核配置
TI的ARM平台构建需要使用特定的交叉编译工具链。在TI的Processor SDK中,通常会包含一个预编译好的工具链,比如gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf。你需要在构建前,确保工具链的路径被正确设置到环境变量中,或者TI的构建脚本已经自动处理了这一点。
内核方面,TI提供了与Android版本匹配的Linux内核树,例如ti-android-linux-4.19.y。你不需要单独编译内核,因为Android的构建系统(通过make bootimage)会负责内核的编译。但是,如果你需要为AAOS启用特定的内核驱动或配置(比如某些车载总线或传感器),你可能需要进入内核目录进行自定义配置。不过,对于初次启用AAOS的基本功能,TI默认的内核配置通常已经足够。
注意:构建环境的搭建是一次性的,但也是最容易出错的环节。务必严格按照TI官方提供的“Processor SDK Android Getting Started Guide”操作。常见的坑包括:1)磁盘空间不足导致同步失败;2)系统缺少某个依赖库导致编译错误;3)使用了错误版本的工具链或内核。建议在开始前,先完整地构建一次标准的“平板”配置(即
beagle_x15-userdebug),确保基础环境完全正确,然后再进行AAOS的修改。
3. 为Android Automotive修改设备树代码
这是整个项目的核心环节。我们需要告诉Android构建系统:“现在我要构建的不是一个平板设备,而是一个汽车设备。” 这主要通过修改设备特定的Makefile和创建新的配置文件来实现。所有的修改都集中在device/ti/beagle_x15/目录下(以BeagleBoard-X15为例)。
3.1 扩展产品列表与构建目标
首先,我们需要在AndroidProducts.mk文件中定义一个新的“午餐组合”(lunch combo)。这个文件就像一个菜单,lunch命令弹出的列表就来源于此。默认情况下,这里可能只有beagle_x15.mk对应的beagle_x15-userdebug。我们需要添加一个针对汽车版本的新条目。
修改的关键在于将原有的单一行声明,改为一个键值对映射,并添加新的汽车版本目标。修改后,COMMON_LUNCH_CHOICES变量中就会出现beagle_x15_auto-userdebug这个选项。当你执行lunch命令时,就可以选择它来构建汽车版本。这里的“auto”后缀是一个清晰的标识,方便在命令行中区分。
3.2 条件化集成汽车专属策略
接下来,需要修改BoardConfig.mk文件。这个文件定义了开发板的硬件特性和一些全局构建配置。对于AAOS,我们需要条件化地添加一些汽车专属的配置,特别是安全策略(SELinux policy)。
Android的安全模型很大程度上依赖于SELinux。汽车版本引入了一些新的服务(如车辆硬件抽象层服务),它们需要特定的SELinux策略规则才能正常运行。我们通过一个条件判断ifeq ($(TARGET_PRODUCT), beagle_x15_auto),确保只有在构建汽车目标时,才会将汽车产品的通用策略目录packages/services/Car/car_product/sepolicy包含进来。同时,我们还需要添加一个设备清单文件manifest.xml,它用于向系统声明本设备提供的硬件抽象层(HAL)服务,这对于AAOS至关重要。
3.3 创建汽车专属配置目录与文件
现在,在device/ti/beagle_x15/目录下创建一个名为auto的子目录。所有汽车版本特有的配置都将放在这里,与标准配置隔离,结构清晰。
首先,创建auto/beagle_x15.mk文件。这是新“午餐组合”对应的顶级产品定义文件。它的核心作用是继承(inherit)一系列必要的Makefile。它首先继承了标准设备的device.mk,以确保所有基础硬件功能得以保留。然后,它继承了我们将要在auto目录下创建的device.mk(用于添加汽车特有模块)。接着,它继承了AOSP的基础产品配置full_base.mk。最关键的一步,是继承AAOS的核心定义文件car.mk(位于packages/services/Car/car_product/build/)。这个car.mk文件会进一步继承car_base.mk,后者设置了大量汽车设备专用的系统属性,例如启用演示模式的气候控制、收音机等。
然后,创建auto/device.mk文件。这个文件用于声明汽车版本需要额外包含的软件包和文件。最重要的一个包是android.hardware.automotive.vehicle@2.0-service,这就是车辆硬件抽象层(Vehicle HAL)的服务实现。虽然TI的通用开发板没有真实的车辆网络(如CAN总线),但这个服务是AAOS框架所必需的,它提供了一个与车辆通信的标准化接口。此外,还需要复制两个关键的权限XML文件:android.hardware.type.automotive.xml将设备类型标记为“Automotive”,这会触发系统加载汽车专用的框架和服务;android.hardware.screen.landscape.xml声明设备支持横屏,这是车载屏幕的典型布局。
最后,创建auto/manifest.xml文件。这是一个HAL清单文件,采用HIDL(HAL接口定义语言)格式。它向系统声明:“本设备提供了一个遵循android.hardware.automotive.vehicle@2.0接口规范的HAL服务,实例名为default。” 这样,当AAOS框架启动时,它就知道去哪里查找并绑定这个车辆HAL服务。
实操心得:修改Makefile时,要特别注意空格和Tab键的区别。Makefile语法中,命令行必须以Tab开头。如果你在复制代码时不小心将Tab转换成了空格,会导致
make命令执行失败,并报“missing separator”错误。建议使用能高亮显示空格和Tab的文本编辑器(如VSCode、Vim)。另外,在继承car.mk时,要确认其路径在AOSP源码树中是正确的。不同版本的AOSP或TI SDK,Car模块的路径可能略有差异。
4. 系统构建与镜像烧录
当所有代码修改完成后,就可以开始构建系统并烧录到开发板了。这个过程是对前面所有准备工作的一次总检验。
4.1 配置与执行构建
首先,进入你的AOSP源码根目录,设置构建环境:. build/envsetup.sh。接着,运行lunch命令,这时你应该能在菜单中看到新添加的beagle_x15_auto-userdebug选项,选择它。选择后,终端会显示一系列环境变量被设置,其中TARGET_PRODUCT的值就是beagle_x15_auto,这确保了后续构建会使用我们刚刚配置的汽车版本。
在开始构建前,还需要设置内核源码的路径。执行export KERNELDIR=<你的内核目录绝对路径>。这个路径通常位于TI Processor SDK的board-support目录下。然后,就可以启动构建了:make -j<核心数>。这里的-j参数用于指定并行编译的作业数,通常设置为你的CPU核心数或核心数的1.5倍,以最大化利用多核性能,显著缩短编译时间。一个完整的AAOS构建,在性能较好的机器上可能需要数小时。
构建成功后,所有的输出镜像文件(如boot.img,system.img,vendor.img,userdata.img等)会生成在out/target/product/beagle_x15/目录下。这些镜像文件包含了编译好的内核、系统分区、供应商分区和用户数据分区。
4.2 准备烧录环境与Fastboot
TI开发板通常支持通过Fastboot协议从主机USB口烧录镜像。我们需要准备一个用于烧录的工作目录。一个方便的做法是复制TI SDK中提供的prebuilt-images目录,因为它里面已经包含了一些必要的引导文件(如MLO、u-boot.img)和设备树二进制文件(.dtb)。
你需要将刚刚编译生成的AAOS镜像文件、以及从AOSP构建输出中提取的一些主机工具(如fastboot,adb)复制到这个工作目录。TI通常会提供一个fastboot.sh脚本,这个脚本封装了具体的烧录命令。你需要参考这个脚本,确认需要复制哪些具体的镜像文件。对于AM57xx和AM65x平台,所需的文件列表略有不同,主要是引导文件有差异(AM65x采用了更复杂的多阶段引导tispl.bin和tiboot3.bin)。
4.3 连接设备与执行烧录
将开发板通过USB线连接到主机,并连接串口调试线(如USB转TTL)。打开一个串口终端(例如使用picocom或minicom),设置波特率为115200,用于观察开发板的启动日志。
给开发板上电,在串口终端中快速按下任意键中断U-Boot的自动启动。在U-Boot命令行中,输入fastboot 0命令,这将使开发板进入Fastboot模式,等待主机连接。
在主机上,打开另一个终端,进入之前准备好的烧录工作目录(emmc_files)。首先,给fastboot.sh脚本添加执行权限:chmod +x fastboot.sh。然后,以root权限执行它:sudo ./fastboot.sh。这个脚本会自动调用fastboot工具,依次将各个镜像烧录到开发板的eMMC存储的对应分区中。烧录完成后,脚本通常会执行fastboot reboot命令让开发板重启。
注意事项:烧录过程务必保证供电稳定,USB连接可靠。如果烧录中途失败,可能导致开发板无法启动。此时通常需要重新进入Fastboot模式再次烧录。串口终端是救命稻草,一定要保持开启,任何内核panic或启动失败的信息都会在这里打印出来。第一次启动AAOS可能会比较慢,因为系统需要进行初始化设置,请耐心等待几分钟。
5. 兼容性测试与问题排查
系统成功启动并进入AAOS的汽车界面(你会看到一个带有车辆图示的启动画面和“Let‘s Drive”主界面)只是第一步。为了确保系统符合Android Automotive的标准并且稳定可靠,必须进行严格的测试。Google提供了两套主要的自动化测试框架:兼容性测试套件(CTS)和供应商测试套件(VTS)。
5.1 兼容性测试套件(CTS)配置与执行
CTS旨在确保设备与Android API和兼容性定义文档(CDD)保持一致。对于汽车设备,有专门的CtsCarTestCases测试模块。
首先,需要在你的桌面主机上安装最新版本的adb和aapt工具。虽然Android SDK里自带,但最好用包管理器更新一下:sudo apt-get install adb aapt。接着,你需要从Google开发者网站下载与你设备Android版本和ABI架构匹配的CTS压缩包。
将下载的CTS包解压到之前烧录用的emmc_files工作目录下。有时,为了通过某些CTS测试,你可能需要覆盖设备的首个API级别属性。这可以通过在设备的device.mk文件中添加PRODUCT_PROPERTY_OVERRIDES += ro.product.first_api_level=<级别>来实现,具体的级别值需要查询Android版本代号与API级别的对应关系。
测试执行时,首先通过串口和ADB确保设备已连接并处于可用状态。然后,进入解压后的CTS工具的tools目录,运行./cts-tradefed启动CTS控制台。在控制台提示符cts-tf >下,运行run cts --module CtsCarTestCases来执行汽车相关的测试用例。测试过程是自动化的,会持续一段时间。完成后,测试结果(包括通过的、失败的和未执行的用例)会以HTML和XML格式保存在android-cts/results/目录下的一个时间戳文件夹中。
5.2 供应商测试套件(VTS)与汽车HAL测试
VTS更侧重于测试设备的硬件抽象层(HAL)和内核的兼容性。对于AAOS,车辆HAL(Vehicle HAL)是测试的重点。
运行VTS也需要先启动其控制台:vts-tradefed。在vts-tf >提示符下,可以使用list plans查看所有测试计划。我们关注的是vts-hal-auto计划,它专门用于测试汽车车辆HAL。执行命令run vts-hal-auto即可开始测试。VTS测试的结果会输出到AOSP源码构建输出的特定目录下,路径类似out/host/linux-x86/vts/android-vts/results/<时间戳>。
5.3 已知问题与调试技巧
在实际测试中,你可能会遇到一些已知或未知的问题。根据TI的文档和我的实践,这里有几个典型的已知问题和排查思路:
SELinux拒绝(Denial)日志:系统运行时,可能会在
dmesg日志中看到一些SELinux拒绝访问的信息。你可以使用adb shell dmesg | grep denied来查看。这些拒绝通常是因为某些汽车服务(如carservice_app或hal_vehicle_default)尝试访问某些资源(如套接字、文件),但当前的安全策略(neverallow规则)禁止了这些访问。在开发阶段,有时可以通过audit2allow工具生成临时策略规则,但最终解决方案需要向AOSP上游提交策略修改。对于原型开发,你可以在userdebug版本的设备上使用setenforce 0临时禁用SELinux来快速验证功能,但这绝不是生产环境的解决方案。电源管理服务错误:日志中可能会出现
CarPowerManagerNative: Received unknown bootReason = 0或PowerTestService: Could not read bootReason!!的错误。这是因为车辆HAL服务没有上报正确的启动原因。在真实的汽车硬件上,这个信息来自车辆网络。在通用开发板上,车辆HAL运行在“模拟”或“默认”模式,可能无法提供此信息。这个错误通常不影响基本功能的演示,但意味着与电源状态深度集成的功能(如深度睡眠唤醒)可能无法正常工作。蓝牙测试失败:在CTS的
CtsCarTestCases中,android.car.cts.CarBluetoothTest测试用例很可能会失败,并抛出NullPointerException,提示BluetoothAdapter为null。这是预期中的,因为像BeagleBoard-X15和AM65x EVM这样的通用开发板,其标准硬件配置可能不包含蓝牙模块,或者蓝牙驱动没有正确集成到Android系统中。这个测试失败可以安全忽略,除非你特意为开发板添加并配置了蓝牙硬件。
排查心得:当遇到启动失败或功能异常时,串口日志(
dmesg)和Android日志(logcat)是你最好的朋友。优先使用adb logcat -b all查看所有缓冲区的日志,或者使用adb logcat | grep -iE “error|fail|exception|crash”来过滤关键错误信息。对于系统服务启动问题,可以重点关注SystemServer和CarService相关的日志。另外,确保你的设备有足够的存储空间,/data分区被正确挂载且可读写,许多诡异的问题都源于存储空间不足或权限错误。
6. 向新平台迁移与未来展望
成功在BeagleBoard-X15上启用AAOS后,这套方法论可以迁移到其他TI平台上,例如AM65x EVM。迁移工作的核心是复用和适配设备树配置。
6.1 AM65x EVM迁移要点
对于AM65x平台,整体思路与X15完全一致:在device/ti/am65xevm/目录下进行相同的修改。创建auto子目录,仿照X15的步骤修改AndroidProducts.mk、BoardConfig.mk,并创建对应的auto/am65xevm.mk、auto/device.mk和auto/manifest.xml文件。
主要的差异点可能在于:
- 内核与引导加载程序:AM65x是异构多核架构(Cortex-A53 + Cortex-R5),其引导流程(
tiboot3.bin,tispl.bin)和内核设备树(DTS)与AM57xx不同。你需要确保烧录时使用的是AM65x对应的引导文件和内核镜像。 - 硬件配置:
device.mk中可能需要根据AM65x的实际硬件调整一些产品属性,或者添加/移除特定的硬件HAL模块。 - TI源码仓库:AM65x的AAOS支持可能已经合并到TI独立的Pie版本仓库中,而不是AOSP主线上。因此,在初始化
repo时,需要使用TI为AM65x提供的特定manifest仓库地址和分支。
6.2 未来发展方向与挑战
将AAOS移植到更贴近真实汽车的“车规级”TI平台(如Jacinto系列)是未来的方向。这将带来新的挑战和机遇:
多显示屏支持:真实的数字座舱通常有多个屏幕(仪表盘、中控屏、副驾屏、后排屏)。Android Q及更高版本的AAOS加强了对多硬屏的支持,需要为每个屏幕配置独立的显示ID、输入映射和用户体验策略。例如,驾驶席屏幕有严格的应用限制,而乘客屏则可以运行更多类型的应用。
多用户与无头系统:汽车可能有多个用户配置文件,或者支持“无头”(headless)系统用户(用于后台服务)。这涉及到更复杂的用户管理、数据隔离和权限控制。
多区域音频:高级车载音响系统支持将不同的音频流(如导航提示、主媒体、后排娱乐)路由到不同的扬声器区域。AAOS的多区域音频框架需要与底层的音频HAL和策略进行细致配置。
真实的车辆HAL实现:在开发板上,我们使用了一个默认或模拟的Vehicle HAL。在真实平台中,需要实现一个与车辆网络(如CAN、LIN、以太网)通信的真实HAL,将车辆信号(车速、转速、车门状态等)转换为AAOS框架可以理解的属性。
功能安全与可靠性:车载系统对功能安全(如ISO 26262 ASIL等级)和长期可靠性有极高要求。这涉及到从硬件选型、内核驱动到上层系统服务的全栈考量,远超出在通用开发板上进行功能验证的范畴。
这个过程让我深刻体会到,在嵌入式平台上启用一个复杂的系统如AAOS,远不止是敲几行命令。它要求你对Android构建系统、设备树配置、硬件抽象层、以及系统安全模型都有深入的理解。每一个步骤的细节都至关重要,从Makefile的一个Tab,到烧录时的一个文件,都可能成为成功与失败的分水岭。希望这份详细的指南能帮你少走弯路,顺利启动你的车载系统探索之旅。如果在实际操作中遇到新的问题,多查日志、多翻阅AOSP和TI的官方文档,社区的资源和经验分享也是解决问题的宝贵途径。
