暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

学得懂的 Android Framework 教程——玩转 AOSP 之添加 Product

原创 wpp 2023-02-26
1063

阅读本文前,需要以下前置基础知识:

什么是 Product

实际开发中,一份系统源码可以产出多个产品,例如小米 12s,小米12s pro,小米12s ultra 均源于骁龙8+平台。

源码中通过一系列的配置文件,将我们的源码配置为了不同的产品,这一系列的配置文件我们称为 Product

我们在编译源码之前需要执行 lunch :

lunch

You're building on Linux Lunch menu... pick a combo: 1. aosp_arm-eng 2. aosp_arm64-eng 3. aosp_blueline-userdebug 4. aosp_bonito-userdebug 5. aosp_car_arm-userdebug 6. aosp_car_arm64-userdebug 7. aosp_car_x86-userdebug 8. aosp_car_x86_64-userdebug 9. aosp_cf_arm64_phone-userdebug 10. aosp_cf_x86_64_phone-userdebug 11. aosp_cf_x86_auto-userdebug 12. aosp_cf_x86_phone-userdebug 13. aosp_cf_x86_tv-userdebug 14. aosp_coral-userdebug 15. aosp_coral_car-userdebug 16. aosp_crosshatch-userdebug 17. aosp_crosshatch_car-userdebug 18. aosp_flame-userdebug 19. aosp_marlin-userdebug 20. aosp_sailfish-userdebug 21. aosp_sargo-userdebug 22. aosp_taimen-userdebug 23. aosp_walleye-userdebug 24. aosp_walleye_test-userdebug 25. aosp_x86-eng 26. aosp_x86_64-eng 27. beagle_x15-userdebug 28. car_x86_64-userdebug 29. fuchsia_arm64-eng 30. fuchsia_x86_64-eng 31. hikey-userdebug 32. hikey64_only-userdebug 33. hikey960-userdebug 34. hikey960_tv-userdebug 35. hikey_tv-userdebug 36. m_e_arm-userdebug 37. mini_emulator_arm64-userdebug 38. mini_emulator_x86-userdebug 39. mini_emulator_x86_64-userdebug 40. poplar-eng 41. poplar-user 42. poplar-userdebug 43. qemu_trusty_arm64-userdebug 44. uml-userdebug Which would you like? [aosp_arm-eng] 复制代码

这里的每一个选项就是一个 Product, AOSP 预制了很多 Product。我们对 framework 做定制的第一步就是构建一个我们的 Product。

AOSP 中预制的 Product

AOSP 中 Product 配置文件保存在以下两个目录:

  • build/target:aosp 提供的 product 配置文件保存在这个目录下
  • device:芯片及方案厂商提供的 product 配置文件保存在这个目录下

我们主要关注 build/target 目录和我们编译时选择的产品 aosp_x86_64-eng

先使用 tree 命令查看 build/target 基本的目录结构:

