用于 Linux 测试的 Machina 运行时

本指南介绍了如何使用 Machina 针对 Linux 环境运行和调试 Starnix 测试。

Machina 在 Linux 虚拟机内运行测试,使用目标内核版本提供隔离且标准化的环境。请注意,运行基于 Machina 的 Starnix 测试需要本地提供 Debian guest 映像。Google 员工默认可以使用此类映像,而外部开发者需要自带映像。外部开发者应参阅虚拟化入门指南,详细了解如何构建和提供自己的 Debian 映像。

在本地运行现有的 Machina 测试

主机前提条件

Machina 是一种虚拟化环境,仅限于基于 Intel 的现代主机。对于 Google 员工,支持现代虚拟机的 Cloudtop 可提供理想的环境。旧版已弃用的 Cloudtop 可能需要调整为更现代的图片。确保您的主机与以下检查兼容:

  • 基于 Intel 的

    lscpu | grep "Vendor ID"

    您应该会看到:Vendor ID: GenuineIntel。如果不是,您需要购买一台基于 Intel 的机器。对于 Google 员工,使用支持嵌套虚拟化的 Cloudtop 应该就足够了。

  • 支持虚拟化

    按照启用虚拟机加速中的说明进行操作。

  • 现代高性能 CPU

    if lscpu | grep -qE "Clear CPU buffers"; then echo 'CPU has performance-hindering mitigations.'; else echo 'No performance issues found.'; fi

    您应该会看到:No performance issues found。某些旧版 Intel CPU 可能具有安全漏洞缓解措施,这些措施会严重影响 Machina 性能。

如果您的环境满足 Intel 要求,但不满足其他要求,您可以考虑增加 fx test 超时时间作为一种解决方法。

环境设置

  1. 设置支持虚拟化的产品配置。只要主板是 x64,大多数产品都可以正常运行。以下是一个配置示例:

    fx set fuchsia.x64 --main-pb workbench_eng.x64
  2. 添加 linux_vm_tests 目标:

    fx add-test //src/starnix/tests:linux_vm_tests
  3. 使用标准工作流引导无头模拟器和软件包代码库。如果您不熟悉 FEMU,可以参考设置 FEMU 指南。

运行测试

测试套件与原始系统调用相同,但以 linux_ 为前缀。以下是一些常见的目标包含示例:

  • 运行所有 C++ 系统调用测试套件

    fx test linux_syscalls_cpp_tests
  • 运行所有 Rust 系统调用测试套件

    fx test linux_syscalls_rust_tests
  • 运行单个套件

    fx test linux_fcntl_test
    fx test linux_device_mapper_test
  • 同时在 Starnix 和 Linux 上运行:指定目标的库名,该目标将运行您的环境可能配置为运行的所有变体(Starnix、Machina、Host)。例如:

    fx test mount_test
    fx test fscrypt_test

调试失败的基于 Machina 的系统调用测试

了解日志

系统调用测试可以是 GoogleTest 套件(对于 C++),也可以是 Rust 测试套件(使用 libtest),并且输出通过测试框架进行管道传输。这意味着,在测试失败时,测试输出会显示在 stdout 中。无论结果如何,您都可以使用 fx test 调用中的 --output 实参查看所有测试日志。

与 Machina 运行时相关的日志会输出到系统日志 (ffx log),并且通常与标识标记相关联。目前,所有系统调用测试都使用一个运行时(通过 linux_guest 标记指定)。不过,与内核端虚拟化相关的系统日志(例如 Zircon Hypervisor 发出的日志)除外。这些日志不会包含与访客相关的特定标识符。

