blob: 307d9e9e3b5d669ae964e74418e6a476045115e4 [file] [log] [blame] [view] [edit]
# Developing with Fuchsia packages
Almost everything that exists on a Fuchsia system is a [Fuchsia package][pkg-struct].
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][pkg-doc] a package and push it to a
Fuchsia device which 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 which 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
<!-- TODO(jmatt): improve to talk about wider variety of build options -->
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][pkg-doc] for this. Some build rule types are actually
extensions of the package rule type, for example [`flutter_app`][flutter-gni]
extends the package type.
Once an appropriate build rule is available the target package can be
re-generated by running `fx build`.
## Connecting host and target
The Fuchsia source contains a simple HTTP server which serves static files. The
build generates a [TUF][TUF-home] file tree which is served.
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` or `fx serve-updates -v`. `fx serve` will run both the bootserver
and the update server and is often what people use. `fx serve-updates` runs just
the update server. In both cases, `-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. 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** The ephemeral software is provided to the system in
one of two ways, either as a member of the "cache" build group, or entirely
ephemerally. Typically users configure software in the Fuchsia build as
ephemerally available by adding that package to the `fx set` line such as
`--with //examples/rolldice`. Ephemeral software, whether in "cache" or
entirely ephemeral, is always updated whenever a component is launched with a
package URL. For example, if a user executes `fx run
fuchsia-pkg://fuchsia.com/rolldice#meta/rolldice.cmx`, the rolldice latest
rolldice package will be cached before execution.
## 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][paver] 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 serve-updates -v` (to run only the update server, not the bootserver)
* `fx run <component-url>` (each time a change is made you want to run)
* `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 forceufully stopping the
component using `fx shell killall <component-name>`. Upon reconnection to the
component services, or by invocation via `fx run` 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][pkg-struct] 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'.
[pkg-struct]: /src/sys/pkg/bin/pm/README.md#structure-of-a-fuchsia-package "Package structure"
[TUF-home]: https://theupdateframework.github.io "TUF Homepage"
[pkg-doc]: /docs/concepts/build_system/fuchsia_build_system_overview.md "Build overview"
[flutter-gni]: https://fuchsia.googlesource.com/topaz/+/HEAD/runtime/flutter_runner/flutter_app.gni "Flutter GN build template"
[paver]: /docs/development/hardware/paving.md "Fuchsia paver"
[OTA]: #triggering-an-ota "Triggering an OTA"