tree . -L 2
.
├── board
│   ├── Android.mk
│   ├── BoardConfigEmuCommon.mk
│   ├── BoardConfigGsiCommon.mk
│   ├── BoardConfigMainlineCommon.mk
│   ├── BoardConfigModuleCommon.mk
│   ├── BoardConfigPixelCommon.mk
│   ├── emulator_arm
│   ├── emulator_arm64
│   ├── emulator_x86
│   ├── emulator_x86_64
│   ├── emulator_x86_64_arm64
│   ├── emulator_x86_arm
│   ├── generic
│   ├── generic_64bitonly_x86_64
│   ├── generic_arm64
│   ├── generic_x86
│   ├── generic_x86_64
│   ├── generic_x86_64_arm64
│   ├── generic_x86_arm
│   ├── go_defaults_512.prop
│   ├── go_defaults_common.prop
│   ├── go_defaults.prop
│   ├── gsi_arm64
│   ├── gsi_system_ext.prop
│   ├── gsi_system_ext_user.prop
│   ├── mainline_arm64
│   ├── mainline_sdk
│   ├── mainline_x86
│   ├── mainline_x86_64
│   ├── mainline_x86_arm
│   ├── module_arm
│   ├── module_arm64
│   ├── module_x86
│   ├── module_x86_64
│   └── ndk
├── OWNERS
└── product
    ├── AndroidProducts.mk
    ├── aosp_64bitonly_x86_64.mk
    ├── aosp_arm64.mk
    ├── aosp_arm.mk
    ├── aosp_base.mk
    ├── aosp_base_telephony.mk
    ├── aosp_product.mk
    ├── aosp_x86_64.mk
    ├── aosp_x86_arm.mk
    ├── aosp_x86.mk
    ├── base.mk
    ├── base_product.mk
    ├── base_system_ext.mk
    ├── base_system.mk
    ├── base_vendor.mk
    ├── cfi-common.mk
    ├── core_64_bit.mk
    ├── core_64_bit_only.mk
    ├── core_minimal.mk
    ├── core_no_zygote.mk
    ├── default_art_config.mk
    ├── developer_gsi_keys.mk
    ├── empty-preloaded-classes
    ├── empty-profile
    ├── emulated_storage.mk
    ├── emulator.mk
    ├── emulator_system.mk
    ├── emulator_vendor.mk
    ├── full_base.mk
    ├── full_base_telephony.mk
    ├── full.mk
    ├── full_x86.mk
    ├── generic.mk
    ├── generic_no_telephony.mk
    ├── generic_ramdisk.mk
    ├── generic_system_arm64.mk
    ├── generic_system.mk
    ├── generic_system_x86_64.mk
    ├── generic_system_x86_arm.mk
    ├── generic_system_x86.mk
    ├── generic_x86.mk
    ├── go_defaults_512.mk
    ├── go_defaults_common.mk
    ├── go_defaults.mk
    ├── gsi
    ├── gsi_release.mk
    ├── handheld_product.mk
    ├── handheld_system_ext.mk
    ├── handheld_system.mk
    ├── handheld_vendor.mk
    ├── languages_default.mk
    ├── languages_full.mk
    ├── mainline_sdk.mk
    ├── mainline_system_arm64.mk
    ├── mainline_system.mk -> generic_system.mk
    ├── mainline_system_x86_64.mk
    ├── mainline_system_x86_arm.mk
    ├── mainline_system_x86.mk
    ├── media_product.mk
    ├── media_system_ext.mk
    ├── media_system.mk
    ├── media_vendor.mk
    ├── module_arm64.mk
    ├── module_arm.mk
    ├── module_common.mk
    ├── module_x86_64.mk
    ├── module_x86.mk
    ├── ndk.mk
    ├── non_ab_device.mk
    ├── OWNERS
    ├── product_launched_with_k.mk
    ├── product_launched_with_l.mk
    ├── product_launched_with_l_mr1.mk
    ├── product_launched_with_m.mk
    ├── product_launched_with_n.mk
    ├── product_launched_with_n_mr1.mk
    ├── product_launched_with_o.mk
    ├── product_launched_with_o_mr1.mk
    ├── product_launched_with_p.mk
    ├── profile_boot_common.mk
    ├── runtime_libart.mk
    ├── sdk_arm64.mk
    ├── sdk.mk
    ├── sdk_phone_arm64.mk
    ├── sdk_phone_armv7.mk
    ├── sdk_phone_x86_64.mk
    ├── sdk_phone_x86.mk
    ├── sdk_x86_64.mk
    ├── sdk_x86.mk
    ├── security
    ├── sysconfig
    ├── telephony.mk
    ├── telephony_product.mk
    ├── telephony_system_ext.mk
    ├── telephony_system.mk
    ├── telephony_vendor.mk
    ├── updatable_apex.mk
    ├── userspace_reboot.mk
    ├── vboot.mk
    ├── verity.mk
    ├── virtual_ab_ota
    ├── virtual_ab_ota.mk -> virtual_ab_ota/launch.mk
    ├── virtual_ab_ota_plus_non_ab.mk -> virtual_ab_ota/plus_non_ab.mk
    └── virtual_ab_ota_retrofit.mk -> virtual_ab_ota/retrofit.mk
