1#![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
37const ROOT_NODE_ID: ino_t = 1;
39
40const 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
50const FUNCTIONFS_MAGIC: u32 = 0xa647361;
53
54const ADB_DIRECTORY: &str = "/svc/fuchsia.hardware.adb.Service";
55
56const 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
69async 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 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 message_counter.as_ref().map(mark_proxy_message_handled);
126 }
127
128 queue_event(usb_functionfs_event_type_FUNCTIONFS_UNBIND);
129 }
130
131 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 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 let receive_future = proxy.receive();
164
165 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 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 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 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 num_control_file_objects: usize,
309
310 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 device_proxy: Option<fadb::DeviceSynchronousProxy>,
319
320 event_queue: VecDeque<usb_functionfs_event>,
323
324 waiters: WaitQueue,
325}
326
327pub enum AdbProxyMode {
328 None,
330
331 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 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 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 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
550struct 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 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 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
662struct 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
708struct 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 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}