6、产品配置与 BoardConfig:产品定义文件(product.mk)、BoardConfig.mk 配置、设备树概念

好,咱们今天聊聊 Android Build 系统里最核心的两个配置文件——product.mkBoardConfig.mk。还有那个听起来很玄乎的「设备树」概念。

说实话,我刚入行那会儿,看到一堆 .mk 文件就头大。后来踩了几个坑才明白,这两兄弟分工特别明确:一个管「软件长什么样」,一个管「硬件怎么跑」。

6.1 product.mk:产品定义文件

product.mk 说白了就是告诉编译系统:你要做一个什么样的手机/平板/电视

它定义的是「产品级」的属性。比如:

  • 产品叫什么名字(PRODUCT_NAME)
  • 包含哪些应用(PRODUCT_PACKAGES)
  • 系统属性(PRODUCT_PROPERTY_OVERRIDES)
  • 语言、时区等默认配置

我习惯把 product.mk 想象成一张「购物清单」——你要往系统里装什么,全写在这里。

一个典型的 product.mk 长这样:

# 产品名称
PRODUCT_NAME := my_device

# 品牌和型号
PRODUCT_BRAND := MyBrand
PRODUCT_MODEL := MyPhoneX

# 要打包的应用
PRODUCT_PACKAGES += \
    MyLauncher \
    MySettings \
    MyCamera

# 系统属性
PRODUCT_PROPERTY_OVERRIDES += \
    ro.product.manufacturer=MyBrand \
    ro.build.version.sdk=34

# 默认语言
PRODUCT_LOCALES := zh_CN en_US

嗯,这里要注意:PRODUCT_NAME 必须唯一。我见过有人把两个产品写成同一个名字,结果编译出来的镜像完全乱套了。

6.2 BoardConfig.mk:硬件配置

BoardConfig.mk 管的是「硬件层面」的东西。它告诉编译系统:你的板子用什么 CPU?内存多大?分区怎么分?

说白了,product.mk 决定「装什么软件」,BoardConfig.mk 决定「硬件怎么支持这些软件」。

我个人习惯:把 BoardConfig.mk 放在 device/<厂商>/<设备名>/ 目录下,和 product.mk 做邻居。这样找起来方便。

来看一个实际例子:

# 芯片架构
TARGET_ARCH := arm64
TARGET_ARCH_VARIANT := armv8-a
TARGET_CPU_VARIANT := cortex-a75

# 分区大小(单位:字节)
BOARD_BOOTIMAGE_PARTITION_SIZE := 67108864
BOARD_SYSTEMIMAGE_PARTITION_SIZE := 2147483648
BOARD_USERDATAIMAGE_PARTITION_SIZE := 5368709120

# 内核相关
TARGET_NO_KERNEL := false
BOARD_KERNEL_CMDLINE := console=ttyS0,115200

# 是否使用 A/B 分区
AB_OTA_UPDATES := true

这里有个坑,我曾经踩过:分区大小写错了,编译出来的镜像刷进去直接变砖。所以每次改 BoardConfig.mk,我都会反复检查分区数值。

6.3 设备树概念

设备树(Device Tree)是 Android 从 Linux 内核继承过来的概念。它用文本文件描述硬件信息,编译成 .dtb 文件后给内核用。

为什么要用设备树?

  • 同一个内核可以支持不同硬件
  • 硬件信息不用写死在代码里
  • 改硬件配置只需要改 .dts 文件

你想想看,如果没有设备树,每换一个屏幕型号就得改内核代码,那得多麻烦?

注意:设备树文件(.dts)和 BoardConfig.mk 是两回事。BoardConfig.mk 是给 Android Build 系统看的,设备树是给 Linux 内核看的。它们描述的是同一个硬件,但视角不同。

一个简单的设备树片段:

/dts-v1/;

/ {
    model = "MyDevice";
    compatible = "mycompany,mydevice";

    memory@80000000 {
        device_type = "memory";
        reg = <0x80000000 0x40000000>;  // 1GB RAM
    };

    chosen {
        bootargs = "console=ttyS0,115200";
    };
};

嗯,这里要记住:设备树里的 reg 属性,第一个是基地址,第二个是大小。我刚开始写的时候经常搞反,结果内核死活找不到内存。

6.4 三者的关系

我用一张图来展示它们之间的关系:

产品配置与 BoardConfig 关系图 product.mk 软件配置 应用、属性、语言 BoardConfig.mk 硬件配置 分区、架构、内核参数 设备树 (.dts) 硬件描述 内存、外设、引脚 引用 对应 编译流程中的角色 1. product.mk 决定「做什么产品」—— 选择应用、设置属性 2. BoardConfig.mk 决定「用什么硬件」—— 分区、架构、内核 3. 设备树告诉内核「硬件长什么样」—— 内存、外设地址

从图上可以看得很清楚:product.mk 和 BoardConfig.mk 是 Android Build 系统的左右手,而设备树是它们和内核之间的桥梁。

6.5 实际项目中的经验

我在做某个平板项目时,遇到过这么个问题:

产品经理说「我们要支持 1080p 屏幕」,我就在 product.mk 里加了屏幕分辨率属性。结果刷机后发现,系统确实显示 1080p 了,但触摸屏完全没反应。

查了半天才发现,BoardConfig.mk 里忘了配置触摸屏的 I2C 地址。而设备树里虽然有触摸屏节点,但 BoardConfig.mk 没告诉内核去加载对应的驱动。

这个教训让我养成了一个习惯:改 product.mk 之前,先检查 BoardConfig.mk 是否配套。就像换轮胎之前,得先确认轮毂尺寸对不对。

避坑指南:我曾经在 BoardConfig.mk 里写错了分区大小,导致 OTA 升级总是失败。后来我写了个脚本,每次编译前自动校验分区数值是否合理。建议你也这么做。

6.6 小结

今天的内容其实就三个核心点:

  • product.mk:定义产品软件配置,相当于「菜单」
  • BoardConfig.mk:定义硬件配置,相当于「厨房设备」
  • 设备树:描述硬件细节给内核看,相当于「食材清单」

这三者配合好了,编译出来的系统才能正常跑起来。少一个,或者配错了,轻则功能异常,重则直接变砖。

嗯,下一节我们会深入看看 Android.mk 和 Android.bp 的写法,那是真正开始「写代码」的地方了。


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