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