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