Skip to main content

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}