Sessions are regular components that the session_manager
can launch at startup. This means that creating a session component follows all of the same steps as creating any other component. This document discusses creating an example session that launches at startup and prints “Hello World!” to the system log.
Components require a specific directory structure. The fx
tool provides a generator that creates this structure for you. It takes the name of the component and the language you want to use as arguments. For example, this component is called hello-world-session
and is written in Rust.
Run the following command to create the directory structure for this example:
fx create component-v2 hello-world-session --lang rust
This command creates the following directory structure with a template for a component offering a service:
hello-world-session |- meta | |- hello-world-session-unittests.cml | |- hello-world-session.cml | |- src | |- main.rs | |- BUILD.gn
The component manifest file (hello-world-session.cml
in this case) gives Fuchsia information about our component. The component manifest file has to have the same name as the component that it refers to. This session doesn‘t do much so you don’t need to add anything to the one that was generated.
The following lines of code are from hello-world-session.cml
:
The file starts by including other cml files if needed.
include: [ "sdk/lib/diagnostics/syslog/client.shard.cml" ],
This include
key lets the session component use the fuchsia.logger.LogSink
capability so that it can print to the system log.
Next is the program
block.
program: { // Use the built-in ELF runner to run native binaries. runner: "elf", // The binary to run for this component. binary: "bin/hello_world_session", },
The program
block tells the component_manager
where the binary for the session component can be found. The runner
key tells the component_manager
that is should run the component binary using the ELF runner.
Finally the component manifest describes capabilities that the component can use
, offer
, or expose
.
use: [ // List your component's dependencies here, ex: // { protocol: "fuchsia.net.NameLookup" } ],
session_manager
needs to know to which session component to launch at startup. To do this create a session config JSON file in the meta
directory that contains the URL of the session component.
Component URLs follow the format:
Notice that the path points to a .cm
file. .cm
files are compiled versions of .cml
files that are generated when fx build
is run. So, in this case, the component URL is:
fuchsia-pkg://fuchsia.com/hello-world-session#meta/hello-world-session.cm
The whole session config file looks like this:
{ "session_url": "fuchsia-pkg://fuchsia.com/hello-world-session#meta/hello-world-session.cm" }
Now you can write the actual code for the session component. Inside the src/main.rs
file that was generated there is a lot of code that isn't needed for this example. Replace the contents of src/main.rs
with the following code:
use { anyhow::{Context, Error}, fuchsia_async as fasync, fuchsia_syslog::fx_log_info, }; /// Creates a simple session that just prints "Hello World" to the syslog. #[fasync::run_singlethreaded] async fn main() -> Result<(), Error> { fuchsia_syslog::init_with_tags(&["hello_world_session"]) .context("Failed to initialize logger.")?; fx_log_info!("Hello World!"); Ok(()) } #[cfg(test)] mod tests { #[fuchsia::test] async fn smoke_test() { assert!(true); } }
This code initializes the system log and then prints “Hello World!”. fuchsia_syslog::init_with_tags
can cause an error so the main function returns Result<(), Error>
as well. fx_log_info!
is a macro that prints to the system log with a level of info
. There are similar marcros for error
and warn
.
BUILD.gn
The last file to modify is the BUILD.gn
. This tells the compiler how to build the the session component.
The file starts by importing GN templates that are used in this BUILD.gn
. To build a session component you must import the session_config.gni
.
import("//src/session/build/session_config.gni")
The added import statement gives the BUILD.gn
access to the session_config
command. This command tells the build where to find the session_config.json
for this component. Add the session_config
to the BUILD.gn
just below the import statements:
session_config("hello-world-session-config.json") { config = "meta/hello-world-session-config.json" }
The next section describes the actual Rust binary. It tells the compiler what the name of the binary should be, that it includes unit tests, what dependencies it has, and where it‘s source is located. The only thing that needs to be changed in this section are the dependencies. Since this session component doesn’t have much functionality there are things in the list that aren‘t needed. But, also, syslog
is missing so the session wouldn’t have access to do any logging. Replace the dependencies with the following code:
deps = [ "//src/lib/fuchsia", "//src/lib/fuchsia-async", "//src/lib/syslog/rust:syslog", "//third_party/rust_crates:anyhow", ]
Everything else can stay as it is in the generated BUILD.gn
. The fuchsia_component
and fuchsia_package
commands tell Fuchsia more about the component including what it is called, where to find the manifest, and what dependencies the package and component have.
To build the session fx set
must first be used to configure the build so that session_manager
, your session component, and the session config are included in the base image. This is done with the --with-base
command.
This project is in the session/examples directory so the fx set
for it would be:
fx set core.x64 --with-base=//src/session,//src/session/examples/hello-world-session,//src/session/examples/hello-world-session:hello-world-session-config.json
Once that's done and built session_manager
should automatically start your session on boot.