复制代码

board目录下主要是一些硬件相关的配置, product 目录主要是产品相关的配置

针对我们选择的 aosp_x86_64-eng,我们主要关注以下几个文件:

  • /board/generic_x86_64/BoardConfig.mk : 用于硬件相关配置
  • /product/AndroidProducts.mk /product/aosp_x86_64.mk:用于配置 Product

接下来我们来看看这三个配置文件:

BoardConfig.mk 用于定义和硬件相关的底层特性和变量,比如当前源码支持的 cpu 位数(64/32位),bootloader 和 kernel, 是否支持摄像头,GPS导航等一些板级特性。

# x86_64 emulator specific definitions
TARGET_CPU_ABI := x86_64
TARGET_ARCH := x86_64
TARGET_ARCH_VARIANT := x86_64

TARGET_2ND_CPU_ABI := x86
TARGET_2ND_ARCH := x86
TARGET_2ND_ARCH_VARIANT := x86_64

TARGET_PRELINK_MODULE := false
include build/make/target/board/BoardConfigGsiCommon.mk
include build/make/target/board/BoardConfigEmuCommon.mk

BOARD_USERDATAIMAGE_PARTITION_SIZE := 576716800

BOARD_SEPOLICY_DIRS += device/generic/goldfish/sepolicy/x86

# Wifi.
BOARD_WLAN_DEVICE           := emulator
BOARD_HOSTAPD_DRIVER        := NL80211
BOARD_WPA_SUPPLICANT_DRIVER := NL80211
BOARD_HOSTAPD_PRIVATE_LIB   := lib_driver_cmd_simulated
BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_simulated
WPA_SUPPLICANT_VERSION      := VER_0_8_X
WIFI_DRIVER_FW_PATH_PARAM   := "/dev/null"
WIFI_DRIVER_FW_PATH_STA     := "/dev/null"
WIFI_DRIVER_FW_PATH_AP      := "/dev/null"
复制代码

其中还通过 include 包含了 BoardConfigGsiCommon.mk 和 BoardConfigEmuCommon.mk 两个配置文件,前者用于通用系统映像的配置,后者用于模拟器的配置

主要和硬件相关,有一个基本的了解即可。一般很少改动,实现细节会在构建系统部分进行讲解。

AndroidProducts.mk 文件用于描述产品列表, 表示当前源码对应了哪些产品。

# Unbundled apps will be built with the most generic product config.
# TARGET_BUILD_APPS 编译Android系统时,这个值为空,编译单模块时,这个值为所编译模块的路径

#编译单模块
ifneq ($(TARGET_BUILD_APPS),)
PRODUCT_MAKEFILES := \
    $(LOCAL_DIR)/aosp_arm64.mk \
    $(LOCAL_DIR)/aosp_arm.mk \
    $(LOCAL_DIR)/aosp_x86_64.mk \
    $(LOCAL_DIR)/aosp_x86.mk \
    $(LOCAL_DIR)/full.mk \
    $(LOCAL_DIR)/full_x86.mk \
