This document aims to detail, at a high-level, everything that happens between machine power on and a component (v1 or v2) running on the system.
The process for loading the Fuchsia kernel (zircon) onto the system varies by platform. At a high level the kernel is stored in the ZBI, which holds everything needed to bootstrap Fuchsia.
Once the kernel (zircon) is running on the system its main objective is to start userspace, where processes can be run. Since zircon is a micro kernel, it doesn't have to do a whole lot in this stage (especially compared to Linux). The executable for the first user process is baked into the kernel, which the kernel copies into a new process and starts. This program is called userboot.
Userboot is carefully constructed to be easy for the kernel to start, because otherwise the kernel would have to implement a lot of process bootstrap functionality (like a library loader service) that would never be used after the first process has been started.
Userboot’s job is really straightforward, to find and start the next process. The kernel gives userboot a handle to the ZBI, inside of which is the bootfs image. Userboot reads through the ZBI to find the bootfs image, decompresses it if necessary, and copies it to a fresh VMO. The bootfs image contains a read-only filesystem, which userboot then accesses to find an executable and its libraries. With these it starts the next process, which is bootsvc.
Userboot may exit at this point, unless the userboot.shutdown option was given on the kernel command line.
Bootsvc, the next process, is dynamically linked by userboot. This makes it a better home than userboot for complex logic, as it can use libraries. Because of this bootsvc runs various FIDL services for its children, the most notable of which is bootfs, a FIDL-based filesystem backed by the bootfs image that userboot decompressed.
Aside from hosting various services and the bootfs filesystem, bootsvc’s main job is to start the next process, which is component manager. Just like bootsvc, component manager is stored in bootfs, which is still the only filesystem available at this point.
Note that all of bootsvc’s responsibilities are currently being moved to component manager, and it will eventually be deleted from the system. After this happens, userboot will launch component manager directly instead of bootsvc.
Both bootsvc and component manager mark their processes as critical, which means that if something goes wrong with either and they crash, the job that they are in is killed. Both run in the root job, which has the special property that if it is killed, the kernel force restarts the system.
Component manager is the program that drives the v2 component framework. This framework controls how and when programs are run and which capabilities these programs can access from other programs. A program run by this framework is referred to as a component.
The components that component manager runs are organized into a tree. There is a root component, and it has two children named bootstrap and core. Bootstrap's children are the parts of the system needed to get the system functional enough to run more complex software like appmgr.
The root, bootstrap, and core components are non-executable components, which means that they have no program running on the system that corresponds to them. They exists solely for organizational purposes.
There are two important components under bootstrap, fshost and driver manager. These two components work together to bring up a functional enough system for appmgr, which then starts up all the user-facing software.
Drivers are run by driver hosts, which are child processes that driver manager starts. Each driver is a dynamic library stored in either bootfs or a package, and when a driver is to be run it is dynamically linked into a driver host and then executed.
The drivers stored in packages aren't available when driver manager starts, as those are stored on disk and drivers must be running before block devices for filesystems can appear. driver manager starts a thread that waits on a synchronous open to the /system-delayed handle, and once this open call succeeds it loads the drivers in the system package.
Fshost is a v2 component responsible for finding block devices, starting filesystem processes to service these block devices, and providing handles for these filesystems to the rest of Fuchsia. To accomplish this, fshost attempts to access the /dev handle in its namespace. This capability is provided by driver manager.
As fshost finds block devices, it reads headers from each device to detect the filesystem type. It will initially find the fvm block, which contains partitions for other block devices. Fshost will use devfs to cause driver manager to run the fvm driver for this block device, which causes other block devices to appear for fshost to inspect. It does a similar thing when it discovers a zxcrypt partition, as the disk will need to be decrypted to be usable. Once fvm and zxcrypt are loaded, fshost will find the appropriate block devices and start the minfs and blobfs filesystems, which are needed for a fully functioning system.
Currently fshost runs a memfs for its outgoing directory, and mounts handles into this memfs as filesystems come online. This means that attempting to access a fshost-provided directory too early will result in components seeing an empty directory. The requests are not pipelined in such a way that they are ignored until the given filesystem is available.
/pkgfs-delayed handle is provided to component manager, which uses it to load components that are stored in packages.
Appmgr runs the v1 component framework, which coexists with the v2 component framework. Appmgr is stored in a package, unlike fshost and driver manager which are stored in bootfs, so component manager uses the /pkgfs-delayed handle from fshost to load appmgr.
Capabilities from the v2 framework can be forwarded to the
sys realm in appmgr, and services managed by sysmgr can be exposed to the v2 framework. By this mechanism, the two frameworks can access capabilities from each other and cooperate to run the system.
Component manager generally starts components lazily on-demand in response to something accessing a capability provided by the component. Components may also be marked as “eager”, which causes the component to start at the same point its parent starts.
In order to get the system running, appmgr is marked as an eager component. Since appmgr is stored in a package this causes component manager to attempt to load appmgr, and thus access the /pkgfs-delayed handle from fshost, causing fshost to be started.
Once running, fshost attempts to access the /dev handle from driver manager, which causes driver manager to start. Together they bring up drivers and filesystems, eventually culminating in pkgfs running. At this point fshost starts responding to requests on the /pkgfs-delayed handle, and component manager finishes loading appmgr and starts it.
When appmgr is started it creates a top-level realm called the “app” realm. Into this realm it launches the first v1 component, sysmgr. Sysmgr’s job is to manage the “sys” realm, which is created under the “app” realm.
The sys realm holds a large number of FIDL services, the exact set of which is determined by sysmgr configuration files. Components running in the sys realm are allowed to connect to these sysmgr-managed services. Service connections for the sys realm are handled by sysmgr, which will lazily start components as services they provide are needed.
There is also a set of components that sysmgr will start eagerly, each of which may or may not also provide FIDL services for the sys realm.
With the initial set of v1 components launched, they will cause other components to be launched through accessing FIDL services and by directly launching them with services provided by appmgr. It is at this point that the remaining set of components on the system can be run.