1use crate::device_listener_registry::DeviceListenerRegistry;
6use crate::display_ownership::DisplayOwnership;
7use crate::focus_listener::FocusListener;
8use crate::input_device::{InputEventType, InputPipelineFeatureFlags};
9use crate::input_handler::Handler;
10use crate::{Dispatcher, Incoming, Transport, input_device, input_handler, metrics};
11use anyhow::{Context, Error, format_err};
12use fidl::endpoints::Proxy;
13use focus_chain_provider::FocusChainProviderPublisher;
14
15use fuchsia_inspect::NumericProperty;
16use fuchsia_inspect::health::Reporter;
17use fuchsia_sync::Mutex;
18use futures::channel::mpsc::{self, UnboundedReceiver, UnboundedSender};
19use futures::future::LocalBoxFuture;
20use futures::{FutureExt, StreamExt, TryStreamExt};
21use itertools::Itertools;
22use metrics_registry::*;
23use sorted_vec_map::{SortedVecMap, SortedVecSet};
24use std::rc::Rc;
25use std::sync::atomic::{AtomicU32, Ordering};
26use std::sync::{Arc, LazyLock};
27use strum::EnumCount;
28
29static NEXT_DEVICE_ID: LazyLock<AtomicU32> = LazyLock::new(|| AtomicU32::new(10));
36
37fn get_next_device_id() -> u32 {
41 NEXT_DEVICE_ID.fetch_add(1, Ordering::SeqCst)
42}
43
44type BoxedInputDeviceBinding = Box<dyn input_device::InputDeviceBinding>;
45
46pub struct InputDeviceBindingAndTask {
47 pub binding: BoxedInputDeviceBinding,
48 pub task: crate::dispatcher::TaskHandle<()>,
49}
50
51pub type InputDeviceBindingMap = Arc<Mutex<SortedVecMap<u32, Vec<InputDeviceBindingAndTask>>>>;
54
55pub struct InputPipelineAssembly {
69 sender: UnboundedSender<Vec<input_device::InputEvent>>,
72 receiver: UnboundedReceiver<Vec<input_device::InputEvent>>,
75
76 handlers: Vec<Rc<dyn input_handler::BatchInputHandler>>,
78
79 display_ownership_fut: Option<LocalBoxFuture<'static, ()>>,
81
82 focus_listener_fut: Option<LocalBoxFuture<'static, ()>>,
84
85 metrics_logger: metrics::MetricsLogger,
87
88 display_ownership: Option<Rc<DisplayOwnership>>,
90}
91
92impl InputPipelineAssembly {
93 pub fn new(metrics_logger: metrics::MetricsLogger) -> Self {
96 let (sender, receiver) = mpsc::unbounded();
97 InputPipelineAssembly {
98 sender,
99 receiver,
100 handlers: vec![],
101 metrics_logger,
102 display_ownership_fut: None,
103 focus_listener_fut: None,
104 display_ownership: None,
105 }
106 }
107
108 pub fn add_handler(mut self, handler: Rc<dyn input_handler::BatchInputHandler>) -> Self {
111 self.handlers.push(handler);
112 self
113 }
114
115 pub fn add_all_handlers(self, handlers: Vec<Rc<dyn input_handler::BatchInputHandler>>) -> Self {
117 handlers.into_iter().fold(self, |assembly, handler| assembly.add_handler(handler))
118 }
119
120 pub fn add_display_ownership(
121 self,
122 display_ownership_event: zx::Event,
123 input_handlers_node: &fuchsia_inspect::Node,
124 ) -> InputPipelineAssembly {
125 let h = DisplayOwnership::new(
126 display_ownership_event,
127 input_handlers_node,
128 self.metrics_logger.clone(),
129 );
130 self.add_display_ownership_handler(h)
131 }
132
133 pub fn add_display_ownership_handler(
134 mut self,
135 display_ownership: Rc<DisplayOwnership>,
136 ) -> InputPipelineAssembly {
137 let metrics_logger_clone = self.metrics_logger.clone();
138 let h_clone = display_ownership.clone();
139 let sender_clone = self.sender.clone();
140 let display_ownership_fut = Box::pin(async move {
141 h_clone.clone().set_handler_healthy();
142 h_clone.clone()
143 .handle_ownership_change(sender_clone)
144 .await
145 .map_err(|e| {
146 metrics_logger_clone.log_error(
147 InputPipelineErrorMetricDimensionEvent::InputPipelineDisplayOwnershipIsNotSupposedToTerminate,
148 std::format!(
149 "display ownership is not supposed to terminate - this is likely a problem: {:?}", e));
150 })
151 .unwrap();
152 h_clone.set_handler_unhealthy("Receive loop terminated for handler: DisplayOwnership");
153 });
154 self.display_ownership_fut = Some(display_ownership_fut);
155 self.display_ownership = Some(display_ownership.clone());
156 self.add_handler(display_ownership)
157 }
158
159 fn into_components(
165 self,
166 ) -> (
167 UnboundedSender<Vec<input_device::InputEvent>>,
168 UnboundedReceiver<Vec<input_device::InputEvent>>,
169 Vec<Rc<dyn input_handler::BatchInputHandler>>,
170 metrics::MetricsLogger,
171 Option<LocalBoxFuture<'static, ()>>,
172 Option<LocalBoxFuture<'static, ()>>,
173 Option<Rc<DisplayOwnership>>,
174 ) {
175 (
176 self.sender,
177 self.receiver,
178 self.handlers,
179 self.metrics_logger,
180 self.display_ownership_fut,
181 self.focus_listener_fut,
182 self.display_ownership,
183 )
184 }
185
186 pub fn add_focus_listener(
187 mut self,
188 incoming: &Incoming,
189 focus_chain_publisher: FocusChainProviderPublisher,
190 ) -> Self {
191 let metrics_logger_clone = self.metrics_logger.clone();
192 let incoming2 = incoming.clone();
193 let focus_listener_fut = Box::pin(async move {
194 if let Ok(mut focus_listener) = FocusListener::new(
195 &incoming2,
196 focus_chain_publisher,
197 metrics_logger_clone,
198 )
199 .map_err(|e| {
200 log::warn!("could not create focus listener, focus will not be dispatched: {:?}", e)
201 }) {
202 let _result = focus_listener
205 .dispatch_focus_changes()
206 .await
207 .map(|_| {
208 log::warn!("dispatch focus loop ended, focus will no longer be dispatched")
209 })
210 .map_err(|e| {
211 panic!("could not dispatch focus changes, this is a fatal error: {:?}", e)
212 });
213 }
214 });
215 self.focus_listener_fut = Some(focus_listener_fut);
216 self
217 }
218}
219
220pub struct InputPipeline {
248 pipeline_sender: UnboundedSender<Vec<input_device::InputEvent>>,
252
253 device_event_sender: UnboundedSender<Vec<input_device::InputEvent>>,
256
257 device_event_receiver: UnboundedReceiver<Vec<input_device::InputEvent>>,
259
260 input_device_types: Vec<input_device::InputDeviceType>,
262
263 input_device_bindings: InputDeviceBindingMap,
265
266 inspect_node: fuchsia_inspect::Node,
269
270 metrics_logger: metrics::MetricsLogger,
272
273 pub feature_flags: input_device::InputPipelineFeatureFlags,
275 display_ownership_fut: Option<LocalBoxFuture<'static, ()>>,
277
278 focus_listener_fut: Option<LocalBoxFuture<'static, ()>>,
280
281 watcher_fut: Option<LocalBoxFuture<'static, ()>>,
283
284 runner_fut: Option<LocalBoxFuture<'static, ()>>,
286
287 pub device_listener_registry: DeviceListenerRegistry,
289
290 pub display_ownership: Option<Rc<DisplayOwnership>>,
292}
293
294impl InputPipeline {
295 pub fn display_ownership(&self) -> Option<&Rc<DisplayOwnership>> {
297 self.display_ownership.as_ref()
298 }
299
300 fn new_common(
301 input_device_types: Vec<input_device::InputDeviceType>,
302 assembly: InputPipelineAssembly,
303 inspect_node: fuchsia_inspect::Node,
304 feature_flags: input_device::InputPipelineFeatureFlags,
305 ) -> Self {
306 let (
307 pipeline_sender,
308 receiver,
309 handlers,
310 metrics_logger,
311 display_ownership_fut,
312 focus_listener_fut,
313 display_ownership,
314 ) = assembly.into_components();
315
316 let mut handlers_count = handlers.len();
317 let display_ownership_fut = if let Some(fut) = display_ownership_fut {
318 handlers_count += 1;
319 Some(
320 async move {
321 fut.await;
322 panic!("display_ownership_fut exited unexpectedly, which compromises device state tracking. Terminating to avoid inconsistent state.");
323 }
324 .boxed_local(),
325 )
326 } else {
327 None
328 };
329
330 let focus_listener_fut = if let Some(fut) = focus_listener_fut {
331 handlers_count += 1;
332 Some(
333 async move {
334 fut.await;
335 panic!("focus_listener_fut exited unexpectedly, which breaks input routing. Terminating to avoid inconsistent state.");
336 }
337 .boxed_local(),
338 )
339 } else {
340 None
341 };
342
343 inspect_node.record_string("supported_input_devices", input_device_types.iter().join(", "));
345 inspect_node.record_uint("handlers_registered", handlers_count as u64);
346 inspect_node.record_uint("handlers_healthy", handlers_count as u64);
347
348 let runner_fut = Some(InputPipeline::run(receiver, handlers, metrics_logger.clone()));
350
351 let (device_event_sender, device_event_receiver) = futures::channel::mpsc::unbounded();
352 let input_device_bindings: InputDeviceBindingMap =
353 Arc::new(Mutex::new(SortedVecMap::new()));
354 let device_listener_registry = DeviceListenerRegistry::new();
355 InputPipeline {
356 pipeline_sender,
357 device_event_sender,
358 device_event_receiver,
359 input_device_types,
360 input_device_bindings,
361 inspect_node,
362 metrics_logger,
363 feature_flags,
364 display_ownership_fut,
365 focus_listener_fut,
366 watcher_fut: None,
367 runner_fut,
368 device_listener_registry,
369 display_ownership,
370 }
371 }
372
373 pub fn new_for_test(
381 input_device_types: Vec<input_device::InputDeviceType>,
382 assembly: InputPipelineAssembly,
383 ) -> Self {
384 let inspector = fuchsia_inspect::Inspector::default();
385 let root = inspector.root();
386 let test_node = root.create_child("input_pipeline");
387 Self::new_common(
388 input_device_types,
389 assembly,
390 test_node,
391 input_device::InputPipelineFeatureFlags { enable_merge_touch_events: false },
392 )
393 }
394}
395
396#[derive(Clone)]
397enum DeviceServiceSource {
398 Incoming(Incoming),
399 Service(fuchsia_component::client::Service<fidl_fuchsia_input_report::ServiceMarker>),
400}
401
402impl DeviceServiceSource {
403 fn open_service(
404 &self,
405 ) -> Result<fuchsia_component::client::Service<fidl_fuchsia_input_report::ServiceMarker>, Error>
406 {
407 match self {
408 Self::Incoming(incoming) => incoming
409 .open_service(fidl_fuchsia_input_report::ServiceMarker)
410 .context("failed to open service"),
411 Self::Service(service) => Ok(service.clone()),
412 }
413 }
414}
415
416impl InputPipeline {
417 pub fn new(
424 incoming: &Incoming,
425 input_device_types: Vec<input_device::InputDeviceType>,
426 assembly: InputPipelineAssembly,
427 inspect_node: fuchsia_inspect::Node,
428 feature_flags: input_device::InputPipelineFeatureFlags,
429 metrics_logger: metrics::MetricsLogger,
430 ) -> Result<Self, Error> {
431 Self::new_internal(
432 DeviceServiceSource::Incoming(incoming.clone()),
433 input_device_types,
434 assembly,
435 inspect_node,
436 feature_flags,
437 metrics_logger,
438 )
439 }
440
441 pub fn new_with_service(
444 service: fuchsia_component::client::Service<fidl_fuchsia_input_report::ServiceMarker>,
445 input_device_types: Vec<input_device::InputDeviceType>,
446 assembly: InputPipelineAssembly,
447 inspect_node: fuchsia_inspect::Node,
448 feature_flags: input_device::InputPipelineFeatureFlags,
449 metrics_logger: metrics::MetricsLogger,
450 ) -> Result<Self, Error> {
451 Self::new_internal(
452 DeviceServiceSource::Service(service),
453 input_device_types,
454 assembly,
455 inspect_node,
456 feature_flags,
457 metrics_logger,
458 )
459 }
460
461 fn new_internal(
462 service_source: DeviceServiceSource,
463 input_device_types: Vec<input_device::InputDeviceType>,
464 assembly: InputPipelineAssembly,
465 inspect_node: fuchsia_inspect::Node,
466 feature_flags: input_device::InputPipelineFeatureFlags,
467 metrics_logger: metrics::MetricsLogger,
468 ) -> Result<Self, Error> {
469 let mut input_pipeline =
470 Self::new_common(input_device_types, assembly, inspect_node, feature_flags);
471 let input_device_types = input_pipeline.input_device_types.clone();
472 let input_event_sender = input_pipeline.device_event_sender.clone();
473 let input_device_bindings = input_pipeline.input_device_bindings.clone();
474 let bound_instances: Arc<Mutex<SortedVecSet<String>>> =
475 Arc::new(Mutex::new(SortedVecSet::new()));
476 let device_listener_registry = input_pipeline.device_listener_registry.clone();
477 let devices_node = input_pipeline.inspect_node.create_child("input_devices");
478 let devices_node_weak = devices_node.clone_weak();
479 input_pipeline.inspect_node.record(devices_node);
480 let feature_flags = input_pipeline.feature_flags.clone();
481
482 let devices_inspect: Arc<
483 Mutex<Option<(Arc<fuchsia_inspect::UintProperty>, Arc<fuchsia_inspect::UintProperty>)>>,
484 > = Arc::new(Mutex::new(None));
485
486 let display_ownership = input_pipeline.display_ownership.clone();
487
488 if let Some(display_ownership) = &display_ownership {
489 let bindings_clone = input_device_bindings.clone();
490 let bound_instances_clone = bound_instances.clone();
491 let service_source_for_cb = service_source.clone();
492 let input_device_types_clone = input_device_types.clone();
493 let input_event_sender_clone = input_event_sender.clone();
494 let display_ownership_weak = Rc::downgrade(display_ownership);
495 let devices_node_weak_clone = devices_node_weak.clone_weak();
496 let devices_inspect_clone = devices_inspect.clone();
497 let feature_flags_clone = feature_flags.clone();
498 let metrics_logger_clone = metrics_logger.clone();
499 let device_listener_registry_clone = device_listener_registry.clone();
500
501 display_ownership.set_ownership_change_callback(move |has_ownership: bool| {
502 let bindings = bindings_clone.clone();
503 let bound_instances = bound_instances_clone.clone();
504 let service_source = service_source_for_cb.clone();
505 let input_device_types = input_device_types_clone.clone();
506 let input_event_sender = input_event_sender_clone.clone();
507 let display_ownership_weak = display_ownership_weak.clone();
508 let devices_node_weak = devices_node_weak_clone.clone_weak();
509 let devices_inspect = devices_inspect_clone.clone();
510 let feature_flags = feature_flags_clone.clone();
511 let metrics_logger = metrics_logger_clone.clone();
512 let device_listener_registry = device_listener_registry_clone.clone();
513
514 async move {
515 if !has_ownership {
516 log::info!("Input ownership lost: pausing device reader tasks and clearing bindings");
517 *bindings.lock() = SortedVecMap::new();
518 *bound_instances.lock() = SortedVecSet::new();
519 } else {
520 log::info!("Input ownership restored: resuming device discovery and reading");
521 match service_source.open_service() {
522 Ok(service) => {
523 let (discovered_prop, connected_prop) = {
524 let guard = devices_inspect.lock();
525 (
526 guard.as_ref().map(|(d, _)| d.clone()),
527 guard.as_ref().map(|(_, c)| c.clone()),
528 )
529 };
530 let display_ownership = display_ownership_weak.upgrade();
531 Self::re_enumerate_devices(
532 service,
533 &input_device_types,
534 &input_event_sender,
535 &bindings,
536 &bound_instances,
537 display_ownership.as_ref(),
538 &devices_node_weak,
539 discovered_prop.as_deref(),
540 connected_prop.as_deref(),
541 feature_flags,
542 metrics_logger,
543 device_listener_registry,
544 )
545 .await;
546 }
547 Err(e) => {
548 metrics_logger.log_warn(
549 InputPipelineErrorMetricDimensionEvent::InputPipelineUnableToWatchForNewInputDevices,
550 std::format!("Failed to open service on ownership restore: {:?}", e),
551 );
552 }
553 }
554 }
555 }
556 .boxed_local()
557 });
558 }
559
560 let watcher_fut = async move {
561 let devices_discovered =
562 Arc::new(devices_node_weak.create_uint("devices_discovered", 0));
563 let devices_connected =
564 Arc::new(devices_node_weak.create_uint("devices_connected", 0));
565 *devices_inspect.lock() =
566 Some((devices_discovered.clone(), devices_connected.clone()));
567
568 match service_source.open_service() {
569 Ok(service) => {
570 match Self::watch_for_devices_internal(
571 service,
572 input_device_types,
573 input_event_sender,
574 input_device_bindings,
575 bound_instances,
576 display_ownership,
577 &devices_node_weak,
578 &devices_discovered,
579 &devices_connected,
580 false, feature_flags,
582 metrics_logger.clone(),
583 device_listener_registry,
584 )
585 .await
586 .context("failed to watch for devices")
587 {
588 Ok(()) => {}
589 Err(err) => {
590 metrics_logger.log_warn(
591 InputPipelineErrorMetricDimensionEvent::InputPipelineUnableToWatchForNewInputDevices,
592 std::format!(
593 "Input pipeline is unable to watch for new input devices: {:?}",
594 err
595 ));
596 }
597 }
598 }
599 Err(err) => {
600 metrics_logger.log_warn(
601 InputPipelineErrorMetricDimensionEvent::InputPipelineUnableToWatchForNewInputDevices,
602 std::format!(
603 "Input pipeline is unable to open service for watching new input devices: {:?}",
604 err
605 ));
606 }
607 }
608 }
609 .boxed_local();
610
611 input_pipeline.watcher_fut = Some(watcher_fut);
612
613 Ok(input_pipeline)
614 }
615
616 pub fn input_device_bindings(&self) -> &InputDeviceBindingMap {
618 &self.input_device_bindings
619 }
620
621 pub fn input_event_sender(&self) -> &UnboundedSender<Vec<input_device::InputEvent>> {
624 &self.device_event_sender
625 }
626
627 pub fn input_device_types(&self) -> &[input_device::InputDeviceType] {
629 &self.input_device_types
630 }
631
632 pub fn device_listener_registry(&self) -> &DeviceListenerRegistry {
634 &self.device_listener_registry
635 }
636
637 pub async fn handle_input_events(self) {
639 let metrics_logger_clone = self.metrics_logger.clone();
640 let mut device_event_receiver = self.device_event_receiver;
641 let pipeline_sender = self.pipeline_sender.clone();
642
643 let forwarder = async move {
644 while let Some(input_event) = device_event_receiver.next().await {
645 if let Err(e) = pipeline_sender.unbounded_send(input_event) {
646 metrics_logger_clone.log_error(
647 InputPipelineErrorMetricDimensionEvent::InputPipelineCouldNotForwardEventFromDriver,
648 std::format!("could not forward event from driver: {:?}", e));
649 }
650 }
651
652 metrics_logger_clone.log_error(
653 InputPipelineErrorMetricDimensionEvent::InputPipelineStopHandlingEvents,
654 "Input pipeline stopped handling input events.".to_string(),
655 );
656 }.boxed_local();
657
658 let tasks = crate::task::InputPipelineTasks {
659 watcher: self.watcher_fut.unwrap_or_else(|| Box::pin(futures::future::pending())),
660 runner: self.runner_fut.unwrap_or_else(|| Box::pin(futures::future::pending())),
661 display_ownership: self.display_ownership_fut,
662 focus_listener: self.focus_listener_fut,
663 forwarder,
664 };
665
666 tasks.run().await;
667 }
668
669 async fn re_enumerate_devices(
670 service: fuchsia_component::client::Service<fidl_fuchsia_input_report::ServiceMarker>,
671 device_types: &[input_device::InputDeviceType],
672 input_event_sender: &UnboundedSender<Vec<input_device::InputEvent>>,
673 bindings: &InputDeviceBindingMap,
674 bound_instances: &Arc<Mutex<SortedVecSet<String>>>,
675 display_ownership: Option<&Rc<DisplayOwnership>>,
676 input_devices_node: &fuchsia_inspect::Node,
677 devices_discovered: Option<&fuchsia_inspect::UintProperty>,
678 devices_connected: Option<&fuchsia_inspect::UintProperty>,
679 feature_flags: input_device::InputPipelineFeatureFlags,
680 metrics_logger: metrics::MetricsLogger,
681 device_listener_registry: DeviceListenerRegistry,
682 ) {
683 match service.enumerate().await {
684 Ok(instances) => {
685 for instance in instances {
686 Self::connect_and_bind_device(
687 &instance,
688 device_types,
689 input_event_sender,
690 bindings,
691 bound_instances,
692 display_ownership,
693 input_devices_node,
694 devices_discovered,
695 devices_connected,
696 feature_flags.clone(),
697 metrics_logger.clone(),
698 device_listener_registry.clone(),
699 )
700 .await;
701 }
702 }
703 Err(e) => {
704 metrics_logger.log_warn(
705 InputPipelineErrorMetricDimensionEvent::InputPipelineUnableToWatchForNewInputDevices,
706 std::format!("Failed to enumerate devices on ownership restore: {:?}", e),
707 );
708 }
709 }
710 }
711
712 async fn connect_and_bind_device(
713 instance: &fidl_fuchsia_input_report::ServiceProxy,
714 device_types: &[input_device::InputDeviceType],
715 input_event_sender: &UnboundedSender<Vec<input_device::InputEvent>>,
716 bindings: &InputDeviceBindingMap,
717 bound_instances: &Arc<Mutex<SortedVecSet<String>>>,
718 display_ownership: Option<&Rc<DisplayOwnership>>,
719 input_devices_node: &fuchsia_inspect::Node,
720 devices_discovered: Option<&fuchsia_inspect::UintProperty>,
721 devices_connected: Option<&fuchsia_inspect::UintProperty>,
722 feature_flags: input_device::InputPipelineFeatureFlags,
723 metrics_logger: metrics::MetricsLogger,
724 device_listener_registry: DeviceListenerRegistry,
725 ) {
726 let filename = instance.instance_name().to_string();
727
728 if let Some(ownership) = display_ownership {
729 if ownership.is_display_ownership_lost() {
730 log::info!("skipping device {} because platform input ownership is lost", filename);
731 return;
732 }
733 }
734
735 {
736 let mut bound = bound_instances.lock();
737 if bound.contains(&filename) {
738 log::info!("device {} is already bound, skipping", filename);
739 return;
740 }
741 bound.insert(filename.clone());
742 }
743
744 log::info!("found input device {}", filename);
745 if let Some(devices_discovered) = devices_discovered {
746 devices_discovered.add(1);
747 }
748
749 let bound_instances_clone = bound_instances.clone();
750 let filename_clone = filename.clone();
751 let res = async {
752 let device_proxy =
753 instance.connect_to_input_device().context("connect to input device")?;
754 let channel = device_proxy
755 .into_client_end()
756 .map_err(|_| format_err!("failed to get client end"))?
757 .into_channel();
758 let device_client = fidl_next::ClientEnd::<
759 fidl_next_fuchsia_input_report::InputDevice,
760 zx::Channel,
761 >::from_untyped(channel);
762 let device_client = Dispatcher::client_from_zx_channel(device_client);
763 let (device_client, join_handle) = device_client.spawn_full();
764 let device_id = get_next_device_id();
765 if let Some(descriptor) = add_device_bindings(
766 device_types,
767 &filename,
768 device_client,
769 input_event_sender,
770 bindings,
771 device_id,
772 input_devices_node,
773 devices_connected,
774 feature_flags,
775 metrics_logger,
776 false,
777 )
778 .await
779 {
780 if let Some(ownership) = display_ownership {
781 if ownership.is_display_ownership_lost() {
782 log::info!(
783 "ownership lost while binding device {}, dropping binding",
784 filename
785 );
786 bound_instances_clone.lock().remove(&filename_clone);
787 bindings.lock().remove(&device_id);
788 return Ok::<(), Error>(());
789 }
790 }
791 device_listener_registry.notify_device_changed(
792 fidl_next_fuchsia_ui_input::Action::Added,
793 device_id,
794 descriptor.clone(),
795 );
796 let device_listener_registry_clone = device_listener_registry.clone();
797 let bindings_clone = bindings.clone();
798 let bound_instances_disconnect = bound_instances_clone.clone();
799 let filename_disconnect = filename_clone.clone();
800 let watch_task = Dispatcher::spawn_local(async move {
801 let _ = join_handle.await;
802 log::info!("Device {} disconnected", device_id);
803 device_listener_registry_clone.notify_device_changed(
804 fidl_next_fuchsia_ui_input::Action::Removed,
805 device_id,
806 descriptor,
807 );
808 bindings_clone.lock().remove(&device_id);
809 bound_instances_disconnect.lock().remove(&filename_disconnect);
810 });
811 watch_task.detach();
812 } else {
813 bound_instances_clone.lock().remove(&filename_clone);
814 }
815 Ok::<(), Error>(())
816 }
817 .await;
818
819 if let Err(e) = res {
820 bound_instances.lock().remove(&filename);
821 log::error!("Failed to connect and bind input device {}: {:?}", filename, e);
822 }
823 }
824
825 pub async fn watch_for_devices(
843 service: fuchsia_component::client::Service<fidl_fuchsia_input_report::ServiceMarker>,
844 device_types: Vec<input_device::InputDeviceType>,
845 input_event_sender: UnboundedSender<Vec<input_device::InputEvent>>,
846 bindings: InputDeviceBindingMap,
847 input_devices_node: &fuchsia_inspect::Node,
848 devices_discovered: &fuchsia_inspect::UintProperty,
849 devices_connected: &fuchsia_inspect::UintProperty,
850 break_on_idle: bool,
851 feature_flags: input_device::InputPipelineFeatureFlags,
852 metrics_logger: metrics::MetricsLogger,
853 device_listener_registry: DeviceListenerRegistry,
854 ) -> Result<(), Error> {
855 let bound_instances = Arc::new(Mutex::new(SortedVecSet::new()));
856 Self::watch_for_devices_internal(
857 service,
858 device_types,
859 input_event_sender,
860 bindings,
861 bound_instances,
862 None,
863 input_devices_node,
864 devices_discovered,
865 devices_connected,
866 break_on_idle,
867 feature_flags,
868 metrics_logger,
869 device_listener_registry,
870 )
871 .await
872 }
873
874 async fn watch_for_devices_internal(
875 service: fuchsia_component::client::Service<fidl_fuchsia_input_report::ServiceMarker>,
876 device_types: Vec<input_device::InputDeviceType>,
877 input_event_sender: UnboundedSender<Vec<input_device::InputEvent>>,
878 bindings: InputDeviceBindingMap,
879 bound_instances: Arc<Mutex<SortedVecSet<String>>>,
880 display_ownership: Option<Rc<DisplayOwnership>>,
881 input_devices_node: &fuchsia_inspect::Node,
882 devices_discovered: &fuchsia_inspect::UintProperty,
883 devices_connected: &fuchsia_inspect::UintProperty,
884 break_on_idle: bool,
885 feature_flags: input_device::InputPipelineFeatureFlags,
886 metrics_logger: metrics::MetricsLogger,
887 device_listener_registry: DeviceListenerRegistry,
888 ) -> Result<(), Error> {
889 if break_on_idle {
890 let instances = service.enumerate().await?;
891 for instance in instances {
892 Self::connect_and_bind_device(
893 &instance,
894 &device_types,
895 &input_event_sender,
896 &bindings,
897 &bound_instances,
898 display_ownership.as_ref(),
899 input_devices_node,
900 Some(devices_discovered),
901 Some(devices_connected),
902 feature_flags.clone(),
903 metrics_logger.clone(),
904 device_listener_registry.clone(),
905 )
906 .await;
907 }
908 Ok(())
909 } else {
910 let mut instances = service
911 .watch()
912 .await
913 .context("failed to watch input-report service")?
914 .err_into::<Error>()
915 .boxed();
916
917 while let Some(instance) = instances.try_next().await? {
918 Self::connect_and_bind_device(
919 &instance,
920 &device_types,
921 &input_event_sender,
922 &bindings,
923 &bound_instances,
924 display_ownership.as_ref(),
925 input_devices_node,
926 Some(devices_discovered),
927 Some(devices_connected),
928 feature_flags.clone(),
929 metrics_logger.clone(),
930 device_listener_registry.clone(),
931 )
932 .await;
933 }
934
935 Err(format_err!("Input pipeline stopped watching for new input devices."))
936 }
937 }
938
939 pub async fn handle_input_device_registry_request_stream(
954 mut stream: fidl_fuchsia_input_injection::InputDeviceRegistryRequestStream,
955 device_types: &[input_device::InputDeviceType],
956 input_event_sender: &UnboundedSender<Vec<input_device::InputEvent>>,
957 bindings: &InputDeviceBindingMap,
958 input_devices_node: &fuchsia_inspect::Node,
959 feature_flags: input_device::InputPipelineFeatureFlags,
960 metrics_logger: metrics::MetricsLogger,
961 device_listener_registry: DeviceListenerRegistry,
962 task_sender: UnboundedSender<crate::dispatcher::TaskHandle<()>>,
963 ) -> Result<(), Error> {
964 while let Some(request) = stream
965 .try_next()
966 .await
967 .context("Error handling input device registry request stream")?
968 {
969 match request {
970 fidl_fuchsia_input_injection::InputDeviceRegistryRequest::Register {
971 device,
972 ..
973 } => {
974 let device = fidl_next::ClientEnd::<
976 fidl_next_fuchsia_input_report::InputDevice,
977 zx::Channel,
978 >::from_untyped(device.into_channel());
979 let device = Dispatcher::client_from_zx_channel(device);
980 let (device, join_handle) = device.spawn_full();
981 let device_id = get_next_device_id();
982
983 if let Some(descriptor) = add_device_bindings(
984 device_types,
985 &format!("input-device-registry-{}", device_id),
986 device,
987 input_event_sender,
988 bindings,
989 device_id,
990 input_devices_node,
991 None,
992 feature_flags.clone(),
993 metrics_logger.clone(),
994 true,
995 )
996 .await
997 {
998 device_listener_registry.notify_device_changed(
999 fidl_next_fuchsia_ui_input::Action::Added,
1000 device_id,
1001 descriptor.clone(),
1002 );
1003
1004 let device_listener_registry_clone = device_listener_registry.clone();
1005 let bindings_clone = bindings.clone();
1006 let watch_task = Dispatcher::spawn_local(async move {
1007 let _ = join_handle.await;
1008 log::info!("Injected device {} disconnected", device_id);
1009 device_listener_registry_clone.notify_device_changed(
1010 fidl_next_fuchsia_ui_input::Action::Removed,
1011 device_id,
1012 descriptor,
1013 );
1014 bindings_clone.lock().remove(&device_id);
1015 });
1016 let _ = task_sender.unbounded_send(watch_task);
1017 }
1018 }
1019 fidl_fuchsia_input_injection::InputDeviceRegistryRequest::RegisterAndGetDeviceInfo {
1020 device,
1021 responder,
1022 .. } => {
1023 let device = fidl_next::ClientEnd::<
1025 fidl_next_fuchsia_input_report::InputDevice,
1026 zx::Channel,
1027 >::from_untyped(device.into_channel());
1028 let device = Dispatcher::client_from_zx_channel(device);
1029 let (device, join_handle) = device.spawn_full();
1030 let device_id = get_next_device_id();
1031
1032 let descriptor_opt = add_device_bindings(
1033 device_types,
1034 &format!("input-device-registry-{}", device_id),
1035 device,
1036 input_event_sender,
1037 bindings,
1038 device_id,
1039 input_devices_node,
1040 None,
1041 feature_flags.clone(),
1042 metrics_logger.clone(),
1043 true,
1044 )
1045 .await;
1046
1047 if let Some(descriptor) = descriptor_opt {
1048 device_listener_registry.notify_device_changed(
1049 fidl_next_fuchsia_ui_input::Action::Added,
1050 device_id,
1051 descriptor.clone(),
1052 );
1053
1054 let device_listener_registry_clone = device_listener_registry.clone();
1055 let bindings_clone = bindings.clone();
1056 let watch_task = Dispatcher::spawn_local(async move {
1057 let _ = join_handle.await;
1058 log::info!("Injected device {} disconnected", device_id);
1059 device_listener_registry_clone.notify_device_changed(
1060 fidl_next_fuchsia_ui_input::Action::Removed,
1061 device_id,
1062 descriptor.clone(),
1063 );
1064 bindings_clone.lock().remove(&device_id);
1065 });
1066 let _ = task_sender.unbounded_send(watch_task);
1067 }
1068
1069 responder.send(fidl_fuchsia_input_injection::InputDeviceRegistryRegisterAndGetDeviceInfoResponse{
1070 device_id: Some(device_id),
1071 ..Default::default()
1072 }).expect("Failed to respond to RegisterAndGetDeviceInfo request");
1073 }
1074 }
1075 }
1076
1077 Ok(())
1078 }
1079
1080 fn run(
1082 mut receiver: UnboundedReceiver<Vec<input_device::InputEvent>>,
1083 handlers: Vec<Rc<dyn input_handler::BatchInputHandler>>,
1084 metrics_logger: metrics::MetricsLogger,
1085 ) -> LocalBoxFuture<'static, ()> {
1086 async move {
1087 for handler in &handlers {
1088 handler.clone().set_handler_healthy();
1089 }
1090
1091 let mut handlers_by_type: [Vec<Rc<dyn input_handler::BatchInputHandler>>;
1092 InputEventType::COUNT] = Default::default();
1093
1094 let event_types = vec![
1096 InputEventType::Keyboard,
1097 InputEventType::LightSensor,
1098 InputEventType::ConsumerControls,
1099 InputEventType::Mouse,
1100 InputEventType::TouchScreen,
1101 InputEventType::Touchpad,
1102 #[cfg(test)]
1103 InputEventType::Fake,
1104 ];
1105
1106 for event_type in event_types {
1107 let handlers_for_type: Vec<Rc<dyn input_handler::BatchInputHandler>> = handlers
1108 .iter()
1109 .filter(|h| h.interest().contains(&event_type))
1110 .cloned()
1111 .collect();
1112 handlers_by_type[event_type as usize] = handlers_for_type;
1113 }
1114
1115 while let Some(events) = receiver.next().await {
1116 if events.is_empty() {
1117 continue;
1118 }
1119
1120 let mut groups_seen = 0;
1121 let events = events.into_iter().chunk_by(|e| InputEventType::from(&e.device_event));
1122 let events = events.into_iter().map(|(k, v)| (k, v.collect::<Vec<_>>()));
1123 for (event_type, event_group) in events {
1124 groups_seen += 1;
1125 if groups_seen == 2 {
1126 metrics_logger.log_error(
1127 InputPipelineErrorMetricDimensionEvent::InputFrameContainsMultipleTypesOfEvents,
1128 "it is not recommended to contain multiple types of events in 1 send".to_string(),
1129 );
1130 }
1131 let mut events_in_group = event_group;
1132
1133 let handlers = &handlers_by_type[event_type as usize];
1135
1136 for handler in handlers {
1137 events_in_group =
1138 handler.clone().handle_input_events(events_in_group).await;
1139 }
1140
1141 for event in events_in_group {
1142 if event.handled == input_device::Handled::No {
1143 log::warn!("unhandled input event: {:?}", event);
1144 }
1145 if let Some(trace_id) = event.trace_id {
1146 fuchsia_trace::flow_end!(
1147 "input",
1148 "event_in_input_pipeline",
1149 trace_id.into()
1150 );
1151 }
1152 }
1153 }
1154 }
1155 for handler in &handlers {
1156 handler.clone().set_handler_unhealthy("Pipeline loop terminated");
1157 }
1158 panic!("Runner task is not supposed to terminate.")
1159 }
1160 .boxed_local()
1161 }
1162}
1163
1164async fn add_device_bindings(
1184 device_types: &[input_device::InputDeviceType],
1185 instance_name: &str,
1186 device_proxy: fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
1187 input_event_sender: &UnboundedSender<Vec<input_device::InputEvent>>,
1188 bindings: &InputDeviceBindingMap,
1189 device_id: u32,
1190 input_devices_node: &fuchsia_inspect::Node,
1191 devices_connected: Option<&fuchsia_inspect::UintProperty>,
1192 feature_flags: InputPipelineFeatureFlags,
1193 metrics_logger: metrics::MetricsLogger,
1194 is_injected: bool,
1195) -> Option<fidl_next_fuchsia_input_report::DeviceDescriptor> {
1196 let mut matched_device_types = vec![];
1197 let descriptor = match device_proxy.get_descriptor().await {
1198 Ok(res) => {
1199 for device_type in device_types {
1200 if input_device::is_device_type(&res.descriptor, *device_type).await {
1201 matched_device_types.push(device_type);
1202 match devices_connected {
1203 Some(dev_connected) => {
1204 let _ = dev_connected.add(1);
1205 }
1206 None => (),
1207 };
1208 }
1209 }
1210 if matched_device_types.is_empty() {
1211 log::info!(
1212 "device {} did not match any supported device types: {:?}",
1213 instance_name,
1214 device_types
1215 );
1216 let device_node =
1217 input_devices_node.create_child(format!("{}_Unsupported", instance_name));
1218 let mut health = fuchsia_inspect::health::Node::new(&device_node);
1219 health.set_unhealthy("Unsupported device type.");
1220 device_node.record(health);
1221 input_devices_node.record(device_node);
1222 return None;
1223 }
1224 res.descriptor
1225 }
1226 Err(_) => {
1227 metrics_logger.clone().log_error(
1228 InputPipelineErrorMetricDimensionEvent::InputPipelineNoDeviceDescriptor,
1229 std::format!("cannot bind device {} without a device descriptor", instance_name),
1230 );
1231 return None;
1232 }
1233 };
1234
1235 log::info!(
1236 "binding {} to device types: {}",
1237 instance_name,
1238 matched_device_types
1239 .iter()
1240 .fold(String::new(), |device_types_string, device_type| device_types_string
1241 + &format!("{:?}, ", device_type))
1242 );
1243
1244 let mut new_bindings: Vec<InputDeviceBindingAndTask> = vec![];
1245 for device_type in matched_device_types {
1246 let proxy = device_proxy.clone();
1267 let device_node =
1268 input_devices_node.create_child(format!("{}_{}", instance_name, device_type));
1269 match input_device::get_device_binding(
1270 *device_type,
1271 proxy,
1272 device_id,
1273 input_event_sender.clone(),
1274 device_node,
1275 feature_flags.clone(),
1276 metrics_logger.clone(),
1277 is_injected,
1278 )
1279 .await
1280 {
1281 Ok((binding, task)) => new_bindings.push(InputDeviceBindingAndTask { binding, task }),
1282 Err(e) => {
1283 metrics_logger.log_error(
1284 InputPipelineErrorMetricDimensionEvent::InputPipelineFailedToBind,
1285 std::format!("failed to bind {} as {:?}: {}", instance_name, device_type, e),
1286 );
1287 }
1288 }
1289 }
1290
1291 if !new_bindings.is_empty() {
1292 let mut bindings = bindings.lock();
1293 if let Some(v) = bindings.get_mut(&device_id) {
1294 v.extend(new_bindings);
1295 } else {
1296 bindings.insert(device_id, new_bindings);
1297 }
1298 Some(descriptor)
1299 } else {
1300 None
1301 }
1302}
1303
1304#[cfg(test)]
1305mod tests {
1306 use super::*;
1307 use crate::dispatcher::Transport;
1308 use fidl_next::Request;
1309
1310 struct MockDeviceListener {
1311 event_sender:
1312 futures::channel::mpsc::UnboundedSender<fidl_next_fuchsia_ui_input::DeviceEvent>,
1313 }
1314
1315 impl fidl_next_fuchsia_ui_input::DeviceListenerServerHandler<Transport> for MockDeviceListener {
1316 async fn on_device_changed(
1317 &mut self,
1318 request: Request<
1319 fidl_next_fuchsia_ui_input::device_listener::OnDeviceChanged,
1320 Transport,
1321 >,
1322 ) {
1323 let event = request.payload().event.clone();
1324 let _ = self.event_sender.unbounded_send(event);
1325 }
1326 }
1327 use crate::input_device::{InputDeviceBinding, InputEventType};
1328 use crate::utils::Position;
1329 use crate::{fake_input_device_binding, mouse_binding, observe_fake_events_input_handler};
1330 use async_trait::async_trait;
1331 use diagnostics_assertions::AnyProperty;
1332 use fidl::endpoints::{create_proxy_and_stream, create_request_stream};
1333 use fidl_fuchsia_io as fio;
1334 use fuchsia_async as fasync;
1335 use futures::{FutureExt, StreamExt};
1336 use pretty_assertions::assert_eq;
1337 use rand::RngExt as _;
1338 use sorted_vec_map::SortedVecSet;
1339 use vfs::{pseudo_directory, service as pseudo_fs_service};
1340
1341 fn send_input_event(
1346 sender: UnboundedSender<Vec<input_device::InputEvent>>,
1347 ) -> Vec<input_device::InputEvent> {
1348 let mut rng = rand::rng();
1349 let offset =
1350 Position { x: rng.random_range(0..10) as f32, y: rng.random_range(0..10) as f32 };
1351 let input_event = input_device::InputEvent {
1352 device_event: input_device::InputDeviceEvent::Mouse(mouse_binding::MouseEvent::new(
1353 mouse_binding::MouseLocation::Relative(mouse_binding::RelativeLocation {
1354 counts: Position { x: offset.x, y: offset.y },
1355 }),
1356 None, None, mouse_binding::MousePhase::Move,
1359 SortedVecSet::new(),
1360 SortedVecSet::new(),
1361 None, None, )),
1364 device_descriptor: input_device::InputDeviceDescriptor::Mouse(
1365 mouse_binding::MouseDeviceDescriptor {
1366 device_id: 1,
1367 absolute_x_range: None,
1368 absolute_y_range: None,
1369 wheel_v_range: None,
1370 wheel_h_range: None,
1371 buttons: None,
1372 },
1373 ),
1374 event_time: zx::MonotonicInstant::get(),
1375 handled: input_device::Handled::No,
1376 trace_id: None,
1377 };
1378 match sender.unbounded_send(vec![input_event.clone()]) {
1379 Err(_) => assert!(false),
1380 _ => {}
1381 }
1382
1383 vec![input_event]
1384 }
1385
1386 fn handle_input_device_request(
1391 input_device_request: fidl_fuchsia_input_report::InputDeviceRequest,
1392 ) {
1393 match input_device_request {
1394 fidl_fuchsia_input_report::InputDeviceRequest::GetDescriptor { responder } => {
1395 let _ = responder.send(&fidl_fuchsia_input_report::DeviceDescriptor {
1396 device_information: None,
1397 mouse: Some(fidl_fuchsia_input_report::MouseDescriptor {
1398 input: Some(fidl_fuchsia_input_report::MouseInputDescriptor {
1399 movement_x: None,
1400 movement_y: None,
1401 scroll_v: None,
1402 scroll_h: None,
1403 buttons: Some(vec![0]),
1404 position_x: None,
1405 position_y: None,
1406 ..Default::default()
1407 }),
1408 ..Default::default()
1409 }),
1410 sensor: None,
1411 touch: None,
1412 keyboard: None,
1413 consumer_control: None,
1414 ..Default::default()
1415 });
1416 }
1417 fidl_fuchsia_input_report::InputDeviceRequest::GetInputReportsReaderV2 {
1418 responder,
1419 ..
1420 } => {
1421 let _ = responder.send(2);
1422 }
1423 _ => {}
1424 }
1425 }
1426
1427 #[fuchsia::test]
1429 async fn multiple_devices_single_handler() {
1430 let (device_event_sender, device_event_receiver) = futures::channel::mpsc::unbounded();
1432 let first_device_binding =
1433 fake_input_device_binding::FakeInputDeviceBinding::new(device_event_sender.clone());
1434 let second_device_binding =
1435 fake_input_device_binding::FakeInputDeviceBinding::new(device_event_sender.clone());
1436
1437 let (handler_event_sender, mut handler_event_receiver) =
1439 futures::channel::mpsc::channel(100);
1440 let input_handler = observe_fake_events_input_handler::ObserveFakeEventsInputHandler::new(
1441 handler_event_sender,
1442 );
1443
1444 let (sender, receiver, handlers, _, _, _, _) =
1446 InputPipelineAssembly::new(metrics::MetricsLogger::default())
1447 .add_handler(input_handler)
1448 .into_components();
1449 let inspector = fuchsia_inspect::Inspector::default();
1450 let test_node = inspector.root().create_child("input_pipeline");
1451 let runner_fut =
1452 Some(InputPipeline::run(receiver, handlers, metrics::MetricsLogger::default()));
1453 let input_pipeline = InputPipeline {
1454 pipeline_sender: sender,
1455 device_event_sender,
1456 device_event_receiver,
1457 input_device_types: vec![],
1458 input_device_bindings: Arc::new(Mutex::new(SortedVecMap::new())),
1459 inspect_node: test_node,
1460 metrics_logger: metrics::MetricsLogger::default(),
1461 feature_flags: input_device::InputPipelineFeatureFlags::default(),
1462 display_ownership_fut: None,
1463 focus_listener_fut: None,
1464 watcher_fut: None,
1465 runner_fut,
1466 device_listener_registry: DeviceListenerRegistry::new(),
1467 display_ownership: None,
1468 };
1469
1470 let first_device_events = send_input_event(first_device_binding.input_event_sender());
1472 let second_device_events = send_input_event(second_device_binding.input_event_sender());
1473
1474 let _pipeline_task = fasync::Task::local(input_pipeline.handle_input_events());
1476
1477 let first_handled_event = handler_event_receiver.next().await;
1479 assert_eq!(first_handled_event, first_device_events.into_iter().next());
1480
1481 let second_handled_event = handler_event_receiver.next().await;
1482 assert_eq!(second_handled_event, second_device_events.into_iter().next());
1483 }
1484
1485 #[fuchsia::test]
1487 async fn single_device_multiple_handlers() {
1488 let (device_event_sender, device_event_receiver) = futures::channel::mpsc::unbounded();
1490 let input_device_binding =
1491 fake_input_device_binding::FakeInputDeviceBinding::new(device_event_sender.clone());
1492
1493 let (first_handler_event_sender, mut first_handler_event_receiver) =
1495 futures::channel::mpsc::channel(100);
1496 let first_input_handler =
1497 observe_fake_events_input_handler::ObserveFakeEventsInputHandler::new(
1498 first_handler_event_sender,
1499 );
1500 let (second_handler_event_sender, mut second_handler_event_receiver) =
1501 futures::channel::mpsc::channel(100);
1502 let second_input_handler =
1503 observe_fake_events_input_handler::ObserveFakeEventsInputHandler::new(
1504 second_handler_event_sender,
1505 );
1506
1507 let (sender, receiver, handlers, _, _, _, _) =
1509 InputPipelineAssembly::new(metrics::MetricsLogger::default())
1510 .add_handler(first_input_handler)
1511 .add_handler(second_input_handler)
1512 .into_components();
1513 let inspector = fuchsia_inspect::Inspector::default();
1514 let test_node = inspector.root().create_child("input_pipeline");
1515 let runner_fut =
1516 Some(InputPipeline::run(receiver, handlers, metrics::MetricsLogger::default()));
1517 let input_pipeline = InputPipeline {
1518 pipeline_sender: sender,
1519 device_event_sender,
1520 device_event_receiver,
1521 input_device_types: vec![],
1522 input_device_bindings: Arc::new(Mutex::new(SortedVecMap::new())),
1523 inspect_node: test_node,
1524 metrics_logger: metrics::MetricsLogger::default(),
1525 feature_flags: input_device::InputPipelineFeatureFlags::default(),
1526 display_ownership_fut: None,
1527 focus_listener_fut: None,
1528 watcher_fut: None,
1529 runner_fut,
1530 device_listener_registry: DeviceListenerRegistry::new(),
1531 display_ownership: None,
1532 };
1533
1534 let input_events = send_input_event(input_device_binding.input_event_sender());
1536
1537 let _pipeline_task = fasync::Task::local(input_pipeline.handle_input_events());
1539
1540 let expected_event = input_events.into_iter().next();
1542 let first_handler_event = first_handler_event_receiver.next().await;
1543 assert_eq!(first_handler_event, expected_event);
1544 let second_handler_event = second_handler_event_receiver.next().await;
1545 assert_eq!(second_handler_event, expected_event);
1546 }
1547
1548 #[fuchsia::test]
1551 async fn watch_devices_one_match_exists() {
1552 let dir = pseudo_directory! {
1553 "fuchsia.input.report.Service" => pseudo_directory! {
1554 "instance_0" => pseudo_directory! {
1555 "input_device" => pseudo_fs_service::host(
1556 move |mut request_stream: fidl_fuchsia_input_report::InputDeviceRequestStream| {
1557 async move {
1558 while let Some(input_device_request) =
1559 request_stream.try_next().await.unwrap()
1560 {
1561 handle_input_device_request(input_device_request);
1562 }
1563
1564 }.boxed()
1565 },
1566 )
1567 }
1568 }
1569 };
1570
1571 let svc_proxy =
1574 vfs::directory::serve_read_only(dir, vfs::execution_scope::ExecutionScope::new());
1575
1576 let (input_event_sender, _input_event_receiver) = futures::channel::mpsc::unbounded();
1577 let bindings: InputDeviceBindingMap = Arc::new(Mutex::new(SortedVecMap::new()));
1578 let supported_device_types = vec![input_device::InputDeviceType::Mouse];
1579
1580 let inspector = fuchsia_inspect::Inspector::default();
1581 let test_node = inspector.root().create_child("input_pipeline");
1582 test_node.record_string(
1583 "supported_input_devices",
1584 supported_device_types.clone().iter().join(", "),
1585 );
1586 let input_devices = test_node.create_child("input_devices");
1587 diagnostics_assertions::assert_data_tree!(inspector, root: {
1589 input_pipeline: {
1590 supported_input_devices: "Mouse",
1591 input_devices: {}
1592 }
1593 });
1594
1595 let devices_discovered = input_devices.create_uint("devices_discovered", 0);
1596 let devices_connected = input_devices.create_uint("devices_connected", 0);
1597
1598 let dir = fuchsia_fs::directory::open_directory_async(
1599 &svc_proxy,
1600 "fuchsia.input.report.Service",
1601 fio::PERM_READABLE,
1602 )
1603 .expect("open service directory");
1604 let service = fuchsia_component::client::Service::from_service_dir_proxy(
1605 dir,
1606 fidl_fuchsia_input_report::ServiceMarker,
1607 );
1608
1609 let _ = InputPipeline::watch_for_devices(
1610 service,
1611 supported_device_types,
1612 input_event_sender,
1613 bindings.clone(),
1614 &input_devices,
1615 &devices_discovered,
1616 &devices_connected,
1617 true, InputPipelineFeatureFlags { enable_merge_touch_events: false },
1619 metrics::MetricsLogger::default(),
1620 DeviceListenerRegistry::new(),
1621 )
1622 .await;
1623
1624 {
1626 let bindings_map = bindings.lock();
1627 assert_eq!(bindings_map.len(), 1);
1628 let bindings_vector = bindings_map.get(&10);
1629 assert!(bindings_vector.is_some());
1630 assert_eq!(bindings_vector.unwrap().len(), 1);
1631 let boxed_mouse_binding = bindings_vector.unwrap().get(0);
1632 assert!(boxed_mouse_binding.is_some());
1633 assert_eq!(
1634 boxed_mouse_binding.unwrap().binding.get_device_descriptor(),
1635 input_device::InputDeviceDescriptor::Mouse(mouse_binding::MouseDeviceDescriptor {
1636 device_id: 10,
1637 absolute_x_range: None,
1638 absolute_y_range: None,
1639 wheel_v_range: None,
1640 wheel_h_range: None,
1641 buttons: Some(vec![0]),
1642 })
1643 );
1644 }
1645
1646 diagnostics_assertions::assert_data_tree!(inspector, root: {
1648 input_pipeline: {
1649 supported_input_devices: "Mouse",
1650 input_devices: {
1651 devices_discovered: 1u64,
1652 devices_connected: 1u64,
1653 "instance_0_Mouse": contains {
1654 reports_received_count: 0u64,
1655 reports_filtered_count: 0u64,
1656 events_generated: 0u64,
1657 last_received_timestamp_ns: 0u64,
1658 last_generated_timestamp_ns: 0u64,
1659 "fuchsia.inspect.Health": {
1660 status: "OK",
1661 start_timestamp_nanos: AnyProperty
1664 },
1665 }
1666 }
1667 }
1668 });
1669 }
1670
1671 #[fuchsia::test]
1674 async fn watch_devices_no_matches_exist() {
1675 let dir = pseudo_directory! {
1676 "fuchsia.input.report.Service" => pseudo_directory! {
1677 "instance_0" => pseudo_directory! {
1678 "input_device" => pseudo_fs_service::host(
1679 move |mut request_stream: fidl_fuchsia_input_report::InputDeviceRequestStream| {
1680 async move {
1681 while let Some(input_device_request) =
1682 request_stream.try_next().await.unwrap()
1683 {
1684 handle_input_device_request(input_device_request);
1685 }
1686
1687 }.boxed()
1688 },
1689 )
1690 }
1691 }
1692 };
1693
1694 let svc_proxy =
1697 vfs::directory::serve_read_only(dir, vfs::execution_scope::ExecutionScope::new());
1698
1699 let (input_event_sender, _input_event_receiver) = futures::channel::mpsc::unbounded();
1700 let bindings: InputDeviceBindingMap = Arc::new(Mutex::new(SortedVecMap::new()));
1701 let supported_device_types = vec![input_device::InputDeviceType::Keyboard];
1702
1703 let inspector = fuchsia_inspect::Inspector::default();
1704 let test_node = inspector.root().create_child("input_pipeline");
1705 test_node.record_string(
1706 "supported_input_devices",
1707 supported_device_types.clone().iter().join(", "),
1708 );
1709 let input_devices = test_node.create_child("input_devices");
1710 diagnostics_assertions::assert_data_tree!(inspector, root: {
1712 input_pipeline: {
1713 supported_input_devices: "Keyboard",
1714 input_devices: {}
1715 }
1716 });
1717
1718 let devices_discovered = input_devices.create_uint("devices_discovered", 0);
1719 let devices_connected = input_devices.create_uint("devices_connected", 0);
1720
1721 let dir = fuchsia_fs::directory::open_directory_async(
1722 &svc_proxy,
1723 "fuchsia.input.report.Service",
1724 fio::PERM_READABLE,
1725 )
1726 .expect("open service directory");
1727 let service = fuchsia_component::client::Service::from_service_dir_proxy(
1728 dir,
1729 fidl_fuchsia_input_report::ServiceMarker,
1730 );
1731
1732 let _ = InputPipeline::watch_for_devices(
1733 service,
1734 supported_device_types,
1735 input_event_sender,
1736 bindings.clone(),
1737 &input_devices,
1738 &devices_discovered,
1739 &devices_connected,
1740 true, InputPipelineFeatureFlags { enable_merge_touch_events: false },
1742 metrics::MetricsLogger::default(),
1743 DeviceListenerRegistry::new(),
1744 )
1745 .await;
1746
1747 {
1749 let bindings = bindings.lock();
1750 assert_eq!(bindings.len(), 0);
1751 }
1752
1753 diagnostics_assertions::assert_data_tree!(inspector, root: {
1755 input_pipeline: {
1756 supported_input_devices: "Keyboard",
1757 input_devices: {
1758 devices_discovered: 1u64,
1759 devices_connected: 0u64,
1760 "instance_0_Unsupported": {
1761 "fuchsia.inspect.Health": {
1762 status: "UNHEALTHY",
1763 message: "Unsupported device type.",
1764 start_timestamp_nanos: AnyProperty
1767 },
1768 }
1769 }
1770 }
1771 });
1772 }
1773
1774 #[fuchsia::test]
1777 async fn handle_input_device_registry_request_stream() {
1778 let (input_device_registry_proxy, input_device_registry_request_stream) =
1779 create_proxy_and_stream::<fidl_fuchsia_input_injection::InputDeviceRegistryMarker>();
1780 let (input_device_client_end, mut input_device_request_stream) =
1781 create_request_stream::<fidl_fuchsia_input_report::InputDeviceMarker>();
1782
1783 let device_types = vec![input_device::InputDeviceType::Mouse];
1784 let (input_event_sender, _input_event_receiver) = futures::channel::mpsc::unbounded();
1785 let bindings: InputDeviceBindingMap = Arc::new(Mutex::new(SortedVecMap::new()));
1786
1787 let device_listener_registry = DeviceListenerRegistry::new();
1788 let (listener_client, listener_server) =
1789 fidl_next::fuchsia::create_channel::<fidl_next_fuchsia_ui_input::DeviceListener>();
1790 let listener_client = listener_client.spawn();
1791 let _existing_devices = device_listener_registry.add_listener(listener_client);
1792
1793 let (event_sender, mut event_receiver) = futures::channel::mpsc::unbounded();
1794 let _server_task = listener_server.spawn(MockDeviceListener { event_sender });
1795
1796 let _task = fasync::Task::local(async move {
1798 let _ = input_device_registry_proxy.register(input_device_client_end);
1800
1801 let mut count = 0;
1802 while count < 2 {
1803 if let Some(input_device_request) =
1804 input_device_request_stream.try_next().await.unwrap()
1805 {
1806 handle_input_device_request(input_device_request);
1807 count += 1;
1808 } else {
1809 break;
1810 }
1811 }
1812
1813 input_device_registry_proxy.take_event_stream();
1815 });
1816
1817 let inspector = fuchsia_inspect::Inspector::default();
1818 let test_node = inspector.root().create_child("input_pipeline");
1819
1820 let bindings_clone = bindings.clone();
1822 let device_listener_registry_clone = device_listener_registry.clone();
1823 let (task_sender, mut task_receiver) = futures::channel::mpsc::unbounded();
1824 let mut tasks = futures::stream::FuturesUnordered::new();
1825 let registry_fut = InputPipeline::handle_input_device_registry_request_stream(
1826 input_device_registry_request_stream,
1827 &device_types,
1828 &input_event_sender,
1829 &bindings_clone,
1830 &test_node,
1831 InputPipelineFeatureFlags { enable_merge_touch_events: false },
1832 metrics::MetricsLogger::default(),
1833 device_listener_registry_clone,
1834 task_sender,
1835 )
1836 .fuse();
1837
1838 let mut registry_fut = std::pin::pin!(registry_fut);
1839 loop {
1840 futures::select! {
1841 res = registry_fut => {
1842 res.unwrap();
1843 break;
1844 }
1845 task = task_receiver.next() => {
1846 if let Some(task) = task {
1847 tasks.push(task);
1848 }
1849 }
1850 _ = tasks.select_next_some() => {}
1851 }
1852 }
1853
1854 let device_id = {
1856 let bindings = bindings.lock();
1857 assert_eq!(bindings.len(), 1);
1858 *bindings.keys().next().unwrap()
1859 };
1860
1861 if let Some(event) = event_receiver.next().await {
1863 assert_eq!(event.action, Some(fidl_next_fuchsia_ui_input::Action::Added));
1864 assert_eq!(event.device_id, Some(device_id));
1865 } else {
1866 panic!("Expected a request on listener stream");
1867 }
1868 }
1869
1870 #[fasync::run_singlethreaded(test)]
1873 async fn handle_input_device_registry_disconnection() {
1874 let (input_device_registry_proxy, input_device_registry_request_stream) =
1875 create_proxy_and_stream::<fidl_fuchsia_input_injection::InputDeviceRegistryMarker>();
1876 let (input_device_client_end, mut input_device_request_stream) =
1877 create_request_stream::<fidl_fuchsia_input_report::InputDeviceMarker>();
1878
1879 let device_types = vec![input_device::InputDeviceType::Mouse];
1880 let (input_event_sender, _input_event_receiver) = futures::channel::mpsc::unbounded();
1881 let bindings: InputDeviceBindingMap = Arc::new(Mutex::new(SortedVecMap::new()));
1882
1883 let device_listener_registry = DeviceListenerRegistry::new();
1884 let (listener_client, listener_server) =
1885 fidl_next::fuchsia::create_channel::<fidl_next_fuchsia_ui_input::DeviceListener>();
1886 let listener_client = listener_client.spawn();
1887 let _existing_devices = device_listener_registry.add_listener(listener_client);
1888
1889 let (event_sender, mut event_receiver) = futures::channel::mpsc::unbounded();
1890 let _server_task = listener_server.spawn(MockDeviceListener { event_sender });
1891
1892 let _task = fasync::Task::local(async move {
1894 let _ = input_device_registry_proxy.register(input_device_client_end);
1896
1897 let mut count = 0;
1898 while count < 2 {
1899 if let Some(input_device_request) =
1900 input_device_request_stream.try_next().await.unwrap()
1901 {
1902 handle_input_device_request(input_device_request);
1903 count += 1;
1904 } else {
1905 break;
1906 }
1907 }
1908
1909 std::mem::drop(input_device_request_stream);
1911
1912 fasync::Timer::new(fasync::MonotonicInstant::after(
1914 zx::MonotonicDuration::from_millis(100),
1915 ))
1916 .await;
1917
1918 input_device_registry_proxy.take_event_stream();
1920 });
1921
1922 let inspector = fuchsia_inspect::Inspector::default();
1923 let test_node = inspector.root().create_child("input_pipeline");
1924
1925 let bindings_clone = bindings.clone();
1927 let device_listener_registry_clone = device_listener_registry.clone();
1928 let (task_sender, mut task_receiver) = futures::channel::mpsc::unbounded();
1929 let mut tasks = futures::stream::FuturesUnordered::new();
1930 let registry_fut = InputPipeline::handle_input_device_registry_request_stream(
1931 input_device_registry_request_stream,
1932 &device_types,
1933 &input_event_sender,
1934 &bindings_clone,
1935 &test_node,
1936 InputPipelineFeatureFlags { enable_merge_touch_events: false },
1937 metrics::MetricsLogger::default(),
1938 device_listener_registry_clone,
1939 task_sender,
1940 )
1941 .fuse();
1942
1943 let mut registry_fut = std::pin::pin!(registry_fut);
1944 loop {
1945 futures::select! {
1946 res = registry_fut => {
1947 res.unwrap();
1948 break;
1949 }
1950 task = task_receiver.next() => {
1951 if let Some(task) = task {
1952 tasks.push(task);
1953 }
1954 }
1955 _ = tasks.select_next_some() => {}
1956 }
1957 }
1958 while let Some(_) = tasks.next().await {}
1959
1960 {
1962 let bindings = bindings.lock();
1963 assert_eq!(bindings.len(), 0);
1964 }
1965
1966 let event_added = if let Some(event) = event_receiver.next().await {
1968 event
1969 } else {
1970 panic!("Expected Added event");
1971 };
1972 assert_eq!(event_added.action, Some(fidl_next_fuchsia_ui_input::Action::Added));
1973
1974 let event_removed = if let Some(event) = event_receiver.next().await {
1976 event
1977 } else {
1978 panic!("Expected Removed event");
1979 };
1980 assert_eq!(event_removed.action, Some(fidl_next_fuchsia_ui_input::Action::Removed));
1981 }
1982
1983 #[fuchsia::test]
1985 async fn check_inspect_node_has_correct_properties() {
1986 let device_types = vec![
1987 input_device::InputDeviceType::Touch,
1988 input_device::InputDeviceType::ConsumerControls,
1989 ];
1990 let inspector = fuchsia_inspect::Inspector::default();
1991 let test_node = inspector.root().create_child("input_pipeline");
1992 let (fake_handler_event_sender, _fake_handler_event_receiver) =
1994 futures::channel::mpsc::channel(100);
1995 let fake_input_handler =
1996 observe_fake_events_input_handler::ObserveFakeEventsInputHandler::new(
1997 fake_handler_event_sender,
1998 );
1999 let assembly = InputPipelineAssembly::new(metrics::MetricsLogger::default())
2000 .add_handler(fake_input_handler);
2001 let _test_input_pipeline = InputPipeline::new(
2002 &Incoming::new(),
2003 device_types,
2004 assembly,
2005 test_node,
2006 InputPipelineFeatureFlags { enable_merge_touch_events: false },
2007 metrics::MetricsLogger::default(),
2008 );
2009 diagnostics_assertions::assert_data_tree!(inspector, root: {
2010 input_pipeline: {
2011 supported_input_devices: "Touch, ConsumerControls",
2012 handlers_registered: 1u64,
2013 handlers_healthy: 1u64,
2014 input_devices: {}
2015 }
2016 });
2017 }
2018
2019 struct SpecificInterestFakeHandler {
2020 interest_types: Vec<input_device::InputEventType>,
2021 event_sender: std::cell::RefCell<futures::channel::mpsc::Sender<input_device::InputEvent>>,
2022 }
2023
2024 impl SpecificInterestFakeHandler {
2025 pub fn new(
2026 interest_types: Vec<input_device::InputEventType>,
2027 event_sender: futures::channel::mpsc::Sender<input_device::InputEvent>,
2028 ) -> Rc<Self> {
2029 Rc::new(SpecificInterestFakeHandler {
2030 interest_types,
2031 event_sender: std::cell::RefCell::new(event_sender),
2032 })
2033 }
2034 }
2035
2036 impl Handler for SpecificInterestFakeHandler {
2037 fn set_handler_healthy(self: std::rc::Rc<Self>) {}
2038 fn set_handler_unhealthy(self: std::rc::Rc<Self>, _msg: &str) {}
2039 fn get_name(&self) -> &'static str {
2040 "SpecificInterestFakeHandler"
2041 }
2042
2043 fn interest(&self) -> Vec<input_device::InputEventType> {
2044 self.interest_types.clone()
2045 }
2046 }
2047
2048 #[async_trait(?Send)]
2049 impl input_handler::InputHandler for SpecificInterestFakeHandler {
2050 async fn handle_input_event(
2051 self: Rc<Self>,
2052 input_event: input_device::InputEvent,
2053 ) -> Vec<input_device::InputEvent> {
2054 match self.event_sender.borrow_mut().try_send(input_event.clone()) {
2055 Err(e) => panic!("SpecificInterestFakeHandler failed to send event: {:?}", e),
2056 Ok(_) => {}
2057 }
2058 vec![input_event]
2059 }
2060 }
2061
2062 #[fuchsia::test]
2063 async fn run_only_sends_events_to_interested_handlers() {
2064 let (mouse_sender, mut mouse_receiver) = futures::channel::mpsc::channel(1);
2066 let mouse_handler =
2067 SpecificInterestFakeHandler::new(vec![InputEventType::Mouse], mouse_sender);
2068
2069 let (fake_sender, mut fake_receiver) = futures::channel::mpsc::channel(1);
2071 let fake_handler =
2072 SpecificInterestFakeHandler::new(vec![InputEventType::Fake], fake_sender);
2073
2074 let (pipeline_sender, pipeline_receiver, handlers, _, _, _, _) =
2075 InputPipelineAssembly::new(metrics::MetricsLogger::default())
2076 .add_handler(mouse_handler)
2077 .add_handler(fake_handler)
2078 .into_components();
2079
2080 let _runner_task = fasync::Task::local(InputPipeline::run(
2082 pipeline_receiver,
2083 handlers,
2084 metrics::MetricsLogger::default(),
2085 ));
2086
2087 let fake_event = input_device::InputEvent {
2089 device_event: input_device::InputDeviceEvent::Fake,
2090 device_descriptor: input_device::InputDeviceDescriptor::Fake,
2091 event_time: zx::MonotonicInstant::get(),
2092 handled: input_device::Handled::No,
2093 trace_id: None,
2094 };
2095
2096 pipeline_sender.unbounded_send(vec![fake_event.clone()]).expect("failed to send event");
2098
2099 let received_by_fake = fake_receiver.next().await;
2101 assert_eq!(received_by_fake, Some(fake_event));
2102
2103 assert!(mouse_receiver.try_recv().is_err());
2105 }
2106
2107 fn create_mouse_event(x: f32, y: f32) -> input_device::InputEvent {
2108 input_device::InputEvent {
2109 device_event: input_device::InputDeviceEvent::Mouse(mouse_binding::MouseEvent::new(
2110 mouse_binding::MouseLocation::Relative(mouse_binding::RelativeLocation {
2111 counts: Position { x, y },
2112 }),
2113 None,
2114 None,
2115 mouse_binding::MousePhase::Move,
2116 SortedVecSet::new(),
2117 SortedVecSet::new(),
2118 None,
2119 None,
2120 )),
2121 device_descriptor: input_device::InputDeviceDescriptor::Mouse(
2122 mouse_binding::MouseDeviceDescriptor {
2123 device_id: 1,
2124 absolute_x_range: None,
2125 absolute_y_range: None,
2126 wheel_v_range: None,
2127 wheel_h_range: None,
2128 buttons: None,
2129 },
2130 ),
2131 event_time: zx::MonotonicInstant::get(),
2132 handled: input_device::Handled::No,
2133 trace_id: None,
2134 }
2135 }
2136
2137 #[fuchsia::test]
2138 async fn run_mixed_event_types_dispatched_correctly() {
2139 let (mouse_sender, mut mouse_receiver) = futures::channel::mpsc::channel(10);
2141 let mouse_handler =
2142 SpecificInterestFakeHandler::new(vec![InputEventType::Mouse], mouse_sender);
2143
2144 let (fake_sender, mut fake_receiver) = futures::channel::mpsc::channel(10);
2146 let fake_handler =
2147 SpecificInterestFakeHandler::new(vec![InputEventType::Fake], fake_sender);
2148
2149 let (pipeline_sender, pipeline_receiver, handlers, _, _, _, _) =
2150 InputPipelineAssembly::new(metrics::MetricsLogger::default())
2151 .add_handler(mouse_handler)
2152 .add_handler(fake_handler)
2153 .into_components();
2154
2155 let _runner_task = fasync::Task::local(InputPipeline::run(
2157 pipeline_receiver,
2158 handlers,
2159 metrics::MetricsLogger::default(),
2160 ));
2161
2162 let mouse_event_1 = create_mouse_event(1.0, 1.0);
2164 let mouse_event_2 = create_mouse_event(2.0, 2.0);
2165 let mouse_event_3 = create_mouse_event(3.0, 3.0);
2166
2167 let fake_event_1 = input_device::InputEvent {
2168 device_event: input_device::InputDeviceEvent::Fake,
2169 device_descriptor: input_device::InputDeviceDescriptor::Fake,
2170 event_time: zx::MonotonicInstant::get(),
2171 handled: input_device::Handled::No,
2172 trace_id: None,
2173 };
2174
2175 let mixed_batch = vec![
2178 mouse_event_1.clone(),
2179 mouse_event_2.clone(),
2180 fake_event_1.clone(),
2181 mouse_event_3.clone(),
2182 ];
2183 pipeline_sender.unbounded_send(mixed_batch).expect("failed to send events");
2184
2185 assert_eq!(mouse_receiver.next().await, Some(mouse_event_1));
2187 assert_eq!(mouse_receiver.next().await, Some(mouse_event_2));
2188 assert_eq!(mouse_receiver.next().await, Some(mouse_event_3));
2189
2190 assert_eq!(fake_receiver.next().await, Some(fake_event_1));
2192 }
2193
2194 #[fuchsia::test]
2195 async fn ownership_transition_pauses_and_resumes_device_readers() {
2196 use crate::display_ownership;
2197 use zx::Peered as _;
2198
2199 let readers = Arc::new(Mutex::new(Vec::new()));
2200 let readers_clone = readers.clone();
2201 let dir = pseudo_directory! {
2202 "fuchsia.input.report.Service" => pseudo_directory! {
2203 "instance_0" => pseudo_directory! {
2204 "input_device" => pseudo_fs_service::host(
2205 move |mut request_stream: fidl_fuchsia_input_report::InputDeviceRequestStream| {
2206 let readers = readers_clone.clone();
2207 async move {
2208 while let Ok(Some(input_device_request)) =
2209 request_stream.try_next().await
2210 {
2211 match input_device_request {
2212 fidl_fuchsia_input_report::InputDeviceRequest::GetInputReportsReaderV2 {
2213 reader,
2214 responder,
2215 ..
2216 } => {
2217 let _ = responder.send(2);
2218 readers.lock().push(reader);
2219 }
2220 req => handle_input_device_request(req),
2221 }
2222 }
2223 }.boxed()
2224 },
2225 )
2226 }
2227 }
2228 };
2229
2230 let svc_proxy =
2231 vfs::directory::serve_read_only(dir, vfs::execution_scope::ExecutionScope::new());
2232 let dir = fuchsia_fs::directory::open_directory_async(
2233 &svc_proxy,
2234 "fuchsia.input.report.Service",
2235 fio::PERM_READABLE,
2236 )
2237 .expect("open service directory");
2238 let service = fuchsia_component::client::Service::from_service_dir_proxy(
2239 dir,
2240 fidl_fuchsia_input_report::ServiceMarker,
2241 );
2242
2243 let (test_event, handler_event) = zx::EventPair::create();
2244 test_event
2246 .signal_peer(
2247 zx::Signals::empty(),
2248 *display_ownership::DISPLAY_PLATFORM_OWNED
2249 | *display_ownership::INPUT_PLATFORM_OWNED,
2250 )
2251 .unwrap();
2252
2253 let (loop_done_sender, mut loop_done) = futures::channel::mpsc::unbounded::<()>();
2254 let display_ownership = display_ownership::DisplayOwnership::new_for_test(
2255 handler_event,
2256 loop_done_sender,
2257 metrics::MetricsLogger::default(),
2258 );
2259
2260 let assembly = InputPipelineAssembly::new(metrics::MetricsLogger::default())
2261 .add_display_ownership_handler(display_ownership.clone());
2262
2263 let inspector = fuchsia_inspect::Inspector::default();
2264 let input_pipeline = InputPipeline::new_with_service(
2265 service,
2266 vec![input_device::InputDeviceType::Mouse],
2267 assembly,
2268 inspector.root().create_child("input_pipeline"),
2269 InputPipelineFeatureFlags { enable_merge_touch_events: false },
2270 metrics::MetricsLogger::default(),
2271 )
2272 .expect("failed to create input pipeline");
2273
2274 let bindings = input_pipeline.input_device_bindings().clone();
2275
2276 let _pipeline_task = fasync::Task::local(input_pipeline.handle_input_events());
2278
2279 for _ in 0..50 {
2281 if bindings.lock().len() == 1 {
2282 break;
2283 }
2284 fasync::Timer::new(fasync::MonotonicInstant::after(
2285 zx::MonotonicDuration::from_millis(10),
2286 ))
2287 .await;
2288 }
2289 assert_eq!(bindings.lock().len(), 1);
2290
2291 test_event
2293 .signal_peer(
2294 *display_ownership::DISPLAY_PLATFORM_OWNED,
2295 *display_ownership::DISPLAY_UNOWNED,
2296 )
2297 .unwrap();
2298 loop_done.next().await.expect("loop_done notification");
2299 assert!(bindings.lock().is_empty());
2300
2301 test_event
2303 .signal_peer(
2304 *display_ownership::DISPLAY_UNOWNED,
2305 *display_ownership::DISPLAY_PLATFORM_OWNED,
2306 )
2307 .unwrap();
2308 loop_done.next().await.expect("loop_done notification");
2309 assert_eq!(bindings.lock().len(), 1);
2310
2311 test_event
2313 .signal_peer(
2314 *display_ownership::INPUT_PLATFORM_OWNED,
2315 *display_ownership::INPUT_CLIENT_OWNED,
2316 )
2317 .unwrap();
2318 loop_done.next().await.expect("loop_done notification");
2319 assert!(bindings.lock().is_empty());
2320
2321 test_event
2323 .signal_peer(
2324 *display_ownership::INPUT_CLIENT_OWNED,
2325 *display_ownership::INPUT_PLATFORM_OWNED,
2326 )
2327 .unwrap();
2328 loop_done.next().await.expect("loop_done notification");
2329 assert_eq!(bindings.lock().len(), 1);
2330
2331 std::mem::drop(_pipeline_task);
2332 }
2333
2334 #[fuchsia::test]
2335 async fn device_discovered_while_unowned_is_not_bound_until_ownership_granted() {
2336 use crate::display_ownership;
2337 use zx::Peered as _;
2338
2339 let readers = Arc::new(Mutex::new(Vec::new()));
2340 let readers_clone = readers.clone();
2341 let dir = pseudo_directory! {
2342 "fuchsia.input.report.Service" => pseudo_directory! {
2343 "instance_0" => pseudo_directory! {
2344 "input_device" => pseudo_fs_service::host(
2345 move |mut request_stream: fidl_fuchsia_input_report::InputDeviceRequestStream| {
2346 let readers = readers_clone.clone();
2347 async move {
2348 while let Ok(Some(input_device_request)) =
2349 request_stream.try_next().await
2350 {
2351 match input_device_request {
2352 fidl_fuchsia_input_report::InputDeviceRequest::GetInputReportsReaderV2 {
2353 reader,
2354 responder,
2355 ..
2356 } => {
2357 let _ = responder.send(2);
2358 readers.lock().push(reader);
2359 }
2360 req => handle_input_device_request(req),
2361 }
2362 }
2363 }.boxed()
2364 },
2365 )
2366 }
2367 }
2368 };
2369
2370 let svc_proxy =
2371 vfs::directory::serve_read_only(dir, vfs::execution_scope::ExecutionScope::new());
2372 let dir = fuchsia_fs::directory::open_directory_async(
2373 &svc_proxy,
2374 "fuchsia.input.report.Service",
2375 fio::PERM_READABLE,
2376 )
2377 .expect("open service directory");
2378 let service = fuchsia_component::client::Service::from_service_dir_proxy(
2379 dir,
2380 fidl_fuchsia_input_report::ServiceMarker,
2381 );
2382
2383 let (test_event, handler_event) = zx::EventPair::create();
2384 test_event
2386 .signal_peer(
2387 zx::Signals::empty(),
2388 *display_ownership::DISPLAY_UNOWNED | *display_ownership::INPUT_PLATFORM_OWNED,
2389 )
2390 .unwrap();
2391
2392 let (loop_done_sender, mut loop_done) = futures::channel::mpsc::unbounded::<()>();
2393 let display_ownership = display_ownership::DisplayOwnership::new_for_test(
2394 handler_event,
2395 loop_done_sender,
2396 metrics::MetricsLogger::default(),
2397 );
2398
2399 let assembly = InputPipelineAssembly::new(metrics::MetricsLogger::default())
2400 .add_display_ownership_handler(display_ownership.clone());
2401
2402 let inspector = fuchsia_inspect::Inspector::default();
2403 let input_pipeline = InputPipeline::new_with_service(
2404 service,
2405 vec![input_device::InputDeviceType::Mouse],
2406 assembly,
2407 inspector.root().create_child("input_pipeline"),
2408 InputPipelineFeatureFlags { enable_merge_touch_events: false },
2409 metrics::MetricsLogger::default(),
2410 )
2411 .expect("failed to create input pipeline");
2412
2413 let bindings = input_pipeline.input_device_bindings().clone();
2414
2415 let _pipeline_task = fasync::Task::local(input_pipeline.handle_input_events());
2417
2418 fasync::Timer::new(fasync::MonotonicInstant::after(zx::MonotonicDuration::from_millis(50)))
2420 .await;
2421
2422 assert!(bindings.lock().is_empty());
2424
2425 test_event
2427 .signal_peer(
2428 *display_ownership::DISPLAY_UNOWNED,
2429 *display_ownership::DISPLAY_PLATFORM_OWNED,
2430 )
2431 .unwrap();
2432 loop_done.next().await.expect("loop_done notification");
2433
2434 assert_eq!(bindings.lock().len(), 1);
2436
2437 std::mem::drop(_pipeline_task);
2438 }
2439}