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