第三章:源码结构解析 — AOSP顶层目录与车机相关目录

好,咱们现在正式开始接触AOSP源码。说实话,我第一次下载完AOSP的时候,看着那一堆文件夹,心里是有点懵的。一百多个G的代码,从哪看起?

别急,我帮你理一理。这一章,咱们只挑最核心的目录讲。你记住一句话:搞懂顶层目录,你就拿到了Android移植的钥匙

3.1 AOSP顶层核心目录

先看几个你一定会打交道的目录。我按重要程度排了个序,你心里有个数。

3.1.1 art — Android Runtime

这是Android的运行时环境。说白了,就是App怎么跑起来的。ART负责把dex字节码编译成本地机器码。我当年在移植一个低配车机时,发现ART的GC(垃圾回收)策略导致界面卡顿,后来调了编译模式才解决。嗯,这个坑后面细讲。

3.1.2 bionic — 标准C库

这是Android自己的C库实现,替代了glibc。为什么不用glibc?因为glibc太臃肿了,不适合嵌入式设备。bionic更轻量,而且对多线程支持更好。你在移植过程中,如果遇到某些第三方库链接报错,十有八九是bionic和glibc的差异导致的。

3.1.3 build — 编译系统

这个目录你得重点看。它包含了所有编译相关的脚本、Makefile、配置模板。Android的编译系统经历过从Android.mk到Soong(Blueprint)的演变。我个人习惯直接看build/soong/下面的代码,因为新项目基本都用Soong了。

核心文件:

  • build/make/core/ — 旧的Makefile核心逻辑
  • build/soong/ — 新的编译系统,用Go语言写的
  • build/envsetup.sh — 你每次编译前都要source这个文件

3.1.4 device — 设备配置

这个目录存放各个厂商的设备配置。比如你的车机用的是高通平台,那就在device/qcom/下面。每个设备目录里都有BoardConfig.mk、device.mk、vendorsetup.sh等文件。我建议你从device/generic/开始看,那是Google提供的参考实现。

3.1.5 hardware — 硬件抽象层

HAL层就在这里。它定义了硬件厂商如何实现Android的硬件接口。比如摄像头、音频、传感器等。车机移植中,你主要关注hardware/libhardware/hardware/interfaces/。前者是老式的HAL,后者是Treble架构下的HIDL接口。

3.1.6 kernel — 内核

注意,这个目录在AOSP里是空的!它只是一个占位符。真正的内核代码你得从kernel.org或者芯片厂商那里获取。我记得第一次移植时,傻乎乎地在AOSP里找内核代码找了半天……后来才明白,内核是独立维护的。

3.1.7 packages — 应用包

系统自带的App都在这里。比如设置、电话、联系人、Launcher等。车机移植中,你可能会修改packages/apps/Settings/来添加车机专属设置项,或者替换packages/apps/Launcher3/为车机桌面。

3.1.8 system — 系统核心

这个目录包含了核心系统服务、守护进程、库文件等。比如system/core/里有init进程、logd、adbd等。你想想看,init进程是Android启动的第一个用户空间进程,它解析init.rc脚本,启动各种服务。如果车机启动卡在某个阶段,十有八九要来这里查。

3.2 车机相关目录

好,上面是通用目录。下面这两个目录,是专门为车机准备的。Google从Android 8.0开始,正式把车机支持放进了AOSP主线。

3.2.1 device/generic/car — 车机参考设备

这个目录是Google提供的车机参考实现。它包含了车机专属的配置、权限、预装应用等。我带你看看里面有什么:

device/generic/car/
├── emulator/          # 模拟器配置
├── car_common/        # 车机通用配置
│   ├── car_product.mk # 产品定义文件
│   ├── packages/      # 预装应用列表
│   └── overlay/       # 资源覆盖层
└── car_ui_portrait/   # 竖屏UI配置

你移植车机时,第一步就是参考这个目录的结构,创建你自己的产品目录。比如:device/yourcompany/car_product/

我的经验: 别直接修改device/generic/car,而是复制一份出来改。这样方便以后对比Google的更新。

3.2.2 hardware/interfaces/automotive — 车机HAL接口

这个目录定义了车机专属的硬件抽象接口。比如车辆网络(CAN总线)、座舱传感器、车载诊断等。Google用HIDL语言定义了这些接口,硬件厂商需要实现它们。

常见的接口有:

接口名称 功能描述 我遇到的坑
IVehicle 车辆属性访问(车速、车门状态等) 曾经因为属性ID定义不一致,导致App读不到车速
ICarAudio 车载音频路由(导航、电话、媒体独立声道) 音频焦点管理没处理好,导航和音乐同时出声
ICarCluster 仪表盘显示控制 仪表盘刷新率不够,导致指针动画卡顿
ICarPower 车辆电源管理(ACC、休眠、唤醒) ACC断电后系统没及时休眠,电瓶亏电了

警告: 车机HAL接口的版本号很重要。比如android.hardware.automotive.vehicle@2.0和@2.1,接口有变化。我曾经因为用了旧版本的接口,导致新功能无法启用。记得检查hardware/interfaces/automotive/下的current.txt文件,看当前支持的版本。

3.3 目录之间的依赖关系

你可能会问:这些目录之间怎么配合的?我画个简单的流程:

  1. 编译入口:build/ 目录下的编译系统读取 device/ 目录下的产品配置
  2. 选择组件:根据配置,决定编译哪些 packages/ 里的应用和 system/ 里的服务
  3. 链接库:应用和服务依赖 bionic/ 提供的C库,以及 art/ 提供的运行时
  4. 硬件交互:通过 hardware/ 里的HAL接口,调用 kernel/ 里的驱动
  5. 车机专属:device/generic/car 提供车机配置,hardware/interfaces/automotive 提供车机HAL

嗯,这个流程你记在心里。以后遇到问题,就按这个链条去排查。

3.4 本章小结

这一章我们看了AOSP的顶层目录。你不需要记住每个目录的细节,但要知道:

  • art、bionic、build 是基础,几乎不会动
  • device、hardware、kernel 是移植重点,你要花大量时间在这里
  • packages、system 是功能定制,根据需求修改
  • device/generic/carhardware/interfaces/automotive 是车机专属,必须吃透

下一章,我们开始动手搭建编译环境。到时候你会真正体会到,这些目录是怎么串起来的。

课后作业: 下载AOSP源码后,进入device/generic/car目录,看看car_product.mk里引用了哪些模块。然后对比一下你手上的车机方案,看看哪些模块是通用的。