1#![recursion_limit = "256"]
6
7use fidl::endpoints::Proxy as _;
8use fidl_fuchsia_hardware_adb as fadb;
9use fuchsia_async as fasync;
10use fuchsia_component::client::Service;
11use fuchsia_inspect as inspect;
12use futures::{FutureExt, StreamExt, pin_mut};
13use futures_util as _;
14use starnix_core::power::{create_proxy_for_wake_events_counter_zero, mark_proxy_message_handled};
15use starnix_core::task::{CurrentTask, EventHandler, Kernel, WaitCanceler, WaitQueue, Waiter};
16use starnix_core::vfs::pseudo::vec_directory::{VecDirectory, VecDirectoryEntry};
17use starnix_core::vfs::{
18 CacheMode, DirEntry, DirectoryEntryType, FileObject, FileObjectState, FileOps, FileSystem,
19 FileSystemHandle, FileSystemOps, FileSystemOptions, FsNode, FsNodeInfo, FsNodeOps, FsStr,
20 InputBuffer, OutputBuffer, fileops_impl_noop_sync, fileops_impl_seekless, fs_args,
21 fs_node_impl_dir_readonly, fs_node_impl_not_dir,
22};
23use starnix_logging::{log_info, log_warn, track_stub};
24use starnix_sync::{FunctionFsResultLock, FunctionFsStateLock, InterruptibleEvent, LockDepMutex};
25use starnix_types::vfs::default_statfs;
26use starnix_uapi::auth::FsCred;
27use starnix_uapi::errors::Errno;
28use starnix_uapi::file_mode::mode;
29use starnix_uapi::open_flags::OpenFlags;
30use starnix_uapi::vfs::FdEvents;
31use starnix_uapi::{
32 errno, error, gid_t, ino_t, statfs, uid_t, usb_functionfs_event,
33 usb_functionfs_event_type_FUNCTIONFS_BIND, usb_functionfs_event_type_FUNCTIONFS_DISABLE,
34 usb_functionfs_event_type_FUNCTIONFS_ENABLE, usb_functionfs_event_type_FUNCTIONFS_UNBIND,
35};
36use std::borrow::Cow;
37use std::collections::VecDeque;
38use std::ops::Deref;
39use std::sync::Arc;
40use std::sync::atomic::{AtomicU64, Ordering};
41use zerocopy::IntoBytes;
42
43const ROOT_NODE_ID: ino_t = 1;
45
46const CONTROL_ENDPOINT: &str = "ep0";
48const CONTROL_ENDPOINT_NODE_ID: ino_t = 2;
49
50const OUTPUT_ENDPOINT: &str = "ep1";
51const OUTPUT_ENDPOINT_NODE_ID: ino_t = 3;
52
53const INPUT_ENDPOINT: &str = "ep2";
54const INPUT_ENDPOINT_NODE_ID: ino_t = 4;
55
56const FUNCTIONFS_MAGIC: u32 = 0xa647361;
59
60const ADB_DIRECTORY: &str = "/svc/fuchsia.hardware.adb.Service";
61
62const ADB_INTERACTION_TIMEOUT: zx::Duration<zx::MonotonicTimeline> = zx::Duration::from_seconds(2);
65
66#[derive(Default)]
67struct PendingResult<T: Default> {
68 event: Arc<InterruptibleEvent>,
69 result: LockDepMutex<Option<Result<T, Errno>>, FunctionFsResultLock>,
70}
71
72impl<T: Default> PendingResult<T> {
73 fn set_result(&self, res: Result<T, Errno>) {
74 let mut result = self.result.lock();
75 debug_assert!(result.is_none(), "PendingResult set more than once");
76
77 result.replace(res);
78 self.event.notify();
79 }
80}
81
82struct ReadCommand {
83 pending: Arc<PendingResult<Vec<u8>>>,
84}
85
86struct WriteCommand {
87 data: Vec<u8>,
88 pending: Arc<PendingResult<usize>>,
89}
90
91const MAX_INSPECT_EVENTS: usize = 32;
92
93#[derive(Clone)]
94struct EventRecord {
95 id: usize,
96 timestamp: zx::BootInstant,
97 event: Cow<'static, str>,
98}
99
100#[derive(Default)]
101struct FunctionFsStats {
102 ep1_total_bytes_read: AtomicU64,
103 ep1_read_count: AtomicU64,
104 ep1_read_errors: AtomicU64,
105 ep1_buffer_overflow_errors: AtomicU64,
106
107 ep2_total_bytes_written: AtomicU64,
108 ep2_write_count: AtomicU64,
109 ep2_write_errors: AtomicU64,
110}
111
112fn create_lazy_inspect_node(
113 parent: &inspect::Node,
114 state: &Arc<LockDepMutex<FunctionFsState, FunctionFsStateLock>>,
115 stats: &Arc<FunctionFsStats>,
116) -> inspect::LazyNode {
117 let state_weak = Arc::downgrade(state);
118 let stats_weak = Arc::downgrade(stats);
119 parent.create_lazy_child("usb-functionfs", move || {
120 let state_weak = state_weak.clone();
121 let stats_weak = stats_weak.clone();
122 Box::pin(async move {
123 let inspector = inspect::Inspector::default();
124 let root = inspector.root();
125
126 if let Some(state_arc) = state_weak.upgrade() {
127 let (
128 is_online,
129 num_open_file_objects,
130 event_queue_depth,
131 has_input_output_endpoints,
132 control_resets,
133 events,
134 ) = {
135 let state = state_arc.lock();
136 (
137 state.is_online,
138 state.num_open_file_objects as u64,
139 state.event_queue.len() as u64,
140 state.has_input_output_endpoints,
141 state.control_resets,
142 state.event_history.iter().cloned().collect::<Vec<_>>(),
143 )
144 };
145
146 root.record_bool("is_online", is_online);
147 root.record_uint("num_open_file_objects", num_open_file_objects);
148 root.record_uint("event_queue_depth", event_queue_depth);
149 root.record_bool("has_input_output_endpoints", has_input_output_endpoints);
150 root.record_uint("control_resets", control_resets);
151
152 root.record_child("event_history", |history_node| {
153 for record in events {
154 history_node.record_child(record.id.to_string(), |entry_node| {
155 entry_node.record_int("@time", record.timestamp.into_nanos());
156 entry_node.record_string("event", record.event.as_ref());
157 });
158 }
159 });
160 }
161
162 if let Some(stats) = stats_weak.upgrade() {
163 root.record_child("ep1_bulk_out", |ep1_node| {
164 ep1_node.record_uint(
165 "total_bytes_read",
166 stats.ep1_total_bytes_read.load(Ordering::Relaxed),
167 );
168 ep1_node
169 .record_uint("read_count", stats.ep1_read_count.load(Ordering::Relaxed));
170 ep1_node
171 .record_uint("read_errors", stats.ep1_read_errors.load(Ordering::Relaxed));
172 ep1_node.record_uint(
173 "buffer_overflow_errors",
174 stats.ep1_buffer_overflow_errors.load(Ordering::Relaxed),
175 );
176 });
177
178 root.record_child("ep2_bulk_in", |ep2_node| {
179 ep2_node.record_uint(
180 "total_bytes_written",
181 stats.ep2_total_bytes_written.load(Ordering::Relaxed),
182 );
183 ep2_node
184 .record_uint("write_count", stats.ep2_write_count.load(Ordering::Relaxed));
185 ep2_node.record_uint(
186 "write_errors",
187 stats.ep2_write_errors.load(Ordering::Relaxed),
188 );
189 });
190 }
191
192 Ok(inspector)
193 })
194 })
195}
196
197async fn handle_adb(
206 proxy: fadb::UsbAdbImpl_Proxy,
207 message_counter: Option<zx::Counter>,
208 read_commands: async_channel::Receiver<ReadCommand>,
209 write_commands: async_channel::Receiver<WriteCommand>,
210 state: Arc<LockDepMutex<FunctionFsState, FunctionFsStateLock>>,
211 stats: Arc<FunctionFsStats>,
212 session_id: u64,
213) {
214 async fn handle_events(
230 mut stream: fadb::UsbAdbImpl_EventStream,
231 message_counter: &Option<zx::Counter>,
232 state: Arc<LockDepMutex<FunctionFsState, FunctionFsStateLock>>,
233 session_id: u64,
234 ) {
235 while let Some(Ok(fadb::UsbAdbImpl_Event::OnStatusChanged { status })) = stream.next().await
236 {
237 let is_online = status == fadb::StatusFlags::ONLINE;
238 {
239 let mut state_locked = state.lock();
240 if state_locked.session_id != session_id {
241 return;
242 }
243 state_locked.is_online = is_online;
244 state_locked.event_queue.push_back(usb_functionfs_event {
245 type_: if is_online {
246 usb_functionfs_event_type_FUNCTIONFS_ENABLE
247 } else {
248 usb_functionfs_event_type_FUNCTIONFS_DISABLE
249 } as u8,
250 ..Default::default()
251 });
252 state_locked.record_event(if is_online { "ENABLE" } else { "DISABLE" });
253 state_locked.waiters.notify_fd_events(FdEvents::POLLIN);
254 state_locked.waiters.notify_all();
255 }
256
257 message_counter.as_ref().map(mark_proxy_message_handled);
261 }
262
263 let mut state_locked = state.lock();
264 if state_locked.session_id == session_id {
265 let _ = state_locked.device_proxy.take();
266 state_locked.is_online = false;
267 state_locked.has_input_output_endpoints = false;
268 state_locked.adb_read_channel = None;
269 state_locked.adb_write_channel = None;
270 state_locked.event_queue.push_back(usb_functionfs_event {
271 type_: usb_functionfs_event_type_FUNCTIONFS_UNBIND as u8,
272 ..Default::default()
273 });
274 state_locked.record_event("UNBIND");
275 state_locked.waiters.notify_fd_events(FdEvents::POLLIN);
276 state_locked.waiters.notify_all();
277 }
278 }
279
280 async fn handle_idle_timeouts(
289 timeouts: async_channel::Receiver<zx::MonotonicInstant>,
290 message_counter: &Option<zx::Counter>,
291 ) {
292 timeouts
293 .for_each(|timeout| async move {
294 use fasync::WakeupTime;
295 timeout.into_timer().await;
296 message_counter.as_ref().map(mark_proxy_message_handled);
297 })
298 .await
299 }
300
301 async fn handle_read_commands(
303 proxy: &fadb::UsbAdbImpl_Proxy,
304 timeouts_sender: async_channel::Sender<zx::MonotonicInstant>,
305 commands: async_channel::Receiver<ReadCommand>,
306 stats: &FunctionFsStats,
307 ) {
308 let timeouts_sender = &timeouts_sender;
309 commands
310 .for_each(|ReadCommand { pending }| async move {
311 let receive_future = proxy.receive();
314
315 timeouts_sender
320 .send(zx::MonotonicInstant::after(ADB_INTERACTION_TIMEOUT))
321 .await
322 .expect("Should be able to send timeout");
323
324 let response = match receive_future.await {
325 Err(err) => {
326 if err.is_closed() {
327 log_info!("Receive failed due to connection shutdown: {err}");
328 error!(ESHUTDOWN)
329 } else {
330 log_warn!("Failed to call UsbAdbImpl.Receive: {err}");
331 stats.ep1_read_errors.fetch_add(1, Ordering::Relaxed);
332 error!(EINVAL)
333 }
334 }
335 Ok(Err(err)) => {
336 let status = zx::Status::err_from_raw(err);
337 if matches!(
338 status,
339 zx::Status::BAD_STATE | zx::Status::CANCELED | zx::Status::PEER_CLOSED
340 ) {
341 log_info!("Receive failed due to connection shutdown: {status}");
342 error!(ESHUTDOWN)
343 } else {
344 log_warn!("Failed to receive data from adb driver: {status}");
345 stats.ep1_read_errors.fetch_add(1, Ordering::Relaxed);
346 error!(EINVAL)
347 }
348 }
349 Ok(Ok(payload)) => {
350 stats
351 .ep1_total_bytes_read
352 .fetch_add(payload.len() as u64, Ordering::Relaxed);
353 stats.ep1_read_count.fetch_add(1, Ordering::Relaxed);
354 Ok(payload)
355 }
356 };
357
358 pending.set_result(response);
359 })
360 .await;
361 }
362
363 async fn handle_write_commands(
365 proxy: &fadb::UsbAdbImpl_Proxy,
366 timeouts_sender: async_channel::Sender<zx::MonotonicInstant>,
367 commands: async_channel::Receiver<WriteCommand>,
368 stats: &FunctionFsStats,
369 ) {
370 let timeouts_sender = &timeouts_sender;
371 commands
372 .for_each(|WriteCommand { data, pending }| async move {
373 let response = match proxy.queue_tx(&data).await {
374 Err(err) => {
375 if err.is_closed() {
376 log_info!("QueueTx failed due to connection shutdown: {err}");
377 error!(ESHUTDOWN)
378 } else {
379 log_warn!("Failed to call UsbAdbImpl.QueueTx: {err}");
380 stats.ep2_write_errors.fetch_add(1, Ordering::Relaxed);
381 error!(EINVAL)
382 }
383 }
384 Ok(Err(err)) => {
385 let status = zx::Status::err_from_raw(err);
386 if matches!(
387 status,
388 zx::Status::BAD_STATE | zx::Status::CANCELED | zx::Status::PEER_CLOSED
389 ) {
390 log_info!("QueueTx failed due to connection shutdown: {status}");
391 error!(ESHUTDOWN)
392 } else {
393 log_warn!("Failed to queue data to adb driver: {status}");
394 stats.ep2_write_errors.fetch_add(1, Ordering::Relaxed);
395 error!(EINVAL)
396 }
397 }
398 Ok(Ok(_)) => {
399 stats
400 .ep2_total_bytes_written
401 .fetch_add(data.len() as u64, Ordering::Relaxed);
402 stats.ep2_write_count.fetch_add(1, Ordering::Relaxed);
403 Ok(data.len())
404 }
405 };
406
407 timeouts_sender
411 .send(zx::MonotonicInstant::after(ADB_INTERACTION_TIMEOUT))
412 .await
413 .expect("Should be able to send timeout");
414
415 pending.set_result(response);
416 })
417 .await;
418 }
419
420 let (timeouts_sender, timeouts_receiver) = async_channel::unbounded();
421 let event_future =
422 handle_events(proxy.take_event_stream(), &message_counter, state, session_id);
423 let write_commands_future =
424 handle_write_commands(&proxy, timeouts_sender.clone(), write_commands, &stats);
425 let read_commands_future = handle_read_commands(&proxy, timeouts_sender, read_commands, &stats);
426 let timeout_future = handle_idle_timeouts(timeouts_receiver, &message_counter);
427 futures::join!(event_future, write_commands_future, read_commands_future, timeout_future);
428}
429
430pub struct FunctionFs;
431impl FunctionFs {
432 pub fn new_fs(
433 current_task: &CurrentTask,
434 options: FileSystemOptions,
435 ) -> Result<FileSystemHandle, Errno> {
436 if options.source != "adb" {
437 track_stub!(TODO("https://fxbug.dev/329699340"), "FunctionFS supports other uses");
438 return error!(ENODEV);
439 }
440
441 if let Err(e) = std::fs::read_dir(ADB_DIRECTORY) {
445 log_warn!(
446 "Attempted to mount FunctionFS for adb, but could not read {ADB_DIRECTORY}: {e}"
447 );
448 return error!(ENODEV);
449 }
450
451 let uid = if let Some(uid) = options.params.get(b"uid") {
452 fs_args::parse::<uid_t>(uid.as_ref())?
453 } else {
454 0
455 };
456 let gid = if let Some(gid) = options.params.get(b"gid") {
457 fs_args::parse::<gid_t>(gid.as_ref())?
458 } else {
459 0
460 };
461
462 let fs = FileSystem::new(current_task.kernel(), CacheMode::Uncached, FunctionFs, options)?;
463
464 let creds = FsCred { uid, gid };
465 let info = FsNodeInfo::new(mode!(IFDIR, 0o755), creds);
466 fs.create_root_with_info(
467 ROOT_NODE_ID,
468 FunctionFsRootDir::new(¤t_task.kernel().inspect_node),
469 info,
470 );
471 Ok(fs)
472 }
473}
474
475impl FileSystemOps for FunctionFs {
476 fn statfs(&self, _fs: &FileSystem, _current_task: &CurrentTask) -> Result<statfs, Errno> {
477 Ok(default_statfs(FUNCTIONFS_MAGIC))
478 }
479
480 fn name(&self) -> &'static FsStr {
481 b"functionfs".into()
482 }
483}
484
485#[derive(Default)]
486struct FunctionFsState {
487 num_open_file_objects: usize,
491
492 session_id: u64,
495
496 has_input_output_endpoints: bool,
499
500 is_online: bool,
502
503 control_resets: u64,
505
506 event_history: VecDeque<EventRecord>,
508 next_event_id: usize,
509
510 adb_read_channel: Option<async_channel::Sender<ReadCommand>>,
511 adb_write_channel: Option<async_channel::Sender<WriteCommand>>,
512
513 device_proxy: Option<fadb::DeviceSynchronousProxy>,
515
516 event_queue: VecDeque<usb_functionfs_event>,
519
520 waiters: WaitQueue,
521}
522
523impl FunctionFsState {
524 fn record_event(&mut self, event: impl Into<Cow<'static, str>>) {
525 if self.event_history.len() == MAX_INSPECT_EVENTS {
526 self.event_history.pop_front();
527 }
528 let id = self.next_event_id;
529 self.next_event_id += 1;
530 self.event_history.push_back(EventRecord {
531 id,
532 timestamp: zx::BootInstant::get(),
533 event: event.into(),
534 });
535 }
536}
537
538pub enum AdbProxyMode {
539 None,
541
542 WakeContainer,
546}
547
548async fn connect_to_device(
549 proxy: AdbProxyMode,
550) -> Result<(fadb::DeviceSynchronousProxy, fadb::UsbAdbImpl_Proxy, Option<zx::Counter>), Errno> {
551 let service = Service::open(fadb::ServiceMarker).map_err(|_| errno!(EINVAL))?;
552 let instances = service.enumerate().await.map_err(|_| errno!(EINVAL))?;
553
554 for instance in instances {
555 let Ok(device_proxy) = instance.connect_to_adb() else {
556 continue;
557 };
558
559 let (adb_proxy, server_end) =
560 fidl::endpoints::create_sync_proxy::<fadb::UsbAdbImpl_Marker>();
561 let (adb_channel, message_counter) = match proxy {
562 AdbProxyMode::None => (adb_proxy.into_channel(), None),
563 AdbProxyMode::WakeContainer => {
564 let (channel, message_counter) = create_proxy_for_wake_events_counter_zero(
565 adb_proxy.into_channel(),
566 "adb".to_string(),
567 );
568 (channel, Some(message_counter))
569 }
570 };
571
572 let timer =
573 fasync::Timer::new(zx::MonotonicInstant::after(zx::Duration::from_seconds(5))).fuse();
574 let start_fut = device_proxy.start_adb(server_end).fuse();
575 pin_mut!(timer, start_fut);
576 let start_ok = futures::select! {
577 res = start_fut => matches!(res, Ok(Ok(()))),
578 _ = timer => false,
579 };
580
581 if start_ok {
582 let Ok(channel) = device_proxy.into_channel() else {
583 continue;
584 };
585 let device_proxy = fadb::DeviceSynchronousProxy::new(channel.into_zx_channel());
586 let adb_proxy =
587 fadb::UsbAdbImpl_Proxy::new(fidl::AsyncChannel::from_channel(adb_channel));
588 return Ok((device_proxy, adb_proxy, message_counter));
589 }
590 }
591
592 error!(EBUSY)
593}
594
595async fn manage_adb_connection(
596 read_commands: async_channel::Receiver<ReadCommand>,
597 write_commands: async_channel::Receiver<WriteCommand>,
598 state: Arc<LockDepMutex<FunctionFsState, FunctionFsStateLock>>,
599 stats: Arc<FunctionFsStats>,
600 session_id: u64,
601) {
602 let mut watcher = match Service::open(fadb::ServiceMarker) {
603 Ok(service) => service.watch().await.ok(),
604 Err(_) => None,
605 };
606
607 loop {
608 {
610 let state_locked = state.lock();
611 if state_locked.session_id != session_id
612 || !state_locked.has_input_output_endpoints
613 || state_locked.num_open_file_objects == 0
614 {
615 return;
616 }
617 }
618
619 if let Ok((device_proxy, adb_proxy, message_counter)) =
621 connect_to_device(AdbProxyMode::WakeContainer).await
622 {
623 {
624 let mut state_locked = state.lock();
625 if state_locked.session_id != session_id || !state_locked.has_input_output_endpoints
626 {
627 let deadline = zx::MonotonicInstant::after(zx::Duration::from_seconds(5));
628 if let Err(e) = device_proxy.stop_adb(deadline) {
629 log_warn!("Failed to stop adb driver after session cancelled: {e:?}");
630 }
631 return;
632 }
633 state_locked.device_proxy = Some(device_proxy);
634 }
635
636 handle_adb(
637 adb_proxy,
638 message_counter,
639 read_commands.clone(),
640 write_commands.clone(),
641 Arc::clone(&state),
642 Arc::clone(&stats),
643 session_id,
644 )
645 .await;
646
647 {
648 let mut state_locked = state.lock();
649 if state_locked.session_id == session_id {
650 let _ = state_locked.device_proxy.take();
651 }
652 }
653 } else {
654 fasync::Timer::new(zx::MonotonicInstant::after(zx::Duration::from_millis(500))).await;
656 }
657
658 {
660 let state_locked = state.lock();
661 if state_locked.session_id != session_id
662 || !state_locked.has_input_output_endpoints
663 || state_locked.num_open_file_objects == 0
664 {
665 return;
666 }
667 }
668
669 let has_instances = match Service::open(fadb::ServiceMarker) {
671 Ok(service) => {
672 service.enumerate().await.map(|instances| !instances.is_empty()).unwrap_or(false)
673 }
674 Err(_) => false,
675 };
676 if !has_instances {
677 if let Some(w) = watcher.as_mut() {
678 match w.next().await {
679 Some(Ok(_)) => {}
680 Some(Err(_)) | None => {
681 watcher = match Service::open(fadb::ServiceMarker) {
683 Ok(service) => service.watch().await.ok(),
684 Err(_) => None,
685 };
686 }
687 }
688 } else {
689 fasync::Timer::new(zx::MonotonicInstant::after(zx::Duration::from_millis(500)))
690 .await;
691 watcher = match Service::open(fadb::ServiceMarker) {
692 Ok(service) => service.watch().await.ok(),
693 Err(_) => None,
694 };
695 }
696 }
697 }
698}
699
700#[derive(Default)]
701struct FunctionFsRootDir {
702 state: Arc<LockDepMutex<FunctionFsState, FunctionFsStateLock>>,
703 stats: Arc<FunctionFsStats>,
704 _inspect_node: inspect::LazyNode,
705}
706
707impl FunctionFsRootDir {
708 fn new(parent_inspect_node: &inspect::Node) -> Self {
709 let stats = Arc::new(FunctionFsStats::default());
710 let state = Arc::new(LockDepMutex::new(FunctionFsState {
711 event_history: VecDeque::with_capacity(MAX_INSPECT_EVENTS),
712 ..Default::default()
713 }));
714 let inspect_node = create_lazy_inspect_node(parent_inspect_node, &state, &stats);
715 Self { state, stats, _inspect_node: inspect_node }
716 }
717
718 fn create_endpoints(&self, kernel: &Kernel) -> Result<(), Errno> {
719 let mut state = self.state.lock();
720
721 if state.has_input_output_endpoints {
724 return Ok(());
725 }
726
727 state.session_id = state.session_id.wrapping_add(1);
728 let session_id = state.session_id;
729
730 let (read_command_sender, read_command_receiver) = async_channel::unbounded();
731 state.adb_read_channel = Some(read_command_sender);
732
733 let (write_command_sender, write_command_receiver) = async_channel::unbounded();
734 state.adb_write_channel = Some(write_command_sender);
735
736 state.event_queue.clear();
737 state.event_queue.push_back(usb_functionfs_event {
738 type_: usb_functionfs_event_type_FUNCTIONFS_BIND as u8,
739 ..Default::default()
740 });
741 state.record_event("BIND");
742 state.waiters.notify_fd_events(FdEvents::POLLIN);
743 state.waiters.notify_all();
744 state.has_input_output_endpoints = true;
745 state.record_event("ENDPOINTS_CREATED");
746
747 let state_copy = Arc::clone(&self.state);
748 let stats_copy = Arc::clone(&self.stats);
749 kernel.kthreads.spawn_future(
751 move || async move {
752 manage_adb_connection(
753 read_command_receiver,
754 write_command_receiver,
755 state_copy,
756 stats_copy,
757 session_id,
758 )
759 .await
760 },
761 "functionfs_adb_worker",
762 );
763
764 Ok(())
765 }
766
767 fn from_fs(fs: &FileSystem) -> &Self {
768 fs.root()
769 .node
770 .downcast_ops::<FunctionFsRootDir>()
771 .expect("failed to downcast functionfs root dir")
772 }
773
774 fn from_file(file: &FileObject) -> &Self {
775 Self::from_fs(&file.fs)
776 }
777
778 fn on_control_opened(&self) {
779 let mut state = self.state.lock();
780 state.num_open_file_objects += 1;
781 state.record_event("CONTROL_OPENED");
782 }
783
784 fn on_endpoint_opened(&self) {
785 let mut state = self.state.lock();
786 state.num_open_file_objects += 1;
787 state.record_event("ENDPOINT_OPENED");
788 }
789
790 fn on_control_closed(&self) {
791 self.on_file_closed("CONTROL_CLOSED");
792 }
793
794 fn on_endpoint_closed(&self) {
795 self.on_file_closed("ENDPOINT_CLOSED");
796 }
797
798 fn on_file_closed(&self, event: &'static str) {
799 let mut state = self.state.lock();
800 state.num_open_file_objects -= 1;
801 state.record_event(event);
802 if state.num_open_file_objects == 0 {
803 state.session_id = state.session_id.wrapping_add(1);
804 if let Some(device_proxy) = state.device_proxy.take() {
807 let deadline = zx::MonotonicInstant::after(zx::Duration::from_seconds(5));
811 match device_proxy.stop_adb(deadline) {
812 Ok(Ok(())) => {}
813 Ok(Err(status)) => {
814 log_warn!(
815 "Failed to stop adb driver on control reset: {}",
816 zx::Status::err_from_raw(status)
817 );
818 }
819 Err(err) => {
820 log_warn!("FIDL error calling StopAdb on control reset: {err}");
821 }
822 }
823 }
824
825 state.has_input_output_endpoints = false;
826 state.is_online = false;
827 state.adb_read_channel = None;
828 state.adb_write_channel = None;
829 state.event_queue.clear();
830 state.control_resets += 1;
831 state.record_event("CONTROL_RESET");
832 state.waiters.notify_all();
833 }
834 }
835
836 fn wait_until_online(
837 &self,
838 current_task: &CurrentTask,
839 file: &FileObject,
840 ) -> Result<(), Errno> {
841 let initial_session_id = self.state.lock().session_id;
842 loop {
843 let waiter = {
844 let state = self.state.lock();
845 if !state.has_input_output_endpoints || state.session_id != initial_session_id {
846 return error!(ESHUTDOWN);
847 }
848 if state.is_online {
849 return Ok(());
850 }
851 if file.flags().contains(OpenFlags::NONBLOCK) {
852 return error!(EAGAIN);
853 }
854 let waiter = Waiter::new();
855 state.waiters.wait_async(&waiter);
856 waiter
857 };
858 waiter.wait(current_task)?;
859 }
860 }
861
862 fn available(&self) -> usize {
863 let state = self.state.lock();
864 state.event_queue.len()
865 }
866
867 fn write(
868 &self,
869 current_task: &CurrentTask,
870 file: &FileObject,
871 data: Vec<u8>,
872 ) -> Result<usize, Errno> {
873 self.wait_until_online(current_task, file)?;
874
875 let pending = Arc::<PendingResult<usize>>::default();
876 let guard = pending.event.begin_wait();
877
878 if let Some(channel) = self.state.lock().adb_write_channel.as_ref() {
879 channel.send_blocking(WriteCommand { data, pending: pending.clone() }).map_err(
880 |err| {
881 log_warn!(
882 "FunctionFsRootDir::write (ep2 bulk IN) failed to send command for task {} (pid {}): {err}",
883 current_task.command(),
884 current_task.get_pid()
885 );
886 errno!(EINVAL)
887 },
888 )?;
889 } else {
890 log_warn!(
891 "FunctionFsRootDir::write (ep2 bulk IN) called by task {} (pid {}) with {} bytes, but adb_write_channel is None (ENODEV)",
892 current_task.command(),
893 current_task.get_pid(),
894 data.len()
895 );
896 return error!(ENODEV);
897 }
898
899 current_task.block_until(guard, zx::MonotonicInstant::INFINITE)?;
900
901 let mut result = pending.result.lock();
902 result.take().ok_or_else(|| errno!(EINTR))?
903 }
904
905 fn read(&self, current_task: &CurrentTask, file: &FileObject) -> Result<Vec<u8>, Errno> {
906 self.wait_until_online(current_task, file)?;
907
908 let pending = Arc::<PendingResult<Vec<u8>>>::default();
909 let guard = pending.event.begin_wait();
910 if let Some(channel) = self.state.lock().adb_read_channel.as_ref() {
911 channel.send_blocking(ReadCommand { pending: pending.clone() }).map_err(|err| {
912 log_warn!(
913 "FunctionFsRootDir::read (ep1 bulk OUT) failed to send command for task {} (pid {}): {err}",
914 current_task.command(),
915 current_task.get_pid()
916 );
917 errno!(EINVAL)
918 })?;
919 } else {
920 log_warn!(
921 "FunctionFsRootDir::read (ep1 bulk OUT) called by task {} (pid {}), but adb_read_channel is None (ENODEV)",
922 current_task.command(),
923 current_task.get_pid()
924 );
925 return error!(ENODEV);
926 }
927
928 current_task.block_until(guard, zx::MonotonicInstant::INFINITE)?;
929
930 let mut result = pending.result.lock();
931 result.take().ok_or_else(|| errno!(EINTR))?
932 }
933}
934
935impl FsNodeOps for FunctionFsRootDir {
936 fs_node_impl_dir_readonly!();
937
938 fn create_file_ops(
939 &self,
940 _node: &FsNode,
941 _current_task: &CurrentTask,
942 _flags: OpenFlags,
943 ) -> Result<Box<dyn FileOps>, Errno> {
944 let mut entries = vec![];
945 entries.push(VecDirectoryEntry {
946 entry_type: DirectoryEntryType::REG,
947 name: CONTROL_ENDPOINT.into(),
948 inode: Some(CONTROL_ENDPOINT_NODE_ID),
949 });
950
951 let state = self.state.lock();
952 if state.has_input_output_endpoints {
953 entries.push(VecDirectoryEntry {
954 entry_type: DirectoryEntryType::REG,
955 name: INPUT_ENDPOINT.into(),
956 inode: Some(INPUT_ENDPOINT_NODE_ID),
957 });
958 entries.push(VecDirectoryEntry {
959 entry_type: DirectoryEntryType::REG,
960 name: OUTPUT_ENDPOINT.into(),
961 inode: Some(OUTPUT_ENDPOINT_NODE_ID),
962 });
963 }
964
965 Ok(VecDirectory::new_file(entries))
966 }
967
968 fn lookup(
969 &self,
970 entry: &DirEntry,
971 _current_task: &CurrentTask,
972 name: &FsStr,
973 ) -> Result<starnix_core::vfs::FsNodeHandle, Errno> {
974 let name = std::str::from_utf8(name).map_err(|_| errno!(ENOENT))?;
975 let cred = entry.node.info().cred();
976 match name {
977 CONTROL_ENDPOINT => Ok(entry.node.fs().create_node(
978 CONTROL_ENDPOINT_NODE_ID,
979 FunctionFsControlEndpoint,
980 FsNodeInfo::new(mode!(IFREG, 0o600), cred),
981 )),
982 OUTPUT_ENDPOINT => Ok(entry.node.fs().create_node(
983 OUTPUT_ENDPOINT_NODE_ID,
984 FunctionFsOutputEndpoint,
985 FsNodeInfo::new(mode!(IFREG, 0o600), cred),
986 )),
987 INPUT_ENDPOINT => Ok(entry.node.fs().create_node(
988 INPUT_ENDPOINT_NODE_ID,
989 FunctionFsInputEndpoint,
990 FsNodeInfo::new(mode!(IFREG, 0o600), cred),
991 )),
992 _ => error!(ENOENT),
993 }
994 }
995}
996
997struct FunctionFsControlEndpoint;
1001impl FsNodeOps for FunctionFsControlEndpoint {
1002 fs_node_impl_not_dir!();
1003
1004 fn create_file_ops(
1005 &self,
1006 node: &FsNode,
1007 _current_task: &CurrentTask,
1008 _flags: OpenFlags,
1009 ) -> Result<Box<dyn FileOps>, Errno> {
1010 let fs = node.fs();
1011 let rootdir = fs
1012 .root()
1013 .node
1014 .downcast_ops::<FunctionFsRootDir>()
1015 .expect("failed to downcast functionfs root dir");
1016 rootdir.on_control_opened();
1017 Ok(Box::new(FunctionFsControlEndpoint))
1018 }
1019}
1020
1021impl FileOps for FunctionFsControlEndpoint {
1022 fileops_impl_seekless!();
1023 fileops_impl_noop_sync!();
1024
1025 fn close(self: Box<Self>, file: &FileObjectState, _current_task: &CurrentTask) {
1026 let rootdir = FunctionFsRootDir::from_fs(&file.fs);
1027 rootdir.on_control_closed();
1028 }
1029
1030 fn read(
1031 &self,
1032 file: &FileObject,
1033 _current_task: &CurrentTask,
1034 _offset: usize,
1035 data: &mut dyn OutputBuffer,
1036 ) -> Result<usize, Errno> {
1037 track_stub!(
1040 TODO("https://fxbug.dev/329699340"),
1041 "FunctionFS blocking read on control endpoint"
1042 );
1043
1044 let rootdir = FunctionFsRootDir::from_file(file);
1045
1046 let mut state = rootdir.state.lock();
1047 if !state.event_queue.is_empty() {
1048 if data.available() < std::mem::size_of::<usb_functionfs_event>() {
1049 return error!(EINVAL);
1050 }
1051 } else {
1052 return error!(EAGAIN);
1053 }
1054 let front = state.event_queue.pop_front().expect("pop from non-empty event queue");
1055 data.write(front.as_bytes())
1056 }
1057
1058 fn write(
1059 &self,
1060 file: &FileObject,
1061 current_task: &CurrentTask,
1062 _offset: usize,
1063 data: &mut dyn InputBuffer,
1064 ) -> Result<usize, Errno> {
1065 track_stub!(TODO("https://fxbug.dev/329699340"), "FunctionFS should parse descriptors");
1069
1070 let rootdir = FunctionFsRootDir::from_file(file);
1071 rootdir.create_endpoints(current_task.kernel().deref())?;
1072
1073 Ok(data.drain())
1074 }
1075
1076 fn wait_async(
1077 &self,
1078 file: &FileObject,
1079 _current_task: &CurrentTask,
1080 waiter: &Waiter,
1081 events: FdEvents,
1082 handler: EventHandler,
1083 ) -> Option<WaitCanceler> {
1084 let rootdir = FunctionFsRootDir::from_file(file);
1085 let state = rootdir.state.lock();
1086 Some(state.waiters.wait_async_fd_events(waiter, events, handler))
1087 }
1088
1089 fn query_events(
1090 &self,
1091 file: &FileObject,
1092 _current_task: &CurrentTask,
1093 ) -> Result<FdEvents, Errno> {
1094 let rootdir = FunctionFsRootDir::from_file(file);
1095 if rootdir.available() > 0 { Ok(FdEvents::POLLIN) } else { Ok(FdEvents::empty()) }
1096 }
1097}
1098
1099struct FunctionFsInputEndpoint;
1102impl FsNodeOps for FunctionFsInputEndpoint {
1103 fs_node_impl_not_dir!();
1104
1105 fn create_file_ops(
1106 &self,
1107 node: &FsNode,
1108 _current_task: &CurrentTask,
1109 _flags: OpenFlags,
1110 ) -> Result<Box<dyn FileOps>, Errno> {
1111 FunctionFsRootDir::from_fs(&node.fs()).on_endpoint_opened();
1112 Ok(Box::new(FunctionFsInputEndpoint))
1113 }
1114}
1115
1116impl FileOps for FunctionFsInputEndpoint {
1117 fileops_impl_seekless!();
1118 fileops_impl_noop_sync!();
1119
1120 fn close(self: Box<Self>, file: &FileObjectState, _current_task: &CurrentTask) {
1121 FunctionFsRootDir::from_fs(&file.fs).on_endpoint_closed();
1122 }
1123
1124 fn read(
1125 &self,
1126 _file: &FileObject,
1127 _current_task: &CurrentTask,
1128 _offset: usize,
1129 _data: &mut dyn OutputBuffer,
1130 ) -> Result<usize, Errno> {
1131 error!(EINVAL)
1132 }
1133
1134 fn write(
1135 &self,
1136 file: &FileObject,
1137 current_task: &CurrentTask,
1138 _offset: usize,
1139 data: &mut dyn InputBuffer,
1140 ) -> Result<usize, Errno> {
1141 let bytes = data.read_all().map_err(|err| {
1142 log_warn!(
1143 "FunctionFsInputEndpoint (ep2 bulk IN) input buffer read failed for task {} (pid {}): {err}",
1144 current_task.command(),
1145 current_task.get_pid()
1146 );
1147 err
1148 })?;
1149 let rootdir = FunctionFsRootDir::from_file(file);
1150 rootdir.write(current_task, file, bytes)
1151 }
1152}
1153
1154struct FunctionFsOutputEndpoint;
1157impl FsNodeOps for FunctionFsOutputEndpoint {
1158 fs_node_impl_not_dir!();
1159
1160 fn create_file_ops(
1161 &self,
1162 node: &FsNode,
1163 _current_task: &CurrentTask,
1164 _flags: OpenFlags,
1165 ) -> Result<Box<dyn FileOps>, Errno> {
1166 FunctionFsRootDir::from_fs(&node.fs()).on_endpoint_opened();
1167 Ok(Box::new(FunctionFsOutputFileObject))
1168 }
1169}
1170
1171struct FunctionFsOutputFileObject;
1172
1173impl FileOps for FunctionFsOutputFileObject {
1174 fileops_impl_seekless!();
1175 fileops_impl_noop_sync!();
1176
1177 fn close(self: Box<Self>, file: &FileObjectState, _current_task: &CurrentTask) {
1178 FunctionFsRootDir::from_fs(&file.fs).on_endpoint_closed();
1179 }
1180
1181 fn read(
1182 &self,
1183 file: &FileObject,
1184 current_task: &CurrentTask,
1185 _offset: usize,
1186 data: &mut dyn OutputBuffer,
1187 ) -> Result<usize, Errno> {
1188 let rootdir = FunctionFsRootDir::from_file(file);
1189 let payload = rootdir.read(current_task, file)?;
1190 if payload.len() > data.available() {
1191 log_warn!(
1194 "FunctionFsOutputFileObject (ep1 bulk OUT) buffer overflow for task {} (pid {}): payload len {} > buffer avail {}",
1195 current_task.command(),
1196 current_task.get_pid(),
1197 payload.len(),
1198 data.available()
1199 );
1200 rootdir.stats.ep1_buffer_overflow_errors.fetch_add(1, Ordering::Relaxed);
1201 return error!(EINVAL);
1202 }
1203
1204 data.write(&payload).map_err(|err| {
1205 log_warn!(
1206 "FunctionFsOutputFileObject (ep1 bulk OUT) output buffer write failed for task {} (pid {}): {err}",
1207 current_task.command(),
1208 current_task.get_pid()
1209 );
1210 err
1211 })
1212 }
1213
1214 fn write(
1215 &self,
1216 _file: &FileObject,
1217 _current_task: &CurrentTask,
1218 _offset: usize,
1219 _data: &mut dyn InputBuffer,
1220 ) -> Result<usize, Errno> {
1221 error!(EINVAL)
1222 }
1223}
1224
1225#[cfg(test)]
1226mod tests {
1227 use super::*;
1228 use diagnostics_assertions::{AnyProperty, TreeAssertion, assert_data_tree};
1229 use fidl::endpoints::RequestStream;
1230 use std::pin::pin;
1231
1232 #[fuchsia::test]
1233 async fn test_inspect_initial_hierarchy() {
1234 let inspector = inspect::Inspector::default();
1235 let _rootdir = FunctionFsRootDir::new(inspector.root());
1236
1237 assert_data_tree!(inspector, root: {
1238 "usb-functionfs": {
1239 is_online: false,
1240 num_open_file_objects: 0u64,
1241 event_queue_depth: 0u64,
1242 has_input_output_endpoints: false,
1243 control_resets: 0u64,
1244 event_history: {},
1245 ep1_bulk_out: {
1246 total_bytes_read: 0u64,
1247 read_count: 0u64,
1248 read_errors: 0u64,
1249 buffer_overflow_errors: 0u64,
1250 },
1251 ep2_bulk_in: {
1252 total_bytes_written: 0u64,
1253 write_count: 0u64,
1254 write_errors: 0u64,
1255 },
1256 }
1257 });
1258 }
1259
1260 #[fuchsia::test]
1261 async fn test_control_endpoint_lifecycle_and_reset() {
1262 let inspector = inspect::Inspector::default();
1263 let rootdir = FunctionFsRootDir::new(inspector.root());
1264
1265 rootdir.on_control_opened();
1267 rootdir.on_control_opened();
1268
1269 {
1271 let mut state_locked = rootdir.state.lock();
1272 state_locked.has_input_output_endpoints = true;
1273 state_locked.is_online = true;
1274 state_locked.event_queue.push_back(usb_functionfs_event::default());
1275 }
1276
1277 assert_data_tree!(inspector, root: {
1278 "usb-functionfs": contains {
1279 num_open_file_objects: 2u64,
1280 has_input_output_endpoints: true,
1281 is_online: true,
1282 event_queue_depth: 1u64,
1283 control_resets: 0u64,
1284 event_history: {
1285 "0": {
1286 "@time": AnyProperty,
1287 event: "CONTROL_OPENED",
1288 },
1289 "1": {
1290 "@time": AnyProperty,
1291 event: "CONTROL_OPENED",
1292 },
1293 },
1294 }
1295 });
1296
1297 rootdir.on_control_closed();
1299 {
1300 let state_locked = rootdir.state.lock();
1301 assert_eq!(state_locked.num_open_file_objects, 1);
1302 assert!(state_locked.has_input_output_endpoints);
1303 assert!(state_locked.is_online);
1304 assert_eq!(state_locked.event_queue.len(), 1);
1305 }
1306
1307 assert_data_tree!(inspector, root: {
1308 "usb-functionfs": contains {
1309 num_open_file_objects: 1u64,
1310 has_input_output_endpoints: true,
1311 is_online: true,
1312 event_queue_depth: 1u64,
1313 control_resets: 0u64,
1314 event_history: {
1315 "0": {
1316 "@time": AnyProperty,
1317 event: "CONTROL_OPENED",
1318 },
1319 "1": {
1320 "@time": AnyProperty,
1321 event: "CONTROL_OPENED",
1322 },
1323 "2": {
1324 "@time": AnyProperty,
1325 event: "CONTROL_CLOSED",
1326 },
1327 },
1328 }
1329 });
1330
1331 rootdir.on_control_closed();
1333 {
1334 let state_locked = rootdir.state.lock();
1335 assert_eq!(state_locked.num_open_file_objects, 0);
1336 assert!(!state_locked.has_input_output_endpoints);
1337 assert!(!state_locked.is_online);
1338 assert!(state_locked.event_queue.is_empty());
1339 }
1340
1341 assert_data_tree!(inspector, root: {
1342 "usb-functionfs": contains {
1343 num_open_file_objects: 0u64,
1344 has_input_output_endpoints: false,
1345 is_online: false,
1346 event_queue_depth: 0u64,
1347 control_resets: 1u64,
1348 event_history: {
1349 "0": {
1350 "@time": AnyProperty,
1351 event: "CONTROL_OPENED",
1352 },
1353 "1": {
1354 "@time": AnyProperty,
1355 event: "CONTROL_OPENED",
1356 },
1357 "2": {
1358 "@time": AnyProperty,
1359 event: "CONTROL_CLOSED",
1360 },
1361 "3": {
1362 "@time": AnyProperty,
1363 event: "CONTROL_CLOSED",
1364 },
1365 "4": {
1366 "@time": AnyProperty,
1367 event: "CONTROL_RESET",
1368 },
1369 },
1370 }
1371 });
1372 }
1373
1374 #[fuchsia::test]
1375 async fn test_event_history_ring_buffer_eviction() {
1376 let inspector = inspect::Inspector::default();
1377 let rootdir = FunctionFsRootDir::new(inspector.root());
1378
1379 {
1380 let mut state = rootdir.state.lock();
1381 for i in 0..35 {
1382 state.record_event(format!("event_{i}"));
1383 }
1384 }
1385
1386 let mut event_history_assertion = TreeAssertion::new("event_history", true);
1387 for i in 3..35 {
1388 let mut child = TreeAssertion::new(&i.to_string(), true);
1389 child.add_property_assertion("@time", Arc::new(AnyProperty));
1390 child.add_property_assertion("event", Arc::new(format!("event_{i}")));
1391 event_history_assertion.add_child_assertion(child);
1392 }
1393
1394 assert_data_tree!(inspector, root: {
1395 "usb-functionfs": contains {
1396 event_history_assertion,
1397 }
1398 });
1399 }
1400
1401 #[fuchsia::test]
1402 fn test_handle_adb_inspect_updates_and_error_filtering() {
1403 let mut exec = fasync::TestExecutor::new_with_fake_time();
1404
1405 let mut test_fut = pin!(async {
1406 let inspector = inspect::Inspector::default();
1407 let rootdir = FunctionFsRootDir::new(inspector.root());
1408
1409 let (proxy, mut stream) =
1410 fidl::endpoints::create_proxy_and_stream::<fadb::UsbAdbImpl_Marker>();
1411 let (read_sender, read_receiver) = async_channel::unbounded();
1412 let (write_sender, write_receiver) = async_channel::unbounded();
1413
1414 {
1416 let mut state = rootdir.state.lock();
1417 state.has_input_output_endpoints = true;
1418 state.event_queue.push_back(usb_functionfs_event {
1419 type_: usb_functionfs_event_type_FUNCTIONFS_BIND as u8,
1420 ..Default::default()
1421 });
1422 state.record_event("BIND");
1423 }
1424
1425 let adb_fut = handle_adb(
1426 proxy,
1427 None,
1428 read_receiver,
1429 write_receiver,
1430 Arc::clone(&rootdir.state),
1431 Arc::clone(&rootdir.stats),
1432 0,
1433 );
1434
1435 let driver_fut = async move {
1436 stream
1438 .control_handle()
1439 .send_on_status_changed(fadb::StatusFlags::ONLINE)
1440 .expect("send ONLINE status");
1441
1442 let read_ok = Arc::<PendingResult<Vec<u8>>>::default();
1444 read_sender
1445 .send(ReadCommand { pending: read_ok.clone() })
1446 .await
1447 .expect("send read command");
1448 match stream.next().await.expect("stream item").expect("fidl request") {
1449 fadb::UsbAdbImpl_Request::Receive { responder } => {
1450 responder.send(Ok(&[1, 2, 3, 4])).expect("send Receive Ok");
1451 }
1452 other => panic!("Unexpected request: {other:?}"),
1453 }
1454
1455 let read_io_err = Arc::<PendingResult<Vec<u8>>>::default();
1457 read_sender
1458 .send(ReadCommand { pending: read_io_err.clone() })
1459 .await
1460 .expect("send read command");
1461 match stream.next().await.expect("stream item").expect("fidl request") {
1462 fadb::UsbAdbImpl_Request::Receive { responder } => {
1463 responder
1464 .send(Err(zx::Status::IO.into_raw()))
1465 .expect("send Receive IO error");
1466 }
1467 other => panic!("Unexpected request: {other:?}"),
1468 }
1469
1470 let mut read_shutdown_errs = Vec::new();
1473 for status in [zx::Status::BAD_STATE, zx::Status::CANCELED, zx::Status::PEER_CLOSED]
1474 {
1475 let pending = Arc::<PendingResult<Vec<u8>>>::default();
1476 read_sender
1477 .send(ReadCommand { pending: pending.clone() })
1478 .await
1479 .expect("send read command");
1480 read_shutdown_errs.push(pending);
1481 match stream.next().await.expect("stream item").expect("fidl request") {
1482 fadb::UsbAdbImpl_Request::Receive { responder } => {
1483 responder
1484 .send(Err(status.into_raw()))
1485 .expect("send Receive shutdown error");
1486 }
1487 other => panic!("Unexpected request: {other:?}"),
1488 }
1489 }
1490
1491 let write_ok = Arc::<PendingResult<usize>>::default();
1493 write_sender
1494 .send(WriteCommand {
1495 data: vec![10, 20, 30, 40, 50],
1496 pending: write_ok.clone(),
1497 })
1498 .await
1499 .expect("send write command");
1500 match stream.next().await.expect("stream item").expect("fidl request") {
1501 fadb::UsbAdbImpl_Request::QueueTx { data, responder } => {
1502 assert_eq!(data, vec![10, 20, 30, 40, 50]);
1503 responder.send(Ok(())).expect("send QueueTx Ok");
1504 }
1505 other => panic!("Unexpected request: {other:?}"),
1506 }
1507
1508 let write_io_err = Arc::<PendingResult<usize>>::default();
1510 write_sender
1511 .send(WriteCommand { data: vec![1, 2], pending: write_io_err.clone() })
1512 .await
1513 .expect("send write command");
1514 match stream.next().await.expect("stream item").expect("fidl request") {
1515 fadb::UsbAdbImpl_Request::QueueTx { responder, .. } => {
1516 responder
1517 .send(Err(zx::Status::IO.into_raw()))
1518 .expect("send QueueTx IO error");
1519 }
1520 other => panic!("Unexpected request: {other:?}"),
1521 }
1522
1523 let mut write_shutdown_errs = Vec::new();
1526 for status in [zx::Status::BAD_STATE, zx::Status::CANCELED, zx::Status::PEER_CLOSED]
1527 {
1528 let pending = Arc::<PendingResult<usize>>::default();
1529 write_sender
1530 .send(WriteCommand { data: vec![1], pending: pending.clone() })
1531 .await
1532 .expect("send write command");
1533 write_shutdown_errs.push(pending);
1534 match stream.next().await.expect("stream item").expect("fidl request") {
1535 fadb::UsbAdbImpl_Request::QueueTx { responder, .. } => {
1536 responder
1537 .send(Err(status.into_raw()))
1538 .expect("send QueueTx shutdown error");
1539 }
1540 other => panic!("Unexpected request: {other:?}"),
1541 }
1542 }
1543
1544 stream
1546 .control_handle()
1547 .send_on_status_changed(fadb::StatusFlags::empty())
1548 .expect("send offline status");
1549
1550 drop(stream);
1552
1553 let read_closed = Arc::<PendingResult<Vec<u8>>>::default();
1556 read_sender
1557 .send(ReadCommand { pending: read_closed.clone() })
1558 .await
1559 .expect("send read command on closed channel");
1560 let write_closed = Arc::<PendingResult<usize>>::default();
1561 write_sender
1562 .send(WriteCommand { data: vec![9], pending: write_closed.clone() })
1563 .await
1564 .expect("send write command on closed channel");
1565
1566 drop(read_sender);
1567 drop(write_sender);
1568
1569 (
1570 read_ok,
1571 read_io_err,
1572 read_shutdown_errs,
1573 write_ok,
1574 write_io_err,
1575 write_shutdown_errs,
1576 read_closed,
1577 write_closed,
1578 )
1579 };
1580
1581 let (
1582 (),
1583 (
1584 read_ok,
1585 read_io_err,
1586 read_shutdown_errs,
1587 write_ok,
1588 write_io_err,
1589 write_shutdown_errs,
1590 read_closed,
1591 write_closed,
1592 ),
1593 ) = futures::join!(adb_fut, driver_fut);
1594
1595 assert_eq!(read_ok.result.lock().take(), Some(Ok(vec![1, 2, 3, 4])));
1596 assert_eq!(read_io_err.result.lock().take(), Some(error!(EINVAL)));
1597 for pending in read_shutdown_errs {
1598 assert_eq!(pending.result.lock().take(), Some(error!(ESHUTDOWN)));
1599 }
1600 assert_eq!(write_ok.result.lock().take(), Some(Ok(5)));
1601 assert_eq!(write_io_err.result.lock().take(), Some(error!(EINVAL)));
1602 for pending in write_shutdown_errs {
1603 assert_eq!(pending.result.lock().take(), Some(error!(ESHUTDOWN)));
1604 }
1605 assert_eq!(read_closed.result.lock().take(), Some(error!(ESHUTDOWN)));
1606 assert_eq!(write_closed.result.lock().take(), Some(error!(ESHUTDOWN)));
1607
1608 assert_data_tree!(inspector, root: {
1609 "usb-functionfs": {
1610 is_online: false,
1611 num_open_file_objects: 0u64,
1612 event_queue_depth: 4u64,
1613 has_input_output_endpoints: false,
1614 control_resets: 0u64,
1615 event_history: {
1616 "0": {
1617 "@time": AnyProperty,
1618 event: "BIND",
1619 },
1620 "1": {
1621 "@time": AnyProperty,
1622 event: "ENABLE",
1623 },
1624 "2": {
1625 "@time": AnyProperty,
1626 event: "DISABLE",
1627 },
1628 "3": {
1629 "@time": AnyProperty,
1630 event: "UNBIND",
1631 },
1632 },
1633 ep1_bulk_out: {
1634 total_bytes_read: 4u64,
1635 read_count: 1u64,
1636 read_errors: 1u64,
1637 buffer_overflow_errors: 0u64,
1638 },
1639 ep2_bulk_in: {
1640 total_bytes_written: 5u64,
1641 write_count: 1u64,
1642 write_errors: 1u64,
1643 },
1644 }
1645 });
1646 });
1647
1648 while exec.run_until_stalled(&mut test_fut).is_pending() {
1649 assert!(exec.wake_next_timer().is_some(), "Executor stalled with no pending timers");
1650 }
1651 }
1652
1653 #[fuchsia::test]
1654 fn test_stale_session_stream_closure_does_not_inject_unbind() {
1655 let mut exec = fasync::TestExecutor::new_with_fake_time();
1656
1657 let mut test_fut = pin!(async {
1658 let inspector = inspect::Inspector::default();
1659 let rootdir = FunctionFsRootDir::new(inspector.root());
1660
1661 let (proxy1, stream1) =
1662 fidl::endpoints::create_proxy_and_stream::<fadb::UsbAdbImpl_Marker>();
1663 let (read_sender1, read_receiver1) = async_channel::unbounded();
1664 let (write_sender1, write_receiver1) = async_channel::unbounded();
1665
1666 rootdir.state.lock().session_id = 1;
1668 rootdir.state.lock().is_online = true;
1669
1670 let adb_fut1 = handle_adb(
1671 proxy1,
1672 None,
1673 read_receiver1,
1674 write_receiver1,
1675 Arc::clone(&rootdir.state),
1676 Arc::clone(&rootdir.stats),
1677 1,
1678 );
1679
1680 let (client_channel2, _server_channel2) = zx::Channel::create();
1683 {
1684 let mut state = rootdir.state.lock();
1685 state.session_id = 2;
1686 state.is_online = true;
1687 state.device_proxy = Some(fadb::DeviceSynchronousProxy::new(client_channel2));
1688 state.event_queue.clear();
1689 }
1690
1691 drop(read_sender1);
1693 drop(write_sender1);
1694 drop(stream1);
1695
1696 adb_fut1.await;
1698
1699 let state = rootdir.state.lock();
1702 assert!(state.is_online, "Stale session termination must not set is_online to false");
1703 assert!(
1704 state.device_proxy.is_some(),
1705 "Stale session termination must not take the active session's device_proxy"
1706 );
1707 assert!(
1708 state.event_queue.is_empty(),
1709 "Stale session termination must not push UNBIND into the active session queue"
1710 );
1711 });
1712
1713 while exec.run_until_stalled(&mut test_fut).is_pending() {
1714 assert!(exec.wake_next_timer().is_some(), "Executor stalled with no pending timers");
1715 }
1716 }
1717
1718 #[fuchsia::test]
1719 fn test_stale_session_status_changed_is_ignored() {
1720 let mut exec = fasync::TestExecutor::new_with_fake_time();
1721
1722 let mut test_fut = pin!(async {
1723 let inspector = inspect::Inspector::default();
1724 let rootdir = FunctionFsRootDir::new(inspector.root());
1725
1726 let (proxy1, stream1) =
1727 fidl::endpoints::create_proxy_and_stream::<fadb::UsbAdbImpl_Marker>();
1728 let (read_sender1, read_receiver1) = async_channel::unbounded();
1729 let (write_sender1, write_receiver1) = async_channel::unbounded();
1730
1731 rootdir.state.lock().session_id = 1;
1732
1733 let adb_fut1 = handle_adb(
1734 proxy1,
1735 None,
1736 read_receiver1,
1737 write_receiver1,
1738 Arc::clone(&rootdir.state),
1739 Arc::clone(&rootdir.stats),
1740 1,
1741 );
1742
1743 let driver_state = Arc::clone(&rootdir.state);
1744 let driver_fut = async move {
1745 {
1747 let mut state = driver_state.lock();
1748 state.session_id = 2;
1749 state.is_online = true;
1750 state.event_queue.clear();
1751 }
1752
1753 stream1
1755 .control_handle()
1756 .send_on_status_changed(fadb::StatusFlags::empty())
1757 .expect("send offline status");
1758
1759 drop(read_sender1);
1760 drop(write_sender1);
1761 drop(stream1);
1762 };
1763
1764 futures::join!(adb_fut1, driver_fut);
1765
1766 let state = rootdir.state.lock();
1767 assert!(state.is_online, "Stale status change must not overwrite is_online");
1768 assert!(
1769 state.event_queue.is_empty(),
1770 "Stale status change must not push events to active session"
1771 );
1772 });
1773
1774 while exec.run_until_stalled(&mut test_fut).is_pending() {
1775 assert!(exec.wake_next_timer().is_some(), "Executor stalled with no pending timers");
1776 }
1777 }
1778
1779 #[fuchsia::test]
1780 fn test_unbind_clears_endpoints_and_channels() {
1781 let mut exec = fasync::TestExecutor::new_with_fake_time();
1782
1783 let mut test_fut = pin!(async {
1784 let inspector = inspect::Inspector::default();
1785 let rootdir = FunctionFsRootDir::new(inspector.root());
1786
1787 let (proxy, stream) =
1788 fidl::endpoints::create_proxy_and_stream::<fadb::UsbAdbImpl_Marker>();
1789 let (read_sender, read_receiver) = async_channel::unbounded();
1790 let (write_sender, write_receiver) = async_channel::unbounded();
1791
1792 let (client_channel, _server_channel) = zx::Channel::create();
1794 {
1795 let mut state = rootdir.state.lock();
1796 state.session_id = 1;
1797 state.has_input_output_endpoints = true;
1798 state.device_proxy = Some(fadb::DeviceSynchronousProxy::new(client_channel));
1799 state.adb_read_channel = Some(read_sender);
1800 state.adb_write_channel = Some(write_sender);
1801 state.event_queue.push_back(usb_functionfs_event {
1802 type_: usb_functionfs_event_type_FUNCTIONFS_BIND as u8,
1803 ..Default::default()
1804 });
1805 state.record_event("BIND");
1806 }
1807
1808 drop(stream);
1810
1811 handle_adb(
1812 proxy,
1813 None,
1814 read_receiver,
1815 write_receiver,
1816 Arc::clone(&rootdir.state),
1817 Arc::clone(&rootdir.stats),
1818 1,
1819 )
1820 .await;
1821
1822 let state = rootdir.state.lock();
1823 assert!(!state.is_online);
1824 assert!(
1825 state.device_proxy.is_none(),
1826 "UNBIND must clear device_proxy for the active session"
1827 );
1828 assert!(
1829 !state.has_input_output_endpoints,
1830 "UNBIND must clear has_input_output_endpoints so wait_until_online aborts"
1831 );
1832 assert!(
1833 state.adb_read_channel.is_none(),
1834 "UNBIND must clear adb_read_channel so ep1 reads do not block on dead session"
1835 );
1836 assert!(
1837 state.adb_write_channel.is_none(),
1838 "UNBIND must clear adb_write_channel so ep2 writes do not block on dead session"
1839 );
1840 let events: Vec<u8> = state.event_queue.iter().map(|e| e.type_).collect();
1841 assert_eq!(
1842 events,
1843 vec![
1844 usb_functionfs_event_type_FUNCTIONFS_BIND as u8,
1845 usb_functionfs_event_type_FUNCTIONFS_UNBIND as u8,
1846 ],
1847 "Exactly one BIND and one UNBIND event should be queued"
1848 );
1849 });
1850
1851 while exec.run_until_stalled(&mut test_fut).is_pending() {
1852 assert!(exec.wake_next_timer().is_some(), "Executor stalled with no pending timers");
1853 }
1854 }
1855
1856 #[fuchsia::test]
1857 async fn test_create_endpoints_without_hardware_service() {
1858 starnix_core::testing::spawn_kernel_and_run_sync(|current_task| {
1859 let inspector = inspect::Inspector::default();
1860 let rootdir = FunctionFsRootDir::new(inspector.root());
1861
1862 let result = rootdir.create_endpoints(current_task.kernel());
1863 assert_eq!(result, Ok(()));
1864 assert!(rootdir.state.lock().has_input_output_endpoints);
1865 assert!(rootdir.state.lock().adb_read_channel.is_some());
1866 assert!(rootdir.state.lock().adb_write_channel.is_some());
1867 assert_eq!(
1868 rootdir.state.lock().event_queue.front().map(|e| e.type_),
1869 Some(usb_functionfs_event_type_FUNCTIONFS_BIND as u8)
1870 );
1871 })
1872 .await;
1873 }
1874
1875 #[fuchsia::test]
1876 async fn test_connect_to_device_without_hardware_service() {
1877 let result = connect_to_device(AdbProxyMode::None).await;
1878 assert!(result.is_err());
1879 }
1880
1881 #[fuchsia::test]
1882 async fn test_on_control_closed_clears_device_proxy() {
1883 let inspector = inspect::Inspector::default();
1884 let rootdir = FunctionFsRootDir::new(inspector.root());
1885
1886 let (client_channel, _server_channel) = zx::Channel::create();
1887 let device_proxy = fadb::DeviceSynchronousProxy::new(client_channel);
1888 {
1889 let mut state = rootdir.state.lock();
1890 state.num_open_file_objects = 1;
1891 state.device_proxy = Some(device_proxy);
1892 }
1893
1894 rootdir.on_control_closed();
1895
1896 let state = rootdir.state.lock();
1897 assert_eq!(state.num_open_file_objects, 0);
1898 assert!(state.device_proxy.is_none(), "device_proxy should be taken by on_control_closed");
1899 }
1900
1901 #[fuchsia::test]
1902 async fn test_session_change_stops_device_proxy() {
1903 let inspector = inspect::Inspector::default();
1904 let rootdir = FunctionFsRootDir::new(inspector.root());
1905
1906 let (client_channel, server_channel) = zx::Channel::create();
1907 let device_proxy = fadb::DeviceSynchronousProxy::new(client_channel);
1908
1909 let session_id = 1;
1911 {
1912 let mut state = rootdir.state.lock();
1913 state.session_id = 2; state.has_input_output_endpoints = true;
1915 }
1916
1917 {
1919 let mut state_locked = rootdir.state.lock();
1920 if state_locked.session_id != session_id || !state_locked.has_input_output_endpoints {
1921 let deadline = zx::MonotonicInstant::after(zx::Duration::from_seconds(1));
1922 let _ = device_proxy.stop_adb(deadline);
1923 } else {
1924 state_locked.device_proxy = Some(device_proxy);
1925 }
1926 }
1927
1928 let mut stream = fadb::DeviceRequestStream::from_channel(fidl::AsyncChannel::from_channel(
1930 server_channel,
1931 ));
1932 match stream.next().await {
1933 Some(Ok(fadb::DeviceRequest::StopAdb { responder })) => {
1934 responder.send(Ok(())).expect("send StopAdb response");
1935 }
1936 other => panic!("Expected StopAdb request, got {other:?}"),
1937 }
1938 assert!(rootdir.state.lock().device_proxy.is_none());
1939 }
1940
1941 #[::fuchsia::test]
1942 fn test_functionfs_reset_waits_for_all_endpoint_file_objects() {
1943 let inspector = inspect::Inspector::default();
1944 let rootdir = FunctionFsRootDir::new(inspector.root());
1945
1946 rootdir.on_control_opened();
1948 {
1949 let mut state = rootdir.state.lock();
1950 state.has_input_output_endpoints = true;
1951 state.is_online = true;
1952 }
1953 rootdir.on_endpoint_opened(); rootdir.on_endpoint_opened(); rootdir.on_control_closed();
1959 assert!(rootdir.state.lock().has_input_output_endpoints);
1960 assert_eq!(rootdir.state.lock().control_resets, 0);
1961
1962 rootdir.on_endpoint_closed();
1964 assert!(rootdir.state.lock().has_input_output_endpoints);
1965 assert_eq!(rootdir.state.lock().control_resets, 0);
1966
1967 rootdir.on_endpoint_closed();
1969 assert!(!rootdir.state.lock().has_input_output_endpoints);
1970 assert!(!rootdir.state.lock().is_online);
1971 assert_eq!(rootdir.state.lock().control_resets, 1);
1972 }
1973}