ffx emu
命令用于在宿主机上启动和管理 Fuchsia 模拟器。
概念
Fuchsia 模拟器(也称为 FEMU)提供了一种机制,用于在不使用实体硬件设备的情况下开发和测试 Fuchsia 平台和产品。Fuchsia 模拟器基于 QEMU(一种开源机器模拟器和虚拟化程序)构建。
QEMU 和 AEMU
Fuchsia 模拟器中有两个模拟引擎:第一个是 Android 模拟器 (AEMU) 的扩展版本,第二个是 QEMU(版本 6.2.0)的 build。AEMU 引擎主要用于涉及图形的任务,因为 AEMU 支持 Vulkan 图形库。不过,最新的 AEMU(基于 QEMU 2.12 的分支构建)缺少多个版本的上游修复、功能和性能增强。因此,对于不需要图形的工作流,最好在无头模式下使用 QEMU 引擎。
启动模拟器需要您指定以下信息:
- 用作后端的引擎。
- 要模拟的虚拟设备类型。
- 要在虚拟设备上运行的产品。
默认情况下,ffx emu
命令会选择 AEMU 引擎,因为大多数任务都需要一定程度的图形支持。目前,所有现有产品包都只有一个虚拟设备类型。
产品套装
这两个 FEMU 引擎都使用一组称为产品包的 Fuchsia 映像和元数据。使用 Fuchsia SDK 时,您需要提前检索产品软件包(使用 ffx product download
命令)。产品包包含适用于不同 CPU 架构的系统映像。每个系统映像都包含元数据(例如在不同虚拟设备上运行的硬件规格)和关联的系统软件包。
网络
模拟器与其主机之间有三种联网模式:
这些模式可通过 --net
标志进行选择,选项分别为 tap
、user
和 none
。还有 --net auto
模式,如果未指定任何标志,则默认使用此模式。在 auto
模式下,模拟器会检查主机上是否有 Tun/Tap 接口,如果有,模拟器会选择 --net tap
模式。不过,如果没有 Tun/Tap 接口或该接口已处于忙碌状态(例如,已附加到另一个模拟器进程),模拟器会选择 --net user
模式。
列出所有可用的产品套装
如需查看在线存储空间(默认情况下为 gs://fuchsia
中的 Google Cloud Storage)中所有可用的产品包的列表,请运行以下命令:
ffx --machine json-pretty product list --version <SDK_VERSION>
此命令会显示类似于以下内容的输出:
$ 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"
}
]
下载商品套装
如需从在线存储空间(默认情况下为 gs://fuchsia
的 Google Cloud Storage)下载产品包,请运行以下命令:
ffx product download <TRANSFER_MANIFEST_URL> <LOCAL_PATH>
以下示例命令会下载 minimal.x64
产品 bundle:
$ ffx product download gs://fuchsia-public-artifacts-release/builds/8770722574108649857/transfer.json ~/local_pb --force
此命令会显示类似于以下内容的输出:
$ 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%)
此命令可能需要几分钟时间才能下载图片和商品元数据。
启动 Fuchsia 模拟器
如需启动 Fuchsia 模拟器,请运行以下命令:
ffx emu start PRODUCT_BUNDLE [--name NAME]
将 PRODUCT_BUNDLE
替换为主机上下载的产品软件包的路径。
以下示例命令使用 ~/local_pb
目录启动 Fuchsia 模拟器:
$ ffx emu start ~/local_pb
此命令会显示类似于以下内容的输出:
$ 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.
启动模拟器后,该命令会退出,而模拟器会在后台继续运行。然后,系统会打开一个单独的窗口,开始显示输入产品软件包中包含的 Fuchsia 系统的图形界面。
默认情况下,Fuchsia 模拟器以名称 fuchsia-emulator
启动。不过,如需启动具有不同名称的 Fuchsia 模拟器(例如,当您需要启动多个实例时),可以使用 --name
标志,例如:
$ ffx emu start ~/local_pb --name my-fuchsia-example-01
如需查看所有正在运行的模拟器实例的列表,您可以使用 ffx emu list
命令。
启动不支持图形的 Fuchsia 模拟器
默认情况下,ffx emu start
命令会启动 Fuchsia 模拟器并打开一个新窗口来显示模拟器的图形界面。不过,在某些情况下,您可能希望在不需要视觉效果的任务(例如自动化测试)中停用模拟器实例的图形支持。
如需启动不含图形的 Fuchsia 模拟器,请运行以下命令:
ffx emu start PRODUCT_BUNDLE --headless [--engine qemu]
将 PRODUCT_BUNDLE
替换为主机上下载的产品软件包的路径。
以下示例命令使用 ~/local_pb
目录启动 Fuchsia 模拟器:
$ ffx emu start ~/local_pb --headless --engine qemu
此命令会显示类似于以下内容的输出:
$ 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.
此命令会像往常一样在后台启动 Fuchsia 模拟器实例,但其图形界面不会显示在宿主机器的屏幕上。
列出所有正在运行的模拟器实例
如需查看宿主机上正在运行的 Fuchsia 模拟器实例的列表,请运行以下命令:
ffx emu list
此命令会显示类似于以下内容的输出:
$ ffx emu list
[Inactive] my-fuchsia-example-01
[Active] fuchsia-emulator
在输出中,每个模拟器实例旁边都会显示其状态。如果状态为 [Active]
,则表示实例正在运行,并且可以响应其他 Fuchsia 工具。不过,如果状态为 [Inactive]
,则可能表示实例已停止,但保留了其工作目录,或者实例仍在运行,但没有响应(例如,由于网络故障)。以停用网络的方式启动的实例永远不会显示为 [Active]
,即使该实例正在运行且健康状况良好也是如此。
停止模拟器实例
如需停止正在运行的 Fuchsia 模拟器实例,请运行以下命令:
ffx emu stop INSTANCE_NAME
将 INSTANCE_NAME
替换为正在运行的 Fuchsia 模拟器实例的名称。
以下示例命令会停止 my-fuchsia-example-01
实例:
$ ffx emu stop my-fuchsia-example-01
此命令会显示类似于以下内容的输出:
$ ffx emu stop my-fuchsia-example-01
Stopping emulator 'my-fuchsia-example-01'...
Terminating running instance 2752927
该命令会终止相应模拟器的运行进程,并移除主机上为该实例创建的临时工作目录。(如果您想保留此工作目录,请参阅停止正在运行的模拟器实例,同时保留其工作目录。
如果只有一个正在运行的模拟器实例,您可以省略 INSTANCE_NAME
字段来停止该实例,例如:
$ ffx emu stop
Stopping emulator 'fuchsia-emulator'...
Terminating running instance 2752927
如果您想一次性停止所有正在运行的实例,可以使用 --all
标志,例如:
$ ffx emu stop --all
Stopping emulator 'my-fuchsia-example-01'...
Stopping emulator 'fuchsia-emulator'...
Terminating running instance 2749406
停止模拟器实例,同时保留其工作目录
停止正在运行的模拟器实例时,默认情况下,该实例的工作目录会从宿主机中删除。不过,在某些情况下,您可能希望保留实例的工作目录,以便继续检查该目录的内容以进行调试。
如需停止正在运行的 Fuchsia 模拟器实例,但不删除其工作目录,请运行以下命令:
ffx emu stop INSTANCE_NAME --persist
将 INSTANCE_NAME
替换为正在运行的 Fuchsia 模拟器实例的名称。
以下示例命令会停止 my-fuchsia-example-01
实例:
$ ffx emu stop my-fuchsia-example-01 --persist
此命令会显示类似于以下内容的输出:
$ ffx emu stop my-fuchsia-example-01 --persist
Stopping emulator 'my-fuchsia-example-01'...
Terminating running instance 2752927
运行此命令后,实例的工作目录仍保留在主机上,并且已停止的实例会继续显示在模拟器实例列表 (ffx emu list
) 中,状态为 [Inactive]
。
如需重启此已停止的模拟器实例,请运行带有 --reuse
标志的 ffx emu start
命令,例如:
$ ffx emu start my-fuchsia-example-01 --reuse
如果您不再需要工作目录,可以再次运行 ffx emu stop
命令来删除该目录,例如:
$ ffx emu stop my-fuchsia-example-01
Stopping emulator 'my-fuchsia-example-01'...
显示模拟器配置
如需在宿主机上查看 Fuchsia 模拟器配置,请运行以下命令:
ffx emu show
此命令会显示类似于以下内容的输出:
$ ffx emu show
EmulatorConfiguration {
device: DeviceConfig {
audio: AudioDevice {
model: Hda,
},
cpu: VirtualCpu {
architecture: X64,
count: 0,
},
...
在 Tun/Tap 网络模式下启动 Fuchsia 模拟器
在 --net tap
模式下,宿主机器的内核会设置虚拟网络隧道设备(请参阅 Tun/Tap),并将该设备与宿主机器的物理网络桥接。此设置可将通过虚拟设备的流量路由到物理网络。然后,模拟器将其实例的虚拟网络接口附加到主机上的虚拟隧道设备。这与模拟器实例直接连接到主机物理网络的效果相同。因此,在所有联网选项中,--net tap
模式可提供最快的性能。
不过,此模式的设置需要在宿主机上拥有超级用户访问权限 (sudo
),并且仅在 Linux 宿主机上受支持。
如需在 Tun/Tap 网络模式下启动模拟器,请运行以下命令:
ffx emu start PRODUCT_BUNDLE --net tap
将 PRODUCT_BUNDLE
替换为主机上下载的产品软件包的路径。
以下示例命令使用 ~/local_pb
目录作为商品套装:
$ ffx emu start ~/local_pb --net tap
此命令会显示类似于以下内容的输出:
$ 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.
在 Tun/Tap 网络模式下,您可以选择指定“upscript”来设置网络接口和防火墙例外情况等。此脚本会作为每个以 Tun/Tap 网络模式运行的模拟器实例的启动过程的一部分来执行。
如需向 ffx
配置添加网络启动脚本,请在启动模拟器之前运行以下命令:
ffx config set emu.upscript <PATH_TO_UPSCRIPT>
将 PATH_TO_UPSCRIPT
替换为 upscript 文件的路径。
以下示例命令会将 my-upscript.sh
添加到 ffx
配置中:
$ ffx config set emu.upscript /home/alice/my-fuchsia-project/my-upscript.sh
在用户联网模式下启动 Fuchsia 模拟器
如果您在宿主机上没有超级用户访问权限 (sudo
),则可以使用 --net user
模式配置网络。在此模式下,模拟器充当防火墙(通过 SLiRP)。从模拟器实例传出的流量不受限制。不过,向模拟器实例发送流量需要进行以下设置:
- 虚拟设备的规范(属于产品包,例如
~/local_pb
)预先定义了设备所需的端口映射。 - 在启动模拟器实例期间,这些端口可以映射到主机上未使用的端口。
例如,如需设置从主机到模拟器实例的 SSH 连接,首先产品软件包的虚拟设备规范必须允许设备使用实例的 SSH 端口(通常为 22)。接下来,当您启动 Fuchsia 模拟器时,可以使用 ffx emu start
命令将实例的 SSH 端口映射到主机上未使用的端口(例如 8022)。然后,当模拟器实例开始运行后,您可以通过宿主机器的端口 8022 建立与该实例的 SSH 会话。
在虚拟设备规范中,ports
字段提供服务名称及其端口号的列表,例如:
ports = {
ssh = 22
mdns = 5353
debug = 2345
}
上述示例表明,模拟器必须在启动期间将模拟器实例的三个指定端口(即 22、5353 和 2345)映射到主机上未使用的端口。使用此规范,模拟器将分别使用名称 ssh
、mdns
和 debug
来表示这三个端口。对于每个此类端口,您都可以使用 --port-map
标志将名称映射到主机上未使用的端口,例如:
$ ffx emu start ~/local_pb --net user --port-map ssh:8022 --port-map debug:12345
虚拟设备规范中未使用 --port-map
标志明确映射的任何端口在启动期间都会任意分配给宿主机上未使用的端口。您可以在 ffx emu show
的输出中看到最终的端口映射。
如需在用户联网模式下启动模拟器,请运行以下命令:
ffx emu start PRODUCT_BUNDLE --net user [--port-map PORT_NAME:PORT_NUMBER]
替换以下内容:
PRODUCT_BUNDLE
- 主机上下载的产品软件包的路径。PORT_NAME
-(可选)模拟器实例上服务的名称。PORT_NUMBER
-(可选)您要将PORT_NAME
服务映射到的宿主机上的端口号。
以下示例命令以用户网络模式启动模拟器:
$ ffx emu start ~/local_pb --net user
如果不指定 --port-map
标志,模拟器会将模拟器实例上的服务映射到宿主机上的任何未使用的端口。
以下示例命令展示了在用户联网模式下启动模拟器时如何指定端口映射:
$ ffx emu start ~/local_pb --net user --port-map ssh:8022 --port-map debug:12345
如需查看用户联网模式下模拟器实例的端口映射方式,请运行 ffx emu show
并检查输出的 port_map
字段,例如:
$ 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,
),
},
},
},
[...]
}
启动已停用网络的 Fuchsia 模拟器
如果指定了 --net none
,模拟器实例(从实例的角度来看)将不具备任何联网功能,就像虚拟机上未安装网卡一样。与模拟器实例通信的唯一可用机制是通过 QEMU 监控器和模拟的串行端口。
如需在停用网络的情况下启动模拟器,请运行以下命令:
ffx emu start PRODUCT_BUNDLE --net none [--console]
将 PRODUCT_BUNDLE
替换为主机上下载的产品软件包的路径。
此命令会显示类似于以下内容的输出:
$ 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.
当网络被停用时,ffx emu start
命令无法完成实例的“健康检查”,这会导致实例的状态为 [Inactive]
,这是预期行为,例如:
$ ffx emu list
[Inactive] fuchsia-emulator
启动 Fuchsia 模拟器并使用控制台进行调试
Fuchsia 模拟器提供以下内置控制台,使开发者能够与模拟器实例互动:
这两个控制台都适用于 QEMU 和 AEMU 引擎。
QEMU 监控器
借助 QEMU 监控器,您可以直接向模拟器进程发出命令。借助其中一些命令,您可以修改模拟设备、查询虚拟硬件状态,以及使用虚拟硬件信号终止模拟器进程。(如需详细了解可用命令,请参阅 QEMU 监控器页面。)
如需启动附加到 QEMU 监控器的模拟器实例,请运行以下命令:
ffx emu start PRODUCT_BUNDLE --monitor
将 PRODUCT_BUNDLE
替换为主机上下载的产品软件包的路径。
以下示例命令使用 ~/local_pb
产品套装:
$ ffx emu start ~/local_pb --monitor
此命令会显示类似于以下内容的输出:
$ ffx emu start ~/local_pb --monitor
QEMU 2.12.0 monitor - type 'help' for more information
(qemu)
运行附加了 QEMU 监控器的模拟器实例时,该命令不会立即退出到终端。相反,该命令会将您置于 QEMU 监控器提示符下。
如需退出 QEMU 监控器提示符,您可以发出 quit
命令,该命令还会终止模拟器实例,例如:
$ 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 的模拟串行端口
如果模拟器实例在连接到模拟串行端口时启动,Fuchsia 平台会将该串行端口视为终端。在启动过程中,此终端会通过端口传输内核日志,并在系统启动后显示 Fuchsia 命令行提示符。
如需启动附加到模拟串行端口的模拟器实例,请运行以下命令:
ffx emu start PRODUCT_BUNDLE --console
将 PRODUCT_BUNDLE
替换为主机上下载的产品软件包的路径。
以下示例命令使用 ~/local_pb
产品套装:
$ ffx emu start ~/local_pb --console
此命令会显示类似于以下内容的输出:
$ 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
$
启动模拟器实例后,此命令会将您置于 Fuchsia 命令行提示符下,您可以在其中直接向实例发出各种设备端命令行。
如需退出串行端口控制台,您可以发出 power off
命令,该命令还会终止模拟器实例,例如:
$ power off
[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!
$
启动支持 UEFI 和 GPT 磁盘映像的 Fuchsia 模拟器
Fuchsia 模拟器通过从扁平磁盘映像启动启用 UEFI 的实例,支持对实体设备进行近似模拟。此映像包含 GPT 分区表和常规 Fuchsia ABR(系统分区 A、B 加上 Recovery 分区)分区方案。系统分区支持加密的 ZBI,并且可以通过 fx ota
进行 OTA,以实现系统更新流程的端到端验证。请注意,只有在 Fuchsia 源代码检出中工作时才支持此功能。
如需在此模式下启动模拟器,必须提供 --uefi
标志,以及 ZBI 加密的密钥和密钥元数据。对于测试,Fuchsia 源代码树包含合适的密钥。假设当前目录是 Fuchsia 源代码检出的根目录,则可以按如下方式启动模拟器:
$ ffx emu start --uefi \
--vbmeta-key third_party/android/platform/external/avb/test/data/testkey_atx_psk.pem \
--vbmeta-key-metadata third_party/android/platform/external/avb/test/data/atx_metadata.bin
[emulator] defaulting to qemu engine to support uefi.
Use `--engine` to explicitly set the engine type if needed.
Logging to "/path/to/home/dir/.local/share/Fuchsia/ffx/emu/instances/fuchsia-5254-475e-82ef/emulator.log"
Waiting for Fuchsia to start (up to 60 seconds).....
Emulator is ready.
$
将密钥和元数据设置为配置选项
为了获得更便捷的工作流程,您可以避免每次都在命令行中传递实参 --vbmeta-key
和 --vbmeta-key-metadata
。如果需要,可以通过 ffx config
设置这些参数,例如:
$ ffx config set emu.vbmeta.key $(fx get-src-dir)/third_party/android/platform/external/avb/test/data/testkey_atx_psk.pem
$ ffx config set emu.vbmeta.metadata $(fx get-src-dir)/third_party/android/platform/external/avb/test/data/atx_metadata.bin