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