| RFC-0100:产品元数据 | |
|---|---|
| 状态 | 已接受 |
| 领域 |
|
| 说明 | 产品元数据的规范表示法 |
| Gerrit 更改 | |
| 作者 | |
| 审核人 | |
| 提交日期(年-月-日) | 2021-04-30 |
| 审核日期(年-月-日) | 2021-06-02 |
摘要
Fuchsia 软件开发套件 (SDK) 目前附带所谓的设备配置文件元数据(或本文档中简称为元数据 ),其架构在
//build/sdk/meta/device_profile.json 中定义。元数据旨在描述可安装在设备上的系统映像和软件包。我们发现该架构不完整,需要进行现代化改造。此外,SDK
之外的工具现在也需要元数据,这增加了元数据的重要性。
此 RFC 引入了此信息的新架构,作为平台与工具之间的合约,以及未来更新该架构的流程。
设计初衷
目前,元数据随 SDK 一起提供。它目前包含设备名称、设备文本说明以及用户可以从中下载映像和软件包信息的 URI。我们发现,此元数据 既难以保持最新状态,也不完整,因此无法使用。
工具最终依赖于有关映像和软件包的非官方惯例,或对可能会更改的假设进行硬编码(例如下载 URI 的结构)。这使得工具在这些惯例发生更改时容易出现中断。
我们希望解决这些问题。我们将为元数据指定正式架构,以便工具可以使用它。
当我们分发完整且易于使用的元数据时,SDK 用户将能够选择要刷写到设备的映像,或使用模拟器启动,而无需 Fuchsia 的基础架构或 SDK 团队提供大量帮助。SDK 开发者将拥有一个可信的单一来源,了解如何向用户展示有关产品的信息。工具开发者将拥有一个明确定义的合约,了解如何使用此信息。
易于更新
元数据目前作为 SDK 生成的一部分进行硬编码,每当我们发布新映像时,都需要手动更新。这使得添加、重命名或移除元数据既费力又容易出错。信息经常过时,或者更糟糕的是,根本不会添加。
实际上,由于 SDK 使用者无法依赖于 SDK 附带的元数据的准确性,因此他们会将软件包和映像的位置以及其他易受影响的实现依赖型信息硬编码到其工具中。例如,除了硬编码
网址 之外,树外模拟器启动还依赖于系统映像中是否存在未记录的 images.json 文件。
此提案为我们的元数据提供了一个新架构,我们希望外部用户能够依赖于此架构。这将促使我们保持其最新状态。
完整性
现有设备元数据缺少关键详细信息。例如,用于刷写设备的工具需要分区名称列表,以及要写入这些分区的文件名。目前,这尚未正式确定,因此我们与执行刷写操作的工具之间没有合约。这使得提供稳定性 / 兼容性保证变得具有挑战性。
当您将架构的完整性不足与更新元数据的难度相结合时,问题会变得更加复杂。例如,假设有一个模拟器工具,它希望确保使用与用户想要运行的映像相同的架构来启动模拟器。 在不尝试启动映像的情况下,该工具如何知道特定位置的任何映像是否与特定架构兼容? 借助更新后的架构,我们可以拥有一个元数据集,用于描述映像的架构及其位置。然后,该工具只需为给定映像选择正确的架构即可。
此提案将概述我们元数据的初始架构,并提供更新路径,以确保它们能够保持相关性。
设计
- 为元数据定义新架构。
- 定义更新该架构的流程。
- 在构建过程中生成符合该架构的元数据,并在树内使用它。
- 在 SDK 版本中分发符合该架构的元数据,并在树外使用它。
- 提供 标准工具 和库,用于使用元数据进行刷写和 模拟工作流。
请注意,虽然我们在此处定义了初始架构,但我们将允许通过 API 委员会审核进行演变,而无需额外的 RFC。
定义
在本文档中,我们使用以下定义:
- 架构是对元数据组织的正式描述。
- 元数据是给定架构的具体实例化。
- 工件是任何具体的文件或数据,通常在元数据中通过 URI 引用。
- 清单是包含工件列表的元数据。
- 映像是刷写实体设备或启动模拟器所需的一组工件。
- 软件包是 Fuchsia 中的软件分发单元,通常打包为 Fuchsia 归档 (FAR) 文件。
- 产品是用于创建映像和软件包的 build 配置 。
- 产品包是产品 build 的输出,即一组映像和软件包。
- 目标(设备)是旨在运行产品的实体或虚拟 Fuchsia 设备。
我们将使用 JSON 来表示我们的元数据。架构以 json-schema.org 上定义的 Draft 7 格式表示。
Schemata
本部分详细介绍了我们将对架构进行的初始要求和初始更改。
初始架构的要求
- 元数据必须具有唯一名称或 ID。
- 元数据必须具有人类可读的说明。
- 元数据架构必须进行版本控制。
- 元数据必须指定目标设备的硬件特征。至少必须包括:
- 目标 CPU 架构,目前为 arm64 或 x64。
- 元数据必须指定一个或多个产品包,每个产品包都必须包含:
- 唯一名称。
- 人类可读的说明。
- 映像包。
- 软件包。
- 元数据可以包含其他产品元数据作为键值对,旨在帮助用户选择所需的产品。此类元数据的示例包括 build 类型(用户与工程)和启动类型(正常与中止)。
- 映像或软件包必须:
架构演变
架构的演变可能有多种未来方向。 例如:
- 实体硬件元数据可能包括设备硬件功能,例如是否存在屏幕、键盘或指点设备。
- 虚拟硬件元数据可以指定足以预配模拟器的虚拟设备特征。
为了解决这个问题,架构进行了版本控制。版本是一个字符串,每当添加或移除架构元素时,该字符串都会更新。工具可以面向多个不同版本的架构,或者用户可能需要使用旧版本的工具来使用旧架构。
为了简化版本之间的过渡,我们提出了一种灵活的解析和版本控制方案。我们引入了一个版本控制的信封,简化了 JSON 的解析。解析工具可以读取版本字段,同时忽略 JSON 文档的其余部分。这允许该工具为每个受支持的架构版本选择正确的解析器。
我们建议使用随机生成的 8 位十六进制数字独立对每个架构文件进行版本控制。该数字在所有现有 架构文件中必须是唯一的。为了防止冲突,建议实现 build 时冲突检测,以防止意外重复提交。
由于架构可以通过 $ref 设施包含其他架构,因此我们建议将架构的版本附加到架构文件名中。这不仅可以消除 //build/sdk/meta/common.json
等常见文件的多个版本之间的歧义,还会触发引用架构的版本重新计算。
每个不兼容的架构更改(例如添加或移除必填字段)都会触发版本重新计算。
我们允许通过 API 审核流程 更改架构。 对架构的更改属于开发者功能领域。
实现
架构本身的实现很大程度上是将架构添加到 fuchsia.git 并确保其通过 API 审核。还有两个问题:元数据是在哪里生成的? 以及元数据是在哪里使用的?
设备元数据最初将生成:
- 作为
fuchsia.git中 Fuchsia build 的一部分; - 作为发布映像以供树外使用的一部分;以及
- 作为 SDK 发布的一部分。
它也可能在其他位置生成,尤其是对于在 SDK 版本之外发布的映像和软件包。
设备元数据将主要由 ffx 工具使用,该工具将使用它们来刷写设备和启动模拟器。由于我们将通过 SDK 发布此架构,因此 Fuchsia
树之外的工具也可以使用符合该架构的元数据。
通过这种方法,所有刷写和模拟工作流(无论是用于树内还是树外)都将使用设备元数据进行规范。
这两项工作都需要超出此 RFC 范围的设计。
通用架构
我们将按如下方式扩展 common.json 架构定义。无需考虑向后不兼容性,因为这不是不兼容的更改。为简洁起见,下面省略了 common.json 中的现有定义。
为简洁起见,我们省略了文件的原始内容,并使用 ... 表示省略。
/** build/sdk/meta/common.json */
{
"$schema": "http://json-schema.org/draft-07/schema#",
"id": "http://fuchsia.com/schemas/sdk/common.json",
"definitions": {
...,
"envelope": {
"description": "A versioned envelope.",
"type": "object",
"properties": {
"version": {"$ref": "#/definitions/version"},
"data": {
"description": "The payload."
}
},
"required": [
"version",
"data"
],
"additionalProperties": false
},
"versioned_sdk_element": {
"type": "object",
"allOf": [
{"$ref": "#/definitions/envelope"},
{
"type": "object",
"properties": {
"data": {
"oneOf": [
{"$ref": "#/definitions/sdk_element"}
]
}
}
}
]
},
"version": {
"description": "An opaque version string. The string may include any characters. Tools must not attempt to draw any conclusions about inter version compatibility other than the version 'X' manifest complies with the version 'X' of the schema and is therefore parsable by the version 'X' parser. There are no guarantees, for example, a parser for version 'B' may be able to parse a JSON document versioned 'A'.",
"type": "string",
"minLength": 1
},
}
}
请注意,由于此架构定义了我们使用的架构版本,因此无法轻松更改。工具必须读取符合此架构的文件,才能了解封装的 JSON。
设备
由于设备上可能会安装多个映像,因此我们将设备硬件规范分解为自己的定义。设备硬件规范有两个用途:
- 它描述了运行映像所需的最低硬件要求。
- 它指定了为运行映像而创建的虚拟(模拟)设备。
我们为实体设备和虚拟设备引入了两个新的版本控制 SDK 元素。
实体
目前,我们只关心实体设备的 CPU 架构。其他硬件属性将在架构的未来版本中添加。为了提供完整的示例,下面的架构
定义将信封架构与 sdk_element 架构1 相结合。
/** build/sdk/meta/physical_device-c906d79c.json */
{
"$schema": "http://json-schema.org/draft-07/schema#",
"id": "http://fuchsia.com/schemas/sdk/physical_device-c906d79c.json",
"description": "A physical device specification.",
"type": "object",
"allOf": [
{"$ref": "common.json#/definitions/envelope"},
{
"type": "object",
"properties": {
"data": {
"allOf": [
{"$ref": "common.json#/definitions/sdk_element"},
{
"properties": {
"type": {
"allOf": [
{"$ref": "common.json#/definitions/type"},
{"enum": ["physical_device"]}
]
}
}
},
{"$ref": "hardware-f9928aa4391e2ae3644ce712074a1ef7.json#/definitions/requirements"}
]
}
}
}
]
}
实体设备要求架构
此架构允许我们表示设备硬件要求。这允许工具确保设备硬件与我们将用于预配的工件匹配。 目前,它仅描述 CPU 架构。
/** build/sdk/meta/hardware-c0a116ca.json */
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"requirements": {
"properties": {
"hardware": {
"additionalProperties": false,
"properties": {
"cpu": {
"additionalProperties": false,
"properties": {
"arch": {
"oneOf": [
{"$ref": "common.json#/definitions/target_arch"}
]
}
},
"required": ["arch"],
"type": "object"
}
},
"required": ["cpu"],
"type": "object"
}
},
"required": ["hardware"],
"type": "object"
},
},
"description": "Hardware requirements for running a product image.",
"id": "http://fuchsia.com/schemas/sdk/hardware-c0a116ca.json"
}
虚拟
虚拟设备规范允许我们选择合适的产品包来启动模拟器。在未来的修订版本中,该架构将进一步开发以配置模拟器。为了举例说明,下面的架构定义使用了新定义的
versioned_sdk_element 架构。
/** build/sdk/meta/virtual_device-8a8e2ba9.json */
{
"$schema": "http://json-schema.org/draft-07/schema#",
"id": "http://fuchsia.com/schemas/sdk/virtual_device-8a8e2ba9.json",
"description": "A virtual device specification for launching emulators.",
"type": "object",
"allOf": [
{"$ref": "common.json#/definitions/versioned_sdk_element"},
{
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"type": {
"allOf": [
{"$ref": "common.json#/definitions/type"},
{"enum": ["virtual_device"]}
]
},
"description": {"type": "string"},
"virtual": {"$ref": "virtual_hardware-4c5d1a5d.json#/definitions/spec"}
},
"required": ["virtual"]
}
}
}
]
}
虚拟设备要求架构
虚拟硬件规范用于在启动模拟器时选择合适的产品包。
/** build/sdk/meta/virtual_hardware-4c5d1a5d.json */
{
"$schema": "http://json-schema.org/draft-07/schema#",
"id": "http://fuchsia.com/schemas/sdk/virtual_hardware-4c5d1a5d.json",
"description": "A virtual device specification for launching emulators.",
"definitions": {
"spec": {
"emu": {
"type": "object",
"properties": {
"cpu": {
"type": "object",
"properties": {
"arch": {
"oneOf": [
{"$ref": "common.json#/definitions/target_arch"}
]
}
},
"required": ["arch"],
"additionalProperties": false
}
},
"required": ["cpu"],
"additionalProperties": false
}
},
"required": ["emu"]
}
}
}
产品包
映像和软件包包提供对安装在设备上的软件工件的访问权限。
/** build/sdk/meta/product_bundle-514c2856.json */
{
"$schema": "http://json-schema.org/draft-07/schema#",
"id": "http://fuchsia.com/schemas/sdk/product_bundle-514c2856.json",
"description": "Artifacts required to boot and run software on a device.",
"type": "object",
"allOf": [
{"$ref": "common.json#/definitions/versioned_sdk_element"},
{
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"type": {
"allOf": [
{"$ref": "common.json#/definitions/type"},
{"enum": ["product_bundle"]}
]
},
"description": {
"description": "A human readable description of the product bundle.",
"type": "string"
},
"device_refs": {
"description": "A list of physical or virtual device names this product can run on.",
"type": "array",
"minItems": 1,
"items": {
"type": "string",
"minLength": 1
}
},
"metadata": {
"description": "A list of key-value pairs describing product dimensions. Tools must not rely on the presence or absence of certain keys. Tools may display them to the human user in order to assist them in selecting a desired image or log them for the sake of analytics. Typical metadata keys are: build_info_board, build_info_product, is_debug.",
"$ref": "common.json#/definitions/key_value_list"
},
"manifests": {
"description": "Manifests describing how to boot the product on a device.",
"flash": {"$ref": "flash_manifest-c85dbd8e.json#/definitions/manifest"},
"emu": {"$ref": "emu_manifest-b0708439.json#/definitions/manifest"}
},
"images": {
"description": "A list of system image bundles. Each image bundle must be equivalent to all others. I.e., all image bundle URIs are effectively mirrors of each other. Their formats may vary. Pick an entry that best suits your needs.",
"type": "array",
"minItems": 1,
"items": {"$ref": "#/definitions/image_bundle"}
},
"packages": {
"description": "A list of package bundles. Each package bundle must be equivalent to all otherwise. I.e., all package bundle URIs are effectively mirrors of each other. Their formats may vary. Pick an entry that best suits your needs.",
"type": "array",
"minItems": 1,
"items": {"$ref": "#/definitions/package_bundle"}
}
},
"required": ["device_refs", "manifests", "images", "packages"]
}
}
}
],
"definitions": {
"image_bundle": {
"description": "A set of artifacts necessary to provision a physical or virtual device",
"type": "object",
"properties": {
"base_uri": {
"description": "A base URI for accessing artifacts in the bundle.",
"$ref": "#/definitions/bundle_uri"
},
"format": {
"description": "Bundle format: files - a directory layout; tgz - a gzipped tarball. In case of the 'files' format, the base base path points to a directory. The manifest paths is relative to the directory. To get a full path append a path inside the manifest to base_uri. In case of the 'tgz' format, the base path points to the archive. The manifest path is relative within the archive."
"enum": [
"files",
"tgz"
]
}
},
"required": [
"base_uri",
"format"
],
"additionalProperties": false
},
"package_bundle": {
"description": "A set of artifacts necessary to run a physical or virtual device",
"type": "object",
"properties": {
"repo_uri": {
"description": "A package repository URI. This may be an archive or a directory.",
"$ref": "#/definitions/bundle_uri"
},
"format": {
"description": "Repository format: files - a directory layout; tgz - a gzipped tarball.",
"enum" : [
"files",
"tgz"
]
},
"blob_uri": {
"description": "An optional blob repository URI. If omitted, it is assumed to be <repo_uri>/blobs. If repo_uri refers to a gzipped tarball, ./blobs directory is expected to be found inside the tarball.",
"$ref": "#/definitions/bundle_uri"
}
},
"required": [
"repo_uri",
"format"
],
"additionalProperties": false
},
"bundle_uri": {
"description": "Allowed system image and package bundle URIs.",
"type": "string",
"format": "uri",
"pattern": "^(?:http|https|gs|file):\/\/"
}
}
}
刷写架构
基于刷写架构的清单描述了刷写设备所需的映像工件。该清单与 build 生成的现有 flash.json 相匹配。刷写元数据将嵌入到产品包 SDK 元素中。
/** build/sdk/meta/flash_manifest-c85dbd8e.json */
{
"$schema": "http://json-schema.org/draft-07/schema#",
"id": "http://fuchsia.com/schemas/sdk/flash_manifest-c85dbd8e.json",
"description": "A manifest that describes how to flash a device.",
"type": "object",
"properties": {
"manifest": {"$ref": "#/definitions/manifest"}
},
"required": ["manifest"],
"additionalProperties": false,
"definitions": {
"manifest": {
"description": "A named list of partitions and OEM files necessary to flash a device.",
"type": "object",
"properties": {
"hw_revision" : {
"description": "A board name used to verify whether the device can be flashed using this manifest.",
"type": "string"
},
"products": {
"description": "A list of product specifications that can be flashed onto the device.",
"type": "array",
"items": {"$ref": "#/definitions/product"},
"minItems": 1
}
},
"required": ["hw_revision", "products"],
"additionalProperties": false
},
"product": {
"description": "A named product specification.",
"type": "object",
"properties": {
"name": {
"description": "A unique name of this manifest.",
"type": "string"
},
"partitions": {
"description": "A list of partition names and file names corresponding to the partitions.",
"$ref": "common.json#/definitions/key_value_list"
},
"bootloader_partitions": {
"description": "A list of partition names and file names corresponding to the partitions.",
"$ref": "common.json#/definitions/key_value_list"
},
"oem_files": {
"description": "A list of OEM command and file names corresponding to the command.",
"$ref": "common.json#/definitions/key_value_list"
}
},
"required": ["name", "partitions"],
"additionalProperties": false
}
}
}
模拟器架构
模拟器架构指定了在模拟器上启动产品所需的映像工件。
/** build/sdk/meta/emu_manifest-b0708439.json */
{
"$schema": "http://json-schema.org/draft-07/schema#",
"id": "http://fuchsia.com/schemas/sdk/emu_manifest-b0708439.json",
"definitions": {
"manifest": {
"description": "A manifest that describes how to boot an emulator.",
"type": "object",
"properties": {
"kernel": {
"description": "A path to the kernel image file. The path is relative to the image bundle base.",
"type": "string",
"minLength": 1
},
"initial_ramdisk": {
"description": "A path to the initial ramdisk, the kernel ZBI. The path is relative to the image bundle base.",
"type": "string",
"minLength": 1
},
"disk_images": {
"description": "A list of one or more disk image paths to FVM images. Each path is relative to the image bundle base.",
"type": "array",
"items": {
"type": "string",
"minLength": 1,
},
"minItems": 1
}
},
"required": ["kernel", "initial_ramdisk", "disk_images"],
"additionalProperties": false
}
}
}
其他常见定义
以下是对常见定义的额外补充。如需了解与版本相关的补充,请参阅 section on common.json 部分。为简洁起见,下面省略了 common.json 中的现有定义。
/** build/sdk/meta/common.json */
{
"$schema": "http://json-schema.org/draft-07/schema#",
"id": "http://fuchsia.com/schemas/sdk/common.json",
"definitions": {
...,
"key_value": {
"description": "A key-value pair.",
"type": "array",
"items": [
{"type": "string"},
{"type": ["number", "string"]}
],
"minItems": 2,
"additionalItems": false
},
"key_value_list": {
"description": "A list of key-value pairs.",
"type": "array",
"items": {"$ref": "#/definitions/key_value"}
}
示例
设备
实体设备
以下是设备硬件规范的示例。
{
"version": "c906d79c",
"data": {
"type": "physical_device",
"name": "generic-x64",
"description": "A generic x64 device.",
"hardware": {
"cpu": {
"arch": "x64"
}
}
}
}
产品包
实体设备上的终端
这是一个通用终端产品的示例,该产品可在通用 x64 设备上启动,其中包含两个归档镜像,分别用于通过 gs 和 https
URI 访问的映像和软件包。
{
"version": "514c2856",
"data": {
"type": "product_bundle",
"name": "generic-x64",
"description": "A terminal x64 product.",
"device_refs": ["generic-x64"],
"metadata": [
["build-type", "release"],
["product", "terminal"]
],
"manifests": {
"flash": {
"hw_revision": "x64",
"products" : [
{
"bootloader_partitions": [],
"name": "fuchsia",
"oem_files": [],
"partitions": [
["", "fuchsia.zbi"],
["", "zedboot.zbi"],
["", "fuchsia.vbmeta"],
["", "zedboot.vbmeta"]
]
}
]
}
},
"images": [
{
"base_uri": "gs://fuchsia/development/0.20201216.2.1/images/generic-x64.tgz",
"format": "tgz"
},
{
"base_uri": "https://storage.googleapis.com/fuchsia/development/0.20201216.2.1/images/generic-x64.tgz",
"format": "tgz"
}
],
"packages": [
{
"repo_uri": "gs://fuchsia/development/0.20201216.2.1/packages/generic-x64.tar.gz",
"format": "tgz"
},
{
"repo_uri": "https://storage.googleapis.com/fuchsia/development/0.20201216.2.1/packages/generic-x64.tar.gz",
"format": "tgz"
}
]
}
}
模拟器上的终端
这是一个通用终端产品的示例,该产品可在 x64 模拟器上启动。映像和软件包都可以直接从 GCS 访问。
{
"version": "514c2856",
"data": {
"type": "product_bundle",
"name": "generic-x64",
"description": "A terminal x64 product.",
"device_refs": ["qemu-x64"],
"metadata": [
["build-type" , "debug"],
["product", "terminal"]
],
"manifests": {
"emu": {
"kernel": "qemu-kernel.kernel",
"initial_ramdisk": "zircon-a.zbi",
"disk_images": ["storage-sparse.blk"]
}
},
"images": [
{
"base_uri": "https://storage.googleapis.com/fuchsia-artifacts/builds/8852232026486839104/images/",
"format": "files"
}
],
"packages": [
{
"repo_uri": "https://storage.googleapis.com/fuchsia-artifacts/builds/8852232026486839104/packages/",
"blob_repo_uri": "https://storage.googleapis.com/fuchsia-artifacts/blobs/",
"format": "files"
}
]
}
}
性能
这不太可能对性能产生影响,因为元数据生成和解析不是资源密集型操作。
工效学设计
发布标准化元数据应通过消除对易受影响的硬编码配置的需求,使集成更简单。
我们选择 JSON,因为它是一种成熟的格式,并且是 Fuchsia 配置文件的实际标准。JSON 架构格式已正式确定并经过同行评审。
向后兼容性
引入元数据不会影响向后兼容性,因为现有元数据目前没有用户。
这些架构的未来修订版本将通过 API 审核,并使用标准 LSC 流程进行更改管理,该流程涉及测试以及与高优先级客户的直接互动。此流程将通过对架构定义进行版本控制来辅助完成。
安全注意事项
基于这些架构的元数据与现有解决方案(即类似信息的临时硬编码)一样安全。
我们将在这些架构生命周期的早期阶段提高工件交付的安全性。根据安全团队正在进行的反馈,这可能在部署之前。至关重要的是,工具必须验证下载的工件内容的完整性:工件必须是发布元数据时预期的内容。这可以通过将哈希函数的输出添加到架构中,或使用支持完整性检查的协议(例如 TUF)来实现。
作为 Fuchsia SDK 的一部分销售的工具(使用此架构并提取工件)必须实施额外的安全措施,以确保传输安全,防止中间人攻击等攻击。它们可以通过拒绝从不安全 / 不受信任的位置提取或使用工件来实现这一点。
隐私注意事项
此提案没有已知的隐私注意事项。发布元数据的人员或团队可能需要考虑隐私问题;我们希望他们进行自己的隐私审核。例如,发布元数据的团队可能需要仔细考虑如何跟踪下载。
测试
虽然架构的存在不需要测试,但我们将确保 build 生成的元数据符合架构。我们还将进行兼容性测试,以确保工具在必要时继续使用旧架构。
文档
目前,除了架构本身之外,我们没有计划提供任何文档,但这种情况可能会随着需求而变化。创建或更新架构的开发者可能需要提供术语表、每个架构的使用方式说明以及它们之间的交互方式说明。
缺点、替代方案和未知事项
我们致力于使用特定的 API 来指定设备映像。这样做的好处是提高了跨版本的兼容性,利用了现有的变更管理流程,并使我们能够分发一致运行的工具,但缺点是降低了灵活性(由于官僚障碍,更改架构需要更长时间)。
在先技术和参考文档
本文档收集并系统化了整个树中的常见配置,如上所述。大部分现有元数据都可以在
//build/images/BUILD.gn中找到;例如,当前版本的刷写
架构可以在其中找到。
-
所有元数据都作为 SDK 元素分发。 ↩