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