第28章:系统定制与编译:Product 配置、BoardConfig、Makefile 定制、预置应用

说实话,Android Automotive OS 的定制编译,是很多开发者觉得「头大」的地方。我刚入行那会儿,看着一堆 .mk 文件和配置项,也是一脸懵。但后来我发现,只要理清了几个核心文件的关系,这事儿其实没那么玄乎。

今天我们就来聊聊:Product 配置、BoardConfig、Makefile 定制、预置应用。这四个东西,说白了就是「你要造一辆什么车、用什么零件、怎么组装、出厂带什么软件」。

核心观点:系统定制不是魔法,是配置管理。你只要搞清楚「谁决定什么」,就能掌控整个编译流程。

28.1 整体架构:四个文件的分工

先看一张图,帮你快速建立全局认知。我习惯把 Android 编译系统比作一个「汽车生产线」:

Android Automotive OS 定制编译核心架构 Product 配置 定义产品特性 语言、分区、预置应用 BoardConfig 硬件相关配置 SoC、内存、显示、驱动 Makefile 定制 编译规则与脚本 模块依赖、编译选项 预置应用 系统级预装 不可卸载 编译流程: 1. 选择 Product → 加载对应 BoardConfig(硬件抽象) 2. Makefile 根据配置决定编译哪些模块 3. 预置应用通过 PRODUCT_PACKAGES 加入系统镜像 4. 最终生成 system.img / vendor.img / odm.img

嗯,这张图你多看两眼。后面所有的内容,都是围绕这四个模块展开的。

28.2 Product 配置:定义你的「车型」

Product 配置文件,通常放在 device/<厂商>/<产品名>/ 目录下,文件名一般是 aosp_<产品名>.mk。它决定了:

  • 产品名称和品牌
  • 支持的语言和地区
  • 分区大小(system、vendor、product)
  • 预置哪些应用
  • 系统属性(ro.xxx)

举个例子,我参与过一个车载项目,客户要求系统只支持中文和英文,并且要预置高德地图车机版。Product 配置大概长这样:

# device/automotive/my_car/my_car.mk

PRODUCT_NAME := my_car
PRODUCT_DEVICE := my_car
PRODUCT_BRAND := MyAuto
PRODUCT_MODEL := IVI-2024

# 语言配置
PRODUCT_LOCALES := zh_CN en_US

# 分区大小(单位:字节)
PRODUCT_SYSTEM_SIZE := 2147483648
PRODUCT_VENDOR_SIZE := 1073741824

# 预置应用
PRODUCT_PACKAGES += \
    MyLauncher \
    MyCarSettings \
    AMapAuto

# 系统属性
PRODUCT_PROPERTY_OVERRIDES += \
    ro.car.name=MyAuto \
    ro.car.version=1.0.0

我的经验:PRODUCT_PACKAGES 里加应用时,记得检查应用的 Android.mk 或 Android.bp 是否定义了相同的模块名。我曾经因为拼写错误,编译出来的镜像少了两个应用,排查了半天。

28.3 BoardConfig:告诉系统「你用什么硬件」

BoardConfig 是硬件相关的配置。它通常放在 device/<厂商>/<产品名>/BoardConfig.mk。这里定义的是「底层的东西」:

  • SoC 型号(比如高通 SA8155、联发科 MT2715)
  • 内存大小
  • 显示分辨率
  • 存储类型(eMMC、UFS)
  • Bootloader 和内核参数

我见过不少新手,把 Product 配置和 BoardConfig 搞混。其实很简单:Product 是「软件特性」,BoardConfig 是「硬件能力」

# device/automotive/my_car/BoardConfig.mk

TARGET_BOARD_PLATFORM := sa8155
TARGET_ARCH := arm64
TARGET_ARCH_VARIANT := armv8-a
TARGET_CPU_VARIANT := kryo

# 内存和存储
TARGET_USES_64_BIT_BINDER := true
BOARD_SYSTEMIMAGE_PARTITION_SIZE := 2147483648
BOARD_VENDORIMAGE_PARTITION_SIZE := 1073741824

# 显示
TARGET_SCREEN_WIDTH := 1920
TARGET_SCREEN_HEIGHT := 720
TARGET_HAS_HDR_DISPLAY := true

# 内核
TARGET_PREBUILT_KERNEL := device/automotive/my_car/kernel
BOARD_KERNEL_CMDLINE := console=ttyMSM0,115200n8

