Skip to main content

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