The ffx emu
commands launch and manage the Fuchsia emulator on
your host machine.
Concepts
The Fuchsia emulator (also known as FEMU) provides a mechanism for developing and testing the Fuchsia platform and products without using physical hardware devices. The Fuchsia emulator is built on QEMU, an open-source machine emulator and virtualizer.
QEMU and AEMU
There are two emulation engines available in the Fuchsia emulator: the first is an extension of the Android Emulator (AEMU) and the second is a build of QEMU (version 6.2.0). The AEMU engine is primarily used for tasks that involve graphics because AEMU supports the Vulkan graphics libraries. However, the most recent AEMU (which is built off of a fork of QEMU 2.12) lacks several versions of upstream fixes, features, and performance enhancements. For this reason, using the QEMU engine in headless mode is preferred for workflows that do not require graphics.
Starting an emulator requires you to specify the following information:
- An engine to use as the backend.
- A type of virtual device to emulate.
- A product to run on the virtual device.
By default, the ffx emu
command selects the AEMU engine, as it's expected that
most tasks will require some level of graphics support. At the moment, all
existing product bundles only have a single virtual device type.
Product bundles
Both FEMU engines use a set of Fuchsia images and metadata known as a product
bundle. With the Fuchsia SDK, you need to retrieve product bundles (using the
ffx product download
command) ahead of time.
A product bundle includes system images for different CPU architectures. And
each system image includes metadata (such as hardware specifications
for running on different virtual devices) and associated system packages.
Networking
Three networking modes are available between the emulator and its host machine:
These modes are selected using the --net
flag with the options of tap
, user
,
and none
, respectively. There is also the --net auto
mode, which is the
default if no flag is specified. In the auto
mode, the emulator checks to see
if a Tun/Tap interface is available on the host machine,
and if there is, the emulator selects the --net tap
mode. However, if there is
not or the Tun/Tap interface is already busy (for instance, it’s attached to
another emulator process), the emulator then selects the --net user
mode.
List all available product bundles
To view the list of all available product bundles from an online storage (by
default, Google Cloud Storage at gs://fuchsia
), run the following command:
ffx --machine json-pretty product list --version <SDK_VERSION>
This command prints output similar to the following:
$ ffx --machine json-pretty product list --version 15.20230906.1.1
Progress for "Getting product descriptions"
development/15.20230906.1.1/product_bundles.json
1141 of 1141 bytes (100.00%)
[
{
"name": "core.vim3",
"product_version": "15.20230906.1.1",
"transfer_manifest_url": "gs://fuchsia-public-artifacts-release/builds/8770722574108649889/transfer.json"
},
{
"name": "core.x64",
"product_version": "15.20230906.1.1",
"transfer_manifest_url": "gs://fuchsia-public-artifacts-release/builds/8770722574108649873/transfer.json"
},
{
"name": "minimal.x64",
"product_version": "15.20230906.1.1",
"transfer_manifest_url": "gs://fuchsia-public-artifacts-release/builds/8770722574108649857/transfer.json"
},
{
"name": "terminal.qemu-arm64",
"product_version": "15.20230906.1.1",
"transfer_manifest_url": "gs://fuchsia-public-artifacts-release/builds/8770722574108649841/transfer.json"
},
{
"name": "terminal.x64",
"product_version": "15.20230906.1.1",
"transfer_manifest_url": "gs://fuchsia-public-artifacts-release/builds/8770722574108649809/transfer.json"
}
]
Download a product bundle
To download a product bundle from an online storage (by default, Google Cloud
Storage at gs://fuchsia
), run the following command:
ffx product download <TRANSFER_MANIFEST_URL> <LOCAL_PATH>
The example command below downloads the minimal.x64
product bundle:
$ ffx product download gs://fuchsia-public-artifacts-release/builds/8770722574108649857/transfer.json ~/local_pb --force
This command prints output similar to the following:
$ ffx product download gs://fuchsia-public-artifacts-release/builds/8770722574108649857/transfer.json ~/local_pb --force
Progress for "Transfer download"
complete
2 of 2 steps (100.00%)
This command may take a few minutes to download the image and product metadata.
Start the Fuchsia emulator
To start the Fuchsia emulator, run the following command:
ffx emu start PRODUCT_BUNDLE [--name NAME]
Replace PRODUCT_BUNDLE
with the path to a product bundle
downloaded on your host machine.
The example command below uses the ~/local_pb
directory to
start the Fuchsia emulator:
$ ffx emu start ~/local_pb
This command prints output similar to the following:
$ ffx emu start ~/local_pb
Logging to "/home/alice/.local/share/Fuchsia/ffx/emu/instances/fuchsia-emulator/emulator.log"
Waiting for Fuchsia to start (up to 60 seconds).............................
Emulator is ready.
Once the emulator is launched, the command exits while the emulator continues to run in the background. Then a separate window opens and starts displaying the graphical interface of the Fuchsia system included in the input product bundle.
By default, the Fuchsia emulator is launched with the name fuchsia-emulator
.
However, to start the Fuchsia emulator with a different name (for instance, when
you need to launch multiple instances), you can use the --name
flag, for
example:.
$ ffx emu start ~/local_pb --name my-fuchsia-example-01
To see the list of all running emulator instances, you can use the
ffx emu list
command.
Start the Fuchsia emulator without graphics support
By default, the ffx emu start
command launches the Fuchsia emulator and opens a
new window to display the emulator’s graphic interface. However, in some cases,
you may prefer disabling the graphics support on your emulator instance for
tasks that require no visuals, such as automated testing.
To start the Fuchsia emulator without graphics, run the following command:
ffx emu start PRODUCT_BUNDLE --headless [--engine qemu]
Replace PRODUCT_BUNDLE
with the path to a product bundle
downloaded on your host machine.
The example command below uses the ~/local_pb
directory to
start the Fuchsia emulator:
$ ffx emu start ~/local_pb --headless --engine qemu
This command prints output similar to the following:
$ ffx emu start ~/local_pb --headless --engine qemu
Logging to "/home/alice/.local/share/Fuchsia/ffx/emu/instances/fuchsia-emulator/emulator.log"
Waiting for Fuchsia to start (up to 60 seconds).............................
Emulator is ready.
This command starts an instance of the Fuchsia emulator in the background as usual, but its graphical interface is not displayed on your host machines’ screen.
List all running emulator instances
To view the list of running Fuchsia emulator instances on the host machine, run the following command:
ffx emu list
This command prints output similar to the following:
$ ffx emu list
[Inactive] my-fuchsia-example-01
[Active] fuchsia-emulator
In the output, next to each emulator instance is its status. If the status is
[Active]
, it means the instance is running and is responsive to other Fuchsia
tools. However if the status is [Inactive]
, this may mean the instance is
stopped while preserving its working directory,
or it is still running but is not responsive (for instance, due to a network
failure). An instance that is started with networking disabled is never shown
as [Active]
, even if it is running and healthy.
Stop an emulator instance
To stop a running instance of the Fuchsia emulator, run the following command:
ffx emu stop INSTANCE_NAME
Replace INSTANCE_NAME
with the name of a running Fuchsia emulator instance.
The example command below stops the my-fuchsia-example-01
instance:
$ ffx emu stop my-fuchsia-example-01
This command prints output similar to the following:
$ ffx emu stop my-fuchsia-example-01
Stopping emulator 'my-fuchsia-example-01'...
Terminating running instance 2752927
The command terminates the running process for that emulator and removes the temporary working directory created for that instance on the host machine. (If you want to preserve this working directory, see Stop a running emulator instance while retaining its working directory.
If there is only one running emulator instance, you can omit the INSTANCE_NAME
field to stop the instance, for example:
$ ffx emu stop
Stopping emulator 'fuchsia-emulator'...
Terminating running instance 2752927
If you want to stop all running instances at once, you can use the --all
flag,
for example:
$ ffx emu stop --all
Stopping emulator 'my-fuchsia-example-01'...
Stopping emulator 'fuchsia-emulator'...
Terminating running instance 2749406
Stop an emulator instance while preserving its working directory
When stopping a running emulator instance, by default the working directory for that instance is deleted from the host machine. However, in some cases, you may want to keep the instance’s working directory so that you can continue examining the directory’s contents for debugging purposes.
To stop a running instance of the Fuchsia emulator without deleting its working directory, run the following command:
ffx emu stop INSTANCE_NAME --persist
Replace INSTANCE_NAME
with the name of a running Fuchsia emulator instance.
The example command below stops the my-fuchsia-example-01
instance:
$ ffx emu stop my-fuchsia-example-01 --persist
This command prints output similar to the following:
$ ffx emu stop my-fuchsia-example-01 --persist
Stopping emulator 'my-fuchsia-example-01'...
Terminating running instance 2752927
After this command is run, the instance's working directory remains on the host
machine, and the stopped instance continues to appear on the emulator instances
list (ffx emu list
) with the [Inactive]
status.
To restart this stopped emulator instance, run the ffx emu start
command
with the --reuse
flag, for example:
$ ffx emu start my-fuchsia-example-01 --reuse
When you no longer need the working directory, you can run the ffx emu stop
command again to delete the directory, for example:
$ ffx emu stop my-fuchsia-example-01
Stopping emulator 'my-fuchsia-example-01'...
Show the emulator configuration
To view the Fuchsia emulator configuration on the host machine, run the following command:
ffx emu show
This command prints output similar to the following:
$ ffx emu show
EmulatorConfiguration {
device: DeviceConfig {
audio: AudioDevice {
model: Hda,
},
cpu: VirtualCpu {
architecture: X64,
count: 0,
},
...
Start the Fuchsia emulator in Tun/Tap networking mode
In the --net tap
mode, the host machine's kernel sets up a virtual networking
tunnel device (see Tun/Tap) and bridges that device with
the host machine's physical network. This setup enables traffic coming through
the virtual device to be routed to the physical network. The emulator then
attaches its instance's virtual network interface to the virtual tunnel
device on the host machine. This has the same effect as the emulator instance
being directly connected to the physical network of the host machine. Therefore,
the --net tap
mode delivers the fastest performance among all networking options.
However, this mode’s setup requires superuser access (sudo
) on the host machine,
and it is only supported on Linux hosts.
To start the emulator in the Tun/Tap networking mode, run the following command:
ffx emu start PRODUCT_BUNDLE --net tap
Replace PRODUCT_BUNDLE
with the path to a product bundle
downloaded on your host machine.
The example command below uses the ~/local_pb
directory as product bundle:
$ ffx emu start ~/local_pb --net tap
This command prints output similar to the following:
$ ffx emu start ~/local_pb --net tap
Logging to "/home/alice/.local/share/Fuchsia/ffx/emu/instances/fuchsia-emulator/emulator.log"
Waiting for Fuchsia to start (up to 60 seconds)......................
Emulator is ready.
With the Tun/Tap networking mode, you have the option to specify an “upscript” to, for instance, set up network interfaces and firewall exceptions. This script is executed as part of the start-up for every emulator instance that runs with the Tun/Tap networking mode.
To add a network upscript to your ffx
configuration, run the following command
before starting the emulator:
ffx config set emu.upscript <PATH_TO_UPSCRIPT>
Replace PATH_TO_UPSCRIPT
with the path of an upscript file.
The example command below adds the my-upscript.sh
to the ffx
configuration:
$ ffx config set emu.upscript /home/alice/my-fuchsia-project/my-upscript.sh
Start the Fuchsia emulator in user networking mode
If you don't have superuser access (sudo
) on the host machine, you can
configure the network using the --net user
mode. In this mode, the emulator acts
as a firewall (through SLiRP). Traffic coming out of an emulator
instance is unrestricted. However, sending traffic to an emulator instance requires
the following setup:
- A virtual device’s specification, which is part of a
product bundle (for instance,
~/local_pb
), pre-defines the mapping of the ports needed for the device. - These ports can be mapped to unused ports on the host machine during the start-up of an emulator instance.
For example, to set up an SSH connection from the host machine to an emulator instance,
first the product bundle's virtual device specification must allow an instance's SSH
port (which is 22 commonly) to be used by the device. Next, when you start the Fuchsia
emulator, you can use the ffx emu start
command to map the instance's SSH port to
an unused port on the host machine, let's say 8022. Then once the emulator instance
starts running, you can establish an SSH session to the instance through the host
machine’s port 8022.
In the virtual device specification, the ports
field provides a list of
service names and their port numbers, for example:
ports = {
ssh = 22
mdns = 5353
debug = 2345
}
The example above indicates that the emulator must map an emulator instance's three
specified ports (that is, 22, 5353, and 2345) to unused ports on the host machine
during start-up. Using this specification, the emulator uses the names ssh
,
mdns
, and debug
for the three ports, respectively. For each of these ports,
you can use the --port-map
flag to map the name to an unused port on the host
machine, for example:
$ ffx emu start ~/local_pb --net user --port-map ssh:8022 --port-map debug:12345
Any ports in the virtual device specification that are not explicitly mapped using
the --port-map
flag get arbitrarily assigned to unused ports on the host
machine during start-up. The final port mapping can be seen in the output of
ffx emu show
.
To start the emulator in user networking mode, run the following command:
ffx emu start PRODUCT_BUNDLE --net user [--port-map PORT_NAME:PORT_NUMBER]
Replace the following:
PRODUCT_BUNDLE
– The path to a product bundle downloaded on your host machine.PORT_NAME
– (Optional) The name of a service on the emulator instance.PORT_NUMBER
– (Optional) The port number on the host machine to which you want to map thePORT_NAME
service.
The example command below starts the emulator in user networking mode:
$ ffx emu start ~/local_pb --net user
Without specifying the --port-map
flags, the emulator maps the services on the
emulator instance to any unused ports on the host machine.
The example command below specifies port maps when starting the emulator in user networking mode:
$ ffx emu start ~/local_pb --net user --port-map ssh:8022 --port-map debug:12345
To see how ports are mapped for an emulator instance in user networking
mode, run ffx emu show
and examine the
output's port_map
field, for example:
$ ffx emu show
EmulatorConfiguration {
[...]
host: HostConfig {
[...]
networking: User,
port_map: {
"ssh": PortMapping {
guest: 22,
host: Some(
8022,
),
},
"mdns": PortMapping {
guest: 5353,
host: Some(
35801,
),
},
"debug": PortMapping {
guest: 2345,
host: Some(
12345,
),
},
},
},
[...]
}
Start the Fuchsia emulator with networking disabled
When --net none
is specified, no networking capabilities are available to the
emulator instance (from the instance's perspective), as if there is no
network card installed on the virtual machine. The only mechanisms available for
communicating with the emulator instance are through the QEMU monitor and the
emulated serial port.
To start the emulator with networking disabled, run the following command:
ffx emu start PRODUCT_BUNDLE --net none [--console]
Replace PRODUCT_BUNDLE
with the path to a product bundle
downloaded on your host machine.
This command prints output similar to the following:
$ ffx emu start ~/local_pb --net none
Logging to "/home/alice/.local/share/Fuchsia/ffx/emu/instances/fuchsia-emulator/emulator.log"
Waiting for Fuchsia to start (up to 60 seconds).............................................................
Emulator did not respond to a health check before timing out.
When networking is disabled, the ffx emu start
command cannot complete the “health check”
of the instance, which results in the status of the instance to be [Inactive]
, which is
expected, for example:
$ ffx emu list
[Inactive] fuchsia-emulator
Start the Fuchsia emulator with a console for debugging
The Fuchsia emulator provides the following built-in consoles that enable developers to interact with emulator instances:
Both consoles work with both the QEMU and AEMU engines.
The QEMU monitor
With the QEMU monitor, you can issue commands directly to the emulator process. Some of these commands allow you to modify emulated devices, query virtual hardware state, and terminate the emulator process using virtual hardware signals. (For more information on available commands, see the QEMU Monitor page.)
To start an emulator instance attached to the QEMU monitor, run the following command:
ffx emu start PRODUCT_BUNDLE --monitor
Replace PRODUCT_BUNDLE
with the path to a product bundle
downloaded on your host machine.
The example command below uses the ~/local_pb
product bundle:
$ ffx emu start ~/local_pb --monitor
This command prints output similar to the following:
$ ffx emu start ~/local_pb --monitor
QEMU 2.12.0 monitor - type 'help' for more information
(qemu)
When running an emulator instance with the QEMU monitor attached, the command does not exit to the terminal immediately. Instead, the command drops you into a QEMU monitor prompt.
To exit the QEMU monitor prompt, you can issue the quit
command, which also terminates
the emulator instance, for example:
$ ffx emu start ~/local_pb --monitor
QEMU 2.12.0 monitor - type 'help' for more information
(qemu) quit
WARNING | Write called without a backing file!
$
Fuchsia's emulated serial port
If an emulator instance is started while attached to the emulated serial port, the Fuchsia platform treats the serial port as a terminal. During the boot process, this terminal streams kernel logs over the port, and once the system boots, it displays a Fuchsia command line prompt.
To start an emulator instance attached to the emulated serial port, run the following command:
ffx emu start PRODUCT_BUNDLE --console
Replace PRODUCT_BUNDLE
with the path to a product bundle
downloaded on your host machine.
The example command below uses the ~/local_pb
product bundle:
$ ffx emu start ~/local_pb --console
This command prints output similar to the following:
alice@alice:~$ ffx emu start ~/local_pb --console
INFO | Android emulator version 31.3.8.0 (build_id 8611574) (CL:N/A)
[... various log entries]
[00021.699] 01095:01158> [component_manager] INFO: Connecting fuchsia.sys2.LifecycleController
$
After starting the emulator instance, this command drops you into a Fuchsia command line prompt where you can issue various on-device command lines directly to the instance.
To exit the serial port console, you can issue the dm poweroff
command, which also terminates
the emulator instance, for example:
$ dm poweroff
[00258.335] 26935:26939> [shutdown-shim]: checking power_manager liveness
[... various log entries]
[00260.447] 03742:03744> [00260.447038][3742][3744][driver_manager.cm] WARNING: [src/devices/bin/driver_manager/v1/suspend_handler.cc(211)] Failed to cause VFS exit ourselves, this is expected during orderly shutdown: FIDL operation failed d
[00260.429] 03341:03344> WARNING | Write called without a backing file!
alice@alice:~$