1use core::ffi::c_void;
6use core::ptr::NonNull;
7use std::num::NonZero;
8use std::ops::ControlFlow;
9use std::sync::OnceLock;
10
11use log::{debug, warn};
12use zx::Status;
13
14use fdf::{Channel, Dispatcher, DispatcherBuilder, DispatcherRef};
15use fidl_fuchsia_driver_framework::DriverRequest;
16
17use fdf::{fdf_handle_t, DriverHandle, Message};
18
19use crate::{Driver, DriverContext};
20use fdf_sys::fdf_dispatcher_get_current_dispatcher;
21use fidl_fuchsia_driver_framework::DriverStartArgs;
22
23pub struct DriverServer<T> {
27 server_handle: OnceLock<Channel<[u8]>>,
28 root_dispatcher: DispatcherRef<'static>,
29 driver: OnceLock<T>,
30}
31
32impl<T: Driver> DriverServer<T> {
33 pub unsafe extern "C" fn initialize(server_handle: fdf_handle_t) -> *mut c_void {
40 let root_dispatcher = NonNull::new(unsafe { fdf_dispatcher_get_current_dispatcher() })
43 .expect("Non-null current dispatcher");
44 let server_handle = OnceLock::from(unsafe {
48 Channel::from_driver_handle(DriverHandle::new_unchecked(
49 NonZero::new(server_handle).expect("valid driver handle"),
50 ))
51 });
52
53 let root_dispatcher = unsafe { DispatcherRef::from_raw(root_dispatcher) };
55 let server_ptr = Box::into_raw(Box::new(Self {
58 server_handle,
59 root_dispatcher: root_dispatcher.clone(),
60 driver: OnceLock::default(),
61 }));
62
63 let server = unsafe { &mut *server_ptr };
68
69 let rust_async_dispatcher = DispatcherBuilder::new()
72 .name("fuchsia-async")
73 .allow_thread_blocking()
74 .create_released()
75 .expect("failure creating blocking dispatcher for rust async");
76 rust_async_dispatcher
79 .post_task_sync(move |status| {
80 let Status::OK = status else { return };
82 Dispatcher::override_current(root_dispatcher.clone(), || {
83 let mut executor = fuchsia_async::LocalExecutor::new();
87 executor.run_singlethreaded(async move {
88 server.message_loop(root_dispatcher).await;
89 server.server_handle.take()
94 });
95 });
96 })
97 .expect("failure spawning main event loop for rust async dispatch");
98
99 server_ptr.cast()
103 }
104
105 pub unsafe extern "C" fn destroy(obj: *mut c_void) {
113 let obj: *mut Self = obj.cast();
114 unsafe { drop(Box::from_raw(obj)) }
117 }
118
119 async fn message_loop(&mut self, dispatcher: DispatcherRef<'_>) {
122 loop {
123 let server_handle_lock = self.server_handle.get();
124 let Some(server_handle) = server_handle_lock else {
125 panic!("driver already shut down while message loop was running")
126 };
127 match server_handle.read_bytes(dispatcher.clone()).await {
128 Ok(Some(message)) => {
129 if let ControlFlow::Break(_) = self.handle_message(message).await {
130 return;
132 }
133 }
134 Ok(None) => panic!("unexpected empty message on server channel"),
135 Err(status @ Status::PEER_CLOSED) | Err(status @ Status::UNAVAILABLE) => {
136 warn!("Driver server channel closed before a stop message with status {status}, exiting main loop early but stop() will not be called.");
137 return;
138 }
139 Err(e) => panic!("unexpected error on server channel {e}"),
140 }
141 }
142 }
143
144 async fn handle_start(&self, start_args: DriverStartArgs) -> Result<(), Status> {
151 let context = DriverContext::new(self.root_dispatcher.clone(), start_args)?;
152 context.start_logging(T::NAME)?;
153
154 log::debug!("driver starting");
155
156 let driver = T::start(context).await?;
157 self.driver.set(driver).map_err(|_| ()).expect("Driver received start message twice");
158 Ok(())
159 }
160
161 async fn handle_stop(&mut self) {
162 log::debug!("driver stopping");
163 self.driver
164 .take()
165 .expect("received stop message more than once or without successfully starting")
166 .stop()
167 .await;
168 }
169
170 async fn handle_message(&mut self, message: Message<[u8]>) -> ControlFlow<()> {
177 let (_, request) = DriverRequest::read_from_message(message).unwrap();
178 match request {
179 DriverRequest::Start { start_args, responder } => {
180 let res = self.handle_start(start_args).await.map_err(Status::into_raw);
181 let Some(server_handle) = self.server_handle.get() else {
182 panic!("driver shutting down before it was finished starting")
183 };
184 responder.send_response(server_handle, res).unwrap();
185 if res.is_ok() {
186 ControlFlow::Continue(())
187 } else {
188 debug!("driver failed to start, exiting main loop");
189 ControlFlow::Break(())
190 }
191 }
192 DriverRequest::Stop {} => {
193 self.handle_stop().await;
194 ControlFlow::Break(())
195 }
196 _ => panic!("Unknown message on server channel"),
197 }
198 }
199}
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204
205 use fdf::{Arena, CurrentDispatcher};
206 use fdf_env::test::spawn_in_driver;
207 use zx::Status;
208
209 #[derive(Default)]
210 struct TestDriver {
211 _not_empty: bool,
212 }
213
214 impl Driver for TestDriver {
215 const NAME: &str = "test_driver";
216
217 async fn start(context: DriverContext) -> Result<Self, Status> {
218 let DriverContext { root_dispatcher, start_args, .. } = context;
219 println!("created new test driver on dispatcher: {root_dispatcher:?}");
220 println!("driver start message: {start_args:?}");
221 Ok(Self::default())
222 }
223 async fn stop(&self) {
224 println!("driver stop message");
225 }
226 }
227
228 crate::driver_register!(TestDriver);
229
230 #[test]
231 fn register_driver() {
232 assert_eq!(__fuchsia_driver_registration__.version, 1);
233 let initialize_func = __fuchsia_driver_registration__.v1.initialize.expect("initializer");
234 let destroy_func = __fuchsia_driver_registration__.v1.destroy.expect("destroy function");
235
236 let (server_chan, client_chan) = fdf::Channel::<[u8]>::create();
237 spawn_in_driver("driver registration", async move {
238 let channel_handle = server_chan.into_driver_handle().into_raw().get();
239 let driver_server = unsafe { initialize_func(channel_handle) } as usize;
240 assert_ne!(driver_server, 0);
241
242 let start_msg =
243 DriverRequest::start_as_message(Arena::new(), DriverStartArgs::default(), 1)
244 .unwrap();
245 client_chan.write(start_msg).unwrap();
246 let _ = client_chan.read_bytes(CurrentDispatcher).await.unwrap();
247
248 let stop_msg = DriverRequest::stop_as_message(Arena::new()).unwrap();
249 client_chan.write(stop_msg).unwrap();
250 let Err(Status::PEER_CLOSED) = client_chan.read_bytes(CurrentDispatcher).await else {
251 panic!("expected peer closed from driver server after end message");
252 };
253
254 unsafe {
255 destroy_func(driver_server as *mut c_void);
256 }
257 });
258 }
259}