fdf_component/lib.rs
1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Wrappers around the mechanisms of driver registration for the driver
6//! framework for implementing startup and shutdown of the driver in rust.
7
8#![warn(missing_docs, unsafe_op_in_unsafe_fn)]
9
10use core::future::Future;
11
12mod context;
13mod error;
14mod health;
15mod incoming;
16pub mod macros;
17mod node;
18mod server;
19pub mod testing;
20
21pub use context::*;
22pub use error::DriverError;
23pub use health::{
24 HEALTH_INSPECT_NODE_NAME, HealthAlertReporter, HealthCheckInspect, HealthCheckResult,
25 record_health_check_to_inspect,
26};
27pub use incoming::*;
28pub use node::*;
29
30/// The `fuchsia.driver.framework` health check types used by [`Driver::health_check`] and
31/// [`HealthAlertReporter`], re-exported so drivers do not need a direct dependency on the
32/// `fidl_next` bindings to use them.
33pub use fidl_next_fuchsia_driver_framework::{
34 HealthAlert, HealthCheckError, HealthCheckRequest, HealthCheckResponse, HealthCondition,
35 HealthDiagnosticItem, HealthDiagnosticValue, HealthStatus,
36};
37
38/// Entry points into a driver for starting and stopping.
39///
40/// Driver authors should implement this trait, taking information from the [`DriverContext`]
41/// passed to the [`Driver::start`] method to set up, and then tearing down any resources they use
42/// in the [`Driver::stop`] method.
43pub trait Driver: Sized + Send + Sync + 'static {
44 /// The name of the driver as it will appear in logs
45 const NAME: &str;
46
47 /// This will be called when the driver is started.
48 ///
49 /// The given [`DriverContext`] contains information and functionality necessary to get at the
50 /// driver's incoming and outgoing namespaces, add child nodes in the driver topology, and
51 /// manage dispatchers.
52 ///
53 /// In order for the driver to be properly considered started, it must return `Ok`
54 /// and bind the client end for the [`DriverStartArgs::node`] given in
55 /// [`DriverContext::start_args`].
56 fn start(context: DriverContext) -> impl Future<Output = Result<Self, DriverError>> + Send;
57
58 /// This will be called when the driver has been asked to stop, and should do any
59 /// asynchronous cleanup necessary before the driver is fully shut down.
60 ///
61 /// Note: The driver will not be considered fully stopped until the node client end bound in
62 /// [`Driver::start`] has been closed.
63 fn stop(&self) -> impl Future<Output = ()> + Send;
64
65 /// Called when the driver has been asked to suspend.
66 ///
67 /// This method is invoked after the driver runtime has suspended the driver's dispatchers
68 /// and waited for all executing power-managed (normal) tasks to complete.
69 ///
70 /// The driver should use this opportunity to put its hardware into a low-power state.
71 ///
72 /// Note: This will only be called after the driver has successfully finished [`Driver::start`].
73 /// If a stop is initiated while the driver is suspended, the driver will be fully resumed
74 /// (via [`Driver::system_resume`]) before [`Driver::stop`] is invoked.
75 ///
76 /// Only called when `power_managed_dispatchers_enabled` is set to `"true"` in the
77 /// driver's component manifest.
78 fn system_suspend(&self) -> impl Future<Output = Result<(), DriverError>> + Send {
79 async { Ok(()) }
80 }
81
82 /// Called when the driver has been asked to resume.
83 ///
84 /// This method is invoked when the system resumes or a registered wake vector triggers.
85 /// It executes *before* anything else. The driver should use this opportunity to bring
86 /// its hardware out of its low-power state. Any task queued for the driver to execute will
87 /// only run after this function completes, starting with the wake vector's task if there
88 /// was one.
89 ///
90 /// If the resume was triggered by a wake vector, `lease` will contain a lease token
91 /// representing the lease associated with the wakeup. The driver can retain this lease
92 /// token to keep the driver active and prevent it from suspending again.
93 ///
94 /// Note: This will only be called after the driver has successfully finished [`Driver::start`].
95 /// If the driver is suspended when a stop is initiated, this method is called to resume the
96 /// driver first, ensuring the driver is in a running state during the shutdown hook [`Driver::stop`].
97 ///
98 /// Only called when `power_managed_dispatchers_enabled` is set to `"true"` in the
99 /// driver's component manifest.
100 fn system_resume(
101 &self,
102 _lease: Option<zx::EventPair>,
103 ) -> impl Future<Output = Result<(), DriverError>> + Send {
104 async { Ok(()) }
105 }
106
107 /// Called when the driver framework asks the driver to check its health.
108 ///
109 /// Answers a `fuchsia.driver.framework/Driver.HealthCheck` request at the given level. By
110 /// default `PING` answers with an empty (`OK`) [`HealthCheckResponse`] and `FAST` and `DEEP`
111 /// answer [`HealthCheckError::NotSupported`], matching the C++ `DriverBase2::HealthCheck`
112 /// default. Drivers override this to inspect their hardware and return structured
113 /// diagnostics.
114 ///
115 /// The driver host enforces a deadline per level: 250ms for [`HealthCheckRequest::Ping`], 2s
116 /// for [`HealthCheckRequest::Fast`], and 2 minutes for [`HealthCheckRequest::Deep`]. A check
117 /// that misses its deadline is reported as [`HealthCheckError::Timeout`]. Checks run as their
118 /// own tasks, so a slow check never delays `Stop`, `Suspend` or `Resume`; checks still in
119 /// flight when the driver is asked to stop are cancelled before [`Driver::stop`] is called.
120 ///
121 /// `Ping` must stay cheap (no hardware access or blocking I/O) and must never return
122 /// [`HealthCheckError::Unavailable`]: it answers "is the driver alive", not "is the hardware
123 /// healthy". Before any level reaches this method the framework first confirms that the
124 /// driver's root dispatcher is still processing tasks, so a wedged dispatcher fails the check
125 /// without this method ever running.
126 ///
127 /// Note: This will only be called after the driver has successfully finished [`Driver::start`].
128 fn health_check(
129 &self,
130 request: HealthCheckRequest,
131 ) -> impl Future<Output = Result<HealthCheckResponse, HealthCheckError>> + Send {
132 async move {
133 match request {
134 HealthCheckRequest::Ping => Ok(HealthCheckResponse::default()),
135 _ => Err(HealthCheckError::NotSupported),
136 }
137 }
138 }
139}