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;
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
89impl InputPipelineAssembly {
90 pub fn new(metrics_logger: metrics::MetricsLogger) -> Self {
93 let (sender, receiver) = mpsc::unbounded();
94 InputPipelineAssembly {
95 sender,
96 receiver,
97 handlers: vec![],
98 metrics_logger,
99 display_ownership_fut: None,
100 focus_listener_fut: None,
101 }
102 }
103
104 pub fn add_handler(mut self, handler: Rc<dyn input_handler::BatchInputHandler>) -> Self {
107 self.handlers.push(handler);
108 self
109 }
110
111 pub fn add_all_handlers(self, handlers: Vec<Rc<dyn input_handler::BatchInputHandler>>) -> Self {
113 handlers.into_iter().fold(self, |assembly, handler| assembly.add_handler(handler))
114 }
115
116 pub fn add_display_ownership(
117 mut self,
118 display_ownership_event: zx::Event,
119 input_handlers_node: &fuchsia_inspect::Node,
120 ) -> InputPipelineAssembly {
121 let h = DisplayOwnership::new(
122 display_ownership_event,
123 input_handlers_node,
124 self.metrics_logger.clone(),
125 );
126 let metrics_logger_clone = self.metrics_logger.clone();
127 let h_clone = h.clone();
128 let sender_clone = self.sender.clone();
129 let display_ownership_fut = Box::pin(async move {
130 h_clone.clone().set_handler_healthy();
131 h_clone.clone()
132 .handle_ownership_change(sender_clone)
133 .await
134 .map_err(|e| {
135 metrics_logger_clone.log_error(
136 InputPipelineErrorMetricDimensionEvent::InputPipelineDisplayOwnershipIsNotSupposedToTerminate,
137 std::format!(
138 "display ownership is not supposed to terminate - this is likely a problem: {:?}", e));
139 })
140 .unwrap();
141 h_clone.set_handler_unhealthy("Receive loop terminated for handler: DisplayOwnership");
142 });
143 self.display_ownership_fut = Some(display_ownership_fut);
144 self.add_handler(h)
145 }
146
147 fn into_components(
153 self,
154 ) -> (
155 UnboundedSender<Vec<input_device::InputEvent>>,
156 UnboundedReceiver<Vec<input_device::InputEvent>>,
157 Vec<Rc<dyn input_handler::BatchInputHandler>>,
158 metrics::MetricsLogger,
159 Option<LocalBoxFuture<'static, ()>>,
160 Option<LocalBoxFuture<'static, ()>>,
161 ) {
162 (
163 self.sender,
164 self.receiver,
165 self.handlers,
166 self.metrics_logger,
167 self.display_ownership_fut,
168 self.focus_listener_fut,
169 )
170 }
171
172 pub fn add_focus_listener(
173 mut self,
174 incoming: &Incoming,
175 focus_chain_publisher: FocusChainProviderPublisher,
176 ) -> Self {
177 let metrics_logger_clone = self.metrics_logger.clone();
178 let incoming2 = incoming.clone();
179 let focus_listener_fut = Box::pin(async move {
180 if let Ok(mut focus_listener) = FocusListener::new(
181 &incoming2,
182 focus_chain_publisher,
183 metrics_logger_clone,
184 )
185 .map_err(|e| {
186 log::warn!("could not create focus listener, focus will not be dispatched: {:?}", e)
187 }) {
188 let _result = focus_listener
191 .dispatch_focus_changes()
192 .await
193 .map(|_| {
194 log::warn!("dispatch focus loop ended, focus will no longer be dispatched")
195 })
196 .map_err(|e| {
197 panic!("could not dispatch focus changes, this is a fatal error: {:?}", e)
198 });
199 }
200 });
201 self.focus_listener_fut = Some(focus_listener_fut);
202 self
203 }
204}
205
206pub struct InputPipeline {
234 pipeline_sender: UnboundedSender<Vec<input_device::InputEvent>>,
238
239 device_event_sender: UnboundedSender<Vec<input_device::InputEvent>>,
242
243 device_event_receiver: UnboundedReceiver<Vec<input_device::InputEvent>>,
245
246 input_device_types: Vec<input_device::InputDeviceType>,
248
249 input_device_bindings: InputDeviceBindingMap,
251
252 inspect_node: fuchsia_inspect::Node,
255
256 metrics_logger: metrics::MetricsLogger,
258
259 pub feature_flags: input_device::InputPipelineFeatureFlags,
261 display_ownership_fut: Option<LocalBoxFuture<'static, ()>>,
263
264 focus_listener_fut: Option<LocalBoxFuture<'static, ()>>,
266
267 watcher_fut: Option<LocalBoxFuture<'static, ()>>,
269
270 runner_fut: Option<LocalBoxFuture<'static, ()>>,
272
273 pub device_listener_registry: DeviceListenerRegistry,
275}
276
277impl InputPipeline {
278 fn new_common(
279 input_device_types: Vec<input_device::InputDeviceType>,
280 assembly: InputPipelineAssembly,
281 inspect_node: fuchsia_inspect::Node,
282 feature_flags: input_device::InputPipelineFeatureFlags,
283 ) -> Self {
284 let (
285 pipeline_sender,
286 receiver,
287 handlers,
288 metrics_logger,
289 display_ownership_fut,
290 focus_listener_fut,
291 ) = assembly.into_components();
292
293 let mut handlers_count = handlers.len();
294 let display_ownership_fut = if let Some(fut) = display_ownership_fut {
295 handlers_count += 1;
296 Some(
297 async move {
298 fut.await;
299 panic!("display_ownership_fut exited unexpectedly, which compromises device state tracking. Terminating to avoid inconsistent state.");
300 }
301 .boxed_local(),
302 )
303 } else {
304 None
305 };
306
307 let focus_listener_fut = if let Some(fut) = focus_listener_fut {
308 handlers_count += 1;
309 Some(
310 async move {
311 fut.await;
312 panic!("focus_listener_fut exited unexpectedly, which breaks input routing. Terminating to avoid inconsistent state.");
313 }
314 .boxed_local(),
315 )
316 } else {
317 None
318 };
319
320 inspect_node.record_string("supported_input_devices", input_device_types.iter().join(", "));
322 inspect_node.record_uint("handlers_registered", handlers_count as u64);
323 inspect_node.record_uint("handlers_healthy", handlers_count as u64);
324
325 let runner_fut = Some(InputPipeline::run(receiver, handlers, metrics_logger.clone()));
327
328 let (device_event_sender, device_event_receiver) = futures::channel::mpsc::unbounded();
329 let input_device_bindings: InputDeviceBindingMap =
330 Arc::new(Mutex::new(SortedVecMap::new()));
331 let device_listener_registry = DeviceListenerRegistry::new();
332 InputPipeline {
333 pipeline_sender,
334 device_event_sender,
335 device_event_receiver,
336 input_device_types,
337 input_device_bindings,
338 inspect_node,
339 metrics_logger,
340 feature_flags,
341 display_ownership_fut,
342 focus_listener_fut,
343 watcher_fut: None,
344 runner_fut,
345 device_listener_registry,
346 }
347 }
348
349 pub fn new_for_test(
357 input_device_types: Vec<input_device::InputDeviceType>,
358 assembly: InputPipelineAssembly,
359 ) -> Self {
360 let inspector = fuchsia_inspect::Inspector::default();
361 let root = inspector.root();
362 let test_node = root.create_child("input_pipeline");
363 Self::new_common(
364 input_device_types,
365 assembly,
366 test_node,
367 input_device::InputPipelineFeatureFlags { enable_merge_touch_events: false },
368 )
369 }
370
371 pub fn new(
378 incoming: &Incoming,
379 input_device_types: Vec<input_device::InputDeviceType>,
380 assembly: InputPipelineAssembly,
381 inspect_node: fuchsia_inspect::Node,
382 feature_flags: input_device::InputPipelineFeatureFlags,
383 metrics_logger: metrics::MetricsLogger,
384 ) -> Result<Self, Error> {
385 let mut input_pipeline =
386 Self::new_common(input_device_types, assembly, inspect_node, feature_flags);
387 let input_device_types = input_pipeline.input_device_types.clone();
388 let input_event_sender = input_pipeline.device_event_sender.clone();
389 let input_device_bindings = input_pipeline.input_device_bindings.clone();
390 let device_listener_registry = input_pipeline.device_listener_registry.clone();
391 let devices_node = input_pipeline.inspect_node.create_child("input_devices");
392 let devices_node_weak = devices_node.clone_weak();
393 input_pipeline.inspect_node.record(devices_node);
394 let feature_flags = input_pipeline.feature_flags.clone();
395 let incoming = incoming.clone();
396 let watcher_fut = async move {
397 let devices_discovered = devices_node_weak.create_uint("devices_discovered", 0);
398 let devices_connected = devices_node_weak.create_uint("devices_connected", 0);
399 match async {
402 let service = incoming
403 .open_service(fidl_fuchsia_input_report::ServiceMarker)
404 .context("failed to open service")?;
405 Self::watch_for_devices(
406 service,
407 input_device_types,
408 input_event_sender,
409 input_device_bindings,
410 &devices_node_weak,
411 &devices_discovered,
412 &devices_connected,
413 false, feature_flags,
415 metrics_logger.clone(),
416 device_listener_registry,
417 )
418 .await
419 .context("failed to watch for devices")
420 }
421 .await
422 {
423 Ok(()) => {}
424 Err(err) => {
425 metrics_logger.log_warn(
429 InputPipelineErrorMetricDimensionEvent::InputPipelineUnableToWatchForNewInputDevices,
430 std::format!(
431 "Input pipeline is unable to watch for new input devices: {:?}",
432 err
433 ));
434 }
435 }
436 devices_node_weak.record(devices_discovered);
437 devices_node_weak.record(devices_connected);
438 }.boxed_local();
439
440 input_pipeline.watcher_fut = Some(watcher_fut);
441
442 Ok(input_pipeline)
443 }
444
445 pub fn input_device_bindings(&self) -> &InputDeviceBindingMap {
447 &self.input_device_bindings
448 }
449
450 pub fn input_event_sender(&self) -> &UnboundedSender<Vec<input_device::InputEvent>> {
453 &self.device_event_sender
454 }
455
456 pub fn input_device_types(&self) -> &[input_device::InputDeviceType] {
458 &self.input_device_types
459 }
460
461 pub fn device_listener_registry(&self) -> &DeviceListenerRegistry {
463 &self.device_listener_registry
464 }
465
466 pub async fn handle_input_events(self) {
468 let metrics_logger_clone = self.metrics_logger.clone();
469 let mut device_event_receiver = self.device_event_receiver;
470 let pipeline_sender = self.pipeline_sender.clone();
471
472 let forwarder = async move {
473 while let Some(input_event) = device_event_receiver.next().await {
474 if let Err(e) = pipeline_sender.unbounded_send(input_event) {
475 metrics_logger_clone.log_error(
476 InputPipelineErrorMetricDimensionEvent::InputPipelineCouldNotForwardEventFromDriver,
477 std::format!("could not forward event from driver: {:?}", e));
478 }
479 }
480
481 metrics_logger_clone.log_error(
482 InputPipelineErrorMetricDimensionEvent::InputPipelineStopHandlingEvents,
483 "Input pipeline stopped handling input events.".to_string(),
484 );
485 }.boxed_local();
486
487 let tasks = crate::task::InputPipelineTasks {
488 watcher: self.watcher_fut.unwrap_or_else(|| Box::pin(futures::future::pending())),
489 runner: self.runner_fut.unwrap_or_else(|| Box::pin(futures::future::pending())),
490 display_ownership: self.display_ownership_fut,
491 focus_listener: self.focus_listener_fut,
492 forwarder,
493 };
494
495 tasks.run().await;
496 }
497
498 async fn connect_and_bind_device(
499 instance: &fidl_fuchsia_input_report::ServiceProxy,
500 device_types: &[input_device::InputDeviceType],
501 input_event_sender: &UnboundedSender<Vec<input_device::InputEvent>>,
502 bindings: &InputDeviceBindingMap,
503 input_devices_node: &fuchsia_inspect::Node,
504 devices_discovered: &fuchsia_inspect::UintProperty,
505 devices_connected: &fuchsia_inspect::UintProperty,
506 feature_flags: input_device::InputPipelineFeatureFlags,
507 metrics_logger: metrics::MetricsLogger,
508 device_listener_registry: DeviceListenerRegistry,
509 ) {
510 let filename = instance.instance_name().to_string();
511 log::info!("found input device {}", filename);
512 devices_discovered.add(1);
513
514 let res = async {
515 let device_proxy =
516 instance.connect_to_input_device().context("connect to input device")?;
517 let channel = device_proxy
518 .into_client_end()
519 .map_err(|_| format_err!("failed to get client end"))?
520 .into_channel();
521 let device_client = fidl_next::ClientEnd::<
522 fidl_next_fuchsia_input_report::InputDevice,
523 zx::Channel,
524 >::from_untyped(channel);
525 let device_client = Dispatcher::client_from_zx_channel(device_client);
526 let (device_client, join_handle) = device_client.spawn_full();
527 let device_id = get_next_device_id();
528 if let Some(descriptor) = add_device_bindings(
529 device_types,
530 &filename,
531 device_client,
532 input_event_sender,
533 bindings,
534 device_id,
535 input_devices_node,
536 Some(devices_connected),
537 feature_flags,
538 metrics_logger,
539 false,
540 )
541 .await
542 {
543 device_listener_registry.notify_device_changed(
544 fidl_next_fuchsia_ui_input::Action::Added,
545 device_id,
546 descriptor.clone(),
547 );
548 let device_listener_registry_clone = device_listener_registry.clone();
549 let bindings_clone = bindings.clone();
550 let watch_task = Dispatcher::spawn_local(async move {
551 let _ = join_handle.await;
552 log::info!("Device {} disconnected", device_id);
553 device_listener_registry_clone.notify_device_changed(
554 fidl_next_fuchsia_ui_input::Action::Removed,
555 device_id,
556 descriptor,
557 );
558 bindings_clone.lock().remove(&device_id);
559 });
560 watch_task.detach();
561 }
562 Ok::<(), Error>(())
563 }
564 .await;
565
566 if let Err(e) = res {
567 log::error!("Failed to connect and bind input device {}: {:?}", filename, e);
568 }
569 }
570
571 async fn watch_for_devices(
589 service: fuchsia_component::client::Service<fidl_fuchsia_input_report::ServiceMarker>,
590 device_types: Vec<input_device::InputDeviceType>,
591 input_event_sender: UnboundedSender<Vec<input_device::InputEvent>>,
592 bindings: InputDeviceBindingMap,
593 input_devices_node: &fuchsia_inspect::Node,
594 devices_discovered: &fuchsia_inspect::UintProperty,
595 devices_connected: &fuchsia_inspect::UintProperty,
596 break_on_idle: bool,
597 feature_flags: input_device::InputPipelineFeatureFlags,
598 metrics_logger: metrics::MetricsLogger,
599 device_listener_registry: DeviceListenerRegistry,
600 ) -> Result<(), Error> {
601 if break_on_idle {
602 let instances = service.enumerate().await?;
603 for instance in instances {
604 Self::connect_and_bind_device(
605 &instance,
606 &device_types,
607 &input_event_sender,
608 &bindings,
609 input_devices_node,
610 devices_discovered,
611 devices_connected,
612 feature_flags.clone(),
613 metrics_logger.clone(),
614 device_listener_registry.clone(),
615 )
616 .await;
617 }
618 Ok(())
619 } else {
620 let mut instances = service
621 .watch()
622 .await
623 .context("failed to watch input-report service")?
624 .err_into::<Error>()
625 .boxed();
626
627 while let Some(instance) = instances.try_next().await? {
628 Self::connect_and_bind_device(
629 &instance,
630 &device_types,
631 &input_event_sender,
632 &bindings,
633 input_devices_node,
634 devices_discovered,
635 devices_connected,
636 feature_flags.clone(),
637 metrics_logger.clone(),
638 device_listener_registry.clone(),
639 )
640 .await;
641 }
642
643 Err(format_err!("Input pipeline stopped watching for new input devices."))
644 }
645 }
646
647 pub async fn handle_input_device_registry_request_stream(
662 mut stream: fidl_fuchsia_input_injection::InputDeviceRegistryRequestStream,
663 device_types: &[input_device::InputDeviceType],
664 input_event_sender: &UnboundedSender<Vec<input_device::InputEvent>>,
665 bindings: &InputDeviceBindingMap,
666 input_devices_node: &fuchsia_inspect::Node,
667 feature_flags: input_device::InputPipelineFeatureFlags,
668 metrics_logger: metrics::MetricsLogger,
669 device_listener_registry: DeviceListenerRegistry,
670 task_sender: UnboundedSender<crate::dispatcher::TaskHandle<()>>,
671 ) -> Result<(), Error> {
672 while let Some(request) = stream
673 .try_next()
674 .await
675 .context("Error handling input device registry request stream")?
676 {
677 match request {
678 fidl_fuchsia_input_injection::InputDeviceRegistryRequest::Register {
679 device,
680 ..
681 } => {
682 let device = fidl_next::ClientEnd::<
684 fidl_next_fuchsia_input_report::InputDevice,
685 zx::Channel,
686 >::from_untyped(device.into_channel());
687 let device = Dispatcher::client_from_zx_channel(device);
688 let (device, join_handle) = device.spawn_full();
689 let device_id = get_next_device_id();
690
691 if let Some(descriptor) = add_device_bindings(
692 device_types,
693 &format!("input-device-registry-{}", device_id),
694 device,
695 input_event_sender,
696 bindings,
697 device_id,
698 input_devices_node,
699 None,
700 feature_flags.clone(),
701 metrics_logger.clone(),
702 true,
703 )
704 .await
705 {
706 device_listener_registry.notify_device_changed(
707 fidl_next_fuchsia_ui_input::Action::Added,
708 device_id,
709 descriptor.clone(),
710 );
711
712 let device_listener_registry_clone = device_listener_registry.clone();
713 let bindings_clone = bindings.clone();
714 let watch_task = Dispatcher::spawn_local(async move {
715 let _ = join_handle.await;
716 log::info!("Injected device {} disconnected", device_id);
717 device_listener_registry_clone.notify_device_changed(
718 fidl_next_fuchsia_ui_input::Action::Removed,
719 device_id,
720 descriptor,
721 );
722 bindings_clone.lock().remove(&device_id);
723 });
724 let _ = task_sender.unbounded_send(watch_task);
725 }
726 }
727 fidl_fuchsia_input_injection::InputDeviceRegistryRequest::RegisterAndGetDeviceInfo {
728 device,
729 responder,
730 .. } => {
731 let device = fidl_next::ClientEnd::<
733 fidl_next_fuchsia_input_report::InputDevice,
734 zx::Channel,
735 >::from_untyped(device.into_channel());
736 let device = Dispatcher::client_from_zx_channel(device);
737 let (device, join_handle) = device.spawn_full();
738 let device_id = get_next_device_id();
739
740 let descriptor_opt = add_device_bindings(
741 device_types,
742 &format!("input-device-registry-{}", device_id),
743 device,
744 input_event_sender,
745 bindings,
746 device_id,
747 input_devices_node,
748 None,
749 feature_flags.clone(),
750 metrics_logger.clone(),
751 true,
752 )
753 .await;
754
755 if let Some(descriptor) = descriptor_opt {
756 device_listener_registry.notify_device_changed(
757 fidl_next_fuchsia_ui_input::Action::Added,
758 device_id,
759 descriptor.clone(),
760 );
761
762 let device_listener_registry_clone = device_listener_registry.clone();
763 let bindings_clone = bindings.clone();
764 let watch_task = Dispatcher::spawn_local(async move {
765 let _ = join_handle.await;
766 log::info!("Injected device {} disconnected", device_id);
767 device_listener_registry_clone.notify_device_changed(
768 fidl_next_fuchsia_ui_input::Action::Removed,
769 device_id,
770 descriptor.clone(),
771 );
772 bindings_clone.lock().remove(&device_id);
773 });
774 let _ = task_sender.unbounded_send(watch_task);
775 }
776
777 responder.send(fidl_fuchsia_input_injection::InputDeviceRegistryRegisterAndGetDeviceInfoResponse{
778 device_id: Some(device_id),
779 ..Default::default()
780 }).expect("Failed to respond to RegisterAndGetDeviceInfo request");
781 }
782 }
783 }
784
785 Ok(())
786 }
787
788 fn run(
790 mut receiver: UnboundedReceiver<Vec<input_device::InputEvent>>,
791 handlers: Vec<Rc<dyn input_handler::BatchInputHandler>>,
792 metrics_logger: metrics::MetricsLogger,
793 ) -> LocalBoxFuture<'static, ()> {
794 async move {
795 for handler in &handlers {
796 handler.clone().set_handler_healthy();
797 }
798
799 let mut handlers_by_type: [Vec<Rc<dyn input_handler::BatchInputHandler>>;
800 InputEventType::COUNT] = Default::default();
801
802 let event_types = vec![
804 InputEventType::Keyboard,
805 InputEventType::LightSensor,
806 InputEventType::ConsumerControls,
807 InputEventType::Mouse,
808 InputEventType::TouchScreen,
809 InputEventType::Touchpad,
810 #[cfg(test)]
811 InputEventType::Fake,
812 ];
813
814 for event_type in event_types {
815 let handlers_for_type: Vec<Rc<dyn input_handler::BatchInputHandler>> = handlers
816 .iter()
817 .filter(|h| h.interest().contains(&event_type))
818 .cloned()
819 .collect();
820 handlers_by_type[event_type as usize] = handlers_for_type;
821 }
822
823 while let Some(events) = receiver.next().await {
824 if events.is_empty() {
825 continue;
826 }
827
828 let mut groups_seen = 0;
829 let events = events.into_iter().chunk_by(|e| InputEventType::from(&e.device_event));
830 let events = events.into_iter().map(|(k, v)| (k, v.collect::<Vec<_>>()));
831 for (event_type, event_group) in events {
832 groups_seen += 1;
833 if groups_seen == 2 {
834 metrics_logger.log_error(
835 InputPipelineErrorMetricDimensionEvent::InputFrameContainsMultipleTypesOfEvents,
836 "it is not recommended to contain multiple types of events in 1 send".to_string(),
837 );
838 }
839 let mut events_in_group = event_group;
840
841 let handlers = &handlers_by_type[event_type as usize];
843
844 for handler in handlers {
845 events_in_group =
846 handler.clone().handle_input_events(events_in_group).await;
847 }
848
849 for event in events_in_group {
850 if event.handled == input_device::Handled::No {
851 log::warn!("unhandled input event: {:?}", event);
852 }
853 if let Some(trace_id) = event.trace_id {
854 fuchsia_trace::flow_end!(
855 "input",
856 "event_in_input_pipeline",
857 trace_id.into()
858 );
859 }
860 }
861 }
862 }
863 for handler in &handlers {
864 handler.clone().set_handler_unhealthy("Pipeline loop terminated");
865 }
866 panic!("Runner task is not supposed to terminate.")
867 }
868 .boxed_local()
869 }
870}
871
872async fn add_device_bindings(
892 device_types: &[input_device::InputDeviceType],
893 instance_name: &str,
894 device_proxy: fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
895 input_event_sender: &UnboundedSender<Vec<input_device::InputEvent>>,
896 bindings: &InputDeviceBindingMap,
897 device_id: u32,
898 input_devices_node: &fuchsia_inspect::Node,
899 devices_connected: Option<&fuchsia_inspect::UintProperty>,
900 feature_flags: InputPipelineFeatureFlags,
901 metrics_logger: metrics::MetricsLogger,
902 is_injected: bool,
903) -> Option<fidl_next_fuchsia_input_report::DeviceDescriptor> {
904 let mut matched_device_types = vec![];
905 let descriptor = match device_proxy.get_descriptor().await {
906 Ok(res) => {
907 for device_type in device_types {
908 if input_device::is_device_type(&res.descriptor, *device_type).await {
909 matched_device_types.push(device_type);
910 match devices_connected {
911 Some(dev_connected) => {
912 let _ = dev_connected.add(1);
913 }
914 None => (),
915 };
916 }
917 }
918 if matched_device_types.is_empty() {
919 log::info!(
920 "device {} did not match any supported device types: {:?}",
921 instance_name,
922 device_types
923 );
924 let device_node =
925 input_devices_node.create_child(format!("{}_Unsupported", instance_name));
926 let mut health = fuchsia_inspect::health::Node::new(&device_node);
927 health.set_unhealthy("Unsupported device type.");
928 device_node.record(health);
929 input_devices_node.record(device_node);
930 return None;
931 }
932 res.descriptor
933 }
934 Err(_) => {
935 metrics_logger.clone().log_error(
936 InputPipelineErrorMetricDimensionEvent::InputPipelineNoDeviceDescriptor,
937 std::format!("cannot bind device {} without a device descriptor", instance_name),
938 );
939 return None;
940 }
941 };
942
943 log::info!(
944 "binding {} to device types: {}",
945 instance_name,
946 matched_device_types
947 .iter()
948 .fold(String::new(), |device_types_string, device_type| device_types_string
949 + &format!("{:?}, ", device_type))
950 );
951
952 let mut new_bindings: Vec<InputDeviceBindingAndTask> = vec![];
953 for device_type in matched_device_types {
954 let proxy = device_proxy.clone();
975 let device_node =
976 input_devices_node.create_child(format!("{}_{}", instance_name, device_type));
977 match input_device::get_device_binding(
978 *device_type,
979 proxy,
980 device_id,
981 input_event_sender.clone(),
982 device_node,
983 feature_flags.clone(),
984 metrics_logger.clone(),
985 is_injected,
986 )
987 .await
988 {
989 Ok((binding, task)) => new_bindings.push(InputDeviceBindingAndTask { binding, task }),
990 Err(e) => {
991 metrics_logger.log_error(
992 InputPipelineErrorMetricDimensionEvent::InputPipelineFailedToBind,
993 std::format!("failed to bind {} as {:?}: {}", instance_name, device_type, e),
994 );
995 }
996 }
997 }
998
999 if !new_bindings.is_empty() {
1000 let mut bindings = bindings.lock();
1001 if let Some(v) = bindings.get_mut(&device_id) {
1002 v.extend(new_bindings);
1003 } else {
1004 bindings.insert(device_id, new_bindings);
1005 }
1006 Some(descriptor)
1007 } else {
1008 None
1009 }
1010}
1011
1012#[cfg(test)]
1013mod tests {
1014 use super::*;
1015 use crate::dispatcher::Transport;
1016 use fidl_next::Request;
1017
1018 struct MockDeviceListener {
1019 event_sender:
1020 futures::channel::mpsc::UnboundedSender<fidl_next_fuchsia_ui_input::DeviceEvent>,
1021 }
1022
1023 impl fidl_next_fuchsia_ui_input::DeviceListenerServerHandler<Transport> for MockDeviceListener {
1024 async fn on_device_changed(
1025 &mut self,
1026 request: Request<
1027 fidl_next_fuchsia_ui_input::device_listener::OnDeviceChanged,
1028 Transport,
1029 >,
1030 ) {
1031 let event = request.payload().event.clone();
1032 let _ = self.event_sender.unbounded_send(event);
1033 }
1034 }
1035 use crate::input_device::{InputDeviceBinding, InputEventType};
1036 use crate::utils::Position;
1037 use crate::{fake_input_device_binding, mouse_binding, observe_fake_events_input_handler};
1038 use async_trait::async_trait;
1039 use diagnostics_assertions::AnyProperty;
1040 use fidl::endpoints::{create_proxy_and_stream, create_request_stream};
1041 use fidl_fuchsia_io as fio;
1042 use fuchsia_async as fasync;
1043 use futures::{FutureExt, StreamExt};
1044 use pretty_assertions::assert_eq;
1045 use rand::RngExt as _;
1046 use sorted_vec_map::SortedVecSet;
1047 use vfs::{pseudo_directory, service as pseudo_fs_service};
1048
1049 fn send_input_event(
1054 sender: UnboundedSender<Vec<input_device::InputEvent>>,
1055 ) -> Vec<input_device::InputEvent> {
1056 let mut rng = rand::rng();
1057 let offset =
1058 Position { x: rng.random_range(0..10) as f32, y: rng.random_range(0..10) as f32 };
1059 let input_event = input_device::InputEvent {
1060 device_event: input_device::InputDeviceEvent::Mouse(mouse_binding::MouseEvent::new(
1061 mouse_binding::MouseLocation::Relative(mouse_binding::RelativeLocation {
1062 counts: Position { x: offset.x, y: offset.y },
1063 }),
1064 None, None, mouse_binding::MousePhase::Move,
1067 SortedVecSet::new(),
1068 SortedVecSet::new(),
1069 None, None, )),
1072 device_descriptor: input_device::InputDeviceDescriptor::Mouse(
1073 mouse_binding::MouseDeviceDescriptor {
1074 device_id: 1,
1075 absolute_x_range: None,
1076 absolute_y_range: None,
1077 wheel_v_range: None,
1078 wheel_h_range: None,
1079 buttons: None,
1080 },
1081 ),
1082 event_time: zx::MonotonicInstant::get(),
1083 handled: input_device::Handled::No,
1084 trace_id: None,
1085 };
1086 match sender.unbounded_send(vec![input_event.clone()]) {
1087 Err(_) => assert!(false),
1088 _ => {}
1089 }
1090
1091 vec![input_event]
1092 }
1093
1094 fn handle_input_device_request(
1099 input_device_request: fidl_fuchsia_input_report::InputDeviceRequest,
1100 ) {
1101 match input_device_request {
1102 fidl_fuchsia_input_report::InputDeviceRequest::GetDescriptor { responder } => {
1103 let _ = responder.send(&fidl_fuchsia_input_report::DeviceDescriptor {
1104 device_information: None,
1105 mouse: Some(fidl_fuchsia_input_report::MouseDescriptor {
1106 input: Some(fidl_fuchsia_input_report::MouseInputDescriptor {
1107 movement_x: None,
1108 movement_y: None,
1109 scroll_v: None,
1110 scroll_h: None,
1111 buttons: Some(vec![0]),
1112 position_x: None,
1113 position_y: None,
1114 ..Default::default()
1115 }),
1116 ..Default::default()
1117 }),
1118 sensor: None,
1119 touch: None,
1120 keyboard: None,
1121 consumer_control: None,
1122 ..Default::default()
1123 });
1124 }
1125 _ => {}
1126 }
1127 }
1128
1129 #[fuchsia::test]
1131 async fn multiple_devices_single_handler() {
1132 let (device_event_sender, device_event_receiver) = futures::channel::mpsc::unbounded();
1134 let first_device_binding =
1135 fake_input_device_binding::FakeInputDeviceBinding::new(device_event_sender.clone());
1136 let second_device_binding =
1137 fake_input_device_binding::FakeInputDeviceBinding::new(device_event_sender.clone());
1138
1139 let (handler_event_sender, mut handler_event_receiver) =
1141 futures::channel::mpsc::channel(100);
1142 let input_handler = observe_fake_events_input_handler::ObserveFakeEventsInputHandler::new(
1143 handler_event_sender,
1144 );
1145
1146 let (sender, receiver, handlers, _, _, _) =
1148 InputPipelineAssembly::new(metrics::MetricsLogger::default())
1149 .add_handler(input_handler)
1150 .into_components();
1151 let inspector = fuchsia_inspect::Inspector::default();
1152 let test_node = inspector.root().create_child("input_pipeline");
1153 let runner_fut =
1154 Some(InputPipeline::run(receiver, handlers, metrics::MetricsLogger::default()));
1155 let input_pipeline = InputPipeline {
1156 pipeline_sender: sender,
1157 device_event_sender,
1158 device_event_receiver,
1159 input_device_types: vec![],
1160 input_device_bindings: Arc::new(Mutex::new(SortedVecMap::new())),
1161 inspect_node: test_node,
1162 metrics_logger: metrics::MetricsLogger::default(),
1163 feature_flags: input_device::InputPipelineFeatureFlags::default(),
1164 display_ownership_fut: None,
1165 focus_listener_fut: None,
1166 watcher_fut: None,
1167 runner_fut,
1168 device_listener_registry: DeviceListenerRegistry::new(),
1169 };
1170
1171 let first_device_events = send_input_event(first_device_binding.input_event_sender());
1173 let second_device_events = send_input_event(second_device_binding.input_event_sender());
1174
1175 let _pipeline_task = fasync::Task::local(input_pipeline.handle_input_events());
1177
1178 let first_handled_event = handler_event_receiver.next().await;
1180 assert_eq!(first_handled_event, first_device_events.into_iter().next());
1181
1182 let second_handled_event = handler_event_receiver.next().await;
1183 assert_eq!(second_handled_event, second_device_events.into_iter().next());
1184 }
1185
1186 #[fuchsia::test]
1188 async fn single_device_multiple_handlers() {
1189 let (device_event_sender, device_event_receiver) = futures::channel::mpsc::unbounded();
1191 let input_device_binding =
1192 fake_input_device_binding::FakeInputDeviceBinding::new(device_event_sender.clone());
1193
1194 let (first_handler_event_sender, mut first_handler_event_receiver) =
1196 futures::channel::mpsc::channel(100);
1197 let first_input_handler =
1198 observe_fake_events_input_handler::ObserveFakeEventsInputHandler::new(
1199 first_handler_event_sender,
1200 );
1201 let (second_handler_event_sender, mut second_handler_event_receiver) =
1202 futures::channel::mpsc::channel(100);
1203 let second_input_handler =
1204 observe_fake_events_input_handler::ObserveFakeEventsInputHandler::new(
1205 second_handler_event_sender,
1206 );
1207
1208 let (sender, receiver, handlers, _, _, _) =
1210 InputPipelineAssembly::new(metrics::MetricsLogger::default())
1211 .add_handler(first_input_handler)
1212 .add_handler(second_input_handler)
1213 .into_components();
1214 let inspector = fuchsia_inspect::Inspector::default();
1215 let test_node = inspector.root().create_child("input_pipeline");
1216 let runner_fut =
1217 Some(InputPipeline::run(receiver, handlers, metrics::MetricsLogger::default()));
1218 let input_pipeline = InputPipeline {
1219 pipeline_sender: sender,
1220 device_event_sender,
1221 device_event_receiver,
1222 input_device_types: vec![],
1223 input_device_bindings: Arc::new(Mutex::new(SortedVecMap::new())),
1224 inspect_node: test_node,
1225 metrics_logger: metrics::MetricsLogger::default(),
1226 feature_flags: input_device::InputPipelineFeatureFlags::default(),
1227 display_ownership_fut: None,
1228 focus_listener_fut: None,
1229 watcher_fut: None,
1230 runner_fut,
1231 device_listener_registry: DeviceListenerRegistry::new(),
1232 };
1233
1234 let input_events = send_input_event(input_device_binding.input_event_sender());
1236
1237 let _pipeline_task = fasync::Task::local(input_pipeline.handle_input_events());
1239
1240 let expected_event = input_events.into_iter().next();
1242 let first_handler_event = first_handler_event_receiver.next().await;
1243 assert_eq!(first_handler_event, expected_event);
1244 let second_handler_event = second_handler_event_receiver.next().await;
1245 assert_eq!(second_handler_event, expected_event);
1246 }
1247
1248 #[fuchsia::test]
1251 async fn watch_devices_one_match_exists() {
1252 let dir = pseudo_directory! {
1253 "fuchsia.input.report.Service" => pseudo_directory! {
1254 "instance_0" => pseudo_directory! {
1255 "input_device" => pseudo_fs_service::host(
1256 move |mut request_stream: fidl_fuchsia_input_report::InputDeviceRequestStream| {
1257 async move {
1258 while let Some(input_device_request) =
1259 request_stream.try_next().await.unwrap()
1260 {
1261 handle_input_device_request(input_device_request);
1262 }
1263
1264 }.boxed()
1265 },
1266 )
1267 }
1268 }
1269 };
1270
1271 let svc_proxy =
1274 vfs::directory::serve_read_only(dir, vfs::execution_scope::ExecutionScope::new());
1275
1276 let (input_event_sender, _input_event_receiver) = futures::channel::mpsc::unbounded();
1277 let bindings: InputDeviceBindingMap = Arc::new(Mutex::new(SortedVecMap::new()));
1278 let supported_device_types = vec![input_device::InputDeviceType::Mouse];
1279
1280 let inspector = fuchsia_inspect::Inspector::default();
1281 let test_node = inspector.root().create_child("input_pipeline");
1282 test_node.record_string(
1283 "supported_input_devices",
1284 supported_device_types.clone().iter().join(", "),
1285 );
1286 let input_devices = test_node.create_child("input_devices");
1287 diagnostics_assertions::assert_data_tree!(inspector, root: {
1289 input_pipeline: {
1290 supported_input_devices: "Mouse",
1291 input_devices: {}
1292 }
1293 });
1294
1295 let devices_discovered = input_devices.create_uint("devices_discovered", 0);
1296 let devices_connected = input_devices.create_uint("devices_connected", 0);
1297
1298 let dir = fuchsia_fs::directory::open_directory_async(
1299 &svc_proxy,
1300 "fuchsia.input.report.Service",
1301 fio::PERM_READABLE,
1302 )
1303 .expect("open service directory");
1304 let service = fuchsia_component::client::Service::from_service_dir_proxy(
1305 dir,
1306 fidl_fuchsia_input_report::ServiceMarker,
1307 );
1308
1309 let _ = InputPipeline::watch_for_devices(
1310 service,
1311 supported_device_types,
1312 input_event_sender,
1313 bindings.clone(),
1314 &input_devices,
1315 &devices_discovered,
1316 &devices_connected,
1317 true, InputPipelineFeatureFlags { enable_merge_touch_events: false },
1319 metrics::MetricsLogger::default(),
1320 DeviceListenerRegistry::new(),
1321 )
1322 .await;
1323
1324 {
1326 let bindings_map = bindings.lock();
1327 assert_eq!(bindings_map.len(), 1);
1328 let bindings_vector = bindings_map.get(&10);
1329 assert!(bindings_vector.is_some());
1330 assert_eq!(bindings_vector.unwrap().len(), 1);
1331 let boxed_mouse_binding = bindings_vector.unwrap().get(0);
1332 assert!(boxed_mouse_binding.is_some());
1333 assert_eq!(
1334 boxed_mouse_binding.unwrap().binding.get_device_descriptor(),
1335 input_device::InputDeviceDescriptor::Mouse(mouse_binding::MouseDeviceDescriptor {
1336 device_id: 10,
1337 absolute_x_range: None,
1338 absolute_y_range: None,
1339 wheel_v_range: None,
1340 wheel_h_range: None,
1341 buttons: Some(vec![0]),
1342 })
1343 );
1344 }
1345
1346 diagnostics_assertions::assert_data_tree!(inspector, root: {
1348 input_pipeline: {
1349 supported_input_devices: "Mouse",
1350 input_devices: {
1351 devices_discovered: 1u64,
1352 devices_connected: 1u64,
1353 "instance_0_Mouse": contains {
1354 reports_received_count: 0u64,
1355 reports_filtered_count: 0u64,
1356 events_generated: 0u64,
1357 last_received_timestamp_ns: 0u64,
1358 last_generated_timestamp_ns: 0u64,
1359 "fuchsia.inspect.Health": {
1360 status: "OK",
1361 start_timestamp_nanos: AnyProperty
1364 },
1365 }
1366 }
1367 }
1368 });
1369 }
1370
1371 #[fuchsia::test]
1374 async fn watch_devices_no_matches_exist() {
1375 let dir = pseudo_directory! {
1376 "fuchsia.input.report.Service" => pseudo_directory! {
1377 "instance_0" => pseudo_directory! {
1378 "input_device" => pseudo_fs_service::host(
1379 move |mut request_stream: fidl_fuchsia_input_report::InputDeviceRequestStream| {
1380 async move {
1381 while let Some(input_device_request) =
1382 request_stream.try_next().await.unwrap()
1383 {
1384 handle_input_device_request(input_device_request);
1385 }
1386
1387 }.boxed()
1388 },
1389 )
1390 }
1391 }
1392 };
1393
1394 let svc_proxy =
1397 vfs::directory::serve_read_only(dir, vfs::execution_scope::ExecutionScope::new());
1398
1399 let (input_event_sender, _input_event_receiver) = futures::channel::mpsc::unbounded();
1400 let bindings: InputDeviceBindingMap = Arc::new(Mutex::new(SortedVecMap::new()));
1401 let supported_device_types = vec![input_device::InputDeviceType::Keyboard];
1402
1403 let inspector = fuchsia_inspect::Inspector::default();
1404 let test_node = inspector.root().create_child("input_pipeline");
1405 test_node.record_string(
1406 "supported_input_devices",
1407 supported_device_types.clone().iter().join(", "),
1408 );
1409 let input_devices = test_node.create_child("input_devices");
1410 diagnostics_assertions::assert_data_tree!(inspector, root: {
1412 input_pipeline: {
1413 supported_input_devices: "Keyboard",
1414 input_devices: {}
1415 }
1416 });
1417
1418 let devices_discovered = input_devices.create_uint("devices_discovered", 0);
1419 let devices_connected = input_devices.create_uint("devices_connected", 0);
1420
1421 let dir = fuchsia_fs::directory::open_directory_async(
1422 &svc_proxy,
1423 "fuchsia.input.report.Service",
1424 fio::PERM_READABLE,
1425 )
1426 .expect("open service directory");
1427 let service = fuchsia_component::client::Service::from_service_dir_proxy(
1428 dir,
1429 fidl_fuchsia_input_report::ServiceMarker,
1430 );
1431
1432 let _ = InputPipeline::watch_for_devices(
1433 service,
1434 supported_device_types,
1435 input_event_sender,
1436 bindings.clone(),
1437 &input_devices,
1438 &devices_discovered,
1439 &devices_connected,
1440 true, InputPipelineFeatureFlags { enable_merge_touch_events: false },
1442 metrics::MetricsLogger::default(),
1443 DeviceListenerRegistry::new(),
1444 )
1445 .await;
1446
1447 {
1449 let bindings = bindings.lock();
1450 assert_eq!(bindings.len(), 0);
1451 }
1452
1453 diagnostics_assertions::assert_data_tree!(inspector, root: {
1455 input_pipeline: {
1456 supported_input_devices: "Keyboard",
1457 input_devices: {
1458 devices_discovered: 1u64,
1459 devices_connected: 0u64,
1460 "instance_0_Unsupported": {
1461 "fuchsia.inspect.Health": {
1462 status: "UNHEALTHY",
1463 message: "Unsupported device type.",
1464 start_timestamp_nanos: AnyProperty
1467 },
1468 }
1469 }
1470 }
1471 });
1472 }
1473
1474 #[fuchsia::test]
1477 async fn handle_input_device_registry_request_stream() {
1478 let (input_device_registry_proxy, input_device_registry_request_stream) =
1479 create_proxy_and_stream::<fidl_fuchsia_input_injection::InputDeviceRegistryMarker>();
1480 let (input_device_client_end, mut input_device_request_stream) =
1481 create_request_stream::<fidl_fuchsia_input_report::InputDeviceMarker>();
1482
1483 let device_types = vec![input_device::InputDeviceType::Mouse];
1484 let (input_event_sender, _input_event_receiver) = futures::channel::mpsc::unbounded();
1485 let bindings: InputDeviceBindingMap = Arc::new(Mutex::new(SortedVecMap::new()));
1486
1487 let device_listener_registry = DeviceListenerRegistry::new();
1488 let (listener_client, listener_server) =
1489 fidl_next::fuchsia::create_channel::<fidl_next_fuchsia_ui_input::DeviceListener>();
1490 let listener_client = listener_client.spawn();
1491 let _existing_devices = device_listener_registry.add_listener(listener_client);
1492
1493 let (event_sender, mut event_receiver) = futures::channel::mpsc::unbounded();
1494 let _server_task = listener_server.spawn(MockDeviceListener { event_sender });
1495
1496 let _task = fasync::Task::local(async move {
1498 let _ = input_device_registry_proxy.register(input_device_client_end);
1500
1501 let mut count = 0;
1502 while count < 2 {
1503 if let Some(input_device_request) =
1504 input_device_request_stream.try_next().await.unwrap()
1505 {
1506 handle_input_device_request(input_device_request);
1507 count += 1;
1508 } else {
1509 break;
1510 }
1511 }
1512
1513 input_device_registry_proxy.take_event_stream();
1515 });
1516
1517 let inspector = fuchsia_inspect::Inspector::default();
1518 let test_node = inspector.root().create_child("input_pipeline");
1519
1520 let bindings_clone = bindings.clone();
1522 let device_listener_registry_clone = device_listener_registry.clone();
1523 let (task_sender, mut task_receiver) = futures::channel::mpsc::unbounded();
1524 let mut tasks = futures::stream::FuturesUnordered::new();
1525 let registry_fut = InputPipeline::handle_input_device_registry_request_stream(
1526 input_device_registry_request_stream,
1527 &device_types,
1528 &input_event_sender,
1529 &bindings_clone,
1530 &test_node,
1531 InputPipelineFeatureFlags { enable_merge_touch_events: false },
1532 metrics::MetricsLogger::default(),
1533 device_listener_registry_clone,
1534 task_sender,
1535 )
1536 .fuse();
1537
1538 let mut registry_fut = std::pin::pin!(registry_fut);
1539 loop {
1540 futures::select! {
1541 res = registry_fut => {
1542 res.unwrap();
1543 break;
1544 }
1545 task = task_receiver.next() => {
1546 if let Some(task) = task {
1547 tasks.push(task);
1548 }
1549 }
1550 _ = tasks.select_next_some() => {}
1551 }
1552 }
1553
1554 let device_id = {
1556 let bindings = bindings.lock();
1557 assert_eq!(bindings.len(), 1);
1558 *bindings.keys().next().unwrap()
1559 };
1560
1561 if let Some(event) = event_receiver.next().await {
1563 assert_eq!(event.action, Some(fidl_next_fuchsia_ui_input::Action::Added));
1564 assert_eq!(event.device_id, Some(device_id));
1565 } else {
1566 panic!("Expected a request on listener stream");
1567 }
1568 }
1569
1570 #[fasync::run_singlethreaded(test)]
1573 async fn handle_input_device_registry_disconnection() {
1574 let (input_device_registry_proxy, input_device_registry_request_stream) =
1575 create_proxy_and_stream::<fidl_fuchsia_input_injection::InputDeviceRegistryMarker>();
1576 let (input_device_client_end, mut input_device_request_stream) =
1577 create_request_stream::<fidl_fuchsia_input_report::InputDeviceMarker>();
1578
1579 let device_types = vec![input_device::InputDeviceType::Mouse];
1580 let (input_event_sender, _input_event_receiver) = futures::channel::mpsc::unbounded();
1581 let bindings: InputDeviceBindingMap = Arc::new(Mutex::new(SortedVecMap::new()));
1582
1583 let device_listener_registry = DeviceListenerRegistry::new();
1584 let (listener_client, listener_server) =
1585 fidl_next::fuchsia::create_channel::<fidl_next_fuchsia_ui_input::DeviceListener>();
1586 let listener_client = listener_client.spawn();
1587 let _existing_devices = device_listener_registry.add_listener(listener_client);
1588
1589 let (event_sender, mut event_receiver) = futures::channel::mpsc::unbounded();
1590 let _server_task = listener_server.spawn(MockDeviceListener { event_sender });
1591
1592 let _task = fasync::Task::local(async move {
1594 let _ = input_device_registry_proxy.register(input_device_client_end);
1596
1597 let mut count = 0;
1598 while count < 2 {
1599 if let Some(input_device_request) =
1600 input_device_request_stream.try_next().await.unwrap()
1601 {
1602 handle_input_device_request(input_device_request);
1603 count += 1;
1604 } else {
1605 break;
1606 }
1607 }
1608
1609 std::mem::drop(input_device_request_stream);
1611
1612 fasync::Timer::new(fasync::MonotonicInstant::after(
1614 zx::MonotonicDuration::from_millis(100),
1615 ))
1616 .await;
1617
1618 input_device_registry_proxy.take_event_stream();
1620 });
1621
1622 let inspector = fuchsia_inspect::Inspector::default();
1623 let test_node = inspector.root().create_child("input_pipeline");
1624
1625 let bindings_clone = bindings.clone();
1627 let device_listener_registry_clone = device_listener_registry.clone();
1628 let (task_sender, mut task_receiver) = futures::channel::mpsc::unbounded();
1629 let mut tasks = futures::stream::FuturesUnordered::new();
1630 let registry_fut = InputPipeline::handle_input_device_registry_request_stream(
1631 input_device_registry_request_stream,
1632 &device_types,
1633 &input_event_sender,
1634 &bindings_clone,
1635 &test_node,
1636 InputPipelineFeatureFlags { enable_merge_touch_events: false },
1637 metrics::MetricsLogger::default(),
1638 device_listener_registry_clone,
1639 task_sender,
1640 )
1641 .fuse();
1642
1643 let mut registry_fut = std::pin::pin!(registry_fut);
1644 loop {
1645 futures::select! {
1646 res = registry_fut => {
1647 res.unwrap();
1648 break;
1649 }
1650 task = task_receiver.next() => {
1651 if let Some(task) = task {
1652 tasks.push(task);
1653 }
1654 }
1655 _ = tasks.select_next_some() => {}
1656 }
1657 }
1658 while let Some(_) = tasks.next().await {}
1659
1660 {
1662 let bindings = bindings.lock();
1663 assert_eq!(bindings.len(), 0);
1664 }
1665
1666 let event_added = if let Some(event) = event_receiver.next().await {
1668 event
1669 } else {
1670 panic!("Expected Added event");
1671 };
1672 assert_eq!(event_added.action, Some(fidl_next_fuchsia_ui_input::Action::Added));
1673
1674 let event_removed = if let Some(event) = event_receiver.next().await {
1676 event
1677 } else {
1678 panic!("Expected Removed event");
1679 };
1680 assert_eq!(event_removed.action, Some(fidl_next_fuchsia_ui_input::Action::Removed));
1681 }
1682
1683 #[fuchsia::test]
1685 async fn check_inspect_node_has_correct_properties() {
1686 let device_types = vec![
1687 input_device::InputDeviceType::Touch,
1688 input_device::InputDeviceType::ConsumerControls,
1689 ];
1690 let inspector = fuchsia_inspect::Inspector::default();
1691 let test_node = inspector.root().create_child("input_pipeline");
1692 let (fake_handler_event_sender, _fake_handler_event_receiver) =
1694 futures::channel::mpsc::channel(100);
1695 let fake_input_handler =
1696 observe_fake_events_input_handler::ObserveFakeEventsInputHandler::new(
1697 fake_handler_event_sender,
1698 );
1699 let assembly = InputPipelineAssembly::new(metrics::MetricsLogger::default())
1700 .add_handler(fake_input_handler);
1701 let _test_input_pipeline = InputPipeline::new(
1702 &Incoming::new(),
1703 device_types,
1704 assembly,
1705 test_node,
1706 InputPipelineFeatureFlags { enable_merge_touch_events: false },
1707 metrics::MetricsLogger::default(),
1708 );
1709 diagnostics_assertions::assert_data_tree!(inspector, root: {
1710 input_pipeline: {
1711 supported_input_devices: "Touch, ConsumerControls",
1712 handlers_registered: 1u64,
1713 handlers_healthy: 1u64,
1714 input_devices: {}
1715 }
1716 });
1717 }
1718
1719 struct SpecificInterestFakeHandler {
1720 interest_types: Vec<input_device::InputEventType>,
1721 event_sender: std::cell::RefCell<futures::channel::mpsc::Sender<input_device::InputEvent>>,
1722 }
1723
1724 impl SpecificInterestFakeHandler {
1725 pub fn new(
1726 interest_types: Vec<input_device::InputEventType>,
1727 event_sender: futures::channel::mpsc::Sender<input_device::InputEvent>,
1728 ) -> Rc<Self> {
1729 Rc::new(SpecificInterestFakeHandler {
1730 interest_types,
1731 event_sender: std::cell::RefCell::new(event_sender),
1732 })
1733 }
1734 }
1735
1736 impl Handler for SpecificInterestFakeHandler {
1737 fn set_handler_healthy(self: std::rc::Rc<Self>) {}
1738 fn set_handler_unhealthy(self: std::rc::Rc<Self>, _msg: &str) {}
1739 fn get_name(&self) -> &'static str {
1740 "SpecificInterestFakeHandler"
1741 }
1742
1743 fn interest(&self) -> Vec<input_device::InputEventType> {
1744 self.interest_types.clone()
1745 }
1746 }
1747
1748 #[async_trait(?Send)]
1749 impl input_handler::InputHandler for SpecificInterestFakeHandler {
1750 async fn handle_input_event(
1751 self: Rc<Self>,
1752 input_event: input_device::InputEvent,
1753 ) -> Vec<input_device::InputEvent> {
1754 match self.event_sender.borrow_mut().try_send(input_event.clone()) {
1755 Err(e) => panic!("SpecificInterestFakeHandler failed to send event: {:?}", e),
1756 Ok(_) => {}
1757 }
1758 vec![input_event]
1759 }
1760 }
1761
1762 #[fuchsia::test]
1763 async fn run_only_sends_events_to_interested_handlers() {
1764 let (mouse_sender, mut mouse_receiver) = futures::channel::mpsc::channel(1);
1766 let mouse_handler =
1767 SpecificInterestFakeHandler::new(vec![InputEventType::Mouse], mouse_sender);
1768
1769 let (fake_sender, mut fake_receiver) = futures::channel::mpsc::channel(1);
1771 let fake_handler =
1772 SpecificInterestFakeHandler::new(vec![InputEventType::Fake], fake_sender);
1773
1774 let (pipeline_sender, pipeline_receiver, handlers, _, _, _) =
1775 InputPipelineAssembly::new(metrics::MetricsLogger::default())
1776 .add_handler(mouse_handler)
1777 .add_handler(fake_handler)
1778 .into_components();
1779
1780 let _runner_task = fasync::Task::local(InputPipeline::run(
1782 pipeline_receiver,
1783 handlers,
1784 metrics::MetricsLogger::default(),
1785 ));
1786
1787 let fake_event = input_device::InputEvent {
1789 device_event: input_device::InputDeviceEvent::Fake,
1790 device_descriptor: input_device::InputDeviceDescriptor::Fake,
1791 event_time: zx::MonotonicInstant::get(),
1792 handled: input_device::Handled::No,
1793 trace_id: None,
1794 };
1795
1796 pipeline_sender.unbounded_send(vec![fake_event.clone()]).expect("failed to send event");
1798
1799 let received_by_fake = fake_receiver.next().await;
1801 assert_eq!(received_by_fake, Some(fake_event));
1802
1803 assert!(mouse_receiver.try_next().is_err());
1805 }
1806
1807 fn create_mouse_event(x: f32, y: f32) -> input_device::InputEvent {
1808 input_device::InputEvent {
1809 device_event: input_device::InputDeviceEvent::Mouse(mouse_binding::MouseEvent::new(
1810 mouse_binding::MouseLocation::Relative(mouse_binding::RelativeLocation {
1811 counts: Position { x, y },
1812 }),
1813 None,
1814 None,
1815 mouse_binding::MousePhase::Move,
1816 SortedVecSet::new(),
1817 SortedVecSet::new(),
1818 None,
1819 None,
1820 )),
1821 device_descriptor: input_device::InputDeviceDescriptor::Mouse(
1822 mouse_binding::MouseDeviceDescriptor {
1823 device_id: 1,
1824 absolute_x_range: None,
1825 absolute_y_range: None,
1826 wheel_v_range: None,
1827 wheel_h_range: None,
1828 buttons: None,
1829 },
1830 ),
1831 event_time: zx::MonotonicInstant::get(),
1832 handled: input_device::Handled::No,
1833 trace_id: None,
1834 }
1835 }
1836
1837 #[fuchsia::test]
1838 async fn run_mixed_event_types_dispatched_correctly() {
1839 let (mouse_sender, mut mouse_receiver) = futures::channel::mpsc::channel(10);
1841 let mouse_handler =
1842 SpecificInterestFakeHandler::new(vec![InputEventType::Mouse], mouse_sender);
1843
1844 let (fake_sender, mut fake_receiver) = futures::channel::mpsc::channel(10);
1846 let fake_handler =
1847 SpecificInterestFakeHandler::new(vec![InputEventType::Fake], fake_sender);
1848
1849 let (pipeline_sender, pipeline_receiver, handlers, _, _, _) =
1850 InputPipelineAssembly::new(metrics::MetricsLogger::default())
1851 .add_handler(mouse_handler)
1852 .add_handler(fake_handler)
1853 .into_components();
1854
1855 let _runner_task = fasync::Task::local(InputPipeline::run(
1857 pipeline_receiver,
1858 handlers,
1859 metrics::MetricsLogger::default(),
1860 ));
1861
1862 let mouse_event_1 = create_mouse_event(1.0, 1.0);
1864 let mouse_event_2 = create_mouse_event(2.0, 2.0);
1865 let mouse_event_3 = create_mouse_event(3.0, 3.0);
1866
1867 let fake_event_1 = input_device::InputEvent {
1868 device_event: input_device::InputDeviceEvent::Fake,
1869 device_descriptor: input_device::InputDeviceDescriptor::Fake,
1870 event_time: zx::MonotonicInstant::get(),
1871 handled: input_device::Handled::No,
1872 trace_id: None,
1873 };
1874
1875 let mixed_batch = vec![
1878 mouse_event_1.clone(),
1879 mouse_event_2.clone(),
1880 fake_event_1.clone(),
1881 mouse_event_3.clone(),
1882 ];
1883 pipeline_sender.unbounded_send(mixed_batch).expect("failed to send events");
1884
1885 assert_eq!(mouse_receiver.next().await, Some(mouse_event_1));
1887 assert_eq!(mouse_receiver.next().await, Some(mouse_event_2));
1888 assert_eq!(mouse_receiver.next().await, Some(mouse_event_3));
1889
1890 assert_eq!(fake_receiver.next().await, Some(fake_event_1));
1892 }
1893}