下文记录了与典型流程相关的系统日志。

  1. 初始 guest 引导加载程序

    在以下日志中,您会看到 starnix_test_runner 组件请求带有 linux_guest 标记的 Machina Guest。starnix_test_runner 会记录有关其互动请求的两行日志。第三行来自 interactive-debian-guest 组件,可以将其视为正在运行的 Machina 访客组件。它会收到请求并开始启动。您可以看到,整个系统中的所有日志都带有标识符 (linux_guest)。如日志所示,Machina 访客是延迟启动的。此初始启动通常需要 60 秒左右才能准备好进行互动,但仅在首次运行时需要。

    [00043.071313][starnix_test_runner][linux_guest] INFO: Pushing data to guest (destination: /data/tests/deps/clone_exec_helper)
    [00043.071321][starnix_test_runner][linux_guest] INFO: Interaction requested, lazily starting the guest instance.
    [00046.686157][interactive-debian-guest][linux_guest] INFO: [interactive_debian_guest_impl.cc(110)] Start requested for an interactive Debian guest.
    
  2. 推送测试依赖项和二进制文件

    来宾启动后,系统会开始将初步数据推送到来宾。以下是系统调用测试所需的依赖项(从软件包的 /pkg/data 推送到 guest 上的 /data/),后面是测试二进制文件本身:

    [00439.934416][starnix_test_runner.cm][linux_guest,starnix_test_runner] INFO: Pushing data to guest (destination: /data/tests/deps/simple_ext4.img)
    [00441.040568][starnix_test_runner.cm][linux_guest,starnix_test_runner] INFO: Successfully pushed data to guest (destination: /data/tests/deps/simple_ext4.img)
    [00444.834216][starnix_test_runner.cm][linux_guest,starnix_test_runner] INFO: Pushing data to guest (destination: /starnix_linux_fuse_test_fuse_test_bin)
    [00448.652779][starnix_test_runner.cm][linux_guest,starnix_test_runner] INFO: Successfully pushed data to guest (destination: /starnix_linux_fuse_test_fuse_test_bin)
    
  3. 测试作业和处理

    完成环境设置步骤后,您应该会看到已发出执行命令。对于 C++ (gTest) 套件,此命令会在 guest 上执行测试二进制文件,并将结果文件复制回主机以进行处理:

    [00448.653126][starnix_test_runner.cm][linux_guest,starnix_test_runner] INFO: Executing command on guest: /starnix_linux_fuse_test_fuse_test_bin --gtest_output=json:/test_result-ccde95ca-acb3-4b84-af4d-f371b9582d20.json)
    [00448.848658][starnix_test_runner.cm][linux_guest,starnix_test_runner] INFO: Command '/starnix_linux_fuse_test_fuse_test_bin --gtest_output=json:/test_result-ccde95ca-acb3-4b84-af4d-f371b9582d20.json'
    ...terminated with status Status(OK), return code 0
    [00448.849066][starnix_test_runner.cm][linux_guest,starnix_test_runner] INFO: Fetching file from guest (remote_path: /test_result-ccde95ca-acb3-4b84-af4d-f371b9582d20.json)
    

    对于 Rust (libtest) 套件,测试运行程序会在 guest 上单独执行每个测试用例(传递 --exact --nocapture),并通过套接字将 stdout 和 stderr 直接流式传输回测试框架。在这两种情况下,测试输出都会通过管道传输到终端上的标准输出,就像任何其他 fx test 调用一样。

了解运行时

Starnix 测试运行程序负责编排测试,可以看作是 Fuchsia 测试框架和 Machina 运行时之间的粘合剂。与运行时相关的重要注意事项:

C++ 系统调用测试 (syscall_gtest)

  • C++ 系统调用测试通过其 CML 中的 [syscalls_gtest.cml][syscalls-gtest-cml] 中的 test_type: "syscall_gtest" 程序标记来标识。
  • Starnix 测试运行程序在处理套件请求时会查找此标记,并相应地分支逻辑来处理这些测试。核心处理逻辑位于 [syscalls_gtest.rs][syscalls-gtest-rs] 中,主要入口点为 run_syscall_gtests

