启动 Fuchsia 模拟器

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 时,您需要提前检索商品 bundle(使用 ffx product download 命令)。一个产品软件包中包括适用于不同 CPU 架构的系统映像。每个系统映像都包含元数据(例如适用于在不同虚拟设备上运行的硬件规格)和关联的系统软件包。

网络

模拟器与其宿主机之间有三种网络模式可用:

这些模式的选择方式是使用 --net 标志,并分别选择 tapusernone 选项。此外,还有 --net auto 模式,如果未指定标志,则默认为该模式。在 auto 模式下,模拟器会检查主机上是否有 Tun/Tap 接口,如果有,模拟器会选择 --net tap 模式。但是,如果没有可用的 Tun/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-emulator 启动 Fuchsia 模拟器。不过,如需使用其他名称启动 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 网络模式,您可以选择指定“上标”,例如设置网络接口和防火墙例外。系统会在使用 Tun/Tap 网络模式运行的每个模拟器实例的启动过程中执行此脚本。

如需向您的 ffx 配置添加网络上标,请在启动模拟器之前运行以下命令:

ffx config set emu.upscript <PATH_TO_UPSCRIPT>

PATH_TO_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)映射到宿主机上未使用的端口。根据此规范,模拟器将三个端口分别使用名称 sshmdnsdebug。对于这些端口中的每一个,您都可以使用 --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

此命令会输出类似于以下内容的输出:

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
$

启动模拟器实例后,此命令会将您转到 Fuchsia 命令行提示符,您可以在其中直接向该实例发出各种设备端命令行。

如需退出串行端口控制台,您可以发出 dm poweroff 命令,该命令也会终止模拟器实例,例如:

$ 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:~$