#编译系统
else
PRODUCT_MAKEFILES := \
    $(LOCAL_DIR)/aosp_64bitonly_x86_64.mk \
    $(LOCAL_DIR)/aosp_arm64.mk \
    $(LOCAL_DIR)/aosp_arm.mk \
    $(LOCAL_DIR)/aosp_x86_64.mk \
    $(LOCAL_DIR)/aosp_x86_arm.mk \
    $(LOCAL_DIR)/aosp_x86.mk \
    $(LOCAL_DIR)/full.mk \
    $(LOCAL_DIR)/full_x86.mk \
    $(LOCAL_DIR)/generic.mk \
    $(LOCAL_DIR)/generic_system_arm64.mk \
    $(LOCAL_DIR)/generic_system_x86.mk \
    $(LOCAL_DIR)/generic_system_x86_64.mk \
    $(LOCAL_DIR)/generic_system_x86_arm.mk \
    $(LOCAL_DIR)/generic_x86.mk \
    $(LOCAL_DIR)/mainline_system_arm64.mk \
    $(LOCAL_DIR)/mainline_system_x86.mk \
    $(LOCAL_DIR)/mainline_system_x86_64.mk \
    $(LOCAL_DIR)/mainline_system_x86_arm.mk \
    $(LOCAL_DIR)/ndk.mk \
    $(LOCAL_DIR)/sdk_arm64.mk \
    $(LOCAL_DIR)/sdk.mk \
    $(LOCAL_DIR)/sdk_phone_arm64.mk \
    $(LOCAL_DIR)/sdk_phone_armv7.mk \
    $(LOCAL_DIR)/sdk_phone_x86_64.mk \
    $(LOCAL_DIR)/sdk_phone_x86.mk \
    $(LOCAL_DIR)/sdk_x86_64.mk \
    $(LOCAL_DIR)/sdk_x86.mk \

endif

PRODUCT_MAKEFILES += \
    $(LOCAL_DIR)/mainline_sdk.mk \
    $(LOCAL_DIR)/module_arm.mk \
    $(LOCAL_DIR)/module_arm64.mk \
    $(LOCAL_DIR)/module_x86.mk \
    $(LOCAL_DIR)/module_x86_64.mk \

# 配置我们在 lunch 时的选项
COMMON_LUNCH_CHOICES := \
    aosp_arm64-eng \
    aosp_arm-eng \
    aosp_x86_64-eng \
    aosp_x86-eng \
复制代码

PRODUCT_MAKEFILES 用于引入产品的配置文件 COMMON_LUNCH_CHOICES 用于添加 lunch 时的选项,选项的名字由两部分过程 产品名 + 构建模式

  • 产品名就是 PRODUCT_MAKEFILES 中引入的产品配置文件名去掉 .mk 后缀,例如 aosp_x86_64
  • 构建模式有三种:用户模式 user、用户调试模式 userdebug 和工程模式 eng

主要区别如下:、

用户模式 user

  • 仅安装标签为 user 的模块
  • 设定属性 ro.secure=1,打开安全检查功能
  • 设定属性 ro.debuggable=0,关闭应用调试功能
  • 默认关闭 adb 功能
  • 打开 Proguard 混淆器
  • 打开 DEXPREOPT 预先编译优化

用户调试模式 userdebug

  • 安装标签为 user、debug 的模块
  • 设定属性 ro.secure=1,打开安全检查功能
  • 设定属性 ro.debuggable=1,启用应用调试功能
  • 默认打开 adb 功能
  • 打开 Proguard 混淆器
  • 打开 DEXPREOPT 预先编译优化

工程模式 eng

  • 安装标签为 user、debug、eng 的模块
  • 设定属性 ro.secure=0,关闭安全检查功能
  • 设定属性 ro.debuggable=1,启用应用调试功能
  • 设定属性 ro.kernel.android.checkjni=1,启用 JNI 调用检查
  • 默认打开 adb 功能
  • 关闭 Proguard 混淆器
  • 关闭 DEXPREOPT 预先编译优化

aosp_x86_64.mk:这个文件就是我们产品配置的主基地。

PRODUCT_USE_DYNAMIC_PARTITIONS := true

# The system image of aosp_x86_64-userdebug is a GSI for the devices with:
# - x86 64 bits user space
# - 64 bits binder interface
# - system-as-root
# - VNDK enforcement
# - compatible property override enabled

# This is a build configuration for a full-featured build of the
# Open-Source part of the tree. It's geared toward a US-centric
# build quite specifically for the emulator, and might not be
# entirely appropriate to inherit from for on-device configurations.

