添加新设备

您可以参考本页中的信息为自己的设备和产品创建 Makefile。

每个新的 Android 模块都必须具有配置文件,以使用模块元数据、编译时依赖项和打包指令来指引构建系统。Android 使用 Soong 构建系统。如需详细了解 Android 构建系统,请参阅构建 Android

了解构建层

构建层次结构包括与设备的物理结构对应的抽象层。下表中介绍了这些层。每一层都与上一层存在一对多的关系。例如,一个架构可以有多个主板,一个主板可以有多个产品。您可以将指定层中的某个元素定义为同一层中某个元素的特化元素,这样可以免去复制操作并简化维护工作。

示例 说明
产品 myProduct、myProduct_eu、myProduct_eu_fr、j2 和 sdk 产品层用于定义所开发产品的功能规范,例如要构建的模块、支持的语言区域,以及针对各语言区域的配置。也就是说,这是总体产品的名称。产品特定变量在产品定义 Makefile 中进行定义。一个产品可以沿用其他产品的定义,这有助于简化维护工作。一种常用的方法是:先创建一个基础产品,其中包含会应用到所有产品的功能,然后再基于这个基础产品创建产品变体。例如,如果有两个产品只是使用的无线技术不同(分别使用 CDMA 和 GSM),那么它们可以沿用未定义无线技术的同一个基础产品的定义。
主板/设备 marlin、blueline 和 coral 主板/设备层表示设备上由可塑材料组成的物理层(即,设备的工业设计)。此层还表示产品的基本架构图。这些架构图包括板上的外围设备及其配置。所使用的名称只不过是代表不同主板/设备配置的代码。
架构 arm、x86、arm64 和 x86_64 架构层用于描述主板上运行的处理器配置和应用二进制接口 (ABI)。

使用 build 变体

在针对特定产品进行构建时,如果能在最终发布 build 的基础上有细微的变化,会非常有用。在模块定义中,模块可以通过 LOCAL_MODULE_TAGS 指定标记,这些标记可以是以下一个或多个值:optional(默认值)、debugeng

如果某个模块没有通过 LOCAL_MODULE_TAGS 指定标记,则其标记默认设置为 optional。仅当 PRODUCT_PACKAGES 的产品配置需要可选模块时,系统才会安装可选模块。

下面是当前定义的 build 变体。

变体 说明
eng 这是默认变种。
  • 安装带有 engdebug 标记的模块。
  • 除了带有标记的模块之外,还会根据产品定义文件安装相应模块。
  • ro.secure=0
  • ro.debuggable=1
  • ro.kernel.android.checkjni=1
  • adb 默认处于启用状态。
user 打算作为最终发布版本的变体。
  • 安装带有 user 标记的模块。
  • 除了带有标记的模块之外,还会根据产品定义文件安装相应模块。
  • ro.secure=1
  • ro.debuggable=0
  • adb 默认处于停用状态。
userdebug user 相同,但以下几点除外:
  • 还会安装带有 debug 标记的模块。
  • ro.debuggable=1
  • adb 默认处于启用状态。

userdebug 的准则

在测试中运行 userdebug build 有助于设备开发者了解开发中版本的性能和功耗。为了让 user build 和 userdebug build 保持一致,并在用于调试的 build 中获得可靠的指标,设备开发者应遵循以下准则:

  • userdebug 定义为已启用 root 权限的 user build,但以下情况除外:
    • 仅由用户视需要运行且仅用于 userdebug build 的应用
    • 仅在空闲维护(连接充电器/充满电)期间执行的操作,例如,使用 dex2oatd 而不是 dex2oat 来进行后台编译
  • 不要添加根据 build 类型默认启用/停用的功能。建议开发者不要使用任何影响电池续航时间的日志记录形式(例如调试日志记录或堆转储)。
  • 在 userdebug build 中默认启用的任何调试功能都应明确定义,并告知处理相关项目的所有开发者。您应该只在限定的时间内启用调试功能,直到您尝试调试的问题得到解决。

利用资源叠加层自定义 build

Android 构建系统会在构建时使用资源叠加层来自定义产品。资源叠加层用于指定在默认文件之上应用的资源文件。如需使用资源叠加层,请修改项目构建文件,将 PRODUCT_PACKAGE_OVERLAYS 设为相对于顶级目录的路径。当构建系统搜索资源时,该路径会变为影子根目录,系统除了在当前根目录中进行搜索外,还会一并在该路径中进行搜索。

最常自定义的设置包含在 frameworks/base/core/res/res/values/config.xml 文件中。

如需在此文件上设置资源叠加层,请使用以下某个命令将叠加层目录添加到项目构建文件:

PRODUCT_PACKAGE_OVERLAYS := device/device-implementer/device-name/overlay

PRODUCT_PACKAGE_OVERLAYS := vendor/vendor-name/overlay

然后,将一个叠加层文件添加到该目录下,例如:

vendor/foobar/overlay/frameworks/base/core/res/res/values/config.xml

