Skip to main content

input_pipeline/
input_pipeline.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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
29/// Use a self incremental u32 unique id for device_id.
30///
31/// device id start from 10 to avoid conflict with default devices in Starnix.
32/// Currently, Starnix using 0 and 1 as default devices' id. Starnix need to
33/// use default devices to deliver events from physical devices until we have
34/// API to expose device changes to UI clients.
35static NEXT_DEVICE_ID: LazyLock<AtomicU32> = LazyLock::new(|| AtomicU32::new(10));
36
37/// Each time this function is invoked, it returns the current value of its
38/// internal counter (serving as a unique id for device_id) and then increments
39/// that counter in preparation for the next call.
40fn 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
51/// An [`InputDeviceBindingMap`] maps an input device to one or more InputDeviceBindings and their tasks.
52/// It uses unique device id as key.
53pub type InputDeviceBindingMap = Arc<Mutex<SortedVecMap<u32, Vec<InputDeviceBindingAndTask>>>>;
54
55/// An input pipeline assembly.
56///
57/// Represents a partial stage of the input pipeline which accepts inputs through an asynchronous
58/// sender channel, and emits outputs through an asynchronous receiver channel.  Use [new] to
59/// create a new assembly.  Use [add_handler], or [add_all_handlers] to add the input pipeline
60/// handlers to use.  When done, [InputPipeline::new] can be used to make a new input pipeline.
61///
62/// # Implementation notes
63///
64/// Internally, when a new [InputPipelineAssembly] is created with multiple [InputHandler]s, the
65/// handlers are connected together using async queues.  This allows fully streamed processing of
66/// input events, and also allows some pipeline stages to generate events spontaneously, i.e.
67/// without an external stimulus.
68pub struct InputPipelineAssembly {
69    /// The top-level sender: send into this queue to inject an event into the input
70    /// pipeline.
71    sender: UnboundedSender<Vec<input_device::InputEvent>>,
72    /// The bottom-level receiver: any events that fall through the entire pipeline can
73    /// be read from this receiver.
74    receiver: UnboundedReceiver<Vec<input_device::InputEvent>>,
75
76    /// The input handlers that comprise the input pipeline.
77    handlers: Vec<Rc<dyn input_handler::BatchInputHandler>>,
78
79    /// The display ownership watcher task.
80    display_ownership_fut: Option<LocalBoxFuture<'static, ()>>,
81
82    /// The focus listener task.
83    focus_listener_fut: Option<LocalBoxFuture<'static, ()>>,
84
85    /// The metrics logger.
86    metrics_logger: metrics::MetricsLogger,
87
88    /// The display ownership handler, if configured.
89    display_ownership: Option<Rc<DisplayOwnership>>,
90}
91
92impl InputPipelineAssembly {
93    /// Create a new but empty [InputPipelineAssembly]. Use [add_handler] or similar
94    /// to add new handlers to it.
95    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    /// Adds another [input_handler::BatchInputHandler] into the [InputPipelineAssembly]. The handlers
109    /// are invoked in the order they are added. Returns `Self` for chaining.
110    pub fn add_handler(mut self, handler: Rc<dyn input_handler::BatchInputHandler>) -> Self {
111        self.handlers.push(handler);
112        self
113    }
114
115    /// Adds all handlers into the assembly in the order they appear in `handlers`.
116    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    /// Deconstructs the assembly into constituent components, used when constructing
160    /// [InputPipeline].
161    ///
162    /// You should call [catch_unhandled] on the returned [async_channel::Receiver], and
163    /// [run] on the returned [fuchsia_async::Tasks] (or supply own equivalents).
164    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                // This will await indefinitely and process focus messages in a loop, unless there
203                // is a problem.
204                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
220/// An [`InputPipeline`] manages input devices and propagates input events through input handlers.
221///
222/// On creation, clients declare what types of input devices an [`InputPipeline`] manages. The
223/// [`InputPipeline`] will continuously detect new input devices of supported type(s).
224///
225/// # Example
226/// ```
227/// let ime_handler =
228///     ImeHandler::new(scene_manager.session.clone(), scene_manager.compositor_id).await?;
229/// let touch_handler = TouchHandler::new(
230///     scene_manager.session.clone(),
231///     scene_manager.compositor_id,
232///     scene_manager.display_size
233/// ).await?;
234///
235/// let assembly = InputPipelineAssembly::new()
236///     .add_handler(Box::new(ime_handler)),
237///     .add_handler(Box::new(touch_handler)),
238/// let input_pipeline = InputPipeline::new(
239///     vec![
240///         input_device::InputDeviceType::Touch,
241///         input_device::InputDeviceType::Keyboard,
242///     ],
243///     assembly,
244/// );
245/// input_pipeline.handle_input_events().await;
246/// ```
247pub struct InputPipeline {
248    /// The entry point into the input handler pipeline. Incoming input events should
249    /// be inserted into this async queue, and the input pipeline will ensure that they
250    /// are propagated through all the input handlers in the appropriate sequence.
251    pipeline_sender: UnboundedSender<Vec<input_device::InputEvent>>,
252
253    /// A clone of this sender is given to every InputDeviceBinding that this pipeline owns.
254    /// Each InputDeviceBinding will send InputEvents to the pipeline through this channel.
255    device_event_sender: UnboundedSender<Vec<input_device::InputEvent>>,
256
257    /// Receives InputEvents from all InputDeviceBindings that this pipeline owns.
258    device_event_receiver: UnboundedReceiver<Vec<input_device::InputEvent>>,
259
260    /// The types of devices this pipeline supports.
261    input_device_types: Vec<input_device::InputDeviceType>,
262
263    /// The InputDeviceBindings bound to this pipeline.
264    input_device_bindings: InputDeviceBindingMap,
265
266    /// This node is bound to the lifetime of this InputPipeline.
267    /// Inspect data will be dumped for this pipeline as long as it exists.
268    inspect_node: fuchsia_inspect::Node,
269
270    /// The metrics logger.
271    metrics_logger: metrics::MetricsLogger,
272
273    /// The feature flags for the input pipeline.
274    pub feature_flags: input_device::InputPipelineFeatureFlags,
275    /// The display ownership future, if configured.
276    display_ownership_fut: Option<LocalBoxFuture<'static, ()>>,
277
278    /// The focus listener future, if configured.
279    focus_listener_fut: Option<LocalBoxFuture<'static, ()>>,
280
281    /// The watcher future.
282    watcher_fut: Option<LocalBoxFuture<'static, ()>>,
283
284    /// The runner future.
285    runner_fut: Option<LocalBoxFuture<'static, ()>>,
286
287    /// The registry for device listeners.
288    pub device_listener_registry: DeviceListenerRegistry,
289
290    /// The display ownership handler, if configured.
291    pub display_ownership: Option<Rc<DisplayOwnership>>,
292}
293
294impl InputPipeline {
295    /// Gets the display ownership handler, if configured.
296    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        // Add properties to inspect node
344        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        // Initializes all handlers and starts the input pipeline loop.
349        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    /// Creates a new [`InputPipeline`] for integration testing.
374    /// Unlike a production input pipeline, this pipeline will not monitor
375    /// `/svc/fuchsia.input.report.Service` for devices.
376    ///
377    /// # Parameters
378    /// - `input_device_types`: The types of devices the new [`InputPipeline`] will support.
379    /// - `assembly`: The input handlers that the [`InputPipeline`] sends InputEvents to.
380    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    /// Creates a new [`InputPipeline`] for production use.
418    ///
419    /// # Parameters
420    /// - `input_device_types`: The types of devices the new [`InputPipeline`] will support.
421    /// - `assembly`: The input handlers that the [`InputPipeline`] sends InputEvents to.
422    /// - `inspect_node`: The root node for InputPipeline's Inspect tree
423    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    /// Creates a new [`InputPipeline`] with an explicitly provided [`Service`].
442    /// Useful for testing with mock service directories.
443    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, /* break_on_idle */
581                        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    /// Gets the input device bindings.
617    pub fn input_device_bindings(&self) -> &InputDeviceBindingMap {
618        &self.input_device_bindings
619    }
620
621    /// Gets the input device sender: this is the channel that should be cloned
622    /// and used for injecting events from the drivers into the input pipeline.
623    pub fn input_event_sender(&self) -> &UnboundedSender<Vec<input_device::InputEvent>> {
624        &self.device_event_sender
625    }
626
627    /// Gets a list of input device types supported by this input pipeline.
628    pub fn input_device_types(&self) -> &[input_device::InputDeviceType] {
629        &self.input_device_types
630    }
631
632    /// Gets the device listener registry.
633    pub fn device_listener_registry(&self) -> &DeviceListenerRegistry {
634        &self.device_listener_registry
635    }
636
637    /// Forwards all input events into the input pipeline.
638    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    /// Watches the input report service for new input devices. Creates InputDeviceBindings
826    /// if new devices match a type in `device_types`.
827    ///
828    /// # Parameters
829    /// - `service`: The service to watch for new devices.
830    /// - `device_types`: The types of devices to watch for.
831    /// - `input_event_sender`: The channel new InputDeviceBindings will send InputEvents to.
832    /// - `bindings`: Holds all the InputDeviceBindings
833    /// - `input_devices_node`: The parent node for all device bindings' inspect nodes.
834    /// - `devices_discovered`: Inspect property to track discovered devices.
835    /// - `devices_connected`: Inspect property to track connected devices.
836    /// - `break_on_idle`: If true, stops watching for devices once all existing devices are handled.
837    /// - `feature_flags`: The feature flags.
838    /// - `metrics_logger`: The metrics logger.
839    ///
840    /// # Errors
841    /// If the input report service or a connection within it fails.
842    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    /// Handles the incoming InputDeviceRegistryRequestStream.
940    ///
941    /// This method will end when the request stream is closed. If the stream closes with an
942    /// error the error will be returned in the Result.
943    ///
944    /// **NOTE**: Only one stream is handled at a time. https://fxbug.dev/42061078
945    ///
946    /// # Parameters
947    /// - `stream`: The stream of InputDeviceRegistryRequests.
948    /// - `device_types`: The types of devices to watch for.
949    /// - `input_event_sender`: The channel new InputDeviceBindings will send InputEvents to.
950    /// - `bindings`: Holds all the InputDeviceBindings associated with the InputPipeline.
951    /// - `input_devices_node`: The parent node for all injected devices' inspect nodes.
952    /// - `metrics_logger`: The metrics logger.
953    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                    // Add a binding if the device is a type being tracked
975                    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                    // Add a binding if the device is a type being tracked
1024                    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    /// Initializes all handlers and starts the input pipeline loop in an asynchronous executor.
1081    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            // TODO: b/478262850 - We can use supported_input_devices to populate this list.
1095            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                    // Get pre-computed handlers for this event type.
1134                    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
1164/// Adds `InputDeviceBinding`s to `bindings` for all `device_types` exposed by `device_proxy`.
1165///
1166/// # Parameters
1167/// - `device_types`: The types of devices to watch for.
1168/// - `device_proxy`: A proxy to the input device.
1169/// - `input_event_sender`: The channel new InputDeviceBindings will send InputEvents to.
1170/// - `bindings`: Holds all the InputDeviceBindings associated with the InputPipeline.
1171/// - `device_id`: The device id of the associated bindings.
1172/// - `input_devices_node`: The parent node for all device bindings' inspect nodes.
1173///
1174/// # Note
1175/// This will create multiple bindings, in the case where
1176/// * `device_proxy().get_descriptor()` returns a `fidl_fuchsia_input_report::DeviceDescriptor`
1177///   with multiple table fields populated, and
1178/// * multiple populated table fields correspond to device types present in `device_types`
1179///
1180/// This is used, for example, to support the Atlas touchpad. In that case, a single
1181/// instance of `fuchsia.input.report.Service` provides both a `fuchsia.input.report.MouseDescriptor` and
1182/// a `fuchsia.input.report.TouchDescriptor`.
1183async 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        // Clone `device_proxy`, so that multiple bindings (e.g. a `MouseBinding` and a
1247        // `TouchBinding`) can read data from the same `fuchsia.input.report.Service` instance.
1248        //
1249        // There's no conflict in having multiple bindings read from the same node,
1250        // since:
1251        // * each binding will create its own `fuchsia.input.report.InputReportsReader`, and
1252        // * the device driver will copy each incoming report to each connected reader.
1253        //
1254        // This does mean that reports from the Atlas touchpad device get read twice
1255        // (by a `MouseBinding` and a `TouchBinding`), regardless of whether the device
1256        // is operating in mouse mode or touchpad mode.
1257        //
1258        // This hasn't been an issue because:
1259        // * Semantically: things are fine, because each binding discards irrelevant reports.
1260        //   (E.g. `MouseBinding` discards anything that isn't a `MouseInputReport`), and
1261        // * Performance wise: things are fine, because the data rate of the touchpad is low
1262        //   (125 HZ).
1263        //
1264        // If we add additional cases where bindings share an underlying service instance,
1265        // we might consider adding a multiplexing binding, to avoid reading duplicate reports.
1266        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    /// Returns the InputEvent sent over `sender`.
1342    ///
1343    /// # Parameters
1344    /// - `sender`: The channel to send the InputEvent over.
1345    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, /* wheel_delta_v */
1357                None, /* wheel_delta_h */
1358                mouse_binding::MousePhase::Move,
1359                SortedVecSet::new(),
1360                SortedVecSet::new(),
1361                None, /* is_precision_scroll */
1362                None, /* wake_lease */
1363            )),
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    /// Returns a MouseDescriptor on an InputDeviceRequest.
1387    ///
1388    /// # Parameters
1389    /// - `input_device_request`: The request to handle.
1390    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    /// Tests that an input pipeline handles events from multiple devices.
1428    #[fuchsia::test]
1429    async fn multiple_devices_single_handler() {
1430        // Create two fake device bindings.
1431        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        // Create a fake input handler.
1438        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        // Build the input pipeline.
1445        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        // Send an input event from each device.
1471        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        // Run the pipeline.
1475        let _pipeline_task = fasync::Task::local(input_pipeline.handle_input_events());
1476
1477        // Assert the handler receives the events.
1478        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    /// Tests that an input pipeline handles events through multiple input handlers.
1486    #[fuchsia::test]
1487    async fn single_device_multiple_handlers() {
1488        // Create two fake device bindings.
1489        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        // Create two fake input handlers.
1494        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        // Build the input pipeline.
1508        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        // Send an input event.
1535        let input_events = send_input_event(input_device_binding.input_event_sender());
1536
1537        // Run the pipeline.
1538        let _pipeline_task = fasync::Task::local(input_pipeline.handle_input_events());
1539
1540        // Assert both handlers receive the event.
1541        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    /// Tests that a single mouse device binding is created for the one input device in the
1549    /// input report service directory.
1550    #[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        // Get a proxy to the pseudo directory for the input pipeline. The input pipeline uses this
1572        // proxy to get connections to input devices.
1573        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        // Assert that inspect tree is initialized with no devices.
1588        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, /* break_on_idle */
1618            InputPipelineFeatureFlags { enable_merge_touch_events: false },
1619            metrics::MetricsLogger::default(),
1620            DeviceListenerRegistry::new(),
1621        )
1622        .await;
1623
1624        // Assert that one mouse device with accurate device id was found.
1625        {
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        // Assert that inspect tree reflects new device discovered and connected.
1647        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                            // Timestamp value is unpredictable and not relevant in this context,
1662                            // so we only assert that the property is present.
1663                            start_timestamp_nanos: AnyProperty
1664                        },
1665                    }
1666                }
1667            }
1668        });
1669    }
1670
1671    /// Tests that no device bindings are created because the input pipeline looks for keyboard devices
1672    /// but only a mouse exists.
1673    #[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        // Get a proxy to the pseudo directory for the input pipeline. The input pipeline uses this
1695        // proxy to get connections to input devices.
1696        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        // Assert that inspect tree is initialized with no devices.
1711        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, /* break_on_idle */
1741            InputPipelineFeatureFlags { enable_merge_touch_events: false },
1742            metrics::MetricsLogger::default(),
1743            DeviceListenerRegistry::new(),
1744        )
1745        .await;
1746
1747        // Assert that no devices were found.
1748        {
1749            let bindings = bindings.lock();
1750            assert_eq!(bindings.len(), 0);
1751        }
1752
1753        // Assert that inspect tree reflects new device discovered, but not connected.
1754        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                            // Timestamp value is unpredictable and not relevant in this context,
1765                            // so we only assert that the property is present.
1766                            start_timestamp_nanos: AnyProperty
1767                        },
1768                    }
1769                }
1770            }
1771        });
1772    }
1773
1774    /// Tests that a single keyboard device binding is created for the input device registered
1775    /// through InputDeviceRegistry.
1776    #[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        // Handle input device requests.
1797        let _task = fasync::Task::local(async move {
1798            // Register a device.
1799            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            // End handle_input_device_registry_request_stream() by taking the event stream.
1814            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        // Start listening for InputDeviceRegistryRequests.
1821        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        // Assert that a device was registered.
1855        let device_id = {
1856            let bindings = bindings.lock();
1857            assert_eq!(bindings.len(), 1);
1858            *bindings.keys().next().unwrap()
1859        };
1860
1861        // Assert that device listener was notified.
1862        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    /// Tests that an injected device is removed and listeners are notified with Action::Removed
1871    /// when the injected device channel is closed.
1872    #[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        // Handle input device requests.
1893        let _task = fasync::Task::local(async move {
1894            // Register a device.
1895            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            // Close the device channel by dropping the request stream.
1910            std::mem::drop(input_device_request_stream);
1911
1912            // Wait a bit to let the local task run.
1913            fasync::Timer::new(fasync::MonotonicInstant::after(
1914                zx::MonotonicDuration::from_millis(100),
1915            ))
1916            .await;
1917
1918            // End handle_input_device_registry_request_stream() by taking the event stream.
1919            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        // Start listening for InputDeviceRegistryRequests.
1926        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        // Assert that the device was registered and then removed.
1961        {
1962            let bindings = bindings.lock();
1963            assert_eq!(bindings.len(), 0);
1964        }
1965
1966        // Assert that device listener was notified of Addition.
1967        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        // Assert that device listener was notified of Removal.
1975        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    // Tests that correct properties are added to inspect node when InputPipeline is created.
1984    #[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        // Create fake input handler for assembly
1993        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        // Mouse Handler (Specific Interest: Mouse)
2065        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        // Fake Handler (Specific Interest: Fake)
2070        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        // Run the pipeline logic
2081        let _runner_task = fasync::Task::local(InputPipeline::run(
2082            pipeline_receiver,
2083            handlers,
2084            metrics::MetricsLogger::default(),
2085        ));
2086
2087        // Create a Fake event
2088        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        // Send the Fake event
2097        pipeline_sender.unbounded_send(vec![fake_event.clone()]).expect("failed to send event");
2098
2099        // Verify Fake Handler received it
2100        let received_by_fake = fake_receiver.next().await;
2101        assert_eq!(received_by_fake, Some(fake_event));
2102
2103        // Verify Mouse Handler did NOT receive it
2104        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        // Mouse Handler (Specific Interest: Mouse)
2140        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        // Fake Handler (Specific Interest: Fake)
2145        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        // Run the pipeline logic
2156        let _runner_task = fasync::Task::local(InputPipeline::run(
2157            pipeline_receiver,
2158            handlers,
2159            metrics::MetricsLogger::default(),
2160        ));
2161
2162        // Create events
2163        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        // Send mixed batch: [Mouse, Mouse, Fake, Mouse]
2176        // This should result in 3 chunks: [Mouse, Mouse], [Fake], [Mouse]
2177        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        // Verify Mouse Handler received M1, M2, and then M3
2186        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        // Verify Fake Handler received F1
2191        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        // Initial state: platform owns both display and input.
2245        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        // Run the pipeline tasks in the background.
2277        let _pipeline_task = fasync::Task::local(input_pipeline.handle_input_events());
2278
2279        // Wait until initial device is discovered and bound.
2280        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        // 1. Lose display ownership: DISPLAY_PLATFORM_OWNED -> DISPLAY_UNOWNED.
2292        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        // 2. Regain display ownership: DISPLAY_UNOWNED -> DISPLAY_PLATFORM_OWNED.
2302        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        // 3. Lose input ownership: INPUT_PLATFORM_OWNED -> INPUT_CLIENT_OWNED.
2312        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        // 4. Regain input ownership: INPUT_CLIENT_OWNED -> INPUT_PLATFORM_OWNED.
2322        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        // Initial state: platform does NOT own display.
2385        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        // Run the pipeline tasks in the background.
2416        let _pipeline_task = fasync::Task::local(input_pipeline.handle_input_events());
2417
2418        // Wait a bit to ensure watcher has run and attempted to bind.
2419        fasync::Timer::new(fasync::MonotonicInstant::after(zx::MonotonicDuration::from_millis(50)))
2420            .await;
2421
2422        // Device should NOT be bound because ownership was lost.
2423        assert!(bindings.lock().is_empty());
2424
2425        // Regain display ownership: DISPLAY_UNOWNED -> DISPLAY_PLATFORM_OWNED.
2426        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        // Device should now be re-enumerated and bound.
2435        assert_eq!(bindings.lock().len(), 1);
2436
2437        std::mem::drop(_pipeline_task);
2438    }
2439}