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                        log_warn!("Failed to call UsbAdbImpl.Receive: {err}");
204                        error!(EINVAL)
205                    }
206                    Ok(Err(err)) => {
207                        let status = zx::Status::from_raw(err);
208                        if matches!(
209                            status,
210                            zx::Status::BAD_STATE | zx::Status::CANCELED | zx::Status::PEER_CLOSED
211                        ) {
212                            log_info!("Receive failed due to connection shutdown: {status}");
213                        } else {
214                            log_warn!("Failed to receive data from adb driver: {status}");
215                        }
216                        // TODO(b/536021189): Fix POSIX error mapping. We should return ESHUTDOWN
217                        // on endpoint disable.
218                        error!(EINVAL)
219                    }
220                    Ok(Ok(payload)) => Ok(payload),
221                };
222
223                pending.set_result(response);
224            })
225            .await;
226    }
227
228    /// Handle the commands coming from the main thread.
229    async fn handle_write_commands(
230        proxy: &fadb::UsbAdbImpl_Proxy,
231        timeouts_sender: async_channel::Sender<zx::MonotonicInstant>,
232        commands: async_channel::Receiver<WriteCommand>,
233    ) {
234        let timeouts_sender = &timeouts_sender;
235        commands
236            .for_each(|WriteCommand { data, pending }| async move {
237                let response = match proxy.queue_tx(&data).await {
238                    Err(err) => {
239                        log_warn!("Failed to call UsbAdbImpl.QueueTx: {err}");
240                        error!(EINVAL)
241                    }
242                    Ok(Err(err)) => {
243                        log_warn!("Failed to queue data to adb driver: {err}");
244                        error!(EINVAL)
245                    }
246                    Ok(Ok(_)) => Ok(data.len()),
247                };
248
249                // Don't decrement the message counter immediately. We use the
250                // ADB output as a signal that the ADB session is still
251                // interactive.
252                timeouts_sender
253                    .send(zx::MonotonicInstant::after(ADB_INTERACTION_TIMEOUT))
254                    .await
255                    .expect("Should be able to send timeout");
256
257                pending.set_result(response);
258            })
259            .await;
260    }
261
262    let (timeouts_sender, timeouts_receiver) = async_channel::unbounded();
263    let event_future = handle_events(proxy.take_event_stream(), &message_counter, state);
264    let write_commands_future =
265        handle_write_commands(&proxy, timeouts_sender.clone(), write_commands);
266    let read_commands_future = handle_read_commands(&proxy, timeouts_sender, read_commands);
267    let timeout_future = handle_idle_timeouts(timeouts_receiver, &message_counter);
268    futures::join!(event_future, write_commands_future, read_commands_future, timeout_future);
269}
270
271pub struct FunctionFs;
272impl FunctionFs {
273    pub fn new_fs(
274        current_task: &CurrentTask,
275        options: FileSystemOptions,
276    ) -> Result<FileSystemHandle, Errno> {
277        if options.source != "adb" {
278            track_stub!(TODO("https://fxbug.dev/329699340"), "FunctionFS supports other uses");
279            return error!(ENODEV);
280        }
281
282        // ADB daemon assumes that ADB works over USB if FunctionFS is able to mount.
283        // Check that the ADB directory capability is provided to the kernel, and fail to mount
284        // if it is not.
285        if let Err(e) = std::fs::read_dir(ADB_DIRECTORY) {
286            log_warn!(
287                "Attempted to mount FunctionFS for adb, but could not read {ADB_DIRECTORY}: {e}"
288            );
289            return error!(ENODEV);
290        }
291
292        let uid = if let Some(uid) = options.params.get(b"uid") {
293            fs_args::parse::<uid_t>(uid.as_ref())?
294        } else {
295            0
296        };
297        let gid = if let Some(gid) = options.params.get(b"gid") {
298            fs_args::parse::<gid_t>(gid.as_ref())?
299        } else {
300            0
301        };
302
303        let fs = FileSystem::new(current_task.kernel(), CacheMode::Uncached, FunctionFs, options)?;
304
305        let creds = FsCred { uid, gid };
306        let info = FsNodeInfo::new(mode!(IFDIR, 0o777), creds);
307        fs.create_root_with_info(ROOT_NODE_ID, FunctionFsRootDir::default(), info);
308        Ok(fs)
309    }
310}
311
312impl FileSystemOps for FunctionFs {
313    fn statfs(&self, _fs: &FileSystem, _current_task: &CurrentTask) -> Result<statfs, Errno> {
314        Ok(default_statfs(FUNCTIONFS_MAGIC))
315    }
316
317    fn name(&self) -> &'static FsStr {
318        b"functionfs".into()
319    }
320}
321
322#[derive(Default)]
323struct FunctionFsState {
324    // Keeps track of the number of FileObject's created for the control endpoint.
325    // When all FileObjects are closed, the filesystem resets to its initial state.
326    // See https://docs.kernel.org/usb/functionfs.html.
327    num_control_file_objects: usize,
328
329    // Whether the FunctionFS has input/output endpoints, which are /ep2 and /ep1
330    // respectively. /ep0 is the control endpoint and is always available.
331    has_input_output_endpoints: bool,
332
333    // Whether the FunctionFS is currently online (host connected).
334    is_online: bool,
335
336    adb_read_channel: Option<async_channel::Sender<ReadCommand>>,
337    adb_write_channel: Option<async_channel::Sender<WriteCommand>>,
338
339    // FIDL binding to the adb driver, for start and stop calls.
340    device_proxy: Option<fadb::DeviceSynchronousProxy>,
341
342    // FunctionFs events that indicate the connection state, to be read through
343    // the control endpoint.
344    event_queue: VecDeque<usb_functionfs_event>,
345
346    waiters: WaitQueue,
347}
348
349pub enum AdbProxyMode {
350    /// Don't proxy events at all.
351    None,
352
353    /// Have the Starnix runner proxy events such that the container
354    /// will wake up if events are received while the container is
355    /// suspended.
356    WakeContainer,
357}
358
359fn connect_to_device(
360    proxy: AdbProxyMode,
361) -> Result<
362    (fadb::DeviceSynchronousProxy, fadb::UsbAdbImpl_SynchronousProxy, Option<zx::Counter>),
363    Errno,
364> {
365    let mut dir = std::fs::read_dir(ADB_DIRECTORY).map_err(|_| errno!(EINVAL))?;
366
367    let Some(Ok(entry)) = dir.next() else {
368        return error!(EBUSY);
369    };
370    let path =
371        entry.path().join("adb").into_os_string().into_string().map_err(|_| errno!(EINVAL))?;
372
373    let (client_channel, server_channel) = zx::Channel::create();
374    fdio::service_connect(&path, server_channel).map_err(|_| errno!(EINVAL))?;
375    let device_proxy = fadb::DeviceSynchronousProxy::new(client_channel);
376
377    let (adb_proxy, server_end) = fidl::endpoints::create_sync_proxy::<fadb::UsbAdbImpl_Marker>();
378    let (adb_proxy, message_counter) = match proxy {
379        AdbProxyMode::None => (adb_proxy, None),
380        AdbProxyMode::WakeContainer => {
381            let (adb_proxy, message_counter) = create_proxy_for_wake_events_counter_zero(
382                adb_proxy.into_channel(),
383                "adb".to_string(),
384            );
385            let adb_proxy = fadb::UsbAdbImpl_SynchronousProxy::from_channel(adb_proxy);
386            (adb_proxy, Some(message_counter))
387        }
388    };
389
390    device_proxy
391        .start_adb(server_end, zx::MonotonicInstant::INFINITE)
392        .map_err(|_| errno!(EINVAL))?
393        .map_err(|_| errno!(EINVAL))?;
394    return Ok((device_proxy, adb_proxy, message_counter));
395}
396
397#[derive(Default)]
398struct FunctionFsRootDir {
399    state: Arc<LockDepMutex<FunctionFsState, FunctionFsStateLock>>,
400}
401
402impl FunctionFsRootDir {
403    fn create_endpoints(&self, kernel: &Kernel) -> Result<(), Errno> {
404        let mut state = self.state.lock();
405
406        // create_endpoints can be called multiple times as descriptors are written
407        // to the control endpoint.
408        if state.has_input_output_endpoints {
409            return Ok(());
410        }
411        let (device_proxy, adb_proxy, message_counter) =
412            connect_to_device(AdbProxyMode::WakeContainer)?;
413        state.device_proxy = Some(device_proxy);
414
415        let (read_command_sender, read_command_receiver) = async_channel::unbounded();
416        state.adb_read_channel = Some(read_command_sender);
417
418        let (write_command_sender, write_command_receiver) = async_channel::unbounded();
419        state.adb_write_channel = Some(write_command_sender);
420
421        state.event_queue.clear();
422
423        let state_copy = Arc::clone(&self.state);
424        // Spawn our future that will handle all of the ADB messages.
425        // Spawn our future that will handle all of the ADB messages.
426        kernel.kthreads.spawn_future(
427            move || async move {
428                let adb_proxy = fadb::UsbAdbImpl_Proxy::new(fidl::AsyncChannel::from_channel(
429                    adb_proxy.into_channel(),
430                ));
431                handle_adb(
432                    adb_proxy,
433                    message_counter,
434                    read_command_receiver,
435                    write_command_receiver,
436                    state_copy,
437                )
438                .await
439            },
440            "functionfs_adb_worker",
441        );
442
443        state.has_input_output_endpoints = true;
444        Ok(())
445    }
446
447    fn from_fs(fs: &FileSystem) -> &Self {
448        fs.root()
449            .node
450            .downcast_ops::<FunctionFsRootDir>()
451            .expect("failed to downcast functionfs root dir")
452    }
453
454    fn from_file(file: &FileObject) -> &Self {
455        Self::from_fs(&file.fs)
456    }
457
458    fn on_control_opened(&self) {
459        let mut state = self.state.lock();
460        state.num_control_file_objects += 1;
461    }
462
463    fn on_control_closed(&self) {
464        let mut state = self.state.lock();
465        state.num_control_file_objects -= 1;
466        if state.num_control_file_objects == 0 {
467            // When all control endpoints are closed, the filesystem resets to its initial state.
468            if let Some(device_proxy) = state.device_proxy.as_ref() {
469                let _ = device_proxy
470                    .stop_adb(zx::MonotonicInstant::INFINITE)
471                    .map_err(|_| errno!(EINVAL));
472            }
473
474            state.has_input_output_endpoints = false;
475            state.is_online = false;
476            state.adb_read_channel = None;
477            state.adb_write_channel = None;
478        }
479    }
480
481    fn wait_until_online(
482        &self,
483        current_task: &CurrentTask,
484        file: &FileObject,
485    ) -> Result<(), Errno> {
486        loop {
487            let waiter = {
488                let state = self.state.lock();
489                if state.is_online {
490                    return Ok(());
491                }
492                if file.flags().contains(OpenFlags::NONBLOCK) {
493                    return error!(EAGAIN);
494                }
495                let waiter = Waiter::new();
496                state.waiters.wait_async(&waiter);
497                waiter
498            };
499            waiter.wait(current_task)?;
500        }
501    }
502
503    fn available(&self) -> usize {
504        let state = self.state.lock();
505        state.event_queue.len()
506    }
507
508    fn write(
509        &self,
510        current_task: &CurrentTask,
511        file: &FileObject,
512        bytes: &[u8],
513    ) -> Result<usize, Errno> {
514        self.wait_until_online(current_task, file)?;
515
516        let data = Vec::from(bytes);
517        let pending = Arc::<PendingResult<usize>>::default();
518        let guard = pending.event.begin_wait();
519
520        if let Some(channel) = self.state.lock().adb_write_channel.as_ref() {
521            channel
522                .send_blocking(WriteCommand { data, pending: pending.clone() })
523                .map_err(|_| errno!(EINVAL))?;
524        } else {
525            return error!(ENODEV);
526        }
527
528        current_task.block_until(guard, zx::MonotonicInstant::INFINITE)?;
529
530        let mut result = pending.result.lock();
531        result.take().ok_or_else(|| errno!(EINTR))?
532    }
533
534    fn read(&self, current_task: &CurrentTask, file: &FileObject) -> Result<Vec<u8>, Errno> {
535        self.wait_until_online(current_task, file)?;
536
537        let pending = Arc::<PendingResult<Vec<u8>>>::default();
538        let guard = pending.event.begin_wait();
539        if let Some(channel) = self.state.lock().adb_read_channel.as_ref() {
540            channel
541                .send_blocking(ReadCommand { pending: pending.clone() })
542                .map_err(|_| errno!(EINVAL))?;
543        } else {
544            return error!(ENODEV);
545        }
546
547        current_task.block_until(guard, zx::MonotonicInstant::INFINITE)?;
548
549        let mut result = pending.result.lock();
550        result.take().ok_or_else(|| errno!(EINTR))?
551    }
552}
553
554impl FsNodeOps for FunctionFsRootDir {
555    fs_node_impl_dir_readonly!();
556
557    fn create_file_ops(
558        &self,
559        _node: &FsNode,
560        _current_task: &CurrentTask,
561        _flags: OpenFlags,
562    ) -> Result<Box<dyn FileOps>, Errno> {
563        let mut entries = vec![];
564        entries.push(VecDirectoryEntry {
565            entry_type: DirectoryEntryType::REG,
566            name: CONTROL_ENDPOINT.into(),
567            inode: Some(CONTROL_ENDPOINT_NODE_ID),
568        });
569
570        let state = self.state.lock();
571        if state.has_input_output_endpoints {
572            entries.push(VecDirectoryEntry {
573                entry_type: DirectoryEntryType::REG,
574                name: INPUT_ENDPOINT.into(),
575                inode: Some(INPUT_ENDPOINT_NODE_ID),
576            });
577            entries.push(VecDirectoryEntry {
578                entry_type: DirectoryEntryType::REG,
579                name: OUTPUT_ENDPOINT.into(),
580                inode: Some(OUTPUT_ENDPOINT_NODE_ID),
581            });
582        }
583
584        Ok(VecDirectory::new_file(entries))
585    }
586
587    fn lookup(
588        &self,
589        node: &FsNode,
590        _current_task: &CurrentTask,
591        name: &FsStr,
592    ) -> Result<starnix_core::vfs::FsNodeHandle, Errno> {
593        let name = std::str::from_utf8(name).map_err(|_| errno!(ENOENT))?;
594        let cred = node.info().cred();
595        match name {
596            CONTROL_ENDPOINT => Ok(node.fs().create_node(
597                CONTROL_ENDPOINT_NODE_ID,
598                FunctionFsControlEndpoint,
599                FsNodeInfo::new(mode!(IFREG, 0o600), cred),
600            )),
601            OUTPUT_ENDPOINT => Ok(node.fs().create_node(
602                OUTPUT_ENDPOINT_NODE_ID,
603                FunctionFsOutputEndpoint,
604                FsNodeInfo::new(mode!(IFREG, 0o600), cred),
605            )),
606            INPUT_ENDPOINT => Ok(node.fs().create_node(
607                INPUT_ENDPOINT_NODE_ID,
608                FunctionFsInputEndpoint,
609                FsNodeInfo::new(mode!(IFREG, 0o600), cred),
610            )),
611            _ => error!(ENOENT),
612        }
613    }
614}
615
616// FunctionFS Control Endpoint is both readable and writable.
617// Clients should write USB descriptors to the endpoint to setup the USB connection.
618// Clients can read `usb_functionfs_event`s to know about the USB connection state.
619struct FunctionFsControlEndpoint;
620impl FsNodeOps for FunctionFsControlEndpoint {
621    fs_node_impl_not_dir!();
622
623    fn create_file_ops(
624        &self,
625        node: &FsNode,
626        _current_task: &CurrentTask,
627        _flags: OpenFlags,
628    ) -> Result<Box<dyn FileOps>, Errno> {
629        let fs = node.fs();
630        let rootdir = fs
631            .root()
632            .node
633            .downcast_ops::<FunctionFsRootDir>()
634            .expect("failed to downcast functionfs root dir");
635        rootdir.on_control_opened();
636        Ok(Box::new(FunctionFsControlEndpoint))
637    }
638}
639
640impl FileOps for FunctionFsControlEndpoint {
641    fileops_impl_seekless!();
642    fileops_impl_noop_sync!();
643
644    fn close(self: Box<Self>, file: &FileObjectState, _current_task: &CurrentTask) {
645        let rootdir = FunctionFsRootDir::from_fs(&file.fs);
646        rootdir.on_control_closed();
647    }
648
649    fn read(
650        &self,
651        file: &FileObject,
652        _current_task: &CurrentTask,
653        _offset: usize,
654        data: &mut dyn OutputBuffer,
655    ) -> Result<usize, Errno> {
656        // The control endpoint does not currently implement blocking read.
657        // ADB would only read from this endpoint after polling it.
658        track_stub!(
659            TODO("https://fxbug.dev/329699340"),
660            "FunctionFS blocking read on control endpoint"
661        );
662
663        let rootdir = FunctionFsRootDir::from_file(file);
664
665        let mut state = rootdir.state.lock();
666        if !state.event_queue.is_empty() {
667            if data.available() < std::mem::size_of::<usb_functionfs_event>() {
668                return error!(EINVAL);
669            }
670        } else {
671            return error!(EAGAIN);
672        }
673        let front = state.event_queue.pop_front().expect("pop from non-empty event queue");
674        data.write(front.as_bytes())
675    }
676
677    fn write(
678        &self,
679        file: &FileObject,
680        current_task: &CurrentTask,
681        _offset: usize,
682        data: &mut dyn InputBuffer,
683    ) -> Result<usize, Errno> {
684        // The ADB driver creates and passes its own descriptors to the host system over the wire,
685        // and so, Starnix does not need to parse the descriptors that Android sends.
686        // Here we directly attempt to connect to the driver via FIDL, and create endpoints for data transfer.
687        track_stub!(TODO("https://fxbug.dev/329699340"), "FunctionFS should parse descriptors");
688
689        let rootdir = FunctionFsRootDir::from_file(file);
690        rootdir.create_endpoints(current_task.kernel().deref())?;
691
692        Ok(data.drain())
693    }
694
695    fn wait_async(
696        &self,
697        file: &FileObject,
698        _current_task: &CurrentTask,
699        waiter: &Waiter,
700        events: FdEvents,
701        handler: EventHandler,
702    ) -> Option<WaitCanceler> {
703        let rootdir = FunctionFsRootDir::from_file(file);
704        let state = rootdir.state.lock();
705        Some(state.waiters.wait_async_fd_events(waiter, events, handler))
706    }
707
708    fn query_events(
709        &self,
710        file: &FileObject,
711        _current_task: &CurrentTask,
712    ) -> Result<FdEvents, Errno> {
713        let rootdir = FunctionFsRootDir::from_file(file);
714        if rootdir.available() > 0 { Ok(FdEvents::POLLIN) } else { Ok(FdEvents::empty()) }
715    }
716}
717
718// FunctionFSInputEndpoint is device to host communication, a.k.a. the "IN" USB direction.
719// This endpoint is writable, and not readable.
720struct FunctionFsInputEndpoint;
721impl FsNodeOps for FunctionFsInputEndpoint {
722    fs_node_impl_not_dir!();
723
724    fn create_file_ops(
725        &self,
726        _node: &FsNode,
727        _current_task: &CurrentTask,
728        _flags: OpenFlags,
729    ) -> Result<Box<dyn FileOps>, Errno> {
730        Ok(Box::new(FunctionFsInputEndpoint))
731    }
732}
733
734impl FileOps for FunctionFsInputEndpoint {
735    fileops_impl_seekless!();
736    fileops_impl_noop_sync!();
737
738    fn read(
739        &self,
740        _file: &FileObject,
741        _current_task: &CurrentTask,
742        _offset: usize,
743        _data: &mut dyn OutputBuffer,
744    ) -> Result<usize, Errno> {
745        error!(EINVAL)
746    }
747
748    fn write(
749        &self,
750        file: &FileObject,
751        current_task: &CurrentTask,
752        _offset: usize,
753        data: &mut dyn InputBuffer,
754    ) -> Result<usize, Errno> {
755        let bytes = data.read_all()?;
756        let rootdir = FunctionFsRootDir::from_file(file);
757        rootdir.write(current_task, file, &bytes)
758    }
759}
760
761// FunctionFSOutputEndpoint is host to device communication, a.k.a. the "OUT" USB direction.
762// This endpoint is readable, and not writable.
763struct FunctionFsOutputEndpoint;
764impl FsNodeOps for FunctionFsOutputEndpoint {
765    fs_node_impl_not_dir!();
766
767    fn create_file_ops(
768        &self,
769        _node: &FsNode,
770        _current_task: &CurrentTask,
771        _flags: OpenFlags,
772    ) -> Result<Box<dyn FileOps>, Errno> {
773        Ok(Box::new(FunctionFsOutputFileObject))
774    }
775}
776
777struct FunctionFsOutputFileObject;
778
779impl FileOps for FunctionFsOutputFileObject {
780    fileops_impl_seekless!();
781    fileops_impl_noop_sync!();
782
783    fn read(
784        &self,
785        file: &FileObject,
786        current_task: &CurrentTask,
787        _offset: usize,
788        data: &mut dyn OutputBuffer,
789    ) -> Result<usize, Errno> {
790        let rootdir = FunctionFsRootDir::from_file(file);
791        let payload = rootdir.read(current_task, file)?;
792        if payload.len() > data.available() {
793            // This means the data will only be partially written, with the rest discarded.
794            // Instead of attempting this, we'll instead return error to the client.
795            return error!(EINVAL);
796        }
797
798        data.write(&payload)
799    }
800
801    fn write(
802        &self,
803        _file: &FileObject,
804        _current_task: &CurrentTask,
805        _offset: usize,
806        _data: &mut dyn InputBuffer,
807    ) -> Result<usize, Errno> {
808        error!(EINVAL)
809    }
810}