注意:BoardConfig 里的分区大小必须和 Product 配置里的 PRODUCT_*_SIZE 保持一致,否则编译会报错。我踩过这个坑,当时分区大小差了 1MB,编译通过了但刷机后系统无法挂载 vendor 分区。

28.4 Makefile 定制:编译系统的「指挥中心」

Android 的编译系统基于 GNU Make,但 Google 封装了一层 Soong(Android.bp)。不过,在 Automotive 定制中,我们仍然大量使用 .mk 文件。

Makefile 定制主要做三件事:

  1. 定义模块编译规则——比如你的 Launcher 需要依赖哪些库
  2. 添加编译选项——比如开启某个功能开关
  3. 控制编译顺序——确保依赖模块先编译

来看一个实际例子。假设我们要定制一个系统服务 MyCarService

# packages/services/MyCarService/Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := MyCarService
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_REQUIRED_MODULES := \
    CarServiceHelper \
    VehicleHal

LOCAL_STATIC_JAVA_LIBRARIES := \
    android.car \
    androidx.core

LOCAL_PRIVILEGED_MODULE := true
LOCAL_PROGUARD_FLAG_FILES := proguard.flags

include $(BUILD_PACKAGE)

这里有个关键点:LOCAL_PRIVILEGED_MODULE := true。这意味着这个应用会被安装到 /system/priv-app 目录,拥有系统级权限。车载场景下,很多核心服务都需要这个标志。

避坑指南:我曾经把一个普通应用误设为 privileged,结果它获得了不该有的权限,导致安全测试没通过。所以,只有真正需要系统权限的服务才用 privileged,普通应用别乱加。

28.5 预置应用:出厂就装好的软件

预置应用是 Automotive OS 定制中最常见的需求。车厂通常要求:导航、音乐、语音助手等应用必须出厂预装,且用户不能卸载。

预置应用分两种:

类型 安装位置 能否卸载 典型场景
系统预置 (Priv-app) /system/priv-app 不可卸载 Launcher、设置、系统服务
普通预置 (App) /system/app 可卸载(恢复出厂设置后恢复) 导航、音乐、第三方应用

预置应用的具体做法,就是在 Product 配置的 PRODUCT_PACKAGES 里加上模块名。但要注意,应用本身需要有对应的编译文件(Android.mk 或 Android.bp)。

举个例子,预置一个第三方 APK(没有源码):

# vendor/myauto/apps/AMapAuto/Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := AMapAuto
LOCAL_SRC_FILES := AMapAuto.apk
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_TAGS := optional
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_MODULE_PATH := $(TARGET_OUT_APPS)

include $(BUILD_PREBUILT)

然后在 Product 配置里加上:

PRODUCT_PACKAGES += AMapAuto

我的习惯:预置第三方 APK 时,尽量用 LOCAL_CERTIFICATE := PRESIGNED,保留原签名。如果重新签名,可能会导致应用签名校验失败,尤其是那些用了签名绑定的 SDK(比如某些支付 SDK)。

28.6 实战:完整的定制流程

好了,理论说完了。我们走一遍完整的流程。假设我们要定制一个叫 MyAutoIVI 的车机系统:

  1. 创建目录结构
    device/myauto/myautoivi/
    ├── BoardConfig.mk
    ├── myautoivi.mk
    ├── kernel
    ├── device.mk
    └── overlays/
  2. 编写 BoardConfig.mk(定义硬件参数)
  3. 编写 myautoivi.mk(定义产品特性、预置应用)
  4. 添加预置应用(在 vendor/myauto/apps/ 下放 APK 和 Android.mk)
  5. 编译
    source build/envsetup.sh
    lunch myautoivi-userdebug
    make -j16
  6. 验证:检查 out/target/product/myautoivi/ 下是否生成了 system.img、vendor.img

嗯,流程看起来简单,但实际中你会遇到各种问题。比如依赖缺失、分区空间不足、签名冲突等等。我的建议是:每次只改一个配置,编译验证通过后再改下一个。别一次性改一堆,出了问题根本不知道是哪一步导致的。

最后说一句:系统定制编译,本质上就是「配置管理」。你把 Product、BoardConfig、Makefile、预置应用这四个东西理解透了,任何车机项目都能快速上手。我在项目中见过太多人把时间花在「试错」上,其实只要静下心把文档读一遍,很多坑都能避免。


公众号:蓝海资料掘金营,微信deep3321