# GSI for system/product
$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/product/gsi_common.mk)

# Emulator for vendor
$(call inherit-product-if-exists, device/generic/goldfish/x86_64-vendor.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/product/emulator_vendor.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/board/generic_x86_64/device.mk)

# Enable mainline checking for excat this product name
ifeq (aosp_x86_64,$(TARGET_PRODUCT))
PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := relaxed
endif

PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST += \
    root/init.zygote32_64.rc \
    root/init.zygote64_32.rc \

# Copy different zygote settings for vendor.img to select by setting property
# ro.zygote=zygote64_32 or ro.zygote=zygote32_64:
# 1. 64-bit primary, 32-bit secondary OR
# 2. 32-bit primary, 64-bit secondary
# init.zygote64_32.rc is in the core_64_bit.mk below
PRODUCT_COPY_FILES += \
    system/core/rootdir/init.zygote32_64.rc:root/init.zygote32_64.rc

# Product 基本信息
PRODUCT_NAME := aosp_x86_64
PRODUCT_DEVICE := generic_x86_64
PRODUCT_BRAND := Android
PRODUCT_MODEL := AOSP on x86_64
复制代码

inherit-product 函数表示继承另外一个文件

$(call inherit-product, $(SRC_TARGET_DIR)/product/emulator_vendor.mk)
$(call inherit-product-if-exists, device/generic/goldfish/x86_64-vendor.mk)
复制代码

在 Makefile 中可使用 “-include” 来代替 “include”,来忽略由于包含文件不存在或者无法创建时的错误提示(“-”的意思是告诉make,忽略此操作的错误。make继续执行),如果不加-,当 include 的文件出错或者不存在的时候, make 会报错并退出。

-include $(TARGET_DEVICE_DIR)/AndroidBoard.mk
复制代码

include 和 inherit-product 的区别

  • 假设 PRODUCT_VAR := a 在 A.mk 中, PRODUCT_VAR := b 在 B.mk 中。
  • 如果你在 A.mk 中 include B.mk,你最终会得到 PRODUCT_VAR := b
  • 但是如果你在 A.mk inherit-product B.mk,你会得到 PRODUCT_VAR := a b。并 inherit-product 确保您不会两次包含同一个 makefile 。

Product 配置文件中涉及的变量可分为一下几类:

  • 通用变量
  • 路径变量
  • 自定义变量
  • 功能变量

通用变量

PRODUCT_BRAND := Android

PRODUCT_NAME := sdk_phone_x86_64

PRODUCT_DEVICE := generic_x86_64

PRODUCT_MODEL := Android SDK built for x86_64
复制代码

常用的路径变量

  • SRC_TARGET_DIR 其值为 build/target
  • LOCAL_DIR 代表当前目录

自定义变量,表示该变量如何使用, 取决于自己,如:

BOARD_DDR_VAR_ENABLED := true
复制代码

功能变量:表示改变量有特殊功能

  • PRODUCT_COPY_FILES: 用于完成拷贝,可以将源码中的文件拷贝到编译好的分区文件中
PRODUCT_COPY_FILES += vendor/rockchip/common/phone/etc/spn-conf.xml:system/etc/spn-conf.xml
复制代码
  • PRODUCT_PROPERTY_OVERRIDES: 用于设置系统属性(覆盖)
PRODUCT_PROPERTY_OVERRIDES += \
    ro.product.version = 1.0.0 \
复制代码

添加自己的 Product

这里假设我们的公司名叫果冻(Jelly),我们准备开发一款对标苹果 14 的手机,取名叫 大米14(Rice14)。

接下来我们在源码中添加我们自己的产品(Product)

在 device 目录下添加如下的目录与文件:

Jelly/
└── Rice14
    ├── AndroidProducts.mk
    ├── BoardConfig.mk
    └── Rice14.mk
复制代码

