Emulator Engine Configuration Types

This crate contains a suite of data structures we've designed to carry all of the parameters needed to define a virtual device, the guest OS running on the device, and host-specific configuration for multiple emulation backends. To ensure a consistent approach to defining these data types, our philosophy is documented here. Please be sure you understand the roles of each type before making changes to the structures herein.

The Types

An emulation engine requires four distinct types to define its operation:

  • GuestConfig: This defines the operating system that will be running within the emulated environment. The guest OS is primarily defined by the disk images which are loaded to the virtual disks. This data structure includes information such as the virtual disk files, kernel files and arguments, etc.

  • VirtualDevice: This defines the virtual hardware the emulation backend will expose to the guest OS. The virtual hardware includes information about the system memory, screen size, peripheral devices, and CPU type and count, etc.

  • HostConfig: This provides information to the emulator about the host it will be running on which impacts how it initializes and performs the emulation. This can include host-side interfaces to attach to the virtual hardware, disk locations for logs or companion programs, terminal environment variables, etc.

  • RuntimeConfig: This holds parameters that are specific to one instance of emulation which directly impact the behavior of the program. This can include logging verbosity levels, selectors for attaching to a debugger or emulated consoles or whether to open the GUI, etc.

The Justification

The primary justification for this grouping of parameters is reuse. The ffx emulator launcher is designed to support multiple backing emulation programs, such as Qemu, Aemu, Google Cloud Engine, or Vanadium. Each of these engines can emulate various devices, and each of those devices can potentially run various operating systems.

The goal of our design is to be able to define a set of virtual devices (think a Nest Hub, a Chromebook, a smart speaker), and run the same OS on each of them just by swapping out the VirtualDevice configuration; or, build a set of sample OS versions and run them on identical emulated hardware just by swapping out the GuestConfig, which points to the image files for each version.

The Code

The code in this crate is primarily type definitions, and all the fields are public. The data for those types may come from anywhere: a test can populate a GuestConfig with test input files, a developer can write code which defines a VirtualDevice on-the-fly, and a RuntimeConfig will usually be populated by command-line flags.

The primary expected use case, though, is to get configuration data from a Product Bundle Manifest (PBM). The PBM is a well-defined set of configuration parameters designed to emulate a specific system and device, and is included in the Fuchsia SDK for public use. It is also generated by the build system for in-tree users, according to the parameters supplied to the build.

This crate contains utility functions which call into the PBM library to retrieve configuration data, and convert it from the PBM library‘s data structures into the emulator data structures. The result of these functions will be checked for internal consistency - for example, if the virtual device has no audio interface defined, the host shouldn’t contain physical device configuration either. The specific guarantees on each field will be documented by the internal doc comments for each type.

The Takeaway

Each of the types laid out in this document serves a specific purpose, and while they are closely related, they should not have any overlap. If a user attempting to run identical guest systems on two devices has to change more than just the VirtualDevice configs for those devices, something is in the wrong place.

On the back end, these types will probably be manipulated by the emulation engine, combined and adjusted to fit that back-end's design, and ultimately used to form a single command-line to invoke the emulator. This crate has no interest in how that happens; the details of how the engine uses the config types are specific to the engine itself and so out of scope here.