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