4、AOSP中的设备树文件结构:BoardConfig.mk、device.mk、AndroidProducts.mk的作用与配置
好,咱们今天聊聊设备树里最核心的三个文件。很多新手刚接触AOSP时,看到device目录下一堆.mk文件就头大。其实说白了,这三个文件各司其职,搞懂了它们,设备树配置就掌握了一半。
4.1 BoardConfig.mk —— 硬件的“身份证”
这个文件描述的是硬件本身的能力。我习惯把它理解为“这块板子长什么样”。
它主要定义的是芯片架构、内存大小、分区布局、Bootloader参数等。这些信息跟具体的产品型号无关,只跟硬件平台有关。
# BoardConfig.mk 示例
TARGET_ARCH := arm64
TARGET_ARCH_VARIANT := armv8-a
TARGET_CPU_VARIANT := generic
TARGET_CPU_ABI := arm64-v8a
TARGET_NO_BOOTLOADER := true
TARGET_NO_KERNEL := false
BOARD_KERNEL_CMDLINE := console=ttyS0,115200 androidboot.hardware=mydevice
BOARD_KERNEL_BASE := 0x80000000
BOARD_KERNEL_PAGESIZE := 2048
BOARD_BOOTIMAGE_PARTITION_SIZE := 33554432
BOARD_SYSTEMIMAGE_PARTITION_SIZE := 1073741824
BOARD_USERDATAIMAGE_PARTITION_SIZE := 2147483648
这里有个坑,我踩过好几次。就是BOARD_KERNEL_CMDLINE里的参数,一定要跟你的内核实际支持的参数匹配。我曾经因为多写了一个不支持的参数,导致内核启动时直接panic,查了两天才发现是cmdline的问题。
4.2 device.mk —— 产品的“配置单”
这个文件描述的是产品层面的东西。比如要编译哪些模块、预装哪些应用、系统属性的默认值等。
你想想看,同一个硬件平台,可能出好几个型号。比如标准版和Pro版,它们的BoardConfig.mk可以一样,但device.mk肯定不同。
# device.mk 示例
$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/product/full_base_telephony.mk)
PRODUCT_NAME := mydevice
PRODUCT_DEVICE := mydevice
PRODUCT_BRAND := MyBrand
PRODUCT_MODEL := MyDevice Pro
PRODUCT_MANUFACTURER := MyCompany
# 预装应用
PRODUCT_PACKAGES += \
MyLauncher \
MyCamera \
MySettings
# 系统属性
PRODUCT_PROPERTY_OVERRIDES += \
ro.sf.lcd_density=480 \
ro.product.display.resolution=1080x1920
# 权限配置
PRODUCT_COPY_FILES += \
frameworks/native/data/etc/android.hardware.camera.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.xml
我个人习惯把PRODUCT_PACKAGES按功能模块分组,比如系统应用、第三方应用、测试工具等。这样后期维护时,一眼就能看出哪些模块是干什么的。
PRODUCT_PACKAGES_ENG。同理还有PRODUCT_PACKAGES_DEBUG和PRODUCT_PACKAGES_USER。这个我在做调试版本时经常用,省去了手动修改mk文件的麻烦。
4.3 AndroidProducts.mk —— 产品列表的“目录”
这个文件最简单,但也很容易被忽略。它的作用就是告诉编译系统:我这个设备目录下有哪些产品配置。
# AndroidProducts.mk 示例
PRODUCT_MAKEFILES := \
$(LOCAL_DIR)/device.mk
# 如果有多个产品变体
# PRODUCT_MAKEFILES := \
# $(LOCAL_DIR)/device.mk \
# $(LOCAL_DIR)/device_lite.mk
嗯,这里要注意。如果你在AndroidProducts.mk里漏掉了某个产品,那你在执行lunch命令时就看不到它。我记得有一次帮同事排查问题,他明明写了device.mk,但lunch列表里就是没有。最后发现是AndroidProducts.mk里忘记引用了。
4.4 三个文件的关系
说白了,这三个文件的关系是这样的:
| 文件 | 作用域 | 定义内容 | 典型变量 |
|---|---|---|---|
| BoardConfig.mk | 硬件平台 | CPU架构、分区大小、内核参数 | TARGET_ARCH, BOARD_KERNEL_* |
| device.mk | 产品型号 | 预装模块、系统属性、权限 | PRODUCT_PACKAGES, PRODUCT_PROPERTY_* |
| AndroidProducts.mk | 产品列表 | 注册可编译的产品 | PRODUCT_MAKEFILES |
它们的加载顺序也很有意思。编译系统会先读AndroidProducts.mk,拿到所有可用的产品列表。然后根据你lunch选择的产品,加载对应的device.mk。而BoardConfig.mk则是在device.mk中被inherit-product引入的。
- BoardConfig.mk —— 硬件说了算,跟产品无关
- device.mk —— 产品说了算,决定软件配置
- AndroidProducts.mk —— 目录索引,告诉系统有哪些产品可选
4.5 实战中的配置建议
基于我这些年做AOSP移植的经验,给你几个建议:
- BoardConfig.mk尽量保持纯净 —— 只放跟硬件强相关的配置。别把产品相关的变量塞进去,否则后面维护起来会很痛苦。
- 善用
inherit-product—— 如果你的多个产品有共同配置,可以抽到一个公共的mk文件里,然后用inherit-product引入。这样改一处,所有产品都生效。 - 命名规范要统一 —— 我见过有人把BoardConfig.mk写成boardconfig.mk,结果编译时死活找不到。AOSP对文件名大小写是敏感的,别在这种细节上翻车。
- 版本管理要跟上 —— 每次修改这三个文件,都建议在commit message里写清楚改了啥、为什么改。不然三个月后回头看,你自己都忘了当初为啥要加那个变量。
好了,这三个文件的内容就讲到这里。下一章咱们聊聊设备树里更进阶的内容——如何调试和排查配置问题。到时候我会分享一些我实际踩过的坑,保证让你少走弯路。