| # FFX Plugin for Product and Image Assembly | |
| TODO: Document Product Assembly | |
| [Image Assembly RFC-0072](/docs/contribute/governance/rfcs/0072_standalone_image_assembly_tool.md). | |
| Image Assembly is responsible for taking prebuilt artifacts and generating | |
| images that can be used to update or flash a Fuchsia device. The FFX plugin has | |
| three subcommands: [`create-system`](#create_system), | |
| [`create-update`](#create_update), and | |
|  | |
| # create-system | |
| Create a Fuchsia system that minimally includes a ZBI, and optionally a VBMeta | |
| and FVM images. | |
| ```bash | |
| ffx assembly create-system \ | |
| --image-assembly-config image_assembly_config.json \ | |
| --images images_config.json \ | |
| --outdir <output-directory> | |
| ``` | |
| ## Arguments | |
| | input | format | description | | |
| | --- | --- | --- | | |
| | `--image-assembly-config` | [Image Assembly Config](#image-assembly-config) | Contents of the Fuchsia system that are put into the images. | | |
| | `--images` | [Images Config](#images-config) | Which images to generate and how. | | |
| | `--outdir` | path | Directory to write outputs. | | |
| | `--gendir` | path | (optional; default=outdir) Directory to write intermediate files. | | |
| | `--base-package-name` | string | (optional; default="system_image") Name to give the Base Package. This is currently only used by OTA tests to allow publishing muliple base packages to the same amber repository without naming collisions. | | |
| | `--mode` | [Modes](#modes) | (optional; default="standard") Where to put the packages. | | |
| ## Modes | |
| | mode | description | | |
| | --- | --- | | |
| | `standard` | Packages are placed in a blobfs in a FVM that is flashed to a separate partition. | | |
| | `fvm_in_zbi` | Packages are placed in a blobfs in a FVM that is embedded into the ZBI as a ramdisk. | | |
| | `bootfs_only` | Packages are placed into BootFS. | | |
| ## Outputs | |
| | output | format | description | | |
| | --- | --- | --- | | |
| | `packages.json` | [Package Manifest](/docs/concepts/packages/update_pkg.md) | List of packages in the system. | | |
| | `images.json` | [Images Manifest](#images-manifest) | List of images generated. | | |
| | `fuchsia.zbi` | | Fuchsia Zircon Boot Image (ZBI). | | |
| | `fuchsia.vbmeta` | | Fuchsia Verified Boot Metadata (VBMeta). | | |
| | `fvm.blk` | | Fuchsia Volume Manager (FVM). | | |
| # create-update | |
| Create an update package for updating a running Fuchsia system. | |
| ```bash | |
| ffx assembly create-update \ | |
| --packages packages.json \ | |
| --partitions partitions.json \ | |
| --system-a images.json \ | |
| --system-r recovery_images.jso \ | |
| --board-name "board" \ | |
| --epoch 0 \ | |
| --outdir <output-directory> | |
| ``` | |
| ## Arguments | |
| input | format | description | |
| ----------------------- | --------------------------------------------------------- | ----------- | |
| `--packages` | [Package Manifest](/docs/concepts/packages/update_pkg.md) | List of packages in the system. | |
| `--partitions` | [Partitions Config](#partitions-config) | Where in the partition table the images are put. | |
| `--system-[a,b,r]` | [Images Manifest](#images-manifest) | The system to place in the slot. | |
| `--board-name` | string | The name of the board. Fuchsia will reject an Update Package with a different board name. | |
| `--epoch` | int | The backstop OTA version. Fuchsia will reject updates with a lower epoch. | |
| `--outdir` | path | Directory to write outputs. | |
| `--gendir` | path | (optional; default=outdir) Directory to write intermediate files. | |
| `--update-package-name` | string | (optional; default="update") Name to give the Update Package. This is currently only used by OTA tests to allow publishing multiple update packages to the same amber repository without naming collisions. | |
| ## Outputs | |
| output | format | description | |
| ------------ | ----------------------------------------------- | --------------- | |
| `update.far` | [Format](/docs/concepts/packages/update_pkg.md) | Update package. | |
| # Image Assembly Config | |
| The image assembly config specifies the **contents** of the Fuchsia system that is put | |
| into the images. | |
| ```json5 | |
| { | |
| // The set of packages included when flashing or updating a device, and should | |
| // not be removed by the garbage collector. | |
| base: [ "path/to/package_manifest.json" ], | |
| // The set of packages included when flashing or updating a device, but can be | |
| // removed by the garbage collector. | |
| cache: [ "path/to/package_manifest.json" ], | |
| // The set of system-critical packages included in the "System Image" | |
| // (i.e. base package). | |
| system: [ "path/to/package_manifest.json" ], | |
| kernel: { | |
| // Path on host to the kernel ZBI. | |
| path: "path/to/kernel.zbi", | |
| // The arguments to pass to the kernel on boot. | |
| args: [ "arg1", "arg2" ], | |
| }, | |
| // Arguments available in the boot service for userspace programs. | |
| boot_args: [ "arg1", "arg2" ], | |
| // Files to put in BootFS. | |
| bootfs_files: [ | |
| { | |
| source: "path/to/file/on/host", | |
| destination: "path/to/file/in/bootfs", | |
| } | |
| ], | |
| // Packages to put in BootFS. | |
| bootfs_packages: [ | |
| "path/to/package_manifest.json", | |
| "path/to/package_manifest.json", | |
| ] | |
| } | |
| ``` | |
| # Images Config | |
| The images config specifies **which images** to generate and how. | |
| ```json5 | |
| { | |
| images: [ | |
| <image>, | |
| <image>, | |
| ], | |
| } | |
| ``` | |
| `<image>` specifies a single image to generate, and has the following format. | |
| ```json5 | |
| { | |
| type: "<type>", | |
| name: "<name>", | |
| <type-specific-parameters>, | |
| } | |
| ``` | |
| `<type>` can be one of: zbi, vbmeta, or fvm. | |
| ## zbi type | |
| ```json5 | |
| { | |
| type: "zbi", | |
| // The name to give the file: fuchsia.zbi | |
| name: "fuchsia", | |
| // The compression format for the ZBI. | |
| compression: "zstd.max", | |
| // An optional script to post-process the ZBI. | |
| // This is often used to prepare the ZBI for the | |
| postprocessing_script: <post-processing-script>, | |
| } | |
| ``` | |
| `<post-processing-script>` has the following format. | |
| ```json5 | |
| { | |
| // The path to the script on host. | |
| // This script _musts_ take the following arguments: | |
| // -z <path to ZBI> | |
| // -o <output path> | |
| // -B <build directory, relative to script's source directory> | |
| path: "path/to/script/on/host.sh", | |
| // Additional arguments to pass to the script after the above arguments. | |
| args: [ "arg1", "arg2" ], | |
| } | |
| ``` | |
| ## VBMeta Type | |
| ```json5 | |
| { | |
| type: "vbmeta", | |
| // The name to give the file: fuchsia.vbmeta | |
| name: "fuchsia", | |
| // Path on host to the key for signing VBMeta. | |
| key: "path/to/key/on/host", | |
| // Path on host to the key metadata to add to the VBMeta. | |
| key_metadata: "path/to/key/metadata/on/host", | |
| // Optional descriptors to add to the VBMeta image. | |
| additional_descriptors: [ | |
| <descriptor>, | |
| <descriptor>, | |
| ], | |
| } | |
| ``` | |
| ### VBMeta Descriptor | |
| `<descriptor>` has the following format. | |
| ```json5 | |
| { | |
| // Name of the partition. | |
| name: "mypart", | |
| // Size of the partition in bytes. | |
| size: 12345, | |
| // Custom VBMeta flags to add. | |
| flags: 1, | |
| // Minimum AVB version to add. | |
| min_avb_version: "1.1", | |
| } | |
| ``` | |
| ## FVM Type | |
| ```json5 | |
| { | |
| type: "fvm", | |
| // The name to give the file: fvm.blk | |
| name: "fvm", | |
| // The size of a slice within the FVM. | |
| slice_size: 0, | |
| // The list of filesystems to generate that can be added to the outputs. | |
| filesystems: [ | |
| <filesystem>, | |
| <filesystem>, | |
| ], | |
| // The FVM images to generate. | |
| outputs: [ | |
| <fvm-output>, | |
| <fvm-output>, | |
| ], | |
| } | |
| ``` | |
| ### Filesystem | |
| `<filesystem>` can be one of the following. | |
| ```json5 | |
| { | |
| type: "blobfs", | |
| // The name of the volume in the FVM. | |
| name: "blob", | |
| // Optionally compress the volume file. | |
| compress: true, | |
| // Optional deprecated layout. | |
| layout: "deprecated-padded", | |
| // Reserve |minimum_data_bytes| and |minimum_inodes| in the FVM, and ensure | |
| // that the final reserved size does not exceed |maximum_bytes|. | |
| maximum_bytes: 0, | |
| minimum_data_bytes: 0, | |
| minimum_inodes: 0, | |
| } | |
| ``` | |
| ```json5 | |
| { | |
| type: "empty-data", | |
| // The name of the volume in the FVM. | |
| name: "empty-data", | |
| } | |
| ``` | |
| ```json5 | |
| { | |
| type: "reserved", | |
| // The name of the volume in the FVM. | |
| name: "internal", | |
| // The number of slices to reserve. | |
| slices: 1000, | |
| } | |
| ``` | |
| ### FVM Output | |
| `<fvm-output>` can be one of the following. | |
| ```json5 | |
| { | |
| type: "standard", | |
| // The name to give the file: fvm.blk. | |
| name: "fvm", | |
| // The filesystems to include in the FVM. | |
| filesystems: [ | |
| "blob", | |
| "data", | |
| "internal", | |
| ], | |
| // Whether to compress the FVM. | |
| compress: true, | |
| // Shrink the FVM to fit exactly the contents. | |
| resize_image_file_to_fit: true, | |
| // After the optional resize, truncate the file to this length. | |
| truncate_to_length: 0, | |
| } | |
| ``` | |
| ```json5 | |
| { | |
| type: "sparse", | |
| // The name to give the file: fvm.sparse.blk. | |
| name: "fvm.sparse", | |
| // The filesystems to include in the FVM. | |
| filesystems: [ | |
| "blob", | |
| "data", | |
| "internal", | |
| ], | |
| // Whether to compress the FVM. | |
| compress: true, | |
| // The maximum size the FVM can expand to at runtime. | |
| // This sets the amount of slice metadata to allocate during construction, | |
| // which cannot be modified at runtime. | |
| max_disk_size: 0, | |
| } | |
| ``` | |
| ```json5 | |
| { | |
| type: "nand", | |
| // The name to give the file: fvm.nand.blk. | |
| name: "fvm.nand", | |
| // The filesystems to include in the FVM. | |
| filesystems: [ | |
| "blob", | |
| "data", | |
| "internal", | |
| ], | |
| // Whether to compress the FVM. | |
| compress: true, | |
| // The maximum size the FVM can expand to at runtime. | |
| // This sets the amount of slice metadata to allocate during construction, | |
| // which cannot be modified at runtime. | |
| max_disk_size: 0, | |
| block_count: 0, | |
| oob_size: 0, | |
| page_size: 0, | |
| pages_per_block: 0, | |
| } | |
| ``` | |
| ## Example | |
| ```json5 | |
| { | |
| images: [ | |
| { | |
| type: "zbi", | |
| name: "fuchsia", | |
| }, | |
| { | |
| type: "vbmeta", | |
| name: "fuchsia", | |
| key: "path/to/key", | |
| key_metadata: "path/to/key/metadata", | |
| }, | |
| { | |
| type: "fvm", | |
| name: "fvm", | |
| slice_size: 0, | |
| filesystems: [ | |
| { | |
| type: "blobfs", | |
| name: "blob", | |
| compress: true, | |
| maximum_bytes: 65536, | |
| minimum_data_bytes: 0, | |
| minimum_inodes: 4096, | |
| }, | |
| ], | |
| outputs: [ | |
| { | |
| type: "standard", | |
| name: "fvm", | |
| filesystems: [ | |
| "blob", | |
| "empty-data", | |
| ], | |
| }, | |
| { | |
| type: "sparse", | |
| name: "fvm.sparse", | |
| filesystems: [ | |
| "blob", | |
| "empty-data", | |
| ], | |
| compress: true, | |
| max_disk_size: 65536, | |
| }, | |
| ], | |
| }, | |
| ], | |
| } | |
| ``` | |
| # Images Manifest | |
| ```json5 | |
| [ | |
| <image>, | |
| <image>, | |
| ] | |
| ``` | |
| ## Image | |
| `<image>` has the following format. | |
| ```json5 | |
| { | |
| name: "zircon-a", | |
| path: "path/on/host/to/image", | |
| type: <image-type>, | |
| } | |
| ``` | |
| `<image-type>` must be one of: zbi, vbmeta, base-package, blob, storage-full, | |
| storage-sparse, storage-sparse-blob, or fvm.fastboot. | |
| ## Example | |
| ```json5 | |
| [ | |
| { | |
| name: "zircon-a", | |
| path: "path/to/fuchsia.zbi", | |
| type: "zbi", | |
| }, | |
| { | |
| name: "zircon-a", | |
| path: "path/to/fuchsia.vbmeta", | |
| type: "vbmeta", | |
| } | |
| ] | |
| ``` | |
| # Partitions Config | |
| ```json5 | |
| { | |
| // The list of bootloader partitions that are not slot-specific. | |
| booloader_partitions: [ | |
| <bootloader-partition>, | |
| <bootloader-partition>, | |
| ], | |
| // The list of non-bootloader partitions that are slot-specific. | |
| partitions: [ | |
| <partition>, | |
| <partition>, | |
| ], | |
| } | |
| ``` | |
| ## Bootloader Partition | |
| `<bootloader-partition>` has the following format. | |
| ```json5 | |
| { | |
| // The name of the partition known to fastboot. | |
| name: "bootloader", | |
| // The firmware type provided to the update system. | |
| // See documentation here: | |
| // https://fuchsia.dev/fuchsia-src/concepts/packages/update_pkg | |
| type: "tpl", | |
| // Path on host to the image. | |
| image: "path/on/host/to/image", | |
| } | |
| ``` | |
| ## Partition | |
| `<partition>` has the following format. | |
| ```json5 | |
| { | |
| // The name of the partition known to fastboot. | |
| name: "zircon_a", | |
| type: "<partition-type>", | |
| slot: "<partition-slot>", | |
| } | |
| ``` | |
| `<partition-type>` can be one of: `ZBI`, `VBMeta`, `FVM`. `<partition-slot>` can be | |
| one of: `A`, `B`, `R`. | |
| ## Example | |
| ```json5 | |
| { | |
| booloader_partitions: [ | |
| { | |
| name: "bootloader", | |
| type: "tpl", | |
| image: "path/to/bootloader.tpl", | |
| }, | |
| ], | |
| partitions: [ | |
| { | |
| name: "zircon_a", | |
| type: "ZBI", | |
| slot: "A", | |
| }, | |
| { | |
| name: "vbmeta_a", | |
| type: "VBMeta", | |
| slot: "A", | |
| }, | |
| { | |
| name: "zircon_b", | |
| type: "ZBI", | |
| slot: "B", | |
| }, | |
| { | |
| name: "vbmeta_b", | |
| type: "VBMeta", | |
| slot: "B", | |
| }, | |
| { | |
| name: "fvm", | |
| type: "FVM", | |
| slot: "A", | |
| }, | |
| ], | |
| } | |
| ``` |