Driver components offer the features and services they provide to other drivers and non-driver components through capabilities. This enables Fuchsia's component framework to route those capabilities to the target component when necessary. For more details, see the Driver Communication guide.
In this section, you‘ll expose the qemu_edu
driver’s factorial capabilities and consume those from a component running elsewhere in the system.
Create a new project directory in your Bazel workspace for a new FIDL library:
mkdir -p fuchsia-codelab/qemu_edu/fidl
After you complete this section, the project should have the following directory structure:
//fuchsia-codelab/qemu_edu/fidl |- BUILD.bazel |- qemu_edu.fidl
Create the qemu_edu/fidl/BUILD.bazel
file and add the following statement to include the necessary build rules from the Fuchsia SDK:
qemu_edu/fidl/BUILD.bazel
:
{% includecode gerrit_repo="fuchsia/sdk-samples/drivers" gerrit_path="src/qemu_edu/fidl/BUILD.bazel" region_tag="imports" adjust_indentation="auto" %}
The driver exposes the capabilities of the edu
device using a custom FIDL service. This service contains one or more protocols that clients can connect to. Add a new qemu_edu/qemu_edu.fidl
file to your project workspace with the following contents:
qemu_edu/fidl/qemu_edu.fidl
:
{% includecode gerrit_repo="fuchsia/sdk-samples/drivers" gerrit_path="src/qemu_edu/fidl/qemu_edu.fidl" region_tag="example_snippet" adjust_indentation="auto" %}
This FIDL file defines the Device
protocol with two methods, and the DeviceService
which makes the Device
protocol available to clients.
Add the following build rules to the bottom of the project's build configuration to compile the FIDL library and generate C++ bindings:
fuchsia_fidl_library()
: Declares the examples.qemuedu
FIDL library and describes the FIDL source files it includes.fuchsia_fidl_llcpp_library()
: Describes the generated C++ wirebindings for components to interact with this FIDL library.qemu_edu/fidl/BUILD.bazel
:
{% includecode gerrit_repo="fuchsia/sdk-samples/drivers" gerrit_path="src/qemu_edu/fidl/BUILD.bazel" region_tag="fidl_library" adjust_indentation="auto" %}
With the FIDL service defined, you'll need to update the driver to implement the Device
protocol and serve the DeviceService
to other components.
After you complete this section, the project should have the following directory structure:
//fuchsia-codelab/qemu_edu/drivers |- BUILD.bazel |- meta | |- qemu_edu.cml |- edu_device.cc |- edu_device.h {{ '<strong>' }} |- edu_server.cc {{ '</strong>' }} {{ '<strong>' }} |- edu_server.h {{ '</strong>' }} |- qemu_edu.bind |- qemu_edu.cc |- qemu_edu.h
Create the new qemu_edu/drivers/edu_server.h
file in your project directory with the following contents to include the FIDL bindings for the examples.qemuedu
library and create a new QemuEduServer
class to implement the server end of the Device
protocol:
qemu_edu/drivers/edu_server.h
:
#ifndef FUCHSIA_CODELAB_QEMU_EDU_SERVER_H_ #define FUCHSIA_CODELAB_QEMU_EDU_SERVER_H_ {% includecode gerrit_repo="fuchsia/sdk-samples/drivers" gerrit_path="src/qemu_edu/drivers/edu_server.h" region_tag="imports" adjust_indentation="auto" %} {% includecode gerrit_repo="fuchsia/sdk-samples/drivers" gerrit_path="src/qemu_edu/drivers/edu_server.h" region_tag="namespace_start" adjust_indentation="auto" %} {% includecode gerrit_repo="fuchsia/sdk-samples/drivers" gerrit_path="src/qemu_edu/drivers/edu_server.h" region_tag="fidl_server" adjust_indentation="auto" %} {% includecode gerrit_repo="fuchsia/sdk-samples/drivers" gerrit_path="src/qemu_edu/drivers/edu_server.h" region_tag="namespace_end" adjust_indentation="auto" %} #endif // FUCHSIA_CODELAB_QEMU_EDU_SERVER_H_
Create the new qemu_edu/drivers/edu_server.cc
file in your project directory with the following contents to implement the examples.qemuedu/Device
protocol methods and map them to the device resource methods:
qemu_edu/drivers/edu_server.cc
:
{% includecode gerrit_repo="fuchsia/sdk-samples/drivers" gerrit_path="src/qemu_edu/drivers/edu_server.cc" region_tag="imports" adjust_indentation="auto" %} {% includecode gerrit_repo="fuchsia/sdk-samples/drivers" gerrit_path="src/qemu_edu/drivers/edu_server.cc" region_tag="namespace_start" adjust_indentation="auto" %} {% includecode gerrit_repo="fuchsia/sdk-samples/drivers" gerrit_path="src/qemu_edu/drivers/edu_server.cc" region_tag="compute_factorial" adjust_indentation="auto" %} {% includecode gerrit_repo="fuchsia/sdk-samples/drivers" gerrit_path="src/qemu_edu/drivers/edu_server.cc" region_tag="liveness_check" adjust_indentation="auto" %} {% includecode gerrit_repo="fuchsia/sdk-samples/drivers" gerrit_path="src/qemu_edu/drivers/edu_server.cc" region_tag="namespace_end" adjust_indentation="auto" %}
Update the driver's build configuration to depend on the FIDL bindings for the new examples.qemuedu
library:
qemu_edu/drivers/BUILD.bazel
:
{% set build_bazel_snippet %} {% includecode gerrit_repo=“fuchsia/sdk-samples/drivers” gerrit_path=“src/qemu_edu/drivers/BUILD.bazel” region_tag=“binary” adjust_indentation=“auto” exclude_regexp=“fuchsia.device.fs” highlight=“13” %} {% endset %}
{{ build_bazel_snippet|replace("//src/qemu_edu","//fuchsia-codelab/qemu_edu")|trim() }}
The qemu_edu
driver makes the fuchsia.examples.qemuedu.DeviceService
discoverable to other components by serving it from its outgoing directory. To do this, the driver must:
capability
in its component manifest.expose
this capability to the component framework in its component manifest.This allows other components, including non-driver components, to request the service by its type without needing to know the topological path of the driver. The component framework is responsible for routing the service connection from the client to the driver that provides it.
Update the driver's component manifest to declare and expose the device service as a capability:
qemu_edu/drivers/meta/qemu_edu.cml
:
{ {% includecode gerrit_repo="fuchsia/sdk-samples/drivers" gerrit_path="src/qemu_edu/drivers/meta/qemu_edu.cml" region_tag="driver" %} {% includecode gerrit_repo="fuchsia/sdk-samples/drivers" gerrit_path="src/qemu_edu/drivers/meta/qemu_edu.cml" region_tag="use_capabilities" exclude_regexp="protocol" %} {{ '<strong>' }}{% includecode gerrit_repo="fuchsia/sdk-samples/drivers" gerrit_path="src/qemu_edu/drivers/meta/qemu_edu.cml" region_tag="expose_capabilities" %}{{ '</strong>' }} }
With the manifest updated, the component framework can now route requests for this service. The final step is for the driver to implement the server for the service and serve it on its outgoing directory.
Update the driver‘s Start()
method to begin serving the fuchsia.examples.qemuedu.DeviceService
from the component’s outgoing directory:
qemu_edu/drivers/qemu_edu.cc
:
{% includecode gerrit_repo="fuchsia/sdk-samples/drivers" gerrit_path="src/qemu_edu/drivers/qemu_edu.cc" region_tag="imports" adjust_indentation="auto" %} {{ '<strong>' }}{% includecode gerrit_repo="fuchsia/sdk-samples/drivers" gerrit_path="src/qemu_edu/drivers/qemu_edu.cc" region_tag="fidl_imports" adjust_indentation="auto" %}{{ '</strong>' }} {% includecode gerrit_repo="fuchsia/sdk-samples/drivers" gerrit_path="src/qemu_edu/drivers/qemu_edu.cc" region_tag="start_method_start" adjust_indentation="auto" %} // ... {% includecode gerrit_repo="fuchsia/sdk-samples/drivers" gerrit_path="src/qemu_edu/drivers/qemu_edu.cc" region_tag="device_registers" %} {{ '<strong>' }}{% includecode gerrit_repo="fuchsia/sdk-samples/drivers" gerrit_path="src/qemu_edu/drivers/qemu_edu.cc" region_tag="serve_outgoing" %}{{ '</strong>' }} {% includecode gerrit_repo="fuchsia/sdk-samples/drivers" gerrit_path="src/qemu_edu/drivers/qemu_edu.cc" region_tag="start_method_end" adjust_indentation="auto" %}
The qemu_edu
driver's capabilities are now discoverable by other components.
Use the bazel build
command to verify that the driver builds successfully with your code changes:
bazel build //fuchsia-codelab/qemu_edu/drivers:pkg
Congratulations! You've successfully exposed FIDL services from a Fuchsia driver.