在叠加层 config.xml 文件中找到的所有字符串或字符串数组都会替换在原始文件中找到的对应字符串或字符串数组。

构建产品

您可以通过多种不同的方式来组织设备的源文件。下面简要说明了 Pixel 实现的一种组织方式。

为 Pixel 实现名为 marlin 的主设备配置。根据此设备配置,为产品创建产品定义 Makefile,用于声明关于设备的产品特定信息,例如名称和型号。您可以查看 device/google/marlin 目录,了解所有相关配置的具体设置方式。

编写产品 Makefile

以下步骤介绍了如何采用与设置 Pixel 产品线类似的方式设置产品 Makefile:

  1. 为您的产品创建一个 device/<company-name>/<device-name> 目录。例如,device/google/marlin。此目录将包含您设备的源代码以及构建这些代码所需的 Makefile。
  2. 创建一个 device.mk Makefile,用来声明设备所需的文件和模块。有关示例,请查看 device/google/marlin/device-marlin.mk
  3. 创建一个产品定义 Makefile,以便基于设备创建具体产品。以下示例 Makefile 来自于 device/google/marlin/aosp_marlin.mk。请注意,该产品会通过 Makefile 沿用 device/google/marlin/device-marlin.mkvendor/google/marlin/device-vendor-marlin.mk 文件中的设置,同时还会声明产品特定信息,例如名称、品牌和型号。
    # Inherit from the common Open Source product configuration
    $(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
    $(call inherit-product, $(SRC_TARGET_DIR)/product/aosp_base_telephony.mk)
    
    PRODUCT_NAME := aosp_marlin
    PRODUCT_DEVICE := marlin
    PRODUCT_BRAND := Android
    PRODUCT_MODEL := AOSP on msm8996
    PRODUCT_MANUFACTURER := Google
    PRODUCT_RESTRICT_VENDOR_FILES := true
    
    PRODUCT_COPY_FILES += device/google/marlin/fstab.common:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.marlin
    
    $(call inherit-product, device/google/marlin/device-marlin.mk)
    $(call inherit-product-if-exists, vendor/google_devices/marlin/device-vendor-marlin.mk)
    
    PRODUCT_PACKAGES += \
        Launcher3QuickStep \
        WallpaperPicker
    

    如需了解可添加到 Makefile 的其他产品特定变量,请参阅设置产品定义变量

  4. 创建一个指向产品的 Makefile 的 AndroidProducts.mk 文件。在此示例中,仅需要产品定义 Makefile。以下示例来自于 device/google/marlin/AndroidProducts.mk(该文件同时包含 marlin (Pixel) 和 sailfish (Pixel XL),它们共享大部分配置):
    PRODUCT_MAKEFILES := \
    	$(LOCAL_DIR)/aosp_marlin.mk \
    	$(LOCAL_DIR)/aosp_sailfish.mk
    
    COMMON_LUNCH_CHOICES := \
    	aosp_marlin-userdebug \
    	aosp_sailfish-userdebug
    
  5. 创建一个包含主板特定配置的 BoardConfig.mk Makefile。有关示例,请查看 device/google/marlin/BoardConfig.mk
  6. 适用于 Android 9 及更低版本)创建一个 vendorsetup.sh 文件,以便将您的产品(“午餐套餐”)与 build 变体(使用短划线将两者分隔开)一起添加到 build 中。例如:
    add_lunch_combo <product-name>-userdebug
    
  7. 这时,您就可以基于同一设备创建更多产品变体了。

设置产品定义变量

产品特定变量在产品的 Makefile 中进行定义。下表显示了在产品定义文件中维护的部分变量。

变量 说明 示例
PRODUCT_AAPT_CONFIG 创建软件包时使用的 aapt 配置。
PRODUCT_BRAND 对软件进行自定义所针对的品牌(如果有),例如运营商。
PRODUCT_CHARACTERISTICS 用于允许向软件包中添加变体特定资源的 aapt 特性。 tabletnosdcard
PRODUCT_COPY_FILES 字词列表,如 source_path:destination_path。在构建相应产品时,应将源路径下的文件复制到目标路径。config/makefile 中定义了针对复制步骤的规则。
PRODUCT_DEVICE 工业设计的名称。这也是主板名称,构建系统会使用它来查找 BoardConfig.mk tuna
PRODUCT_LOCALES 以空格分隔的列表,用于列出由双字母语言代码和双字母国家/地区代码组成的代码对,以便说明针对用户的一些设置,例如界面语言和时间、日期以及货币格式。PRODUCT_LOCALES 中列出的第一个语言区域会用作产品的默认语言区域。 en_GBde_DEes_ESfr_CA
PRODUCT_MANUFACTURER 制造商的名称。 acme
PRODUCT_MODEL 最终产品的最终用户可见名称。
PRODUCT_NAME 总体产品的最终用户可见名称,将显示在设置 > 关于屏幕中。
PRODUCT_OTA_PUBLIC_KEYS 产品的无线下载 (OTA) 公钥列表。
PRODUCT_PACKAGES 将要安装的 APK 和模块列表。 日历联系人
PRODUCT_PACKAGE_OVERLAYS 指明是使用默认资源还是添加任何产品特定叠加层。 vendor/acme/overlay
PRODUCT_SYSTEM_PROPERTIES 系统分区的系统属性分配(采用 "key=value" 格式)列表。其他分区的系统属性可通过 PRODUCT_<PARTITION>_PROPERTIES 设置,如供应商分区的 PRODUCT_VENDOR_PROPERTIES。支持的分区名称:SYSTEMVENDORODMSYSTEM_EXTPRODUCT