Rust 系统调用测试 (syscall_libtest)

  • Rust 系统调用测试通过 [syscalls_libtest.shard.cml][syscalls-libtest-shard-cml]test_type: "syscall_libtest" 程序标记在 CML 中进行标识。
  • Starnix 测试运行程序在处理套件请求时会查找此标记,并相应地分支逻辑来处理这些测试。核心处理逻辑位于 [syscalls_libtest.rs][syscalls-libtest-rs] 中,主要入口点为 run_syscall_libtests
  • 使用 [//src/starnix/tests/syscalls/rust/BUILD.gn][rust-syscalls-build-gn][rust_syscall_test.gni][rust-syscall-test-gni] 内的 rust_syscall_test GN 模板定义测试,以生成 Starnix 和 Linux 虚拟机测试组件。

虽然运行时不仅仅包含这些核心点,但将所有内容都记录在文档中会非常困难。希望这些核心系统组件能为您的调查和调试提供可靠的锚点。

高级调试

详细的 Linux 内核日志记录

如果您怀疑 Linux 内核本身出了问题,可以通过设置以下 GN 实参来启用更详细的 Linux 内核日志记录:

redirect_guest_serial_logs = true

这会将 Linux 内核日志输送到标准系统输出,这意味着您可以通过 ffx log 查看客户机内核日志。日志在 vmm 组件下发出,并会标记 (guest klog) 为清晰起见,以明确来源。例如:

[00352.454169][vmm.cm][vmm] INFO: [vmm.cc(491)] (guest klog): [    0.000000] Linux version 6.6.13-amd64 (debian-kernel@lists.debian.org) (gcc-13 (Debian 13.2.0-10) 13.2.0, GNU ld (GNU Binutils for Debian) 2.41.90.20240115) #1 SMP PREEMPT_DYNAMIC Debian 6.6.13-1 (2024-01-20)

在此日志示例中,您会看到 vmm 组件发出 Linux 内核日志行。 vmm 在系统运行时间为 00352.454169 时发出了此日志。(guest klog) 表明 Linux 内核在 [ 0.000000](从内核的角度来看,这是正常运行时间的第 0 秒)发出了相应行。

通过 shell 进入 Machina

您可以访问正在运行的 Linux 虚拟机的相当标准的命令行界面。请注意,测试二进制文件和制品默认情况下将不会出现在映像中,因为它们是由测试运行程序框架动态推送的。如需详细了解如何将测试二进制文件和制品放入 guest 中,请参阅以下部分。以下是获取此 shell 的步骤:

  1. 按照虚拟化入门指南操作,该指南会向您展示如何设置本地 GN 实参以启用虚拟化工具。
  2. 启动模拟器并连接到 shell:

    fx shell
  3. 启动 Debian guest:

    guest launch debian

    这会将您置于 Debian shell 中。

请注意,shell 行为可能会令人困惑:

  • exit不会退出 guest shell。
  • CTRL+C不会终止正在运行的程序,而是会退出 Debian shell 并返回到 Fuchsia。

提示:如果您不小心按 CTRL+C 从 Linux 客户机退出并进入 Fuchsia,可以使用 guest attach debian 返回到 shell。

在本地修改 Debian 映像

在某些情况下,您可能希望更改默认的 Debian 映像(例如,添加二进制文件或调试程序)。由于没有简单的方法来推送伪影,您必须直接修改图片。

  1. 装载映像:在 Linux 主机上,安装工具并装载映像:

    sudo apt-get install libguestfs-tools
    sudo mkdir /mnt/machina_guest_img
    sudo guestmount -a prebuilt/virtualization/packages/debian_guest/images/x64/rootfs.qcow2 -m /dev/vda /mnt/machina_guest_img/
    
  2. 与映像互动:您现在可以将文件复制到已挂载的目录。例如,如需复制装载测试二进制文件和依赖项,请执行以下操作:

    sudo cp ./out/core.x64-balanced/linux_x64/linux_mount_test_bin /mnt/machina_guest_img/home/
    sudo mkdir -p /mnt/machina_guest_img/home/data/tests/deps/
    sudo cp src/starnix/tests/syscalls/cpp/data/* /mnt/machina_guest_img/home/data/tests/deps/
    
  3. 卸载映像

    sudo guestunmount /mnt/machina_guest_img

卸载后,映像将包含您所做的更改。然后,您可以进入环境(如上文所述),并根据需要执行二进制文件。

更新 Debian 映像

目前,Debian 映像没有自动滚动更新功能。您需要提交 bug 并将其分配给有权上传新制品的某人。然后,具有相应权限的用户可以根据 Debian guest README 修改映像并上传新的制品。