Developing with Fuchsia packages

Almost everything that exists on a Fuchsia system is a Fuchsia package. Whether it is immediately apparent or not almost everything you see on Fuchsia lives in a package. This document will cover the basics of a package-driven workflow where you build a package and push it to a Fuchsia device that is reachable via IP from your development host.

Pre-requisites and overview

The host and target must be able to communicate over IP. In particular it must be possible to SSH from the development host to the target device, and the target device must be able to connect via TCP to the development host on port 8083. The SSH connection is used to issue commands to the target device.

The development host will run a simple, static file, HTTP server that makes the updates available to the target. This HTTP server is part of the Fuchsia source code and built automatically.

The target is instructed to look for changes on the development host via a couple of commands that are run manually. When the update system on the target sees these changes it will fetch the new software from the HTTP server running on the host. The new software will be available until the target is rebooted.

Building

To build a package containing the required code, a package type build rule is used. If one of these needs to be created for the target package, consult the reference page for this.

Once an appropriate build rule is available the target package can be re-generated by running fx build.

Inspecting packages

Fuchsia comes with a tool far to work with package archives. After the completion of a Fuchsia build the far program can be used to create, list, dump or extract package archives:

$ fx host-tool far
...
Usage: far <command> ...
  where <command> is create, list, cat, extract, or extract-file.

For example, to list the contents of a package, observe that its meta.far contains meta/contents:

$  fx host-tool far list --archive=out/default/obj/third_party/sbase/sed/meta.far
meta/contents
meta/fuchsia.abi/abi-revision
meta/package

The meta/contents file maps the user-facing file names of a package to the Merkle root of those files, allowing to see which files belong to it:

$ fx host-tool far cat --archive=out/default/obj/third_party/sbase/sed/meta.far --file=meta/contents
bin/sed=6a07c6a584dadc9700ad6904ad920704592f706b4b8f55ec6fc736391588a1ef
lib/ld.so.1=2debd7e1b8542e3a9004794a4417a55d27c928030277364e597cc3e6f80f5407
lib/libasync-default.so=55482d52d72b63a0f51d20991ea49fa939b2559d4a7002606bc9e50e42af64e4
lib/libbackend_fuchsia_globals.so=8da42bd2ad7fc246a6ecba016753fa4e9b0b7f6c685e22da4de997888fd18b06
lib/libc++.so.2=e4145c4b3fd40b6d5371a5f21b46fb965d7c82d4b8bb438c9e94254ea58d8cba
lib/libc++abi.so.1=1b5b77954855602b64b877c37defc450d8741d4bb95bd60427cbf234561090e2
lib/libfdio.so=1e47faf9e335206ca73a253dece42a5d537912fc6abceadd0a06ea1462aa8e33
lib/libunwind.so.1=dffab54d807a4352e088529a7a2112b651042bf511e7df7d2adca40aaec77c86

Connecting host and target

The Fuchsia source contains a simple HTTP server that serves static files. The build generates and serves a TUF file tree.

The update agent on the target does not initially know where to look for updates. To connect the agent on the target to the HTTP server running on the development host, it must be told the IP address of the development host. The host HTTP server is started and the update agent is configured by calling fx serve -v. fx serve will run the update server and is often what people use. -v is recommended because the command will print more output, which may assist with debugging. If the host connects successfully to the target you will see the message Ready to push packages! in the shell on your host.

The update agent on the target will remain configured until it is repaved or persistent data is lost. The host will attempt to reconfigure the update agent when the target is rebooted.

Triggering package updates

Packages in Fuchsia are not "installed", they are cached on an as needed basis. There are two collections of packages on a Fuchsia system:

  • base The base package set is a group of software critical to proper system function that must remain congruent. The Fuchsia build system assigns packages to base when they are provided to fx set using the --with-base flag. This set of software can only be updated by performing a whole system update, typically referred to as OTA, described below. This is updated using fx ota.

  • ephemeral software Packages included in the cache or universe package set are ephemeral software, with updates delivered on demand. The Fuchsia build system assigns packages to universe when they are provided to fx set using the --with flag. Ephemeral software updates to the latest available version whenever the package URL is resolved.

Triggering an OTA

Sometimes there may be many packages changed or the kernel may change or there may be changes in the system package. To get kernel changes or changes in the system package an OTA or pave is required as base packages are immutable for the runtime of a system. An OTA update will usually be faster than paving or flashing the device.

The command fx ota asks the target device to perform an update from any of the update sources available to it. To OTA update a build made on the dev host to a target on the same LAN, first build the system you want. If fx serve [-v] isn't already running, start it so the target can use the development host as an update source. The -v option will show more information about the files the target is requesting from the host. If the -v flag was used there should be a flurry of output as the target retrieves all the new files. Following completion of the OTA the device will reboot.

Just the commands

  • fx serve -v (to run the update server for both build-push and ota)
  • fx test <component-url> (to build and run tests)
  • fx ota (to trigger a full system update and reboot)

Issues and considerations

You can fill up your disk

Every update pushed is stored in the content-addressed file system, blobfs. Following a reboot the updated packages may not be available because the index that locates them in blobfs is only held in RAM. The system currently does not garbage collect inaccessible or no-longer-used packages (having garbage to collect is a recent innovation!), but will eventually.

The command fx gc will reboot the target device and then evict all old ephemeral software from the device, freeing up space.

Restarting without rebooting

If the package being updated hosts a service managed by Fuchsia that service may need to be restarted. Rebooting is undesirable both because it is slow and because the package will revert to the version paved on the device. Typically a user can terminate one or more running components on the system, either by asking the component to terminate gracefully, or by forcefully stopping the component using ffx component stop <component-moniker>. Upon reconnection to the component services, or by invocation via ffx component start or fx test, new versions available in the package server will be cached before launch.

Packaging code outside the Fuchsia tree

Packaging and pushing code that lives outside the Fuchsia tree is possible, but will require more work. The Fuchsia package format is quite simple. It consists of a metadata file describing the package contents, which is described in more detail in the Fuchsia package documentation. The metadata file is added to a TUF file tree and each of the contents are named after their Merkle root hash and put in a directory at the root of the TUF file tree called 'blobs'.