BoardConfig.mk 包含了硬件芯片架构配置,分区大小配置等信息这里我们直接使用 aosp_x86_64 的 BoardConfig.mk 就行。BoardConfig.mk 拷贝自 build/target/board/generic_x86_64/BoardConfig.mk

# x86_64 emulator specific definitions
TARGET_CPU_ABI := x86_64
TARGET_ARCH := x86_64
TARGET_ARCH_VARIANT := x86_64

TARGET_2ND_CPU_ABI := x86
TARGET_2ND_ARCH := x86
TARGET_2ND_ARCH_VARIANT := x86_64

TARGET_PRELINK_MODULE := false
include build/make/target/board/BoardConfigGsiCommon.mk
include build/make/target/board/BoardConfigEmuCommon.mk

BOARD_USERDATAIMAGE_PARTITION_SIZE := 576716800

BOARD_SEPOLICY_DIRS += device/generic/goldfish/sepolicy/x86

# Wifi.
BOARD_WLAN_DEVICE           := emulator
BOARD_HOSTAPD_DRIVER        := NL80211
BOARD_WPA_SUPPLICANT_DRIVER := NL80211
BOARD_HOSTAPD_PRIVATE_LIB   := lib_driver_cmd_simulated
BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_simulated
WPA_SUPPLICANT_VERSION      := VER_0_8_X
WIFI_DRIVER_FW_PATH_PARAM   := "/dev/null"
WIFI_DRIVER_FW_PATH_STA     := "/dev/null"
WIFI_DRIVER_FW_PATH_AP      := "/dev/null"
复制代码

Rice14.mk 拷贝自 build/target/product/aosp_x86_64.mk

其中的 if 语句需要注释掉,同时需要修改最后四行

PRODUCT_USE_DYNAMIC_PARTITIONS := true

# The system image of aosp_x86_64-userdebug is a GSI for the devices with:
# - x86 64 bits user space
# - 64 bits binder interface
# - system-as-root
# - VNDK enforcement
# - compatible property override enabled

# This is a build configuration for a full-featured build of the
# Open-Source part of the tree. It's geared toward a US-centric
# build quite specifically for the emulator, and might not be
# entirely appropriate to inherit from for on-device configurations.

# GSI for system/product
$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/product/gsi_common.mk)

# Emulator for vendor
$(call inherit-product-if-exists, device/generic/goldfish/x86_64-vendor.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/product/emulator_vendor.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/board/generic_x86_64/device.mk)

# Enable mainline checking for excat this product name
#ifeq (aosp_x86_64,$(TARGET_PRODUCT))
PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := relaxed
#endif

PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST += \
    root/init.zygote32_64.rc \
    root/init.zygote64_32.rc \

# Copy different zygote settings for vendor.img to select by setting property
# ro.zygote=zygote64_32 or ro.zygote=zygote32_64:
# 1. 64-bit primary, 32-bit secondary OR
# 2. 32-bit primary, 64-bit secondary
# init.zygote64_32.rc is in the core_64_bit.mk below
PRODUCT_COPY_FILES += \
    system/core/rootdir/init.zygote32_64.rc:root/init.zygote32_64.rc

# Overrides
PRODUCT_BRAND := Jelly
PRODUCT_NAME := Rice14
PRODUCT_DEVICE := Rice14
PRODUCT_MODEL := Android SDK built for x86_64 Rice14
复制代码

AndroidProducts.mk 内容如下:

PRODUCT_MAKEFILES := \
    $(LOCAL_DIR)/Rice14.mk

COMMON_LUNCH_CHOICES := \
    Rice14-eng
    Rice14-userdebug
    Rice14-user
复制代码

最后验证:

source build/envsetup.sh
lunch Rice14-eng
make -j16
emulator
复制代码

以上示例给出了最简单的模拟器 Product 的添加,主要是用于我们的学习。后续我们会在 pixel 真机刷机教程中介绍真实硬件的 Product 配置。在构建系统的分析中来详细分析这些配置文件是怎么加载和指导构建过程的。

参考资料

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论