配置默认系统语言和语言区域过滤器

使用此信息配置默认语言和系统语言区域过滤器,然后为新的设备类型启用语言区域过滤器。

属性

使用专用系统属性配置默认语言和系统语言区域过滤器:

  • ro.product.locale:用于设置默认语言区域。此属性最初被设置为 PRODUCT_LOCALES 变量中的第一个语言区域;您可以替换该值。(如需了解详情,请参阅设置产品定义变量表。)
  • ro.localization.locale_filter:使用正则表达式(应用于语言区域名称)设置语言区域过滤器。例如:
    • 包含过滤器:^(de-AT|de-DE|en|uk).* - 只允许德语(奥地利变体和德国变体)、所有英语变体和乌克兰语
    • 排除过滤器:^(?!de-IT|es).* - 不包括德语(意大利变体)和西班牙语的所有变体。

启用语言区域过滤器

如需启用过滤器,请设置 ro.localization.locale_filter 系统属性字符串值。

通过在出厂校准期间使用 oem/oem.prop 设置过滤器属性值和默认语言,您无需将过滤器烘焙 (bake) 到系统映像中即可配置限制。通过将这些属性添加到 PRODUCT_OEM_PROPERTIES 变量中(如下所示),就可以确保从 OEM 分区中获取这些属性:

# Delegation for OEM customization
PRODUCT_OEM_PROPERTIES += \
    ro.product.locale \
    ro.localization.locale_filter

然后,在生产环境中,实际值会被写入 oem/oem.prop 以反映目标要求。借助这种方法,就能在恢复出厂设置期间保留默认值,让初始设置在用户看来与首次设置完全一样。

设置 ADB_VENDOR_KEYS 以通过 USB 进行连接

借助 ADB_VENDOR_KEYS 环境变量,设备制造商无需手动授权,即可通过 adb 访问可调试的 build(userdebug build 和 eng build,但不能访问 user build)。通常,adb 会为每台客户端计算机生成一个唯一的 RSA 身份验证密钥,并将其发送到所有已连接的设备。这就是 adb 授权对话框中显示的 RSA 密钥。或者,您也可以将已知密钥构建到系统映像中,并将其分享给相应的 adb 客户端。这对于操作系统开发来说很有用,对测试来说尤其有用,因为此做法无需与 adb 授权对话框手动进行交互。

如需创建供应商密钥,应安排一个人(通常为发布管理员)执行以下操作:

  1. 使用 adb keygen 生成密钥对。对于 Google 设备,Google 会为每个新操作系统版本生成一个新密钥对。
  2. 将密钥对签入源代码树中的某个位置。例如,Google 会将其存储在 vendor/google/security/adb/ 中。
  3. 设置 build 变量 PRODUCT_ADB_KEYS,使其指向您的密钥目录。为此,Google 会在密钥目录中添加一个 Android.mk 文件,其内容为 PRODUCT_ADB_KEYS := $(LOCAL_PATH)/$(PLATFORM_VERSION).adb_key.pub,以帮助确保我们记得为每个操作系统版本生成新的密钥对。

以下是 Google 在该目录(我们将各版本的已签入密钥对存储在此处)中使用的 Makefile:

PRODUCT_ADB_KEYS := $(LOCAL_PATH)/$(PLATFORM_VERSION).adb_key.pub

ifeq ($(wildcard $(PRODUCT_ADB_KEYS)),)
  $(warning ========================)
  $(warning The adb key for this release)
  $(warning )
  $(warning   $(PRODUCT_ADB_KEYS))
  $(warning )
  $(warning does not exist. Most likely PLATFORM_VERSION in build/core/version_defaults.mk)
  $(warning has changed and a new adb key needs to be generated.)
  $(warning )
  $(warning Please run the following commands to create a new key:)
  $(warning )
  $(warning   make -j8 adb)
  $(warning   LOGNAME=android-eng HOSTNAME=google.com adb keygen $(patsubst %.pub,%,$(PRODUCT_ADB_KEYS)))
  $(warning )
  $(warning and upload/review/submit the changes)
  $(warning ========================)
  $(error done)
endif

如需使用这些供应商密钥,工程师只需将 ADB_VENDOR_KEYS 环境变量设为指向存储相应密钥对的目录。这会告知 adb 先尝试这些规范密钥,然后回退到需要手动授权的已生成主机密钥。当 adb 无法连接到未获授权的设备时,系统会显示错误消息,提示您设置 ADB_VENDOR_KEYS(如果尚未设置)。