fdf_fidl/
lib.rs

1// Copyright 2025 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//! Safe bindings for using FIDL with the fuchsia driver framework C API
6#![deny(unsafe_op_in_unsafe_fn, missing_docs)]
7
8mod wire;
9
10use fuchsia_sync::{Mutex, MutexGuard};
11use std::marker::PhantomData;
12use std::num::NonZero;
13use std::pin::Pin;
14use std::ptr::NonNull;
15use std::task::{Context, Poll};
16
17use fidl_next::{Chunk, HasExecutor};
18use zx::{HandleBased, Status};
19
20use fdf_channel::arena::{Arena, ArenaBox};
21use fdf_channel::channel::Channel;
22use fdf_channel::futures::ReadMessageState;
23use fdf_channel::message::Message;
24use fdf_core::dispatcher::{CurrentDispatcher, OnDispatcher};
25use fdf_core::handle::{DriverHandle, MixedHandle, MixedHandleType};
26
27pub use self::wire::*;
28
29/// A fidl-compatible driver channel that also holds a reference to the
30/// dispatcher. Defaults to using [`CurrentDispatcher`].
31#[derive(Debug, PartialEq)]
32pub struct DriverChannel<D = CurrentDispatcher> {
33    dispatcher: D,
34    channel: Channel<[Chunk]>,
35}
36
37impl<D> DriverChannel<D> {
38    /// Create a new driver fidl channel that will perform its operations on the given
39    /// dispatcher handle.
40    pub fn new_with_dispatcher(dispatcher: D, channel: Channel<[Chunk]>) -> Self {
41        Self { dispatcher, channel }
42    }
43
44    /// Create a new driver fidl channel pair that will perform its operations on the given
45    /// dispatcher handles.
46    pub fn create_with_dispatchers(dispatcher1: D, dispatcher2: D) -> (Self, Self) {
47        let (channel1, channel2) = Channel::create();
48        (
49            Self { dispatcher: dispatcher1, channel: channel1 },
50            Self { dispatcher: dispatcher2, channel: channel2 },
51        )
52    }
53
54    /// Create a new driver fidl channel pair that will perform its operations on the given
55    /// dispatcher handle, if the dispatcher implements [`Clone`]
56    pub fn create_with_dispatcher(dispatcher: D) -> (Self, Self)
57    where
58        D: Clone,
59    {
60        Self::create_with_dispatchers(dispatcher.clone(), dispatcher)
61    }
62
63    /// Does a server side token exchange from a [`zx::Channel`]'s handle to obtain
64    /// a driver runtime [`DriverChannel`] synchronously.
65    pub fn receive_from_token_with_dispatcher(
66        dispatcher: D,
67        token: zx::Channel,
68    ) -> Result<DriverChannel<D>, Status> {
69        let mut handle = 0;
70        Status::ok(unsafe { fdf_sys::fdf_token_receive(token.into_raw(), &mut handle) })?;
71        let handle = NonZero::new(handle).ok_or(Status::BAD_HANDLE)?;
72        let channel = unsafe { Channel::from_driver_handle(DriverHandle::new_unchecked(handle)) };
73        Ok(DriverChannel::new_with_dispatcher(dispatcher, channel))
74    }
75
76    /// Returns the underlying data channel
77    pub fn into_channel(self) -> Channel<[Chunk]> {
78        self.channel
79    }
80
81    /// Returns the underlying `fdf_handle_t` for this channel
82    pub fn into_driver_handle(self) -> DriverHandle {
83        self.channel.into_driver_handle()
84    }
85}
86
87impl DriverChannel<CurrentDispatcher> {
88    /// Create a new driver fidl channel that will perform its operations on the
89    /// [`CurrentDispatcher`].
90    pub fn new(channel: Channel<[Chunk]>) -> Self {
91        Self::new_with_dispatcher(CurrentDispatcher, channel)
92    }
93
94    /// Create a new driver fidl channel pair that will perform its operations on the
95    /// [`CurrentDispatcher`].
96    pub fn create() -> (Self, Self) {
97        Self::create_with_dispatcher(CurrentDispatcher)
98    }
99
100    /// Does a server side token exchange from a [`zx::Channel`]'s handle to obtain
101    /// a driver runtime [`DriverChannel`] synchronously.
102    pub fn receive_from_token(token: zx::Channel) -> Result<DriverChannel, Status> {
103        Self::receive_from_token_with_dispatcher(CurrentDispatcher, token)
104    }
105}
106
107impl fidl_next::InstanceFromServiceTransport<zx::Channel> for DriverChannel<CurrentDispatcher> {
108    fn from_service_transport(handle: zx::Channel) -> Self {
109        DriverChannel::receive_from_token(handle).unwrap()
110    }
111}
112
113/// Creates a pair of [`fidl_next::ClientEnd`] and [`fidl_next::ServerEnd`] backed by a new
114/// pair of [`DriverChannel`]s using dispatchers of type `D`.
115pub fn create_channel_with_dispatchers<P, D>(
116    client_dispatcher: D,
117    server_dispatcher: D,
118) -> (fidl_next::ClientEnd<P, DriverChannel<D>>, fidl_next::ServerEnd<P, DriverChannel<D>>) {
119    let (client_channel, server_channel) =
120        DriverChannel::create_with_dispatchers(client_dispatcher, server_dispatcher);
121    (
122        fidl_next::ClientEnd::from_untyped(client_channel),
123        fidl_next::ServerEnd::from_untyped(server_channel),
124    )
125}
126
127/// Creates a pair of [`fidl_next::ClientEnd`] and [`fidl_next::ServerEnd`] backed by a new
128/// pair of [`DriverChannel`]s using dispatchers of type `D`, where `D` implements [`Clone`]
129pub fn create_channel_with_dispatcher<P, D: Clone>(
130    dispatcher: D,
131) -> (fidl_next::ClientEnd<P, DriverChannel<D>>, fidl_next::ServerEnd<P, DriverChannel<D>>) {
132    create_channel_with_dispatchers(dispatcher.clone(), dispatcher)
133}
134
135/// Creates a pair of [`fidl_next::ClientEnd`] and [`fidl_next::ServerEnd`] backed by a new
136/// pair of [`DriverChannel`]s using the default [`CurrentDispatcher`]
137pub fn create_channel<P>()
138-> (fidl_next::ClientEnd<P, DriverChannel>, fidl_next::ServerEnd<P, DriverChannel>) {
139    create_channel_with_dispatcher(CurrentDispatcher)
140}
141
142/// A channel buffer.
143pub struct SendBuffer {
144    handles: Vec<Option<MixedHandle>>,
145    data: Vec<Chunk>,
146}
147
148impl SendBuffer {
149    fn new() -> Self {
150        Self { handles: Vec::new(), data: Vec::new() }
151    }
152}
153
154impl fidl_next::Encoder for SendBuffer {
155    #[inline]
156    fn bytes_written(&self) -> usize {
157        fidl_next::Encoder::bytes_written(&self.data)
158    }
159
160    #[inline]
161    fn write(&mut self, bytes: &[u8]) {
162        fidl_next::Encoder::write(&mut self.data, bytes)
163    }
164
165    #[inline]
166    fn rewrite(&mut self, pos: usize, bytes: &[u8]) {
167        fidl_next::Encoder::rewrite(&mut self.data, pos, bytes)
168    }
169
170    fn write_zeroes(&mut self, len: usize) {
171        fidl_next::Encoder::write_zeroes(&mut self.data, len);
172    }
173}
174
175impl fidl_next::encoder::InternalHandleEncoder for SendBuffer {
176    #[inline]
177    fn __internal_handle_count(&self) -> usize {
178        self.handles.len()
179    }
180}
181
182impl fidl_next::fuchsia::HandleEncoder for SendBuffer {
183    fn push_handle(&mut self, handle: zx::NullableHandle) -> Result<(), fidl_next::EncodeError> {
184        if let Some(handle) = MixedHandle::from_zircon_handle(handle) {
185            if handle.is_driver() {
186                return Err(fidl_next::EncodeError::ExpectedZirconHandle);
187            }
188            self.handles.push(Some(handle));
189        } else {
190            self.handles.push(None);
191        }
192        Ok(())
193    }
194
195    unsafe fn push_raw_driver_handle(&mut self, handle: u32) -> Result<(), fidl_next::EncodeError> {
196        if let Some(handle) = NonZero::new(handle) {
197            // SAFETY: the fidl framework is responsible for providing us with a valid, otherwise
198            // unowned handle.
199            let handle = unsafe { MixedHandle::from_raw(handle) };
200            if !handle.is_driver() {
201                return Err(fidl_next::EncodeError::ExpectedDriverHandle);
202            }
203            self.handles.push(Some(handle));
204        } else {
205            self.handles.push(None);
206        }
207        Ok(())
208    }
209
210    fn handles_pushed(&self) -> usize {
211        self.handles.len()
212    }
213}
214
215#[doc(hidden)] // Internal implementation detail of the fidl bindings.
216pub struct RecvBuffer {
217    buffer: Option<Message<[Chunk]>>,
218    data_offset: usize,
219    handle_offset: usize,
220}
221
222impl RecvBuffer {
223    fn next_handle(&self) -> Result<&MixedHandle, fidl_next::DecodeError> {
224        let Some(buffer) = &self.buffer else {
225            return Err(fidl_next::DecodeError::InsufficientHandles);
226        };
227
228        let Some(handles) = buffer.handles() else {
229            return Err(fidl_next::DecodeError::InsufficientHandles);
230        };
231        if handles.len() < self.handle_offset + 1 {
232            return Err(fidl_next::DecodeError::InsufficientHandles);
233        }
234        handles[self.handle_offset].as_ref().ok_or(fidl_next::DecodeError::RequiredHandleAbsent)
235    }
236}
237
238// SAFETY: The decoder implementation stores the data buffer in a [`Message`] tied to an [`Arena`],
239// and the memory in an [`Arena`] is guaranteed not to move while the arena is valid.
240// Also, since we own the [`Message`] and nothing else can, it is ok to treat its contents
241// as mutable through an `&mut self` reference to the struct.
242unsafe impl fidl_next::Decoder for RecvBuffer {
243    // SAFETY: if the caller requests a number of [`Chunk`]s that we can't supply, we return
244    // `InsufficientData`.
245    fn take_chunks_raw(&mut self, count: usize) -> Result<NonNull<Chunk>, fidl_next::DecodeError> {
246        let Some(buffer) = &mut self.buffer else {
247            return Err(fidl_next::DecodeError::InsufficientData);
248        };
249
250        let Some(data) = buffer.data_mut() else {
251            return Err(fidl_next::DecodeError::InsufficientData);
252        };
253        if data.len() < self.data_offset + count {
254            return Err(fidl_next::DecodeError::InsufficientData);
255        }
256        let pos = self.data_offset;
257        self.data_offset += count;
258        Ok(unsafe { NonNull::new_unchecked((data[pos..(pos + count)]).as_mut_ptr()) })
259    }
260
261    fn commit(&mut self) {
262        if let Some(handles) = self.buffer.as_mut().and_then(Message::handles_mut) {
263            for handle in handles.iter_mut().take(self.handle_offset) {
264                core::mem::forget(handle.take());
265            }
266        }
267    }
268
269    fn finish(&self) -> Result<(), fidl_next::DecodeError> {
270        if let Some(buffer) = &self.buffer {
271            let data_len = buffer.data().unwrap_or(&[]).len();
272            if self.data_offset != data_len {
273                return Err(fidl_next::DecodeError::ExtraBytes {
274                    num_extra: data_len - self.data_offset,
275                });
276            }
277            let handle_len = buffer.handles().unwrap_or(&[]).len();
278            if self.handle_offset != handle_len {
279                return Err(fidl_next::DecodeError::ExtraHandles {
280                    num_extra: handle_len - self.handle_offset,
281                });
282            }
283        }
284
285        Ok(())
286    }
287}
288
289impl fidl_next::decoder::InternalHandleDecoder for RecvBuffer {
290    fn __internal_take_handles(&mut self, count: usize) -> Result<(), fidl_next::DecodeError> {
291        let Some(handles) = self.buffer.as_mut().and_then(Message::handles_mut) else {
292            return Err(fidl_next::DecodeError::InsufficientHandles);
293        };
294        if handles.len() < self.handle_offset + count {
295            return Err(fidl_next::DecodeError::InsufficientHandles);
296        }
297        let pos = self.handle_offset;
298        self.handle_offset = pos + count;
299        Ok(())
300    }
301
302    fn __internal_handles_remaining(&self) -> usize {
303        self.buffer
304            .as_ref()
305            .map(|buffer| buffer.handles().unwrap_or(&[]).len() - self.handle_offset)
306            .unwrap_or(0)
307    }
308}
309
310impl fidl_next::fuchsia::HandleDecoder for RecvBuffer {
311    fn take_raw_handle(&mut self) -> Result<zx::sys::zx_handle_t, fidl_next::DecodeError> {
312        let result = {
313            let handle = self.next_handle()?.resolve_ref();
314            let MixedHandleType::Zircon(handle) = handle else {
315                return Err(fidl_next::DecodeError::ExpectedZirconHandle);
316            };
317            handle.raw_handle()
318        };
319        let pos = self.handle_offset;
320        self.handle_offset = pos + 1;
321        Ok(result)
322    }
323
324    fn take_raw_driver_handle(&mut self) -> Result<u32, fidl_next::DecodeError> {
325        let result = {
326            let handle = self.next_handle()?.resolve_ref();
327            let MixedHandleType::Driver(handle) = handle else {
328                return Err(fidl_next::DecodeError::ExpectedDriverHandle);
329            };
330            unsafe { handle.get_raw().get() }
331        };
332        let pos = self.handle_offset;
333        self.handle_offset = pos + 1;
334        Ok(result)
335    }
336
337    fn handles_remaining(&mut self) -> usize {
338        fidl_next::decoder::InternalHandleDecoder::__internal_handles_remaining(self)
339    }
340}
341
342/// The inner state of a receive future used by [`fidl_next::protocol::Transport`].
343pub struct DriverRecvState(ReadMessageState);
344
345/// The shared part of a driver channel.
346pub struct Shared<D> {
347    channel: Mutex<DriverChannel<D>>,
348}
349
350impl<D> Shared<D> {
351    fn new(channel: Mutex<DriverChannel<D>>) -> Self {
352        Self { channel }
353    }
354
355    fn get_locked(&self) -> MutexGuard<'_, DriverChannel<D>> {
356        self.channel.lock()
357    }
358}
359
360/// The exclusive part of a driver channel.
361pub struct Exclusive {
362    _phantom: PhantomData<()>,
363}
364
365impl<D: OnDispatcher> fidl_next::Transport for DriverChannel<D> {
366    type Error = Status;
367
368    fn split(self) -> (Self::Shared, Self::Exclusive) {
369        (Shared::new(Mutex::new(self)), Exclusive { _phantom: PhantomData })
370    }
371
372    type Shared = Shared<D>;
373
374    type SendBuffer = SendBuffer;
375
376    type SendFutureState = SendBuffer;
377
378    fn acquire(_shared: &Self::Shared) -> Self::SendBuffer {
379        SendBuffer::new()
380    }
381
382    type Exclusive = Exclusive;
383
384    type RecvFutureState = DriverRecvState;
385
386    type RecvBuffer = RecvBuffer;
387
388    fn begin_send(_shared: &Self::Shared, buffer: Self::SendBuffer) -> Self::SendFutureState {
389        buffer
390    }
391
392    fn poll_send(
393        mut buffer: Pin<&mut Self::SendFutureState>,
394        _cx: &mut Context<'_>,
395        shared: &Self::Shared,
396    ) -> Poll<Result<(), Option<Self::Error>>> {
397        let arena = Arena::new();
398        let message = Message::new_with(arena, |arena| {
399            let data = arena.insert_slice(&buffer.data);
400            let handles = buffer.handles.split_off(0);
401            let handles = arena.insert_from_iter(handles);
402            (Some(data), Some(handles))
403        });
404        let result = match shared.get_locked().channel.write(message) {
405            Ok(()) => Ok(()),
406            Err(Status::PEER_CLOSED) => Err(None),
407            Err(e) => Err(Some(e)),
408        };
409        Poll::Ready(result)
410    }
411
412    fn begin_recv(
413        shared: &Self::Shared,
414        _exclusive: &mut Self::Exclusive,
415    ) -> Self::RecvFutureState {
416        // SAFETY: The `receiver` owns the channel we're using here and will be the same
417        // receiver given to `poll_recv`, so must outlive the state object we're constructing.
418        let state =
419            unsafe { ReadMessageState::register_read_wait(&mut shared.get_locked().channel) };
420        DriverRecvState(state)
421    }
422
423    fn poll_recv(
424        mut future: Pin<&mut Self::RecvFutureState>,
425        cx: &mut Context<'_>,
426        shared: &Self::Shared,
427        _exclusive: &mut Self::Exclusive,
428    ) -> Poll<Result<Self::RecvBuffer, Option<Self::Error>>> {
429        use std::task::Poll::*;
430        match future.as_mut().0.poll_with_dispatcher(cx, shared.get_locked().dispatcher.clone()) {
431            Ready(Ok(maybe_buffer)) => {
432                let buffer = maybe_buffer.map(|buffer| {
433                    buffer.map_data(|_, data| {
434                        let bytes = data.len();
435                        assert_eq!(
436                            0,
437                            bytes % size_of::<Chunk>(),
438                            "Received driver channel buffer was not a multiple of {} bytes",
439                            size_of::<Chunk>()
440                        );
441                        // SAFETY: we verified that the size of the message we received was the correct
442                        // multiple of chunks and we know that the data pointer is otherwise valid and
443                        // from the correct arena by construction.
444                        unsafe {
445                            let ptr = ArenaBox::into_ptr(data).cast();
446                            ArenaBox::new(NonNull::slice_from_raw_parts(
447                                ptr,
448                                bytes / size_of::<Chunk>(),
449                            ))
450                        }
451                    })
452                });
453
454                Ready(Ok(RecvBuffer { buffer, data_offset: 0, handle_offset: 0 }))
455            }
456            Ready(Err(err)) => {
457                if err == Status::PEER_CLOSED {
458                    Ready(Err(None))
459                } else {
460                    Ready(Err(Some(err)))
461                }
462            }
463            Pending => Pending,
464        }
465    }
466}
467
468impl<D> fidl_next::RunsTransport<DriverChannel<D>> for fidl_next::fuchsia_async::FuchsiaAsync {}
469
470impl<D: OnDispatcher + 'static> HasExecutor for DriverChannel<D> {
471    type Executor = fidl_next::fuchsia_async::FuchsiaAsync;
472
473    fn executor(&self) -> Self::Executor {
474        fidl_next::fuchsia_async::FuchsiaAsync
475    }
476}
477
478#[cfg(test)]
479mod test {
480    // Normally, the FIDL types and traits used here would omit the `DriverChannel` type argument,
481    // since it can be inferred from the protocol. However, this test is in the crate which defines
482    // `DriverChannel` and the build system is set up in such a way that the generated FIDL crate we
483    // pull in references `DriverChannel` from a different crate. So for now, these have to keep
484    // their transport type arguments.
485
486    use fidl_next::{ClientDispatcher, ClientEnd, Responder, ServerDispatcher, ServerEnd};
487    use fidl_next_fuchsia_examples_gizmo::device::{GetEvent, GetHardwareId};
488    use fidl_next_fuchsia_examples_gizmo::{Device, DeviceClientHandler, DeviceServerHandler};
489    use fuchsia_async::OnSignals;
490    use zx::{AsHandleRef, Event, Signals};
491
492    use super::*;
493    use fdf_core::dispatcher::{CurrentDispatcher, OnDispatcher};
494    use fdf_env::test::spawn_in_driver;
495
496    struct DeviceServer;
497    impl DeviceServerHandler<DriverChannel> for DeviceServer {
498        async fn get_hardware_id(&mut self, responder: Responder<GetHardwareId, DriverChannel>) {
499            responder.respond(4004u32).await.unwrap();
500        }
501
502        async fn get_event(&mut self, responder: Responder<GetEvent, DriverChannel>) {
503            let event = Event::create();
504            event.signal_handle(Signals::empty(), Signals::USER_0).unwrap();
505            responder.respond(event).await.unwrap();
506        }
507    }
508
509    struct DeviceClient;
510    impl DeviceClientHandler<DriverChannel> for DeviceClient {}
511
512    #[test]
513    fn driver_fidl_server() {
514        spawn_in_driver("driver fidl server", async {
515            let (server_chan, client_chan) = Channel::<[Chunk]>::create();
516            let client_end: ClientEnd<Device, _> =
517                ClientEnd::<Device, _>::from_untyped(DriverChannel::new(client_chan));
518            let server_end: ServerEnd<Device, _> =
519                ServerEnd::from_untyped(DriverChannel::new(server_chan));
520            let client_dispatcher = ClientDispatcher::new(client_end);
521            let server_dispatcher = ServerDispatcher::new(server_end);
522            let client = client_dispatcher.client();
523
524            CurrentDispatcher
525                .spawn(async {
526                    server_dispatcher.run(DeviceServer).await.unwrap();
527                    println!("server task finished");
528                })
529                .unwrap();
530            CurrentDispatcher
531                .spawn(async {
532                    client_dispatcher.run(DeviceClient).await.unwrap();
533                    println!("client task finished");
534                })
535                .unwrap();
536
537            {
538                let res = client.get_hardware_id().await.unwrap();
539                let hardware_id = res.unwrap();
540                assert_eq!(hardware_id.response, 4004);
541            }
542
543            {
544                let res = client.get_event().await.unwrap();
545
546                // wait for the event on a fuchsia_async executor
547                let mut executor = fuchsia_async::LocalExecutor::default();
548                let signalled = executor
549                    .run_singlethreaded(OnSignals::new(res.event, Signals::USER_0))
550                    .unwrap();
551                assert_eq!(Signals::USER_0, signalled);
552            }
553        });
554    }
555}