启动 Fuchsia 模拟器

ffx emu 命令会在主机上启动和管理 Fuchsia 模拟器。

概念

Fuchsia 模拟器(也称为 FEMU)提供了一种机制,用于在不使用实体硬件设备的情况下开发和测试 Fuchsia 平台及产品。Fuchsia 模拟器基于开源机器模拟器和虚拟化器 QEMU 构建而成。

QEMU 和 AEMU

Fuchsia 模拟器中有两个模拟引擎:第一个是 Android 模拟器的扩展 (AEMU),第二个是 QEMU 的 build(6.2.0 版)。AEMU 引擎主要用于涉及图形的任务,因为 AEMU 支持 Vulkan 图形库。但是,最新的 AEMU(基于 QEMU 2.12 的分支构建)缺少多个版本的上游修复、功能和性能增强功能。因此,对于不需要图形的工作流,建议在无头模式下使用 QEMU 引擎。

启动模拟器需要指定以下信息:

  • 用作后端的引擎。
  • 要模拟的虚拟设备类型。
  • 要在虚拟设备上运行的产品。

默认情况下,ffx emu 命令会选择 AEMU 引擎,因为预计大多数任务都需要一定程度的图形支持。目前,所有现有的产品包都只有一种虚拟设备类型。

商品套装

两个 FEMU 引擎都会使用一组 Fuchsia 映像和元数据(称为“商品套装”)。使用 Fuchsia SDK 时,您需要提前(使用 ffx product download 命令)检索商品套装。产品软件包包含适用于不同 CPU 架构的系统映像。每个系统映像都包含元数据(例如在不同虚拟设备上运行的硬件规格)和关联的系统软件包。

网络

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

这两种模式分别使用 --net 标志和 tapusernone 选项进行选择。此外,还有 --net auto 模式,如果未指定任何标志,则默认为默认模式。在 auto 模式下,模拟器会检查主机上是否有 Tun/Tap 接口,如果有,模拟器会选择 --net tap 模式。不过,如果没有,或者 Tun/Tap 界面已处于忙碌状态(例如,它已连接到另一个模拟器进程),则模拟器会选择 --net user 模式。

列出所有可用的商品套装

如需查看在线存储空间(默认情况下为 Google Cloud Storage,位于 gs://fuchsia)中的所有可用商品捆绑包列表,请运行以下命令:

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 软件包:

$ 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 系统的图形界面。

默认情况下,Fucsia 模拟器会以名称 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 模式下,主机的内核会设置一个虚拟网络隧道设备(请参阅隧道/点按),并将该设备与宿主机的物理网络桥接。此设置使流经虚拟设备的流量能够路由到物理网络。然后,模拟器会将其实例的虚拟网络接口连接到宿主机上的虚拟隧道设备。这与直接连接到宿主机物理网络的模拟器实例效果相同。因此,--net tap 模式在所有网络选项中可提供最快的性能。但是,此模式的设置需要主机上的超级用户访问权限 (sudo),并且仅在 Linux 主机上受支持(不过也存在一些开源扩展程序,也支持在 macOS 主机上启用此设置)。

如需在 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 网络模式的每个模拟器实例时,都会执行此脚本。

如需将网络 Upscript 添加到 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),或者不想调整 macOS 设置以使用开启/点按模式(请参阅 --net tap 模式),则可以使用 --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:~$