Skip to main content

starnix_modules_functionfs/
lib.rs

1// Copyright 2024 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#![recursion_limit = "256"]
6
7use fidl::endpoints::SynchronousProxy;
8use fidl_fuchsia_hardware_adb as fadb;
9use fuchsia_async as fasync;
10use futures_util::StreamExt;
11use starnix_core::power::{create_proxy_for_wake_events_counter_zero, mark_proxy_message_handled};
12use starnix_core::task::{CurrentTask, EventHandler, Kernel, WaitCanceler, WaitQueue, Waiter};
13use starnix_core::vfs::pseudo::vec_directory::{VecDirectory, VecDirectoryEntry};
14use starnix_core::vfs::{
15    CacheMode, DirectoryEntryType, FileObject, FileObjectState, FileOps, FileSystem,
16    FileSystemHandle, FileSystemOps, FileSystemOptions, FsNode, FsNodeInfo, FsNodeOps, FsStr,
17    InputBuffer, OutputBuffer, fileops_impl_noop_sync, fileops_impl_seekless, fs_args,
18    fs_node_impl_dir_readonly, fs_node_impl_not_dir,
19};
20use starnix_logging::{log_info, log_warn, track_stub};
21use starnix_sync::{FunctionFsResultLock, FunctionFsStateLock, InterruptibleEvent, LockDepMutex};
22use starnix_types::vfs::default_statfs;
23use starnix_uapi::auth::FsCred;
24use starnix_uapi::errors::Errno;
25use starnix_uapi::file_mode::mode;
26use starnix_uapi::open_flags::OpenFlags;
27use starnix_uapi::vfs::FdEvents;
28use starnix_uapi::{
29    errno, error, gid_t, ino_t, statfs, uid_t, usb_functionfs_event,
30    usb_functionfs_event_type_FUNCTIONFS_BIND, usb_functionfs_event_type_FUNCTIONFS_DISABLE,
31    usb_functionfs_event_type_FUNCTIONFS_ENABLE, usb_functionfs_event_type_FUNCTIONFS_UNBIND,
32};
33use std::collections::VecDeque;
34use std::ops::Deref;
35use std::sync::Arc;
36use zerocopy::IntoBytes;
37
38// The node identifiers of different nodes in FunctionFS.
39const ROOT_NODE_ID: ino_t = 1;
40
41// Control endpoint is always present in a mounted FunctionFS.
42const CONTROL_ENDPOINT: &str = "ep0";
43const CONTROL_ENDPOINT_NODE_ID: ino_t = 2;
44
45const OUTPUT_ENDPOINT: &str = "ep1";
46const OUTPUT_ENDPOINT_NODE_ID: ino_t = 3;
47
48const INPUT_ENDPOINT: &str = "ep2";
49const INPUT_ENDPOINT_NODE_ID: ino_t = 4;
50
51// Magic number of the file system, different from the magic used for Descriptors and Strings.
52// Set to the same value as Linux.
53const FUNCTIONFS_MAGIC: u32 = 0xa647361;
54
55const ADB_DIRECTORY: &str = "/svc/fuchsia.hardware.adb.Service";
56
57// How long to keep Starnix awake after an ADB interaction. If no ADB reads or
58// writes occur within this time period, Starnix will be allowed to suspend.
59const ADB_INTERACTION_TIMEOUT: zx::Duration<zx::MonotonicTimeline> = zx::Duration::from_seconds(2);
60
61#[derive(Default)]
62struct PendingResult<T: Default> {
63    event: Arc<InterruptibleEvent>,
64    result: LockDepMutex<Option<Result<T, Errno>>, FunctionFsResultLock>,
65}
66
67impl<T: Default> PendingResult<T> {
68    fn set_result(&self, res: Result<T, Errno>) {
69        let mut result = self.result.lock();
70        debug_assert!(result.is_none(), "PendingResult set more than once");
71
72        result.replace(res);
73        self.event.notify();
74    }
75}
76
77struct ReadCommand {
78    pending: Arc<PendingResult<Vec<u8>>>,
79}
80
81struct WriteCommand {
82    data: Vec<u8>,
83    pending: Arc<PendingResult<usize>>,
84}
85
86/// Handle all of the ADB messages in an async context.
87/// We receive commands from the main thread and then proxy them into the ADB channel.
88/// We want to hold the wakelock until we have at least one outstanding read, because we
89/// are always woken up on a new message. (If we have no outstanding reads we will not
90/// receive any new messages).
91///
92/// At the same time we still need to handle writes and events. These are handled by always
93/// clearing the proxy signal, but only clearing the kernel signal if we have an outstanding read.
94async fn handle_adb(
95    proxy: fadb::UsbAdbImpl_Proxy,
96    message_counter: Option<zx::Counter>,
97    read_commands: async_channel::Receiver<ReadCommand>,
98    write_commands: async_channel::Receiver<WriteCommand>,
99    state: Arc<LockDepMutex<FunctionFsState, FunctionFsStateLock>>,
100) {
101    /// Handle all of the events coming from the ADB device.
102    ///
103    /// adbd expects to receive events FUNCTIONFS_BIND, FUNCTIONFS_ENABLE, FUNCTION_DISABLE, and
104    /// FUNCTIONFS_UNBIND in that order. If it receives these events out of order or does not
105    /// receive some of the adb events, it may behave unexpectedly. In particular, please reference
106    /// the `StartMonitor` function in `UsbFfsConnection` of `adb/daemon/usb.cpp`.
107    ///
108    /// This module sends a FUNCTIONFS_BIND event as soon as it is called because `handle_adb` is
109    /// called after we've successfully bound to the driver. When the driver is ready to take input
110    /// it will send an `OnStatusChanged{ ONLINE }` event, which is when this module sends the
111    /// FUNCTIONFS_ENABLE event to indicate that adbd should start processing data.
112    ///
113    /// When the driver sends an `OnStatusChanged{}` event, meaning that it's not online anymore.
114    /// The module will send a FUNCTIONFS_DISABLE event to stop processing data. When the stream
115    /// closes, we've unbound from the driver, and the module sends a FUNCTIONFS_UNBIND event.
116    async fn handle_events(
117        mut stream: fadb::UsbAdbImpl_EventStream,
118        message_counter: &Option<zx::Counter>,
119        state: Arc<LockDepMutex<FunctionFsState, FunctionFsStateLock>>,
120    ) {
121        let queue_event = |event| {
122            let mut state_locked = state.lock();
123            state_locked
124                .event_queue
125                .push_back(usb_functionfs_event { type_: event as u8, ..Default::default() });
126            state_locked.waiters.notify_fd_events(FdEvents::POLLIN);
127        };
128
129        queue_event(usb_functionfs_event_type_FUNCTIONFS_BIND);
130
131        while let Some(Ok(fadb::UsbAdbImpl_Event::OnStatusChanged { status })) = stream.next().await
132        {
133            let is_online = status == fadb::StatusFlags::ONLINE;
134            {
135                let mut state_locked = state.lock();
136                state_locked.is_online = is_online;
137                state_locked.event_queue.push_back(usb_functionfs_event {
138                    type_: if is_online {
139                        usb_functionfs_event_type_FUNCTIONFS_ENABLE
140                    } else {
141                        usb_functionfs_event_type_FUNCTIONFS_DISABLE
142                    } as u8,
143                    ..Default::default()
144                });
145                state_locked.waiters.notify_fd_events(FdEvents::POLLIN);
146                state_locked.waiters.notify_all();
147            }
148
149            // We can simply clear this after getting a response because we care about
150            // reads. Allow new FIDL messages to come through and only go to sleep if
151            // we have an outstanding read.
152            message_counter.as_ref().map(mark_proxy_message_handled);
153        }
154
155        queue_event(usb_functionfs_event_type_FUNCTIONFS_UNBIND);
156    }
157
158    /// Consumes a stream of instants and decrements `message_counter` after
159    /// each one. As long as one of the instants written to this channel is
160    /// still in the future, we want to keep the container awake.
161    ///
162    /// NOTE: We're reusing `message_counter` in a way that's perhaps confusing:
163    /// both as the number of "in flight" requests, and to track whether the ADB
164    /// session seems to be idle or not. It may be clearer to have two separate
165    /// counters.
166    async fn handle_idle_timeouts(
167        timeouts: async_channel::Receiver<zx::MonotonicInstant>,
168        message_counter: &Option<zx::Counter>,
169    ) {
170        timeouts
171            .for_each(|timeout| async move {
172                use fasync::WakeupTime;
173                timeout.into_timer().await;
174                message_counter.as_ref().map(mark_proxy_message_handled);
175            })
176            .await
177    }
178
179    /// Handle the commands coming from the main thread.
180    async fn handle_read_commands(
181        proxy: &fadb::UsbAdbImpl_Proxy,
182        timeouts_sender: async_channel::Sender<zx::MonotonicInstant>,
183        commands: async_channel::Receiver<ReadCommand>,
184    ) {
185        let timeouts_sender = &timeouts_sender;
186        commands
187            .for_each(|ReadCommand { pending }| async move {
188                // Queue up our receive future. We want to do this before we decrement the counter,
189                // which potentially allows the container to suspend.
190                let receive_future = proxy.receive();
191
192                // Don't decrement the message counter immediately. Instead, we
193                // keep the container awake for some amount of time to allow
194                // Starnix to react to the message. Otherwise, the container
195                // might go directly to sleep without doing anything.
196                timeouts_sender
197                    .send(zx::MonotonicInstant::after(ADB_INTERACTION_TIMEOUT))
198                    .await
199                    .expect("Should be able to send timeout");
200
201                let response = match receive_future.await {
202                    Err(err) => {
203                        if err.is_closed() {
204                            log_info!("Receive failed due to connection shutdown: {err}");
205                        } else {
206                            log_warn!("Failed to call UsbAdbImpl.Receive: {err}");
207                        }
208                        error!(EINVAL)
209                    }
210                    Ok(Err(err)) => {
211                        let status = zx::Status::err_from_raw(err);
212                        if matches!(
213                            status,
214                            zx::Status::BAD_STATE | zx::Status::CANCELED | zx::Status::PEER_CLOSED
215                        ) {
216                            log_info!("Receive failed due to connection shutdown: {status}");
217                        } else {
218                            log_warn!("Failed to receive data from adb driver: {status}");
219                        }
220                        // TODO(b/536021189): Fix POSIX error mapping. We should return ESHUTDOWN
221                        // on endpoint disable.
222                        error!(EINVAL)
223                    }
224                    Ok(Ok(payload)) => Ok(payload),
225                };
226
227                pending.set_result(response);
228            })
229            .await;
230    }
231
232    /// Handle the commands coming from the main thread.
233    async fn handle_write_commands(
234        proxy: &fadb::UsbAdbImpl_Proxy,
235        timeouts_sender: async_channel::Sender<zx::MonotonicInstant>,
236        commands: async_channel::Receiver<WriteCommand>,
237    ) {
238        let timeouts_sender = &timeouts_sender;
239        commands
240            .for_each(|WriteCommand { data, pending }| async move {
241                let response = match proxy.queue_tx(&data).await {
242                    Err(err) => {
243                        if err.is_closed() {
244                            log_info!("QueueTx failed due to connection shutdown: {err}");
245                        } else {
246                            log_warn!("Failed to call UsbAdbImpl.QueueTx: {err}");
247                        }
248                        error!(EINVAL)
249                    }
250                    Ok(Err(err)) => {
251                        let status = zx::Status::err_from_raw(err);
252                        if matches!(
253                            status,
254                            zx::Status::BAD_STATE | zx::Status::CANCELED | zx::Status::PEER_CLOSED
255                        ) {
256                            log_info!("QueueTx failed due to connection shutdown: {status}");
257                        } else {
258                            log_warn!("Failed to queue data to adb driver: {status}");
259                        }
260                        error!(EINVAL)
261                    }
262                    Ok(Ok(_)) => Ok(data.len()),
263                };
264
265                // Don't decrement the message counter immediately. We use the
266                // ADB output as a signal that the ADB session is still
267                // interactive.
268                timeouts_sender
269                    .send(zx::MonotonicInstant::after(ADB_INTERACTION_TIMEOUT))
270                    .await
271                    .expect("Should be able to send timeout");
272
273                pending.set_result(response);
274            })
275            .await;
276    }
277
278    let (timeouts_sender, timeouts_receiver) = async_channel::unbounded();
279    let event_future = handle_events(proxy.take_event_stream(), &message_counter, state);
280    let write_commands_future =
281        handle_write_commands(&proxy, timeouts_sender.clone(), write_commands);
282    let read_commands_future = handle_read_commands(&proxy, timeouts_sender, read_commands);
283    let timeout_future = handle_idle_timeouts(timeouts_receiver, &message_counter);
284    futures::join!(event_future, write_commands_future, read_commands_future, timeout_future);
285}
286
287pub struct FunctionFs;
288impl FunctionFs {
289    pub fn new_fs(
290        current_task: &CurrentTask,
291        options: FileSystemOptions,
292    ) -> Result<FileSystemHandle, Errno> {
293        if options.source != "adb" {
294            track_stub!(TODO("https://fxbug.dev/329699340"), "FunctionFS supports other uses");
295            return error!(ENODEV);
296        }
297
298        // ADB daemon assumes that ADB works over USB if FunctionFS is able to mount.
299        // Check that the ADB directory capability is provided to the kernel, and fail to mount
300        // if it is not.
301        if let Err(e) = std::fs::read_dir(ADB_DIRECTORY) {
302            log_warn!(
303                "Attempted to mount FunctionFS for adb, but could not read {ADB_DIRECTORY}: {e}"
304            );
305            return error!(ENODEV);
306        }
307
308        let uid = if let Some(uid) = options.params.get(b"uid") {
309            fs_args::parse::<uid_t>(uid.as_ref())?
310        } else {
311            0
312        };
313        let gid = if let Some(gid) = options.params.get(b"gid") {
314            fs_args::parse::<gid_t>(gid.as_ref())?
315        } else {
316            0
317        };
318
319        let fs = FileSystem::new(current_task.kernel(), CacheMode::Uncached, FunctionFs, options)?;
320
321        let creds = FsCred { uid, gid };
322        let info = FsNodeInfo::new(mode!(IFDIR, 0o777), creds);
323        fs.create_root_with_info(ROOT_NODE_ID, FunctionFsRootDir::default(), info);
324        Ok(fs)
325    }
326}
327
328impl FileSystemOps for FunctionFs {
329    fn statfs(&self, _fs: &FileSystem, _current_task: &CurrentTask) -> Result<statfs, Errno> {
330        Ok(default_statfs(FUNCTIONFS_MAGIC))
331    }
332
333    fn name(&self) -> &'static FsStr {
334        b"functionfs".into()
335    }
336}
337
338#[derive(Default)]
339struct FunctionFsState {
340    // Keeps track of the number of FileObject's created for the control endpoint.
341    // When all FileObjects are closed, the filesystem resets to its initial state.
342    // See https://docs.kernel.org/usb/functionfs.html.
343    num_control_file_objects: usize,
344
345    // Whether the FunctionFS has input/output endpoints, which are /ep2 and /ep1
346    // respectively. /ep0 is the control endpoint and is always available.
347    has_input_output_endpoints: bool,
348
349    // Whether the FunctionFS is currently online (host connected).
350    is_online: bool,
351
352    adb_read_channel: Option<async_channel::Sender<ReadCommand>>,
353    adb_write_channel: Option<async_channel::Sender<WriteCommand>>,
354
355    // FIDL binding to the adb driver, for start and stop calls.
356    device_proxy: Option<fadb::DeviceSynchronousProxy>,
357
358    // FunctionFs events that indicate the connection state, to be read through
359    // the control endpoint.
360    event_queue: VecDeque<usb_functionfs_event>,
361
362    waiters: WaitQueue,
363}
364
365pub enum AdbProxyMode {
366    /// Don't proxy events at all.
367    None,
368
369    /// Have the Starnix runner proxy events such that the container
370    /// will wake up if events are received while the container is
371    /// suspended.
372    WakeContainer,
373}
374
375fn connect_to_device(
376    proxy: AdbProxyMode,
377) -> Result<
378    (fadb::DeviceSynchronousProxy, fadb::UsbAdbImpl_SynchronousProxy, Option<zx::Counter>),
379    Errno,
380> {
381    let mut dir = std::fs::read_dir(ADB_DIRECTORY).map_err(|_| errno!(EINVAL))?;
382
383    let Some(Ok(entry)) = dir.next() else {
384        return error!(EBUSY);
385    };
386    let path =
387        entry.path().join("adb").into_os_string().into_string().map_err(|_| errno!(EINVAL))?;
388
389    let (client_channel, server_channel) = zx::Channel::create();
390    fdio::service_connect(&path, server_channel).map_err(|_| errno!(EINVAL))?;
391    let device_proxy = fadb::DeviceSynchronousProxy::new(client_channel);
392
393    let (adb_proxy, server_end) = fidl::endpoints::create_sync_proxy::<fadb::UsbAdbImpl_Marker>();
394    let (adb_proxy, message_counter) = match proxy {
395        AdbProxyMode::None => (adb_proxy, None),
396        AdbProxyMode::WakeContainer => {
397            let (adb_proxy, message_counter) = create_proxy_for_wake_events_counter_zero(
398                adb_proxy.into_channel(),
399                "adb".to_string(),
400            );
401            let adb_proxy = fadb::UsbAdbImpl_SynchronousProxy::from_channel(adb_proxy);
402            (adb_proxy, Some(message_counter))
403        }
404    };
405
406    device_proxy
407        .start_adb(server_end, zx::MonotonicInstant::INFINITE)
408        .map_err(|_| errno!(EINVAL))?
409        .map_err(|_| errno!(EINVAL))?;
410    return Ok((device_proxy, adb_proxy, message_counter));
411}
412
413#[derive(Default)]
414struct FunctionFsRootDir {
415    state: Arc<LockDepMutex<FunctionFsState, FunctionFsStateLock>>,
416}
417
418impl FunctionFsRootDir {
419    fn create_endpoints(&self, kernel: &Kernel) -> Result<(), Errno> {
420        let mut state = self.state.lock();
421
422        // create_endpoints can be called multiple times as descriptors are written
423        // to the control endpoint.
424        if state.has_input_output_endpoints {
425            return Ok(());
426        }
427        let (device_proxy, adb_proxy, message_counter) =
428            connect_to_device(AdbProxyMode::WakeContainer)?;
429        state.device_proxy = Some(device_proxy);
430
431        let (read_command_sender, read_command_receiver) = async_channel::unbounded();
432        state.adb_read_channel = Some(read_command_sender);
433
434        let (write_command_sender, write_command_receiver) = async_channel::unbounded();
435        state.adb_write_channel = Some(write_command_sender);
436
437        state.event_queue.clear();
438
439        let state_copy = Arc::clone(&self.state);
440        // Spawn our future that will handle all of the ADB messages.
441        // Spawn our future that will handle all of the ADB messages.
442        kernel.kthreads.spawn_future(
443            move || async move {
444                let adb_proxy = fadb::UsbAdbImpl_Proxy::new(fidl::AsyncChannel::from_channel(
445                    adb_proxy.into_channel(),
446                ));
447                handle_adb(
448                    adb_proxy,
449                    message_counter,
450                    read_command_receiver,
451                    write_command_receiver,
452                    state_copy,
453                )
454                .await
455            },
456            "functionfs_adb_worker",
457        );
458
459        state.has_input_output_endpoints = true;
460        Ok(())
461    }
462
463    fn from_fs(fs: &FileSystem) -> &Self {
464        fs.root()
465            .node
466            .downcast_ops::<FunctionFsRootDir>()
467            .expect("failed to downcast functionfs root dir")
468    }
469
470    fn from_file(file: &FileObject) -> &Self {
471        Self::from_fs(&file.fs)
472    }
473
474    fn on_control_opened(&self) {
475        let mut state = self.state.lock();
476        state.num_control_file_objects += 1;
477    }
478
479    fn on_control_closed(&self) {
480        let mut state = self.state.lock();
481        state.num_control_file_objects -= 1;
482        if state.num_control_file_objects == 0 {
483            // When all control endpoints are closed, the filesystem resets to its initial state.
484            if let Some(device_proxy) = state.device_proxy.as_ref() {
485                let _ = device_proxy
486                    .stop_adb(zx::MonotonicInstant::INFINITE)
487                    .map_err(|_| errno!(EINVAL));
488            }
489
490            state.has_input_output_endpoints = false;
491            state.is_online = false;
492            state.adb_read_channel = None;
493            state.adb_write_channel = None;
494        }
495    }
496
497    fn wait_until_online(
498        &self,
499        current_task: &CurrentTask,
500        file: &FileObject,
501    ) -> Result<(), Errno> {
502        loop {
503            let waiter = {
504                let state = self.state.lock();
505                if state.is_online {
506                    return Ok(());
507                }
508                if file.flags().contains(OpenFlags::NONBLOCK) {
509                    return error!(EAGAIN);
510                }
511                let waiter = Waiter::new();
512                state.waiters.wait_async(&waiter);
513                waiter
514            };
515            waiter.wait(current_task)?;
516        }
517    }
518
519    fn available(&self) -> usize {
520        let state = self.state.lock();
521        state.event_queue.len()
522    }
523
524    fn write(
525        &self,
526        current_task: &CurrentTask,
527        file: &FileObject,
528        bytes: &[u8],
529    ) -> Result<usize, Errno> {
530        self.wait_until_online(current_task, file)?;
531
532        let data = Vec::from(bytes);
533        let pending = Arc::<PendingResult<usize>>::default();
534        let guard = pending.event.begin_wait();
535
536        if let Some(channel) = self.state.lock().adb_write_channel.as_ref() {
537            channel
538                .send_blocking(WriteCommand { data, pending: pending.clone() })
539                .map_err(|_| errno!(EINVAL))?;
540        } else {
541            return error!(ENODEV);
542        }
543
544        current_task.block_until(guard, zx::MonotonicInstant::INFINITE)?;
545
546        let mut result = pending.result.lock();
547        result.take().ok_or_else(|| errno!(EINTR))?
548    }
549
550    fn read(&self, current_task: &CurrentTask, file: &FileObject) -> Result<Vec<u8>, Errno> {
551        self.wait_until_online(current_task, file)?;
552
553        let pending = Arc::<PendingResult<Vec<u8>>>::default();
554        let guard = pending.event.begin_wait();
555        if let Some(channel) = self.state.lock().adb_read_channel.as_ref() {
556            channel
557                .send_blocking(ReadCommand { pending: pending.clone() })
558                .map_err(|_| errno!(EINVAL))?;
559        } else {
560            return error!(ENODEV);
561        }
562
563        current_task.block_until(guard, zx::MonotonicInstant::INFINITE)?;
564
565        let mut result = pending.result.lock();
566        result.take().ok_or_else(|| errno!(EINTR))?
567    }
568}
569
570impl FsNodeOps for FunctionFsRootDir {
571    fs_node_impl_dir_readonly!();
572
573    fn create_file_ops(
574        &self,
575        _node: &FsNode,
576        _current_task: &CurrentTask,
577        _flags: OpenFlags,
578    ) -> Result<Box<dyn FileOps>, Errno> {
579        let mut entries = vec![];
580        entries.push(VecDirectoryEntry {
581            entry_type: DirectoryEntryType::REG,
582            name: CONTROL_ENDPOINT.into(),
583            inode: Some(CONTROL_ENDPOINT_NODE_ID),
584        });
585
586        let state = self.state.lock();
587        if state.has_input_output_endpoints {
588            entries.push(VecDirectoryEntry {
589                entry_type: DirectoryEntryType::REG,
590                name: INPUT_ENDPOINT.into(),
591                inode: Some(INPUT_ENDPOINT_NODE_ID),
592            });
593            entries.push(VecDirectoryEntry {
594                entry_type: DirectoryEntryType::REG,
595                name: OUTPUT_ENDPOINT.into(),
596                inode: Some(OUTPUT_ENDPOINT_NODE_ID),
597            });
598        }
599
600        Ok(VecDirectory::new_file(entries))
601    }
602
603    fn lookup(
604        &self,
605        node: &FsNode,
606        _current_task: &CurrentTask,
607        name: &FsStr,
608    ) -> Result<starnix_core::vfs::FsNodeHandle, Errno> {
609        let name = std::str::from_utf8(name).map_err(|_| errno!(ENOENT))?;
610        let cred = node.info().cred();
611        match name {
612            CONTROL_ENDPOINT => Ok(node.fs().create_node(
613                CONTROL_ENDPOINT_NODE_ID,
614                FunctionFsControlEndpoint,
615                FsNodeInfo::new(mode!(IFREG, 0o600), cred),
616            )),
617            OUTPUT_ENDPOINT => Ok(node.fs().create_node(
618                OUTPUT_ENDPOINT_NODE_ID,
619                FunctionFsOutputEndpoint,
620                FsNodeInfo::new(mode!(IFREG, 0o600), cred),
621            )),
622            INPUT_ENDPOINT => Ok(node.fs().create_node(
623                INPUT_ENDPOINT_NODE_ID,
624                FunctionFsInputEndpoint,
625                FsNodeInfo::new(mode!(IFREG, 0o600), cred),
626            )),
627            _ => error!(ENOENT),
628        }
629    }
630}
631
632// FunctionFS Control Endpoint is both readable and writable.
633// Clients should write USB descriptors to the endpoint to setup the USB connection.
634// Clients can read `usb_functionfs_event`s to know about the USB connection state.
635struct FunctionFsControlEndpoint;
636impl FsNodeOps for FunctionFsControlEndpoint {
637    fs_node_impl_not_dir!();
638
639    fn create_file_ops(
640        &self,
641        node: &FsNode,
642        _current_task: &CurrentTask,
643        _flags: OpenFlags,
644    ) -> Result<Box<dyn FileOps>, Errno> {
645        let fs = node.fs();
646        let rootdir = fs
647            .root()
648            .node
649            .downcast_ops::<FunctionFsRootDir>()
650            .expect("failed to downcast functionfs root dir");
651        rootdir.on_control_opened();
652        Ok(Box::new(FunctionFsControlEndpoint))
653    }
654}
655
656impl FileOps for FunctionFsControlEndpoint {
657    fileops_impl_seekless!();
658    fileops_impl_noop_sync!();
659
660    fn close(self: Box<Self>, file: &FileObjectState, _current_task: &CurrentTask) {
661        let rootdir = FunctionFsRootDir::from_fs(&file.fs);
662        rootdir.on_control_closed();
663    }
664
665    fn read(
666        &self,
667        file: &FileObject,
668        _current_task: &CurrentTask,
669        _offset: usize,
670        data: &mut dyn OutputBuffer,
671    ) -> Result<usize, Errno> {
672        // The control endpoint does not currently implement blocking read.
673        // ADB would only read from this endpoint after polling it.
674        track_stub!(
675            TODO("https://fxbug.dev/329699340"),
676            "FunctionFS blocking read on control endpoint"
677        );
678
679        let rootdir = FunctionFsRootDir::from_file(file);
680
681        let mut state = rootdir.state.lock();
682        if !state.event_queue.is_empty() {
683            if data.available() < std::mem::size_of::<usb_functionfs_event>() {
684                return error!(EINVAL);
685            }
686        } else {
687            return error!(EAGAIN);
688        }
689        let front = state.event_queue.pop_front().expect("pop from non-empty event queue");
690        data.write(front.as_bytes())
691    }
692
693    fn write(
694        &self,
695        file: &FileObject,
696        current_task: &CurrentTask,
697        _offset: usize,
698        data: &mut dyn InputBuffer,
699    ) -> Result<usize, Errno> {
700        // The ADB driver creates and passes its own descriptors to the host system over the wire,
701        // and so, Starnix does not need to parse the descriptors that Android sends.
702        // Here we directly attempt to connect to the driver via FIDL, and create endpoints for data transfer.
703        track_stub!(TODO("https://fxbug.dev/329699340"), "FunctionFS should parse descriptors");
704
705        let rootdir = FunctionFsRootDir::from_file(file);
706        rootdir.create_endpoints(current_task.kernel().deref())?;
707
708        Ok(data.drain())
709    }
710
711    fn wait_async(
712        &self,
713        file: &FileObject,
714        _current_task: &CurrentTask,
715        waiter: &Waiter,
716        events: FdEvents,
717        handler: EventHandler,
718    ) -> Option<WaitCanceler> {
719        let rootdir = FunctionFsRootDir::from_file(file);
720        let state = rootdir.state.lock();
721        Some(state.waiters.wait_async_fd_events(waiter, events, handler))
722    }
723
724    fn query_events(
725        &self,
726        file: &FileObject,
727        _current_task: &CurrentTask,
728    ) -> Result<FdEvents, Errno> {
729        let rootdir = FunctionFsRootDir::from_file(file);
730        if rootdir.available() > 0 { Ok(FdEvents::POLLIN) } else { Ok(FdEvents::empty()) }
731    }
732}
733
734// FunctionFSInputEndpoint is device to host communication, a.k.a. the "IN" USB direction.
735// This endpoint is writable, and not readable.
736struct FunctionFsInputEndpoint;
737impl FsNodeOps for FunctionFsInputEndpoint {
738    fs_node_impl_not_dir!();
739
740    fn create_file_ops(
741        &self,
742        _node: &FsNode,
743        _current_task: &CurrentTask,
744        _flags: OpenFlags,
745    ) -> Result<Box<dyn FileOps>, Errno> {
746        Ok(Box::new(FunctionFsInputEndpoint))
747    }
748}
749
750impl FileOps for FunctionFsInputEndpoint {
751    fileops_impl_seekless!();
752    fileops_impl_noop_sync!();
753
754    fn read(
755        &self,
756        _file: &FileObject,
757        _current_task: &CurrentTask,
758        _offset: usize,
759        _data: &mut dyn OutputBuffer,
760    ) -> Result<usize, Errno> {
761        error!(EINVAL)
762    }
763
764    fn write(
765        &self,
766        file: &FileObject,
767        current_task: &CurrentTask,
768        _offset: usize,
769        data: &mut dyn InputBuffer,
770    ) -> Result<usize, Errno> {
771        let bytes = data.read_all()?;
772        let rootdir = FunctionFsRootDir::from_file(file);
773        rootdir.write(current_task, file, &bytes)
774    }
775}
776
777// FunctionFSOutputEndpoint is host to device communication, a.k.a. the "OUT" USB direction.
778// This endpoint is readable, and not writable.
779struct FunctionFsOutputEndpoint;
780impl FsNodeOps for FunctionFsOutputEndpoint {
781    fs_node_impl_not_dir!();
782
783    fn create_file_ops(
784        &self,
785        _node: &FsNode,
786        _current_task: &CurrentTask,
787        _flags: OpenFlags,
788    ) -> Result<Box<dyn FileOps>, Errno> {
789        Ok(Box::new(FunctionFsOutputFileObject))
790    }
791}
792
793struct FunctionFsOutputFileObject;
794
795impl FileOps for FunctionFsOutputFileObject {
796    fileops_impl_seekless!();
797    fileops_impl_noop_sync!();
798
799    fn read(
800        &self,
801        file: &FileObject,
802        current_task: &CurrentTask,
803        _offset: usize,
804        data: &mut dyn OutputBuffer,
805    ) -> Result<usize, Errno> {
806        let rootdir = FunctionFsRootDir::from_file(file);
807        let payload = rootdir.read(current_task, file)?;
808        if payload.len() > data.available() {
809            // This means the data will only be partially written, with the rest discarded.
810            // Instead of attempting this, we'll instead return error to the client.
811            return error!(EINVAL);
812        }
813
814        data.write(&payload)
815    }
816
817    fn write(
818        &self,
819        _file: &FileObject,
820        _current_task: &CurrentTask,
821        _offset: usize,
822        _data: &mut dyn InputBuffer,
823    ) -> Result<usize, Errno> {
824        error!(EINVAL)
825    }
826}