Skip to main content

starnix_modules_input/
input_event_relay.rs

1// Copyright 2024 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::{
6    InputDevice, InputDeviceInfo, InputDeviceInfoHandle, InputDeviceStatus, InputFile, uinput,
7};
8
9// Add a fuchsia-specific vendor ID. 0xfc1a is currently not allocated
10// to any vendor in the USB spec.
11//
12// May not be zero, see below.
13const FUCHSIA_VENDOR_ID: u16 = 0xfc1a;
14const FUCHSIA_KEYBOARD_PRODUCT_ID: u16 = 0x1;
15const FUCHSIA_TOUCH_PRODUCT_ID: u16 = 0x2;
16const FUCHSIA_MOUSE_PRODUCT_ID: u16 = 0x3;
17
18// Touch, keyboard, and mouse input IDs should be distinct.
19// Per https://www.linuxjournal.com/article/6429, the bus type should be populated with a
20// sensible value, but other fields may not be.
21//
22// While this may be the case for Linux itself, Android is not so relaxed.
23// Devices with apparently-invalid vendor or product IDs don't get extra
24// device configuration.  So we must make a minimum effort to present
25// sensibly-looking product and vendor IDs.  Zero version only means that
26// version-specific config files will not be applied.
27//
28// For background, see:
29//
30// * Allowable file locations:
31//   https://source.android.com/docs/core/interaction/input/input-device-configuration-files#location
32// * Android configuration selection code:
33//   https://source.corp.google.com/h/googleplex-android/platform/superproject/main/+/main:frameworks/native/libs/input/InputDevice.cpp;l=60;drc=285211e60bff87fc5a9c9b4105a4b4ccb7edffaf
34pub const TOUCH_INPUT_ID: uapi::input_id = uapi::input_id {
35    bustype: uapi::BUS_VIRTUAL as u16,
36    vendor: FUCHSIA_VENDOR_ID,
37    product: FUCHSIA_TOUCH_PRODUCT_ID,
38    version: 0,
39};
40pub const KEYBOARD_INPUT_ID: uapi::input_id = uapi::input_id {
41    bustype: uapi::BUS_VIRTUAL as u16,
42    vendor: FUCHSIA_VENDOR_ID,
43    product: FUCHSIA_KEYBOARD_PRODUCT_ID,
44    version: 1,
45};
46pub const MOUSE_INPUT_ID: uapi::input_id = uapi::input_id {
47    bustype: uapi::BUS_VIRTUAL as u16,
48    vendor: FUCHSIA_VENDOR_ID,
49    product: FUCHSIA_MOUSE_PRODUCT_ID,
50    version: 1,
51};
52use fidl::endpoints::{ClientEnd, RequestStream, ServerEnd};
53use fidl_fuchsia_ui_input as fuiinput;
54use fidl_fuchsia_ui_input::TouchDeviceInfo;
55use fidl_fuchsia_ui_input3::{
56    KeyEventStatus, KeyboardListenerMarker, KeyboardListenerRequest, KeyboardListenerRequestStream,
57    KeyboardSynchronousProxy,
58};
59use fidl_fuchsia_ui_pointer::{
60    MouseEvent as FidlMouseEvent, TouchEvent as FidlTouchEvent, TouchPointerSample,
61    {self as fuipointer},
62};
63use fidl_fuchsia_ui_policy as fuipolicy;
64use fidl_fuchsia_ui_views as fuiviews;
65#[cfg(test)]
66use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender, unbounded};
67#[cfg(test)]
68use futures::channel::oneshot;
69#[cfg(test)]
70use futures::channel::oneshot::Sender;
71#[cfg(test)]
72use futures::executor::block_on;
73use futures::{FutureExt as _, StreamExt as _};
74use sorted_vec_map::SortedVecMap;
75use starnix_core::device::kobject::Device;
76use starnix_core::power::{ContainerWakingStream, create_proxy_for_wake_events_counter};
77use starnix_core::task::dynamic_thread_spawner::SpawnRequestBuilder;
78use starnix_core::task::{CurrentTask, Kernel};
79use starnix_logging::{log_debug, log_error, log_warn};
80use starnix_modules_input_event_conversion::button_fuchsia_to_linux::{
81    new_touch_buttons_bitvec, parse_fidl_media_button_event, parse_fidl_touch_button_event,
82};
83use starnix_modules_input_event_conversion::key_fuchsia_to_linux::parse_fidl_keyboard_event_to_linux_input_event;
84use starnix_modules_input_event_conversion::mouse_fuchsia_to_linux::FuchsiaMouseEventToLinuxMouseEventConverter;
85use starnix_modules_input_event_conversion::touch_fuchsia_to_linux::FuchsiaTouchEventToLinuxTouchEventConverter;
86use starnix_sync::{
87    InputEventRelayOpenedFilesLock, InputRelayDeviceInfosLock, InputRelayDisplaySizeLock,
88    LockDepMutex,
89};
90use starnix_uapi::errors::Errno;
91use starnix_uapi::{error, uapi};
92use std::collections::VecDeque;
93use std::sync::atomic::{AtomicU8, AtomicU64, Ordering};
94use std::sync::{Arc, Weak};
95
96const INPUT_RELAY_ROLE_NAME: &str = "fuchsia.starnix.kthread.input_relay";
97
98#[derive(Clone, Copy)]
99pub enum EventProxyMode {
100    /// Don't proxy input events at all.
101    None,
102
103    /// Have the Starnix runner proxy events such that the container
104    /// will wake up if events are received while the container is
105    /// suspended.
106    WakeContainer,
107}
108
109pub struct StartRelaysArgs {
110    pub event_proxy_mode: EventProxyMode,
111    pub touch_source_client_end: ClientEnd<fuipointer::TouchSourceV2Marker>,
112    pub keyboard_proxy: KeyboardSynchronousProxy,
113    pub mouse_source_client_end: ClientEnd<fuipointer::MouseSourceV2Marker>,
114    pub view_ref: fuiviews::ViewRef,
115    pub registry_proxy: fuipolicy::DeviceListenerRegistrySynchronousProxy,
116    pub device_listener_registry: Option<fuiinput::DeviceListenerRegistrySynchronousProxy>,
117    pub display_width: i32,
118    pub display_height: i32,
119}
120
121#[derive(Default)]
122pub struct OpenedFilesState {
123    files: Vec<Weak<InputFile>>,
124    has_been_opened: bool,
125    buffered_events: Vec<uapi::input_event>,
126}
127
128impl OpenedFilesState {
129    pub fn on_file_opened(&mut self, file: &Arc<InputFile>) {
130        if !self.has_been_opened {
131            self.has_been_opened = true;
132            if !self.buffered_events.is_empty() {
133                file.add_events(std::mem::take(&mut self.buffered_events));
134            }
135        }
136        self.files.push(Arc::downgrade(file));
137    }
138}
139
140impl std::ops::Deref for OpenedFilesState {
141    type Target = Vec<Weak<InputFile>>;
142    fn deref(&self) -> &Self::Target {
143        &self.files
144    }
145}
146
147impl std::ops::DerefMut for OpenedFilesState {
148    fn deref_mut(&mut self) -> &mut Self::Target {
149        &mut self.files
150    }
151}
152
153pub type OpenedFiles = Arc<LockDepMutex<OpenedFilesState, InputEventRelayOpenedFilesLock>>;
154
155pub enum InputDeviceType {
156    Touch(FuchsiaTouchEventToLinuxTouchEventConverter),
157    Keyboard,
158    Mouse(FuchsiaMouseEventToLinuxMouseEventConverter),
159}
160
161impl std::fmt::Display for InputDeviceType {
162    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163        match self {
164            InputDeviceType::Touch(_) => write!(f, "touch"),
165            InputDeviceType::Keyboard => write!(f, "keyboard"),
166            InputDeviceType::Mouse(_) => write!(f, "mouse"),
167        }
168    }
169}
170
171enum DeviceRegistration {
172    Pending { kernel: Arc<Kernel>, device: crate::InputDevice, device_id: DeviceId },
173    Registered,
174    Failed,
175}
176
177impl DeviceRegistration {
178    /// Creates a `Pending` registration for `device`, which will be registered with `kernel`
179    /// under `device_id` on the first call to `ensure_registered`.
180    ///
181    /// `device` must not already be registered: `DeviceRegistry::register_device` silently
182    /// overwrites an existing minor device entry, so a double registration would otherwise only
183    /// surface as a warning log.
184    fn pending(kernel: Arc<Kernel>, device: crate::InputDevice, device_id: DeviceId) -> Self {
185        debug_assert!(
186            {
187                let devt = starnix_uapi::device_id::DeviceId::new(
188                    starnix_uapi::device_id::INPUT_MAJOR,
189                    device_id,
190                );
191                let next_devt = starnix_uapi::device_id::DeviceId::new(
192                    starnix_uapi::device_id::INPUT_MAJOR,
193                    device_id + 1,
194                );
195                kernel
196                    .device_registry
197                    .list_minor_devices(starnix_core::device::DeviceMode::Char, devt..next_devt)
198                    .is_empty()
199            },
200            "input device {device_id} must not be registered before lazy registration",
201        );
202        Self::Pending { kernel, device, device_id }
203    }
204
205    fn ensure_registered(&mut self) {
206        let Self::Pending { kernel, device, device_id } = self else { return };
207        match device.clone().register(kernel, *device_id) {
208            Ok(_) => *self = Self::Registered,
209            Err(e) => {
210                log_warn!("unable to register input device {device_id:?}: {e:?}");
211                // Intentionally abandon registering the mouse device after one failed attempt
212                // rather than retrying and logging on every subsequent input event.
213                *self = Self::Failed;
214            }
215        }
216    }
217}
218
219struct DeviceState {
220    device_type: InputDeviceType,
221    open_files: OpenedFiles,
222    inspect_status: Option<Arc<InputDeviceStatus>>,
223    registration: DeviceRegistration,
224    starnix_device: Option<Device>,
225    minor: u32,
226}
227
228impl DeviceState {
229    #[cfg(test)]
230    fn new_touch(
231        device_id: DeviceId,
232        open_files: OpenedFiles,
233        inspect_status: Option<Arc<InputDeviceStatus>>,
234    ) -> Self {
235        Self {
236            device_type: InputDeviceType::Touch(
237                FuchsiaTouchEventToLinuxTouchEventConverter::create(),
238            ),
239            open_files,
240            inspect_status,
241            registration: DeviceRegistration::Registered,
242            starnix_device: None,
243            minor: device_id,
244        }
245    }
246
247    #[cfg(test)]
248    fn new_keyboard(
249        device_id: DeviceId,
250        open_files: OpenedFiles,
251        inspect_status: Option<Arc<InputDeviceStatus>>,
252    ) -> Self {
253        Self {
254            device_type: InputDeviceType::Keyboard,
255            open_files,
256            inspect_status,
257            registration: DeviceRegistration::Registered,
258            starnix_device: None,
259            minor: device_id,
260        }
261    }
262
263    fn new_mouse(
264        device_id: DeviceId,
265        open_files: OpenedFiles,
266        inspect_status: Option<Arc<InputDeviceStatus>>,
267    ) -> Self {
268        Self {
269            device_type: InputDeviceType::Mouse(
270                FuchsiaMouseEventToLinuxMouseEventConverter::create(),
271            ),
272            open_files,
273            inspect_status,
274            registration: DeviceRegistration::Registered,
275            starnix_device: None,
276            minor: device_id,
277        }
278    }
279
280    fn new_pending_mouse(
281        kernel: Arc<Kernel>,
282        device: crate::InputDevice,
283        device_id: DeviceId,
284    ) -> Self {
285        Self {
286            device_type: InputDeviceType::Mouse(
287                FuchsiaMouseEventToLinuxMouseEventConverter::create(),
288            ),
289            open_files: device.open_files.clone(),
290            inspect_status: Some(device.inspect_status.clone()),
291            registration: DeviceRegistration::pending(kernel, device, device_id),
292            starnix_device: None,
293            minor: device_id,
294        }
295    }
296}
297
298pub struct TrackedWakeLease {
299    _lease: fidl::EventPair,
300    device_status: Arc<InputDeviceStatus>,
301}
302
303impl TrackedWakeLease {
304    pub fn new(lease: fidl::EventPair, device_status: Arc<InputDeviceStatus>) -> Self {
305        device_status.increment_active_wake_leases(1);
306        device_status.count_events_with_wake_lease(1);
307        Self { _lease: lease, device_status }
308    }
309}
310
311impl Drop for TrackedWakeLease {
312    fn drop(&mut self) {
313        self.device_status.decrement_active_wake_leases(1);
314    }
315}
316
317pub type DeviceId = u32;
318
319// TODO(https://fxbug.dev/502662433): Default devices are no longer needed because
320// existing devices are enumerated via the DeviceIterator before start_relays().
321// Remove them in a follow-up change.
322pub const DEFAULT_TOUCH_DEVICE_ID: DeviceId = 0;
323pub const DEFAULT_KEYBOARD_DEVICE_ID: DeviceId = 1;
324pub const DEFAULT_MOUSE_DEVICE_ID: DeviceId = 2;
325
326const DEVICE_LISTENER_NOT_ATTEMPTED: u8 = 0;
327const DEVICE_LISTENER_REGISTERED: u8 = 1;
328const DEVICE_LISTENER_DISCONNECTED: u8 = 2;
329
330// TODO(https://fxbug.dev/502662433): Migrate `add_touch_device` and `add_keyboard_device`
331// in tests to `DeviceListener`, and remove `DeviceStateChange` and this channel.
332#[cfg(test)]
333enum DeviceStateChange {
334    Add(DeviceId, Box<DeviceState>, Sender<()>),
335}
336
337pub fn new_input_relay() -> (InputEventsRelay, Arc<InputEventsRelayHandle>) {
338    #[cfg(test)]
339    let (sender, receiver) = unbounded();
340    let num_unregistered_device_events = Arc::new(AtomicU64::new(0));
341    let device_infos = Arc::new(LockDepMutex::new(SortedVecMap::new()));
342    let display_size = Arc::new(LockDepMutex::new(None));
343
344    (
345        InputEventsRelay {
346            devices: SortedVecMap::new(),
347            #[cfg(test)]
348            receiver: Some(receiver),
349            num_unregistered_device_events: num_unregistered_device_events.clone(),
350            num_devices: Arc::new(AtomicU64::new(0)),
351            device_listener_registered: Arc::new(AtomicU8::new(DEVICE_LISTENER_NOT_ATTEMPTED)),
352            _inspect_node: None,
353            device_infos: device_infos.clone(),
354            display_size: display_size.clone(),
355        },
356        Arc::new(InputEventsRelayHandle {
357            #[cfg(test)]
358            sender,
359            num_unregistered_device_events,
360            device_infos,
361            display_size,
362        }),
363    )
364}
365
366/// Handle for managing input devices registered with the input event relay.
367pub struct InputEventsRelayHandle {
368    #[cfg(test)]
369    sender: UnboundedSender<DeviceStateChange>,
370    num_unregistered_device_events: Arc<AtomicU64>,
371    pub(crate) device_infos:
372        Arc<LockDepMutex<SortedVecMap<DeviceId, InputDeviceInfoHandle>, InputRelayDeviceInfosLock>>,
373    pub(crate) display_size: Arc<LockDepMutex<Option<(i32, i32)>, InputRelayDisplaySizeLock>>,
374}
375
376impl InputEventsRelayHandle {
377    /// Returns the number of events received for unregistered devices across all input streams.
378    pub fn num_unregistered_device_events(&self) -> u64 {
379        self.num_unregistered_device_events.load(Ordering::Relaxed)
380    }
381
382    /// Updates or inserts metadata (such as device name and input ID) for a uinput device.
383    pub(crate) fn update_uinput_device(
384        &self,
385        device_id: DeviceId,
386        input_id: uapi::input_id,
387        name: String,
388    ) {
389        let mut device_infos = self.device_infos.lock();
390        if let Some(info) = device_infos.get(&device_id) {
391            *info.lock() = InputDeviceInfo { input_id, name };
392        } else {
393            device_infos.insert(device_id, InputDeviceInfo::new(input_id, name));
394        }
395    }
396
397    /// Adds a touch device to the relay.
398    ///
399    /// # Precondition / Lifecycle
400    /// Only call after [`InputEventsRelay::start_relays`].
401    #[cfg(test)]
402    pub fn add_touch_device(
403        &self,
404        device_id: DeviceId,
405        open_files: OpenedFiles,
406        inspect_status: Option<Arc<InputDeviceStatus>>,
407    ) {
408        let (sender, receiver) = oneshot::channel();
409        let _ = self.sender.unbounded_send(DeviceStateChange::Add(
410            device_id,
411            Box::new(DeviceState::new_touch(device_id, open_files, inspect_status)),
412            sender,
413        ));
414        let _ = block_on(receiver);
415    }
416
417    /// Adds a keyboard device to the relay.
418    ///
419    /// # Precondition / Lifecycle
420    /// Only call after [`InputEventsRelay::start_relays`].
421    #[cfg(test)]
422    pub fn add_keyboard_device(
423        &self,
424        device_id: DeviceId,
425        open_files: OpenedFiles,
426        inspect_status: Option<Arc<InputDeviceStatus>>,
427    ) {
428        let (sender, receiver) = oneshot::channel();
429        let _ = self.sender.unbounded_send(DeviceStateChange::Add(
430            device_id,
431            Box::new(DeviceState::new_keyboard(device_id, open_files, inspect_status)),
432            sender,
433        ));
434        let _ = block_on(receiver);
435    }
436}
437
438pub struct InputEventsRelay {
439    devices: SortedVecMap<DeviceId, DeviceState>,
440    #[cfg(test)]
441    receiver: Option<UnboundedReceiver<DeviceStateChange>>,
442    num_unregistered_device_events: Arc<AtomicU64>,
443    /// Number of devices currently tracked by the relay, exposed via inspect.
444    num_devices: Arc<AtomicU64>,
445    device_listener_registered: Arc<AtomicU8>,
446    _inspect_node: Option<fuchsia_inspect::Node>,
447    device_infos:
448        Arc<LockDepMutex<SortedVecMap<DeviceId, InputDeviceInfoHandle>, InputRelayDeviceInfosLock>>,
449    display_size: Arc<LockDepMutex<Option<(i32, i32)>, InputRelayDisplaySizeLock>>,
450}
451
452impl InputEventsRelay {
453    /// Updates the inspect-visible device count. Must be called after every mutation of
454    /// `self.devices` once the relay has started.
455    fn update_num_devices(&self) {
456        self.num_devices.store(self.devices.len() as u64, Ordering::Relaxed);
457    }
458
459    /// Adds a touch device to the relay prior to starting the relay loop.
460    #[cfg(test)]
461    pub fn add_touch_device(
462        &mut self,
463        device_id: DeviceId,
464        open_files: OpenedFiles,
465        inspect_status: Option<Arc<InputDeviceStatus>>,
466    ) {
467        self.devices
468            .insert(device_id, DeviceState::new_touch(device_id, open_files, inspect_status));
469        self.update_num_devices();
470    }
471
472    /// Adds a keyboard device to the relay prior to starting the relay loop.
473    #[cfg(test)]
474    pub fn add_keyboard_device(
475        &mut self,
476        device_id: DeviceId,
477        open_files: OpenedFiles,
478        inspect_status: Option<Arc<InputDeviceStatus>>,
479    ) {
480        self.devices
481            .insert(device_id, DeviceState::new_keyboard(device_id, open_files, inspect_status));
482        self.update_num_devices();
483    }
484
485    /// Adds a mouse device to the relay prior to starting the relay loop.
486    pub fn add_mouse_device(
487        &mut self,
488        device_id: DeviceId,
489        open_files: OpenedFiles,
490        inspect_status: Option<Arc<InputDeviceStatus>>,
491    ) {
492        self.devices
493            .insert(device_id, DeviceState::new_mouse(device_id, open_files, inspect_status));
494        self.update_num_devices();
495    }
496
497    /// Adds a pending mouse device to the relay prior to starting the relay loop.
498    pub fn add_pending_mouse_device(
499        &mut self,
500        kernel: Arc<Kernel>,
501        device: crate::InputDevice,
502        device_id: DeviceId,
503    ) {
504        self.devices.insert(device_id, DeviceState::new_pending_mouse(kernel, device, device_id));
505        self.update_num_devices();
506    }
507
508    fn record_inspect(&mut self, parent: &fuchsia_inspect::Node) {
509        let inspect_node = parent.create_child("input_events_relay");
510        let unregistered_counter = self.num_unregistered_device_events.clone();
511        let num_devices = self.num_devices.clone();
512        let device_listener_registered = self.device_listener_registered.clone();
513        // `record_lazy_values` records an inline lazy node (LinkNodeDisposition::Inline),
514        // exposing properties directly on `inspect_node` (input_events_relay).
515        inspect_node.record_lazy_values("status", move || {
516            let count = unregistered_counter.load(Ordering::Relaxed);
517            let num_devices = num_devices.load(Ordering::Relaxed);
518            let registration_state = device_listener_registered.load(Ordering::Relaxed);
519            async move {
520                let inspector = fuchsia_inspect::Inspector::default();
521                inspector.root().record_uint("num_unregistered_device_events", count);
522                inspector.root().record_uint("num_devices", num_devices);
523                match registration_state {
524                    DEVICE_LISTENER_REGISTERED => {
525                        inspector.root().record_bool("device_listener_registered", true);
526                    }
527                    DEVICE_LISTENER_DISCONNECTED => {
528                        inspector.root().record_bool("device_listener_registered", false);
529                    }
530                    _ => {}
531                }
532                Ok(inspector)
533            }
534            .boxed()
535        });
536        self._inspect_node = Some(inspect_node);
537    }
538
539    #[cfg(test)]
540    pub fn with_inspect_node(mut self, parent: &fuchsia_inspect::Node) -> Self {
541        self.record_inspect(parent);
542        self
543    }
544
545    // TODO(https://fxbug.dev/371602479): Use `fuchsia.ui.SupportedInputDevices` to create
546    // relays.
547    // start_relays will take over the ownership of InputEventsRelay.
548    pub fn start_relays(mut self: Self, kernel: &Kernel, args: StartRelaysArgs) {
549        if self._inspect_node.is_none() {
550            self.record_inspect(&kernel.inspect_node);
551        }
552        self.update_num_devices();
553
554        let display_width = args.display_width;
555        let display_height = args.display_height;
556        let event_proxy_mode = args.event_proxy_mode;
557        #[cfg(test)]
558        let mut receiver = self.receiver.take().expect("start_relays called once");
559        *self.display_size.lock() = if display_width > 0 && display_height > 0 {
560            Some((display_width, display_height))
561        } else {
562            None
563        };
564        let f = async move |current_task: &CurrentTask| {
565            let kernel = current_task.kernel();
566            // touch
567            let (touch_source_proxy, mut touch_waking_stream) =
568                setup_touch_relay(kernel, event_proxy_mode, args.touch_source_client_end);
569
570            // mouse
571            let (mouse_source_proxy, mut mouse_waking_stream) =
572                setup_mouse_relay(kernel, event_proxy_mode, args.mouse_source_client_end);
573
574            // keyboard
575            // `_keyboard_proxy` is load-bearing despite being unused: it holds the channel to
576            // text_manager open for the lifetime of the relay loop below. Dropping it closes
577            // the channel, which deregisters our `KeyboardListener` and silently stops all
578            // key delivery. Do not remove it as an unused binding.
579            let (mut keyboard_event_stream, _keyboard_proxy) =
580                setup_keyboard_relay(args.keyboard_proxy, args.view_ref);
581
582            // button
583            let (mut media_buttons_waking_stream, mut touch_buttons_waking_stream) =
584                setup_button_relay(kernel, args.registry_proxy, event_proxy_mode);
585
586            let (mut device_listener_stream, existing_devices_iterator) =
587                if let Some(registry) = args.device_listener_registry {
588                    let (client_end, server_end) =
589                        fidl::endpoints::create_endpoints::<fuiinput::DeviceListenerMarker>();
590                    let stream = setup_device_listener_relay(kernel, server_end, event_proxy_mode);
591                    match registry.register_listener(client_end, zx::MonotonicInstant::INFINITE) {
592                        Ok(iterator) => {
593                            self.device_listener_registered
594                                .store(DEVICE_LISTENER_REGISTERED, Ordering::Relaxed);
595                            (Some(stream), Some(iterator))
596                        }
597                        Err(e) => {
598                            log_error!("Failed to register device listener: {:?}", e);
599                            self.device_listener_registered
600                                .store(DEVICE_LISTENER_DISCONNECTED, Ordering::Relaxed);
601                            drop(stream);
602                            (None, None)
603                        }
604                    }
605                } else {
606                    self.device_listener_registered
607                        .store(DEVICE_LISTENER_DISCONNECTED, Ordering::Relaxed);
608                    (None, None)
609                };
610
611            if let Some(iterator) = existing_devices_iterator {
612                let iterator_proxy = iterator.into_proxy();
613                loop {
614                    match iterator_proxy.get_next().await {
615                        Ok(devices) => {
616                            if devices.is_empty() {
617                                log_debug!("Finished getting existing devices (empty batch)");
618                                break;
619                            }
620                            for device in devices {
621                                match device.action {
622                                    Some(fuiinput::Action::Added) => {
623                                        let (Some(device_id), Some(descriptor)) =
624                                            (device.device_id, device.descriptor)
625                                        else {
626                                            log_warn!(
627                                                "DeviceEvent in existing devices iterator missing device_id or descriptor"
628                                            );
629                                            continue;
630                                        };
631                                        if let Err(e) = register_and_add_device(
632                                            current_task,
633                                            &mut self,
634                                            device_id,
635                                            descriptor,
636                                            display_width,
637                                            display_height,
638                                        ) {
639                                            log_warn!(
640                                                "Failed to register existing device {}: {:?}",
641                                                device_id,
642                                                e
643                                            );
644                                        }
645                                    }
646                                    other => {
647                                        log_warn!(
648                                            "Unexpected action in existing devices iterator: {:?}",
649                                            other
650                                        );
651                                    }
652                                }
653                            }
654                        }
655                        Err(e) => {
656                            log_warn!("Error getting existing devices: {:?}", e);
657                            break;
658                        }
659                    }
660                }
661            }
662
663            let mut touch_future = touch_waking_stream.next().fuse();
664            let mut mouse_future = mouse_waking_stream.next().fuse();
665            let mut keyboard_future = keyboard_event_stream.next().fuse();
666            let mut media_buttons_future = media_buttons_waking_stream.next().fuse();
667            let mut touch_buttons_future = touch_buttons_waking_stream.next().fuse();
668            #[cfg(test)]
669            let mut receiver_future = receiver.next().fuse();
670            #[cfg(not(test))]
671            let mut receiver_future =
672                futures::future::Fuse::<futures::future::Pending<()>>::terminated();
673            let mut device_listener_future = futures::future::OptionFuture::from(
674                device_listener_stream.as_mut().map(|s| s.next()),
675            );
676
677            let mut power_was_pressed = false;
678            let mut function_was_pressed = false;
679            let mut volume_up_was_pressed = false;
680            let mut volume_down_was_pressed = false;
681            let mut touch_buttons_were_pressed = new_touch_buttons_bitvec();
682
683            loop {
684                futures::select! {
685                    touch_res = touch_future => {
686                        match touch_res {
687                            Some(Ok(fuipointer::TouchSourceV2Event::OnTouchEvents {
688                                events,
689                                last_event_stamp,
690                            })) => {
691                                self.process_touch_event(
692                                    events,
693                                );
694                                if let Err(e) = touch_source_proxy.acknowledge_events(last_event_stamp) {
695                                    log_warn!("error acknowledging touch events: {:?}", e);
696                                }
697                                drop(touch_future);
698                                touch_future = touch_waking_stream.next().fuse();
699                            }
700                            Some(Ok(fuipointer::TouchSourceV2Event::_UnknownEvent { ordinal, .. })) => {
701                                log_warn!("unknown event on TouchSourceV2: {}", ordinal);
702                                drop(touch_future);
703                                touch_future = touch_waking_stream.next().fuse();
704                            }
705                            Some(Err(e)) => {
706                                log_warn!(
707                                    "error {:?} reading from TouchSourceV2Proxy; input is stopped",
708                                    e
709                                );
710                                touch_future = futures::future::Fuse::terminated();
711                            }
712                            None => {
713                                touch_future = futures::future::Fuse::terminated();
714                            }
715                        }
716                    }
717                    mouse_res = mouse_future => {
718                        match mouse_res {
719                            Some(Ok(fuipointer::MouseSourceV2Event::OnMouseEvents {
720                                events,
721                                last_event_stamp,
722                            })) => {
723                                self.process_mouse_event(events);
724                                if let Err(e) = mouse_source_proxy.acknowledge_events(last_event_stamp) {
725                                    log_warn!("error acknowledging mouse events: {:?}", e);
726                                }
727                                drop(mouse_future);
728                                mouse_future = mouse_waking_stream.next().fuse();
729                            }
730                            Some(Ok(fuipointer::MouseSourceV2Event::_UnknownEvent { ordinal, .. })) => {
731                                log_warn!("unknown event on MouseSourceV2: {}", ordinal);
732                                drop(mouse_future);
733                                mouse_future = mouse_waking_stream.next().fuse();
734                            }
735                            Some(Err(e)) => {
736                                log_warn!(
737                                    "error {:?} reading from MouseSourceV2Proxy; input is stopped",
738                                    e
739                                );
740                                mouse_future = futures::future::Fuse::terminated();
741                            }
742                            None => {
743                                mouse_future = futures::future::Fuse::terminated();
744                            }
745                        }
746                    }
747                    media_buttons_res = media_buttons_future => {
748                        match media_buttons_res {
749                            Some(Ok(event)) => {
750                                (
751                                    power_was_pressed,
752                                    function_was_pressed,
753                                    volume_up_was_pressed,
754                                    volume_down_was_pressed,
755                                ) = self.process_media_button_event(
756                                    event,
757                                    power_was_pressed,
758                                    function_was_pressed,
759                                    volume_up_was_pressed,
760                                    volume_down_was_pressed,
761                                );
762                                drop(media_buttons_future);
763                                media_buttons_future = media_buttons_waking_stream.next().fuse();
764                            }
765                            _ => {
766                                media_buttons_future = futures::future::Fuse::terminated();
767                            }
768                        }
769                    }
770                    touch_buttons_res = touch_buttons_future => {
771                        match touch_buttons_res {
772                            Some(Ok(event)) => {
773                                touch_buttons_were_pressed = self.process_touch_button_event(
774                                    event,
775                                    &touch_buttons_were_pressed,
776                                );
777                                drop(touch_buttons_future);
778                                touch_buttons_future = touch_buttons_waking_stream.next().fuse();
779                            }
780                            _ => {
781                                touch_buttons_future = futures::future::Fuse::terminated();
782                            }
783                        }
784                    }
785                    device_listener_res = device_listener_future => {
786                        match device_listener_res {
787                            Some(Some(Ok(request))) => {
788                                self.process_device_listener_request(
789                                    current_task,
790                                    request,
791                                    display_width,
792                                    display_height,
793                                );
794                                device_listener_future = futures::future::OptionFuture::from(
795                                    device_listener_stream.as_mut().map(|s| s.next()),
796                                );
797                            }
798                            Some(Some(Err(e))) => {
799                                log_warn!("DeviceListener stream error: {:?}", e);
800                                self.device_listener_registered
801                                    .store(DEVICE_LISTENER_DISCONNECTED, Ordering::Relaxed);
802                                device_listener_stream = None;
803                                device_listener_future = futures::future::OptionFuture::from(None);
804                            }
805                            Some(None) => {
806                                log_warn!("DeviceListener stream closed by peer");
807                                self.device_listener_registered
808                                    .store(DEVICE_LISTENER_DISCONNECTED, Ordering::Relaxed);
809                                device_listener_stream = None;
810                                device_listener_future = futures::future::OptionFuture::from(None);
811                            }
812                            None => {
813                                self.device_listener_registered
814                                    .store(DEVICE_LISTENER_DISCONNECTED, Ordering::Relaxed);
815                                device_listener_stream = None;
816                                device_listener_future = futures::future::OptionFuture::from(None);
817                            }
818                        }
819                    }
820                    keyboard_res = keyboard_future => {
821                        match keyboard_res {
822                            Some(Ok(request)) => {
823                                self.process_keyboard(request);
824                                drop(keyboard_future);
825                                keyboard_future = keyboard_event_stream.next().fuse();
826                            }
827                            _ => {
828                                keyboard_future = futures::future::Fuse::terminated();
829                            }
830                        }
831                    }
832                    e = receiver_future => {
833                        #[cfg(test)]
834                        match e {
835                            Some(event) => {
836                                match event {
837                                    DeviceStateChange::Add(id, device_state, sender) => {
838                                        self.devices.insert(id, *device_state);
839                                        self.update_num_devices();
840                                        let _ = sender.send(());
841                                    }
842                                }
843                                drop(receiver_future);
844                                receiver_future = receiver.next().fuse();
845                            }
846                            None => {
847                                receiver_future = futures::future::Fuse::terminated();
848                            }
849                        }
850                        #[cfg(not(test))]
851                        let _ = e;
852                    }
853                    complete => break,
854                }
855            }
856        };
857        let req = SpawnRequestBuilder::new()
858            .with_debug_name("input-event-relay")
859            .with_role(INPUT_RELAY_ROLE_NAME)
860            .with_async_closure(f)
861            .build();
862        kernel.kthreads.spawner().spawn_from_request(req);
863    }
864
865    fn get_device_mut(
866        &mut self,
867        device_id: Option<DeviceId>,
868        default_id: DeviceId,
869        predicate: impl Fn(&InputDeviceType) -> bool,
870    ) -> Option<&mut DeviceState> {
871        let target_device_id = device_id
872            .filter(|id| self.devices.get(id).is_some_and(|d| predicate(&d.device_type)))
873            .unwrap_or(default_id);
874        self.devices.get_mut(&target_device_id).filter(|d| predicate(&d.device_type))
875    }
876
877    fn process_touch_event(self: &mut Self, touch_events: Vec<FidlTouchEvent>) {
878        fuchsia_trace::duration!("input", "starnix_process_touch_event");
879        for e in &touch_events {
880            match e.trace_flow_id {
881                Some(trace_flow_id) => {
882                    fuchsia_trace::flow_end!(
883                        "input",
884                        "dispatch_event_to_client",
885                        trace_flow_id.into()
886                    );
887                }
888                None => {
889                    log_warn!("touch event has no tracing id");
890                }
891            }
892        }
893        let num_received_events: u64 = touch_events.len().try_into().unwrap();
894
895        let mut num_ignored_events: u64 = 0;
896
897        // 1 vec may contains events from different device.
898        let (events_by_device, ignored_events) = group_touch_events_by_device_id(touch_events);
899        num_ignored_events += ignored_events;
900
901        for (device_id, mut events) in events_by_device {
902            fuchsia_trace::duration_begin!("input", "starnix_process_per_device_touch_event");
903
904            // TODO(https://fxbug.dev/502662433): Default devices are no longer needed because
905            // existing devices are enumerated via the DeviceIterator before start_relays().
906            // Remove them in a follow-up change.
907            let Some(dev) = self.get_device_mut(Some(device_id), DEFAULT_TOUCH_DEVICE_ID, |t| {
908                matches!(t, InputDeviceType::Touch(_))
909            }) else {
910                fuchsia_trace::duration_end!("input", "starnix_process_per_device_touch_event");
911                log_warn!(
912                    "Received touch event for unregistered device {} and default touch device is missing",
913                    device_id
914                );
915                self.num_unregistered_device_events
916                    .fetch_add(events.len() as u64, Ordering::Relaxed);
917                continue;
918            };
919
920            let mut num_converted_events: u64 = 0;
921            let mut num_unexpected_events: u64 = 0;
922            let mut new_events: VecDeque<uapi::input_event> = VecDeque::new();
923
924            #[allow(clippy::collection_is_never_read)]
925            let mut tracked_leases = vec![];
926            for event in &mut events {
927                if let Some(lease) = event.wake_lease.take() {
928                    if let Some(status) = &dev.inspect_status {
929                        tracked_leases.push(TrackedWakeLease::new(lease, status.clone()));
930                    }
931                }
932            }
933
934            let InputDeviceType::Touch(ref mut converter) = dev.device_type else { unreachable!() };
935            let mut batch = converter.handle(events);
936            new_events.append(&mut batch.events);
937            num_converted_events += batch.count_converted_fidl_events;
938            num_ignored_events += batch.count_ignored_fidl_events;
939            num_unexpected_events += batch.count_unexpected_fidl_events;
940            let last_event_time_ns = batch.last_event_time_ns;
941
942            if let Some(dev_inspect_status) = &dev.inspect_status {
943                dev_inspect_status.count_total_received_events(num_received_events);
944                dev_inspect_status.count_total_ignored_events(num_ignored_events);
945                dev_inspect_status.count_total_unexpected_events(num_unexpected_events);
946                dev_inspect_status.count_total_converted_events(num_converted_events);
947                dev_inspect_status.count_total_generated_events(
948                    new_events.len().try_into().unwrap(),
949                    last_event_time_ns,
950                );
951            } else {
952                log_warn!(
953                    "unable to record inspect for device_id: {}, device_type: {}",
954                    device_id,
955                    dev.device_type
956                );
957            }
958
959            fuchsia_trace::duration_end!("input", "starnix_process_per_device_touch_event");
960            dev.open_files.lock().retain(|f| {
961                let Some(file) = f.upgrade() else {
962                    log_warn!("Dropping input file for touch that failed to upgrade");
963                    return false;
964                };
965                match &file.inspect_status {
966                    Some(file_inspect_status) => {
967                        file_inspect_status.count_received_events(num_received_events);
968                        file_inspect_status.count_ignored_events(num_ignored_events);
969                        file_inspect_status.count_unexpected_events(num_unexpected_events);
970                        file_inspect_status.count_converted_events(num_converted_events);
971                    }
972                    None => {
973                        log_warn!("unable to record inspect within the input file")
974                    }
975                }
976                if !new_events.is_empty() {
977                    // TODO(https://fxbug.dev/42075438): Reading from an `InputFile` should
978                    // not provide access to events that occurred before the file was
979                    // opened.
980                    if let Some(file_inspect_status) = &file.inspect_status {
981                        file_inspect_status.count_generated_events(
982                            new_events.len().try_into().unwrap(),
983                            last_event_time_ns,
984                        );
985                    }
986                    file.add_events(new_events.clone().into_iter().collect());
987                }
988
989                true
990            });
991        }
992    }
993
994    fn process_keyboard(self: &mut Self, request: KeyboardListenerRequest) {
995        match request {
996            KeyboardListenerRequest::OnKeyEvent { event, responder } => {
997                fuchsia_trace::duration!("input", "starnix_process_keyboard_event");
998
999                let Some(dev) =
1000                    self.get_device_mut(event.device_id, DEFAULT_KEYBOARD_DEVICE_ID, |t| {
1001                        matches!(t, InputDeviceType::Keyboard)
1002                    })
1003                else {
1004                    log_warn!(
1005                        "Received key event for device {:?} but neither it nor default keyboard device is registered",
1006                        event.device_id
1007                    );
1008                    self.num_unregistered_device_events.fetch_add(1, Ordering::Relaxed);
1009                    let _ = responder.send(KeyEventStatus::NotHandled);
1010                    return;
1011                };
1012
1013                let new_events = parse_fidl_keyboard_event_to_linux_input_event(
1014                    &event,
1015                    uinput::uinput_running(),
1016                );
1017
1018                // These counters are denominated in FIDL events, not uapi events: the
1019                // documented invariant is received = ignored + unexpected + converted (see
1020                // `InputDeviceStatus`). One FIDL key event converts to several uapi events
1021                // (the key itself plus a SYN), so only the *generated* counters take
1022                // `new_events.len()`.
1023                let (converted_events, ignored_events, generated_events) = match new_events.len() {
1024                    0 => (0u64, 1u64, 0u64),
1025                    len => (1u64, 0u64, len as u64),
1026                };
1027                let last_time = event.timestamp.unwrap_or(0);
1028
1029                if let Some(dev_inspect_status) = &dev.inspect_status {
1030                    dev_inspect_status.count_total_received_events(1);
1031                    dev_inspect_status.count_total_ignored_events(ignored_events);
1032                    dev_inspect_status.count_total_converted_events(converted_events);
1033                    // Guarded because `count_total_generated_events` *stores* the timestamp:
1034                    // calling it with a count of 0 would move
1035                    // `last_generated_uapi_event_timestamp_ns` on an event that generated
1036                    // nothing.
1037                    if generated_events > 0 {
1038                        dev_inspect_status
1039                            .count_total_generated_events(generated_events, last_time);
1040                    }
1041                } else {
1042                    log_warn!("unable to record inspect for keyboard device");
1043                }
1044
1045                dev.open_files.lock().retain(|f| {
1046                    let Some(file) = f.upgrade() else {
1047                        log_warn!("Dropping input file for keyboard that failed to upgrade");
1048                        return false;
1049                    };
1050                    match &file.inspect_status {
1051                        Some(file_inspect_status) => {
1052                            file_inspect_status.count_received_events(1);
1053                            file_inspect_status.count_ignored_events(ignored_events);
1054                            file_inspect_status.count_converted_events(converted_events);
1055                            if generated_events > 0 {
1056                                file_inspect_status
1057                                    .count_generated_events(generated_events, last_time);
1058                            }
1059                        }
1060                        None => {
1061                            log_warn!("unable to record inspect within the input file")
1062                        }
1063                    }
1064                    if !new_events.is_empty() {
1065                        file.add_events(new_events.clone().into_iter().collect());
1066                    }
1067
1068                    true
1069                });
1070
1071                let _ = responder.send(KeyEventStatus::Handled);
1072            }
1073        }
1074    }
1075
1076    fn process_device_listener_request(
1077        &mut self,
1078        current_task: &CurrentTask,
1079        request: fuiinput::DeviceListenerRequest,
1080        display_width: i32,
1081        display_height: i32,
1082    ) {
1083        match request {
1084            fuiinput::DeviceListenerRequest::OnDeviceChanged { event, control_handle: _ } => {
1085                let action = match event.action {
1086                    Some(fuiinput::Action::Added) => "add",
1087                    Some(fuiinput::Action::Removed) => "remove",
1088                    _ => "unknown",
1089                };
1090                fuchsia_trace::duration!(
1091                    "input",
1092                    "starnix_process_device_changed",
1093                    "action" => action
1094                );
1095                match event.action {
1096                    Some(fuiinput::Action::Added) => {
1097                        let (Some(device_id), Some(descriptor)) =
1098                            (event.device_id, event.descriptor)
1099                        else {
1100                            log_warn!("DeviceEvent missing device_id or descriptor");
1101                            return;
1102                        };
1103                        if let Err(e) = register_and_add_device(
1104                            current_task,
1105                            self,
1106                            device_id,
1107                            descriptor,
1108                            display_width,
1109                            display_height,
1110                        ) {
1111                            log_warn!("Failed to register dynamic device {}: {:?}", device_id, e);
1112                        }
1113                    }
1114                    Some(fuiinput::Action::Removed) => {
1115                        let Some(device_id) = event.device_id else {
1116                            log_warn!("DeviceEvent missing device_id");
1117                            return;
1118                        };
1119                        self.device_infos.lock().remove(&device_id);
1120                        if let Some(device_state) = self.devices.remove(&device_id) {
1121                            self.update_num_devices();
1122                            if let Some(starnix_device) = device_state.starnix_device {
1123                                InputDevice::unregister(current_task, starnix_device);
1124                            }
1125                        }
1126                    }
1127                    action => {
1128                        log_warn!("Unexpected action in DeviceListener event: {:?}", action);
1129                    }
1130                }
1131            }
1132        }
1133    }
1134
1135    fn process_media_button_event(
1136        &mut self,
1137        button_event: fuipolicy::MediaButtonsListenerRequest,
1138        power_was_pressed: bool,
1139        function_was_pressed: bool,
1140        volume_up_was_pressed: bool,
1141        volume_down_was_pressed: bool,
1142    ) -> (bool, bool, bool, bool) {
1143        let mut power_was_pressed_after = power_was_pressed;
1144        let mut function_was_pressed_after = function_was_pressed;
1145        let mut volume_up_was_pressed_after = volume_up_was_pressed;
1146        let mut volume_down_was_pressed_after = volume_down_was_pressed;
1147        match button_event {
1148            fuipolicy::MediaButtonsListenerRequest::OnEvent { mut event, responder } => {
1149                if let Some(trace_flow_id) = event.trace_flow_id {
1150                    fuchsia_trace::flow_end!(
1151                        "input",
1152                        "dispatch_media_buttons_to_listeners",
1153                        trace_flow_id.into()
1154                    );
1155                }
1156                fuchsia_trace::duration!("input", "starnix_process_media_button_event");
1157
1158                let Some(dev) =
1159                    self.get_device_mut(event.device_id, DEFAULT_KEYBOARD_DEVICE_ID, |t| {
1160                        matches!(t, InputDeviceType::Keyboard)
1161                    })
1162                else {
1163                    log_warn!(
1164                        "Received media button event for device {:?} but neither it nor default keyboard device is registered",
1165                        event.device_id
1166                    );
1167                    self.num_unregistered_device_events.fetch_add(1, Ordering::Relaxed);
1168                    let _ = responder.send();
1169                    return (
1170                        power_was_pressed,
1171                        function_was_pressed,
1172                        volume_up_was_pressed,
1173                        volume_down_was_pressed,
1174                    );
1175                };
1176
1177                let batch = parse_fidl_media_button_event(
1178                    &event,
1179                    power_was_pressed,
1180                    function_was_pressed,
1181                    volume_up_was_pressed,
1182                    volume_down_was_pressed,
1183                );
1184
1185                power_was_pressed_after = batch.power_is_pressed;
1186                function_was_pressed_after = batch.function_is_pressed;
1187                volume_up_was_pressed_after = batch.volume_up_is_pressed;
1188                volume_down_was_pressed_after = batch.volume_down_is_pressed;
1189
1190                let (converted_events, ignored_events, generated_events) = match batch.events.len()
1191                {
1192                    0 => (0u64, 1u64, 0u64),
1193                    len => {
1194                        if len % 2 == 1 {
1195                            log_warn!(
1196                                "unexpectedly received {} events: there should always be an even number of non-empty events.",
1197                                len
1198                            );
1199                        }
1200                        (1u64, 0u64, len as u64)
1201                    }
1202                };
1203
1204                #[allow(clippy::collection_is_never_read)]
1205                let mut tracked_leases = vec![];
1206                if let Some(lease) = event.wake_lease.take() {
1207                    if let Some(status) = &dev.inspect_status {
1208                        tracked_leases.push(TrackedWakeLease::new(lease, status.clone()));
1209                    }
1210                }
1211
1212                if let Some(dev_inspect_status) = &dev.inspect_status {
1213                    dev_inspect_status.count_total_received_events(1);
1214                    dev_inspect_status.count_total_ignored_events(ignored_events);
1215                    dev_inspect_status.count_total_converted_events(converted_events);
1216                    dev_inspect_status.count_total_generated_events(
1217                        generated_events,
1218                        batch.event_time.into_nanos().try_into().unwrap(),
1219                    );
1220                } else {
1221                    log_warn!("unable to record inspect for button device");
1222                }
1223
1224                dev.open_files.lock().retain(|f| {
1225                    let Some(file) = f.upgrade() else {
1226                        log_warn!("Dropping input file for buttons that failed to upgrade");
1227                        return false;
1228                    };
1229                    match &file.inspect_status {
1230                        Some(file_inspect_status) => {
1231                            file_inspect_status.count_received_events(1);
1232                            file_inspect_status.count_ignored_events(ignored_events);
1233                            file_inspect_status.count_converted_events(converted_events);
1234                        }
1235                        None => {
1236                            log_warn!("unable to record inspect within the input file")
1237                        }
1238                    }
1239                    if !batch.events.is_empty() {
1240                        if let Some(file_inspect_status) = &file.inspect_status {
1241                            file_inspect_status.count_generated_events(
1242                                generated_events,
1243                                batch.event_time.into_nanos().try_into().unwrap(),
1244                            );
1245                        }
1246                        file.add_events(batch.events.clone());
1247                    }
1248
1249                    true
1250                });
1251
1252                let _ = responder.send();
1253            }
1254            _ => { /* Ignore deprecated OnMediaButtonsEvent */ }
1255        }
1256
1257        (
1258            power_was_pressed_after,
1259            function_was_pressed_after,
1260            volume_up_was_pressed_after,
1261            volume_down_was_pressed_after,
1262        )
1263    }
1264
1265    fn process_touch_button_event(
1266        &mut self,
1267        button_event: fuipolicy::TouchButtonsListenerRequest,
1268        touch_buttons_were_pressed: &bit_vec::BitVec,
1269    ) -> bit_vec::BitVec {
1270        fuchsia_trace::duration!("input", "starnix_process_touch_button_event");
1271        match button_event {
1272            fuipolicy::TouchButtonsListenerRequest::OnEvent { mut event, responder } => {
1273                if let Some(trace_flow_id) = event.trace_flow_id {
1274                    fuchsia_trace::flow_end!(
1275                        "input",
1276                        "dispatch_touch_button_to_listeners",
1277                        trace_flow_id.into()
1278                    );
1279                }
1280                let device_id = match &event.device_info {
1281                    Some(TouchDeviceInfo { id: Some(id), .. }) => Some(*id),
1282                    _ => None,
1283                };
1284
1285                let Some(dev) = self.get_device_mut(device_id, DEFAULT_TOUCH_DEVICE_ID, |t| {
1286                    matches!(t, InputDeviceType::Touch(_))
1287                }) else {
1288                    log_warn!(
1289                        "Received touch button event for device {:?} but neither it nor default touch device is registered",
1290                        device_id
1291                    );
1292                    self.num_unregistered_device_events.fetch_add(1, Ordering::Relaxed);
1293                    let _ = responder.send();
1294                    return touch_buttons_were_pressed.clone();
1295                };
1296
1297                let batch = parse_fidl_touch_button_event(&event, touch_buttons_were_pressed);
1298
1299                let (converted_events, ignored_events, generated_events) = match batch.events.len()
1300                {
1301                    0 => (0u64, 1u64, 0u64),
1302                    len => {
1303                        if len % 2 == 1 {
1304                            log_warn!(
1305                                "unexpectedly received {} events: there should always be an even number of non-empty events.",
1306                                len
1307                            );
1308                        }
1309                        (1u64, 0u64, len as u64)
1310                    }
1311                };
1312
1313                #[allow(clippy::collection_is_never_read)]
1314                let mut tracked_leases = vec![];
1315                if let Some(lease) = event.wake_lease.take() {
1316                    if let Some(status) = &dev.inspect_status {
1317                        tracked_leases.push(TrackedWakeLease::new(lease, status.clone()));
1318                    }
1319                }
1320
1321                if let Some(dev_inspect_status) = &dev.inspect_status {
1322                    dev_inspect_status.count_total_received_events(1);
1323                    dev_inspect_status.count_total_ignored_events(ignored_events);
1324                    dev_inspect_status.count_total_converted_events(converted_events);
1325                    dev_inspect_status.count_total_generated_events(
1326                        generated_events,
1327                        batch.event_time.into_nanos().try_into().unwrap(),
1328                    );
1329                } else {
1330                    log_warn!("unable to record inspect for touch device");
1331                }
1332
1333                dev.open_files.lock().retain(|f| {
1334                    let Some(file) = f.upgrade() else {
1335                        log_warn!("Dropping input file for touch that failed to upgrade");
1336                        return false;
1337                    };
1338                    match &file.inspect_status {
1339                        Some(file_inspect_status) => {
1340                            file_inspect_status.count_received_events(1);
1341                            file_inspect_status.count_ignored_events(ignored_events);
1342                            file_inspect_status.count_converted_events(converted_events);
1343                        }
1344                        None => {
1345                            log_warn!("unable to record inspect within the input file")
1346                        }
1347                    }
1348                    if !batch.events.is_empty() {
1349                        if let Some(file_inspect_status) = &file.inspect_status {
1350                            file_inspect_status.count_generated_events(
1351                                generated_events,
1352                                batch.event_time.into_nanos().try_into().unwrap(),
1353                            );
1354                        }
1355                        file.add_events(batch.events.clone());
1356                    }
1357
1358                    true
1359                });
1360
1361                let _ = responder.send();
1362
1363                batch.touch_buttons
1364            }
1365            fuipolicy::TouchButtonsListenerRequest::_UnknownMethod { ordinal, .. } => {
1366                log_warn!("Received an unknown method with ordinal {ordinal}");
1367                touch_buttons_were_pressed.clone()
1368            }
1369        }
1370    }
1371
1372    fn process_mouse_event(self: &mut Self, mouse_events: Vec<FidlMouseEvent>) {
1373        fuchsia_trace::duration!("input", "starnix_process_mouse_event");
1374        for e in &mouse_events {
1375            if let Some(trace_flow_id) = e.trace_flow_id {
1376                fuchsia_trace::flow_end!("input", "dispatch_event_to_client", trace_flow_id.into());
1377            }
1378        }
1379        // TODO(https://fxbug.dev/563345995): `num_received_events` counts the whole
1380        // batch and `num_ignored_events` accumulates across devices, yet both are
1381        // recorded against every device in the loop below. With more than one mouse
1382        // device in use simultaneously these counters over-report and violate the
1383        // inspect invariants. Scope them per device before multi-mouse is supported.
1384        let num_received_events: u64 = mouse_events.len().try_into().unwrap();
1385        let mut num_ignored_events: u64 = 0;
1386
1387        let (events_by_device, ignored_events) = group_mouse_events_by_device_id(mouse_events);
1388        num_ignored_events += ignored_events;
1389
1390        for (device_id, mut events) in events_by_device {
1391            fuchsia_trace::duration_begin!("input", "starnix_process_per_device_mouse_event");
1392
1393            let Some(dev) = self.get_device_mut(Some(device_id), DEFAULT_MOUSE_DEVICE_ID, |t| {
1394                matches!(t, InputDeviceType::Mouse(_))
1395            }) else {
1396                fuchsia_trace::duration_end!("input", "starnix_process_per_device_mouse_event");
1397                log_warn!(
1398                    "Received mouse event for unregistered device {} and default mouse device is missing",
1399                    device_id
1400                );
1401                self.num_unregistered_device_events
1402                    .fetch_add(events.len() as u64, Ordering::Relaxed);
1403                continue;
1404            };
1405
1406            let mut num_converted_events: u64 = 0;
1407            let mut num_unexpected_events: u64 = 0;
1408            let mut new_events: VecDeque<uapi::input_event> = VecDeque::new();
1409
1410            #[allow(clippy::collection_is_never_read)]
1411            let mut tracked_leases = vec![];
1412            for event in &mut events {
1413                if let Some(lease) = event.wake_lease.take() {
1414                    if let Some(status) = &dev.inspect_status {
1415                        tracked_leases.push(TrackedWakeLease::new(lease, status.clone()));
1416                    }
1417                }
1418            }
1419
1420            let InputDeviceType::Mouse(ref mut converter) = dev.device_type else { unreachable!() };
1421            let mut batch = converter.handle(events);
1422            new_events.append(&mut batch.events);
1423            num_converted_events += batch.count_converted_events;
1424            num_ignored_events += batch.count_ignored_events;
1425            num_unexpected_events += batch.count_unexpected_events;
1426            let last_event_time_ns = batch.last_event_time_ns;
1427
1428            if !new_events.is_empty() {
1429                dev.registration.ensure_registered();
1430            }
1431
1432            if let Some(dev_inspect_status) = &dev.inspect_status {
1433                dev_inspect_status.count_total_received_events(num_received_events);
1434                dev_inspect_status.count_total_ignored_events(num_ignored_events);
1435                dev_inspect_status.count_total_unexpected_events(num_unexpected_events);
1436                dev_inspect_status.count_total_converted_events(num_converted_events);
1437                if !new_events.is_empty() {
1438                    dev_inspect_status.count_total_generated_events(
1439                        new_events.len().try_into().unwrap(),
1440                        last_event_time_ns,
1441                    );
1442                }
1443            } else {
1444                log_warn!(
1445                    "unable to record inspect for device_id: {}, device_type: {}",
1446                    device_id,
1447                    dev.device_type
1448                );
1449            }
1450
1451            fuchsia_trace::duration_end!("input", "starnix_process_per_device_mouse_event");
1452            let mut open_files = dev.open_files.lock();
1453            if !open_files.has_been_opened && !new_events.is_empty() {
1454                open_files.buffered_events.extend(new_events.iter().copied());
1455            }
1456            open_files.retain(|f| {
1457                let Some(file) = f.upgrade() else {
1458                    log_warn!("Dropping input file for mouse that failed to upgrade");
1459                    return false;
1460                };
1461                if let Some(file_inspect_status) = &file.inspect_status {
1462                    file_inspect_status.count_received_events(num_received_events);
1463                    file_inspect_status.count_ignored_events(num_ignored_events);
1464                    file_inspect_status.count_unexpected_events(num_unexpected_events);
1465                    file_inspect_status.count_converted_events(num_converted_events);
1466                }
1467                if !new_events.is_empty() {
1468                    if let Some(file_inspect_status) = &file.inspect_status {
1469                        file_inspect_status.count_generated_events(
1470                            new_events.len().try_into().unwrap(),
1471                            last_event_time_ns,
1472                        );
1473                    }
1474                    file.add_events(new_events.clone().into_iter().collect());
1475                }
1476                true
1477            });
1478        }
1479    }
1480}
1481
1482fn setup_touch_relay(
1483    kernel: &Arc<Kernel>,
1484    event_proxy_mode: EventProxyMode,
1485    touch_source_client_end: ClientEnd<fuipointer::TouchSourceV2Marker>,
1486) -> (fuipointer::TouchSourceV2Proxy, ContainerWakingStream<fuipointer::TouchSourceV2EventStream>) {
1487    let touch_counter_name = "touch";
1488    let (touch_source_proxy, counter) = match event_proxy_mode {
1489        EventProxyMode::WakeContainer => {
1490            // Proxy the touch events through the Starnix runner. This allows touch events to
1491            // wake the container when it is suspended.
1492            let (touch_source_channel, counter) = create_proxy_for_wake_events_counter(
1493                touch_source_client_end.into_channel(),
1494                touch_counter_name.to_string(),
1495            );
1496            (
1497                fuipointer::TouchSourceV2Proxy::new(fidl::AsyncChannel::from_channel(
1498                    touch_source_channel,
1499                )),
1500                Some(counter),
1501            )
1502        }
1503        EventProxyMode::None => (touch_source_client_end.into_proxy(), None),
1504    };
1505    let waking_stream = ContainerWakingStream::new(
1506        kernel.suspend_resume_manager.add_message_counter(touch_counter_name, counter),
1507        touch_source_proxy.take_event_stream(),
1508    );
1509    (touch_source_proxy, waking_stream)
1510}
1511
1512fn setup_keyboard_relay(
1513    keyboard: KeyboardSynchronousProxy,
1514    view_ref: fuiviews::ViewRef,
1515) -> (KeyboardListenerRequestStream, KeyboardSynchronousProxy) {
1516    let (keyboard_listener, event_stream) =
1517        fidl::endpoints::create_request_stream::<KeyboardListenerMarker>();
1518    if let Err(e) =
1519        keyboard.add_listener(view_ref, keyboard_listener, zx::MonotonicInstant::INFINITE)
1520    {
1521        log_warn!("Could not register keyboard listener: {:?}", e);
1522    }
1523
1524    (event_stream, keyboard)
1525}
1526
1527fn setup_button_relay(
1528    kernel: &Arc<Kernel>,
1529    registry_proxy: fuipolicy::DeviceListenerRegistrySynchronousProxy,
1530    event_proxy_mode: EventProxyMode,
1531) -> (
1532    ContainerWakingStream<fuipolicy::MediaButtonsListenerRequestStream>,
1533    ContainerWakingStream<fuipolicy::TouchButtonsListenerRequestStream>,
1534) {
1535    let media_buttons_name = "media buttons";
1536    let touch_buttons_name = "touch buttons";
1537
1538    let (remote_media_button_client, remote_media_button_server) =
1539        fidl::endpoints::create_endpoints::<fuipolicy::MediaButtonsListenerMarker>();
1540    if let Err(e) =
1541        registry_proxy.register_listener(remote_media_button_client, zx::MonotonicInstant::INFINITE)
1542    {
1543        log_warn!("Failed to register media buttons listener: {:?}", e);
1544    }
1545
1546    let (remote_touch_button_client, remote_touch_button_server) =
1547        fidl::endpoints::create_endpoints::<fuipolicy::TouchButtonsListenerMarker>();
1548    if let Err(e) = registry_proxy
1549        .register_touch_buttons_listener(remote_touch_button_client, zx::MonotonicInstant::INFINITE)
1550    {
1551        log_warn!("Failed to register touch buttons listener: {:?}", e);
1552    }
1553
1554    let (
1555        local_media_buttons_listener_stream,
1556        media_buttons_counter,
1557        local_touch_buttons_listener_stream,
1558        touch_buttons_counter,
1559    ) = match event_proxy_mode {
1560        EventProxyMode::WakeContainer => {
1561            let (local_media_buttons_channel, media_buttons_counter) =
1562                create_proxy_for_wake_events_counter(
1563                    remote_media_button_server.into_channel(),
1564                    media_buttons_name.to_string(),
1565                );
1566            let local_media_buttons_listener_stream =
1567                fuipolicy::MediaButtonsListenerRequestStream::from_channel(
1568                    fidl::AsyncChannel::from_channel(local_media_buttons_channel),
1569                );
1570
1571            let (local_touch_buttons_channel, touch_buttons_counter) =
1572                create_proxy_for_wake_events_counter(
1573                    remote_touch_button_server.into_channel(),
1574                    touch_buttons_name.to_string(),
1575                );
1576            let local_touch_buttons_listener_stream =
1577                fuipolicy::TouchButtonsListenerRequestStream::from_channel(
1578                    fidl::AsyncChannel::from_channel(local_touch_buttons_channel),
1579                );
1580            (
1581                local_media_buttons_listener_stream,
1582                Some(media_buttons_counter),
1583                local_touch_buttons_listener_stream,
1584                Some(touch_buttons_counter),
1585            )
1586        }
1587        EventProxyMode::None => (
1588            remote_media_button_server.into_stream(),
1589            None,
1590            remote_touch_button_server.into_stream(),
1591            None,
1592        ),
1593    };
1594
1595    (
1596        ContainerWakingStream::new(
1597            kernel
1598                .suspend_resume_manager
1599                .add_message_counter(media_buttons_name, media_buttons_counter),
1600            local_media_buttons_listener_stream,
1601        ),
1602        ContainerWakingStream::new(
1603            kernel
1604                .suspend_resume_manager
1605                .add_message_counter(touch_buttons_name, touch_buttons_counter),
1606            local_touch_buttons_listener_stream,
1607        ),
1608    )
1609}
1610
1611fn setup_device_listener_relay(
1612    kernel: &Arc<Kernel>,
1613    device_listener_server: ServerEnd<fuiinput::DeviceListenerMarker>,
1614    event_proxy_mode: EventProxyMode,
1615) -> ContainerWakingStream<fuiinput::DeviceListenerRequestStream> {
1616    let device_listener_name = "device listener";
1617
1618    let (local_device_listener_stream, device_listener_counter) = match event_proxy_mode {
1619        EventProxyMode::WakeContainer => {
1620            let (local_device_listener_channel, device_listener_counter) =
1621                create_proxy_for_wake_events_counter(
1622                    device_listener_server.into_channel(),
1623                    device_listener_name.to_string(),
1624                );
1625            let local_device_listener_stream = fuiinput::DeviceListenerRequestStream::from_channel(
1626                fidl::AsyncChannel::from_channel(local_device_listener_channel),
1627            );
1628            (local_device_listener_stream, Some(device_listener_counter))
1629        }
1630        EventProxyMode::None => (device_listener_server.into_stream(), None),
1631    };
1632
1633    ContainerWakingStream::new(
1634        kernel
1635            .suspend_resume_manager
1636            .add_message_counter(device_listener_name, device_listener_counter),
1637        local_device_listener_stream,
1638    )
1639}
1640
1641fn parse_input_id(
1642    info: Option<&fuiinput::DeviceInformation>,
1643    fallback: uapi::input_id,
1644) -> uapi::input_id {
1645    if let Some(info) = info {
1646        uapi::input_id {
1647            bustype: fallback.bustype,
1648            vendor: info.vendor_id.filter(|&id| id != 0).unwrap_or(fallback.vendor as u32) as u16,
1649            product: info.product_id.filter(|&id| id != 0).unwrap_or(fallback.product as u32)
1650                as u16,
1651            version: info.version.unwrap_or(fallback.version as u32) as u16,
1652        }
1653    } else {
1654        fallback
1655    }
1656}
1657
1658fn register_and_add_device(
1659    current_task: &CurrentTask,
1660    devices_relay: &mut InputEventsRelay,
1661    device_id: u32,
1662    descriptor: fuiinput::DeviceDescriptor,
1663    display_width: i32,
1664    display_height: i32,
1665) -> Result<(), Errno> {
1666    let kernel = current_task.kernel();
1667
1668    // Composite devices are registered under their primary function only
1669    // (priority: touch > keyboard/consumer control > mouse).
1670    let (default_name, default_input_id, device_type) = if let Some(_touch) = &descriptor.touch {
1671        let name = descriptor
1672            .device_information
1673            .as_ref()
1674            .and_then(|info| info.product_name.clone())
1675            .unwrap_or_else(|| "starnix_touch".to_string());
1676        let input_id = parse_input_id(descriptor.device_information.as_ref(), TOUCH_INPUT_ID);
1677        (
1678            name,
1679            input_id,
1680            InputDeviceType::Touch(FuchsiaTouchEventToLinuxTouchEventConverter::create()),
1681        )
1682    } else if descriptor.keyboard.is_some() || descriptor.consumer_control.is_some() {
1683        let name = descriptor
1684            .device_information
1685            .as_ref()
1686            .and_then(|info| info.product_name.clone())
1687            .unwrap_or_else(|| "starnix_buttons".to_string());
1688        let input_id = parse_input_id(descriptor.device_information.as_ref(), KEYBOARD_INPUT_ID);
1689        (name, input_id, InputDeviceType::Keyboard)
1690    } else if descriptor.mouse.is_some() {
1691        let name = descriptor
1692            .device_information
1693            .as_ref()
1694            .and_then(|info| info.product_name.clone())
1695            .unwrap_or_else(|| "starnix_mouse".to_string());
1696        let input_id = parse_input_id(descriptor.device_information.as_ref(), MOUSE_INPUT_ID);
1697        (
1698            name,
1699            input_id,
1700            InputDeviceType::Mouse(FuchsiaMouseEventToLinuxMouseEventConverter::create()),
1701        )
1702    } else {
1703        return error!(ENOTSUP);
1704    };
1705    let info = {
1706        let mut device_infos = devices_relay.device_infos.lock();
1707        if let Some(info) = device_infos.get(&device_id) {
1708            info.clone()
1709        } else {
1710            let info = InputDeviceInfo::new(default_input_id, default_name);
1711            device_infos.insert(device_id, info.clone());
1712            info
1713        }
1714    };
1715
1716    let input_device = match &device_type {
1717        InputDeviceType::Touch(_) => InputDevice::new_touch(
1718            display_width,
1719            display_height,
1720            info,
1721            &format!("touch_device_{}", device_id),
1722            &kernel.inspect_node,
1723        ),
1724        InputDeviceType::Keyboard => InputDevice::new_keyboard(
1725            info,
1726            &format!("keyboard_device_{}", device_id),
1727            &kernel.inspect_node,
1728        ),
1729        InputDeviceType::Mouse(_) => InputDevice::new_mouse(
1730            info,
1731            &format!("mouse_device_{}", device_id),
1732            &kernel.inspect_node,
1733        ),
1734    };
1735
1736    if let Some(old_state) = devices_relay.devices.remove(&device_id) {
1737        devices_relay.update_num_devices();
1738        if let Some(old_starnix_device) = old_state.starnix_device {
1739            InputDevice::unregister(current_task, old_starnix_device);
1740        }
1741    }
1742
1743    // Allocate the lowest available minor number for this device.
1744    // Note: `DeviceRegistry` does not provide dynamic minor allocation or recycling for
1745    // `INPUT_MAJOR`, so minors are tracked and recycled locally here.
1746    let minor = (0u32..)
1747        .find(|&m| !devices_relay.devices.values().any(|s| s.minor == m))
1748        .expect("failed to allocate minor number");
1749
1750    let starnix_device = input_device.clone().register(kernel, minor)?;
1751    let device_state = DeviceState {
1752        device_type,
1753        open_files: input_device.open_files,
1754        inspect_status: Some(input_device.inspect_status),
1755        registration: DeviceRegistration::Registered,
1756        starnix_device: Some(starnix_device),
1757        minor,
1758    };
1759    devices_relay.devices.insert(device_id, device_state);
1760    devices_relay.update_num_devices();
1761    Ok(())
1762}
1763
1764fn setup_mouse_relay(
1765    kernel: &Arc<Kernel>,
1766    event_proxy_mode: EventProxyMode,
1767    mouse_source_client_end: ClientEnd<fuipointer::MouseSourceV2Marker>,
1768) -> (fuipointer::MouseSourceV2Proxy, ContainerWakingStream<fuipointer::MouseSourceV2EventStream>) {
1769    let mouse_counter_name = "mouse";
1770    let (mouse_source_proxy, counter) = match event_proxy_mode {
1771        EventProxyMode::WakeContainer => {
1772            // Proxy the mouse events through the Starnix runner. This allows mouse events to
1773            // wake the container when it is suspended.
1774            let (mouse_source_channel, resume_event) = create_proxy_for_wake_events_counter(
1775                mouse_source_client_end.into_channel(),
1776                "mouse".to_string(),
1777            );
1778            (
1779                fuipointer::MouseSourceV2Proxy::new(fidl::AsyncChannel::from_channel(
1780                    mouse_source_channel,
1781                )),
1782                Some(resume_event),
1783            )
1784        }
1785        EventProxyMode::None => (mouse_source_client_end.into_proxy(), None),
1786    };
1787
1788    let waking_stream = ContainerWakingStream::new(
1789        kernel.suspend_resume_manager.add_message_counter(mouse_counter_name, counter),
1790        mouse_source_proxy.take_event_stream(),
1791    );
1792
1793    (mouse_source_proxy, waking_stream)
1794}
1795
1796fn group_mouse_events_by_device_id(
1797    events: Vec<FidlMouseEvent>,
1798) -> (SortedVecMap<DeviceId, Vec<FidlMouseEvent>>, u64) {
1799    let mut events_by_device: SortedVecMap<u32, Vec<FidlMouseEvent>> = SortedVecMap::new();
1800    let mut ignored_events: u64 = 0;
1801    for e in events {
1802        match e {
1803            FidlMouseEvent { pointer_sample: Some(ref sample), .. } => {
1804                let id = sample.device_id.unwrap_or(DEFAULT_MOUSE_DEVICE_ID);
1805                if let Some(vec) = events_by_device.get_mut(&id) {
1806                    vec.push(e);
1807                } else {
1808                    events_by_device.insert(id, vec![e]);
1809                }
1810            }
1811            _ => {
1812                ignored_events += 1;
1813            }
1814        }
1815    }
1816
1817    (events_by_device, ignored_events)
1818}
1819
1820fn group_touch_events_by_device_id(
1821    events: Vec<FidlTouchEvent>,
1822) -> (SortedVecMap<DeviceId, Vec<FidlTouchEvent>>, u64) {
1823    let mut events_by_device: SortedVecMap<u32, Vec<FidlTouchEvent>> = SortedVecMap::new();
1824    let mut ignored_events: u64 = 0;
1825    for e in events {
1826        match e {
1827            FidlTouchEvent {
1828                pointer_sample: Some(TouchPointerSample { interaction: Some(id), .. }),
1829                ..
1830            } => {
1831                if let Some(vec) = events_by_device.get_mut(&id.device_id) {
1832                    vec.push(e);
1833                } else {
1834                    events_by_device.insert(id.device_id, vec![e]);
1835                }
1836            }
1837            _ => {
1838                ignored_events += 1;
1839            }
1840        }
1841    }
1842
1843    (events_by_device, ignored_events)
1844}
1845
1846#[cfg(test)]
1847pub async fn start_input_relays_for_test(
1848    current_task: &starnix_core::task::CurrentTask,
1849    event_proxy_mode: EventProxyMode,
1850) -> (
1851    Arc<InputEventsRelayHandle>,
1852    crate::InputDevice,
1853    crate::InputDevice,
1854    crate::InputDevice,
1855    starnix_core::vfs::FileHandle,
1856    starnix_core::vfs::FileHandle,
1857    starnix_core::vfs::FileHandle,
1858    fuipointer::TouchSourceV2RequestStream,
1859    fuipointer::MouseSourceV2RequestStream,
1860    fidl_fuchsia_ui_input3::KeyboardListenerProxy,
1861    fuipolicy::MediaButtonsListenerProxy,
1862    fuipolicy::TouchButtonsListenerProxy,
1863) {
1864    let inspector = fuchsia_inspect::Inspector::default();
1865
1866    let touch_device = crate::InputDevice::new_touch(
1867        700,
1868        1200,
1869        crate::InputDeviceInfo::new(TOUCH_INPUT_ID, "starnix_touch".to_string()),
1870        "touch_device",
1871        inspector.root(),
1872    );
1873    let touch_file = touch_device.open_test(current_task).expect("Failed to create input file");
1874
1875    let keyboard_device = crate::InputDevice::new_keyboard(
1876        crate::InputDeviceInfo::new(KEYBOARD_INPUT_ID, "starnix_buttons".to_string()),
1877        "keyboard_device",
1878        inspector.root(),
1879    );
1880    let keyboard_file =
1881        keyboard_device.open_test(current_task).expect("Failed to create input file");
1882
1883    let mouse_device = crate::InputDevice::new_mouse(
1884        crate::InputDeviceInfo::new(MOUSE_INPUT_ID, "starnix_mouse".to_string()),
1885        "mouse_device",
1886        inspector.root(),
1887    );
1888    let mouse_file = mouse_device.open_test(current_task).expect("Failed to create input file");
1889
1890    let (touch_source_client_end, touch_source_stream) =
1891        fidl::endpoints::create_request_stream::<fuipointer::TouchSourceV2Marker>();
1892    let (mouse_source_client_end, mouse_stream) =
1893        fidl::endpoints::create_request_stream::<fuipointer::MouseSourceV2Marker>();
1894    let (keyboard_proxy, mut keyboard_stream) =
1895        fidl::endpoints::create_sync_proxy_and_stream::<fidl_fuchsia_ui_input3::KeyboardMarker>();
1896    let view_ref_pair = fuchsia_scenic::ViewRefPair::new().expect("Failed to create ViewRefPair");
1897    let (device_registry_proxy, mut device_listener_stream) =
1898        fidl::endpoints::create_sync_proxy_and_stream::<fuipolicy::DeviceListenerRegistryMarker>();
1899
1900    let (mut relay, relay_handle) = new_input_relay();
1901    // TODO(https://fxbug.dev/502662433): Default devices are no longer needed because
1902    // existing devices are enumerated via the DeviceIterator before start_relays().
1903    // Remove them in a follow-up change.
1904    relay.add_touch_device(
1905        DEFAULT_TOUCH_DEVICE_ID,
1906        touch_device.open_files.clone(),
1907        Some(touch_device.inspect_status.clone()),
1908    );
1909    relay.add_keyboard_device(
1910        DEFAULT_KEYBOARD_DEVICE_ID,
1911        keyboard_device.open_files.clone(),
1912        Some(keyboard_device.inspect_status.clone()),
1913    );
1914    relay.add_mouse_device(
1915        DEFAULT_MOUSE_DEVICE_ID,
1916        mouse_device.open_files.clone(),
1917        Some(mouse_device.inspect_status.clone()),
1918    );
1919    relay.start_relays(
1920        &current_task.kernel(),
1921        StartRelaysArgs {
1922            event_proxy_mode,
1923            touch_source_client_end,
1924            keyboard_proxy,
1925            mouse_source_client_end,
1926            view_ref: view_ref_pair.view_ref,
1927            registry_proxy: device_registry_proxy,
1928            device_listener_registry: None,
1929            display_width: 700,
1930            display_height: 1200,
1931        },
1932    );
1933
1934    let keyboard_listener = match keyboard_stream.next().await {
1935        Some(Ok(fidl_fuchsia_ui_input3::KeyboardRequest::AddListener {
1936            view_ref: _,
1937            listener,
1938            responder,
1939        })) => {
1940            let _ = responder.send();
1941            listener.into_proxy()
1942        }
1943        _ => {
1944            panic!("Failed to get event");
1945        }
1946    };
1947
1948    let media_buttons_listener = match device_listener_stream.next().await {
1949        Some(Ok(fuipolicy::DeviceListenerRegistryRequest::RegisterListener {
1950            listener,
1951            responder,
1952        })) => {
1953            let _ = responder.send();
1954            listener.into_proxy()
1955        }
1956        _ => {
1957            panic!("Failed to get event");
1958        }
1959    };
1960
1961    let touch_buttons_listener = match device_listener_stream.next().await {
1962        Some(Ok(fuipolicy::DeviceListenerRegistryRequest::RegisterTouchButtonsListener {
1963            listener,
1964            responder,
1965        })) => {
1966            let _ = responder.send();
1967            listener.into_proxy()
1968        }
1969        _ => {
1970            panic!("Failed to get event");
1971        }
1972    };
1973
1974    (
1975        relay_handle,
1976        touch_device,
1977        keyboard_device,
1978        mouse_device,
1979        touch_file,
1980        keyboard_file,
1981        mouse_file,
1982        touch_source_stream,
1983        mouse_stream,
1984        keyboard_listener,
1985        media_buttons_listener,
1986        touch_buttons_listener,
1987    )
1988}
1989
1990#[cfg(test)]
1991mod test {
1992    use super::*;
1993    use anyhow::anyhow;
1994    use diagnostics_assertions::assert_data_tree;
1995    use fidl_fuchsia_ui_input::{
1996        MediaButtonsEvent, TouchButton, TouchButtonsEvent, TouchDeviceInfo,
1997    };
1998    use fidl_fuchsia_ui_input3 as fuiinput;
1999    use fuipointer::{
2000        EventPhase, MouseEvent, MousePointerSample, TouchEvent, TouchInteractionId,
2001        TouchPointerSample, TouchSourceV2Request, TouchSourceV2RequestStream,
2002    };
2003    use starnix_core::task::CurrentTask;
2004    use starnix_core::testing::spawn_kernel_and_run;
2005    use starnix_core::vfs::{FileHandle, FileObject, VecOutputBuffer};
2006
2007    use starnix_types::time::timeval_from_time;
2008    use starnix_uapi::errors::{EAGAIN, Errno};
2009    use starnix_uapi::input_id;
2010    use starnix_uapi::open_flags::OpenFlags;
2011    use zerocopy::FromBytes as _;
2012
2013    const INPUT_EVENT_SIZE: usize = std::mem::size_of::<uapi::input_event>();
2014
2015    // Sends `touch_events` to the client stream and waits for `AcknowledgeEvents`.
2016    async fn answer_next_touch_watch_request(
2017        request_stream: &mut TouchSourceV2RequestStream,
2018        touch_events: Vec<TouchEvent>,
2019    ) {
2020        let control_handle = request_stream.control_handle();
2021        control_handle
2022            .send_on_touch_events(touch_events, 1)
2023            .expect("failure sending OnTouchEvents");
2024        match request_stream.next().await {
2025            Some(Ok(TouchSourceV2Request::AcknowledgeEvents { .. })) => {}
2026            unexpected_request => panic!("unexpected request {:?}", unexpected_request),
2027        }
2028    }
2029
2030    // Sends `mouse_events` to the client stream and waits for `AcknowledgeEvents`.
2031    async fn answer_next_mouse_watch_request(
2032        request_stream: &mut fuipointer::MouseSourceV2RequestStream,
2033        mouse_events: Vec<MouseEvent>,
2034    ) {
2035        let control_handle = request_stream.control_handle();
2036        control_handle
2037            .send_on_mouse_events(mouse_events, 1)
2038            .expect("failure sending OnMouseEvents");
2039        match request_stream.next().await {
2040            Some(Ok(fuipointer::MouseSourceV2Request::AcknowledgeEvents { .. })) => {}
2041            unexpected_request => panic!("unexpected request {:?}", unexpected_request),
2042        }
2043    }
2044
2045    fn make_empty_touch_event(device_id: u32) -> TouchEvent {
2046        TouchEvent {
2047            pointer_sample: Some(TouchPointerSample {
2048                interaction: Some(TouchInteractionId {
2049                    pointer_id: 0,
2050                    device_id,
2051                    interaction_id: 0,
2052                }),
2053                ..Default::default()
2054            }),
2055            ..Default::default()
2056        }
2057    }
2058
2059    fn make_touch_event_with_phase_device_id(
2060        phase: EventPhase,
2061        pointer_id: u32,
2062        device_id: u32,
2063    ) -> TouchEvent {
2064        make_touch_event_with_phase_device_id_position(phase, pointer_id, device_id, 0.0, 0.0)
2065    }
2066
2067    fn make_touch_event_with_phase_device_id_position(
2068        phase: EventPhase,
2069        pointer_id: u32,
2070        device_id: u32,
2071        x: f32,
2072        y: f32,
2073    ) -> TouchEvent {
2074        TouchEvent {
2075            timestamp: Some(0),
2076            pointer_sample: Some(TouchPointerSample {
2077                position_in_viewport: Some([x, y]),
2078                phase: Some(phase),
2079                interaction: Some(TouchInteractionId { pointer_id, device_id, interaction_id: 0 }),
2080                ..Default::default()
2081            }),
2082            ..Default::default()
2083        }
2084    }
2085
2086    fn make_mouse_wheel_event(scroll_v_ticks: i64, device_id: u32) -> MouseEvent {
2087        MouseEvent {
2088            timestamp: Some(0),
2089            pointer_sample: Some(MousePointerSample {
2090                device_id: Some(device_id),
2091                scroll_v: Some(scroll_v_ticks),
2092                ..Default::default()
2093            }),
2094            ..Default::default()
2095        }
2096    }
2097
2098    fn read_uapi_events(file: &FileHandle, current_task: &CurrentTask) -> Vec<uapi::input_event> {
2099        std::iter::from_fn(|| {
2100            let mut event_bytes = VecOutputBuffer::new(INPUT_EVENT_SIZE);
2101            match file.read(current_task, &mut event_bytes) {
2102                Ok(INPUT_EVENT_SIZE) => Some(
2103                    uapi::input_event::read_from_bytes(Vec::from(event_bytes).as_slice())
2104                        .map_err(|_| anyhow!("failed to read input_event from buffer")),
2105                ),
2106                Ok(other_size) => {
2107                    Some(Err(anyhow!("got {} bytes (expected {})", other_size, INPUT_EVENT_SIZE)))
2108                }
2109                Err(Errno { code: EAGAIN, .. }) => None,
2110                Err(other_error) => Some(Err(anyhow!("read failed: {:?}", other_error))),
2111            }
2112        })
2113        .enumerate()
2114        .map(|(i, read_res)| match read_res {
2115            Ok(event) => event,
2116            Err(e) => panic!("unexpected result {:?} on iteration {}", e, i),
2117        })
2118        .collect()
2119    }
2120
2121    fn create_test_touch_device(
2122        current_task: &CurrentTask,
2123        input_relay: Arc<InputEventsRelayHandle>,
2124        device_id: u32,
2125    ) -> FileHandle {
2126        let open_files: OpenedFiles = Default::default();
2127        input_relay.add_touch_device(device_id, open_files.clone(), None);
2128        let inspector = fuchsia_inspect::Inspector::default();
2129        let device_file = Arc::new(InputFile::new_touch(
2130            InputDeviceInfo::new(
2131                input_id { bustype: 0, vendor: 0, product: 0, version: 0 },
2132                "touch_device".to_string(),
2133            ),
2134            1000,
2135            1000,
2136            inspector.root(),
2137        ));
2138        open_files.lock().push(Arc::downgrade(&device_file));
2139
2140        let root_namespace_node = current_task
2141            .lookup_path_from_root(".".into())
2142            .expect("failed to get namespace node for root");
2143
2144        FileObject::new(
2145            &current_task,
2146            Box::new(crate::input_file::ArcInputFile(device_file)),
2147            root_namespace_node,
2148            OpenFlags::empty(),
2149        )
2150        .expect("FileObject::new failed")
2151    }
2152
2153    fn make_uapi_input_event(ty: u32, code: u32, value: i32) -> uapi::input_event {
2154        uapi::input_event {
2155            time: timeval_from_time(zx::MonotonicInstant::from_nanos(0)),
2156            type_: ty as u16,
2157            code: code as u16,
2158            value,
2159        }
2160    }
2161
2162    #[::fuchsia::test]
2163    async fn route_touch_event_by_device_id() {
2164        spawn_kernel_and_run(async move |current_task| {
2165            // Set up resources.
2166
2167            let (
2168                input_relay,
2169                _touch_device,
2170                _keyboard_device,
2171                _mouse_device,
2172                input_file,
2173                _keyboard_file,
2174                _mouse_file,
2175                mut touch_source_stream,
2176                _mouse_source_stream,
2177                _keyboard_listener,
2178                _media_buttons_listener,
2179                _touch_buttons_listener,
2180            ) = start_input_relays_for_test(&current_task, EventProxyMode::None).await;
2181
2182            const DEVICE_ID: u32 = 10;
2183
2184            answer_next_touch_watch_request(
2185                &mut touch_source_stream,
2186                vec![make_touch_event_with_phase_device_id(EventPhase::Add, 1, DEVICE_ID)],
2187            )
2188            .await;
2189
2190            // Wait for another `Watch` to ensure input_file done processing the first reply.
2191            // Use an empty `TouchEvent`, to minimize the chance that this event creates unexpected
2192            // `uapi::input_event`s.
2193            answer_next_touch_watch_request(
2194                &mut touch_source_stream,
2195                vec![make_empty_touch_event(DEVICE_ID)],
2196            )
2197            .await;
2198
2199            // Consume all of the `uapi::input_event`s that are available.
2200            let events = read_uapi_events(&input_file, &current_task);
2201            // Default device should receive events because device id 10 falls back to default.
2202            assert_ne!(events.len(), 0);
2203            assert_eq!(input_relay.num_unregistered_device_events(), 0);
2204
2205            // add a device, mock uinput.
2206            let device_id_10_file =
2207                create_test_touch_device(&current_task, input_relay.clone(), DEVICE_ID);
2208
2209            answer_next_touch_watch_request(
2210                &mut touch_source_stream,
2211                vec![make_touch_event_with_phase_device_id(EventPhase::Add, 1, DEVICE_ID)],
2212            )
2213            .await;
2214
2215            answer_next_touch_watch_request(
2216                &mut touch_source_stream,
2217                vec![make_empty_touch_event(DEVICE_ID)],
2218            )
2219            .await;
2220
2221            let events = read_uapi_events(&input_file, &current_task);
2222            // Default device should not receive events because they matched device id 10.
2223            assert_eq!(events.len(), 0);
2224
2225            let events = read_uapi_events(&device_id_10_file, &current_task);
2226            // file of device id 10 should receive events.
2227            assert_ne!(events.len(), 0);
2228        })
2229        .await;
2230    }
2231
2232    #[::fuchsia::test]
2233    async fn route_touch_event_with_wake_lease() {
2234        spawn_kernel_and_run(async move |current_task| {
2235            let (
2236                _input_relay,
2237                touch_device,
2238                _keyboard_device,
2239                _mouse_device,
2240                _input_file,
2241                _keyboard_file,
2242                _mouse_file,
2243                mut touch_source_stream,
2244                _mouse_source_stream,
2245                _keyboard_listener,
2246                _media_buttons_listener,
2247                _touch_buttons_listener,
2248            ) = start_input_relays_for_test(&current_task, EventProxyMode::None).await;
2249
2250            const DEVICE_ID: u32 = DEFAULT_TOUCH_DEVICE_ID;
2251            let mut event = make_touch_event_with_phase_device_id(EventPhase::Add, 1, DEVICE_ID);
2252            let (p1, _p2) = fidl::EventPair::create();
2253            event.wake_lease = Some(p1);
2254
2255            answer_next_touch_watch_request(&mut touch_source_stream, vec![event]).await;
2256
2257            // Wait for another `Watch` to ensure input_file done processing the first reply.
2258            answer_next_touch_watch_request(
2259                &mut touch_source_stream,
2260                vec![make_empty_touch_event(DEVICE_ID)],
2261            )
2262            .await;
2263
2264            let status = &touch_device.inspect_status;
2265            assert_eq!(
2266                status
2267                    .total_events_with_wake_lease_count
2268                    .load(std::sync::atomic::Ordering::Relaxed),
2269                1
2270            );
2271            assert_eq!(
2272                status.active_wake_leases_count.load(std::sync::atomic::Ordering::Relaxed),
2273                0
2274            );
2275        })
2276        .await;
2277    }
2278
2279    #[::fuchsia::test]
2280    async fn route_touch_event_by_device_id_multi_device_events_in_one_sequence() {
2281        spawn_kernel_and_run(async move |current_task| {
2282            let (
2283                input_relay,
2284                _touch_device,
2285                _keyboard_device,
2286                _mouse_device,
2287                _input_file,
2288                _keyboard_file,
2289                _mouse_file,
2290                mut touch_source_stream,
2291                _mouse_source_stream,
2292                _keyboard_listener,
2293                _media_buttons_listener,
2294                _touch_buttons_listener,
2295            ) = start_input_relays_for_test(&current_task, EventProxyMode::None).await;
2296
2297            const DEVICE_ID_10: u32 = 10;
2298            const DEVICE_ID_11: u32 = 11;
2299
2300            let device_id_10_file =
2301                create_test_touch_device(&current_task, input_relay.clone(), DEVICE_ID_10);
2302
2303            let device_id_11_file =
2304                create_test_touch_device(&current_task, input_relay.clone(), DEVICE_ID_11);
2305
2306            // 2 pointer down on different touch device.
2307            answer_next_touch_watch_request(
2308                &mut touch_source_stream,
2309                vec![
2310                    make_touch_event_with_phase_device_id_position(
2311                        EventPhase::Add,
2312                        1,
2313                        DEVICE_ID_10,
2314                        10.0,
2315                        20.0,
2316                    ),
2317                    make_touch_event_with_phase_device_id_position(
2318                        EventPhase::Add,
2319                        2,
2320                        DEVICE_ID_11,
2321                        30.0,
2322                        40.0,
2323                    ),
2324                ],
2325            )
2326            .await;
2327
2328            answer_next_touch_watch_request(&mut touch_source_stream, vec![]).await;
2329
2330            let events_10 = read_uapi_events(&device_id_10_file, &current_task);
2331            let events_11 = read_uapi_events(&device_id_11_file, &current_task);
2332            assert_eq!(events_10.len(), events_11.len());
2333
2334            assert_eq!(
2335                events_10,
2336                vec![
2337                    make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0),
2338                    make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 1),
2339                    make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 10),
2340                    make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 20),
2341                    make_uapi_input_event(uapi::EV_KEY, uapi::BTN_TOUCH, 1),
2342                    make_uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0),
2343                ]
2344            );
2345
2346            assert_eq!(
2347                events_11,
2348                vec![
2349                    make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0),
2350                    make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 2),
2351                    make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 30),
2352                    make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 40),
2353                    make_uapi_input_event(uapi::EV_KEY, uapi::BTN_TOUCH, 1),
2354                    make_uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0),
2355                ]
2356            );
2357        })
2358        .await;
2359    }
2360
2361    #[::fuchsia::test]
2362    async fn route_key_event_by_device_id() {
2363        spawn_kernel_and_run(async move |current_task| {
2364            // Set up resources.
2365
2366            let (
2367                input_relay,
2368                _touch_device,
2369                _keyboard_device,
2370                _mouse_device,
2371                _touch_file,
2372                keyboard_file,
2373                _mouse_file,
2374                _touch_source_stream,
2375                _mouse_source_stream,
2376                keyboard_listener,
2377                _media_buttons_listener,
2378                _touch_buttons_listener,
2379            ) = start_input_relays_for_test(&current_task, EventProxyMode::None).await;
2380
2381            const DEVICE_ID: u32 = 10;
2382
2383            let key_event = fuiinput::KeyEvent {
2384                timestamp: Some(0),
2385                type_: Some(fuiinput::KeyEventType::Pressed),
2386                key: Some(fidl_fuchsia_input::Key::A),
2387                device_id: Some(DEVICE_ID),
2388                ..Default::default()
2389            };
2390
2391            let _ = keyboard_listener.on_key_event(&key_event).await;
2392
2393            let events = read_uapi_events(&keyboard_file, &current_task);
2394            // Default device should receive events because device id 10 falls back to default.
2395            assert_ne!(events.len(), 0);
2396            assert_eq!(input_relay.num_unregistered_device_events(), 0);
2397
2398            // add a device, mock uinput.
2399            let open_files: OpenedFiles = Default::default();
2400            input_relay.add_keyboard_device(DEVICE_ID, open_files.clone(), None);
2401            let inspector = fuchsia_inspect::Inspector::default();
2402            let device_id_10_file = Arc::new(InputFile::new_keyboard(
2403                InputDeviceInfo::new(
2404                    input_id { bustype: 0, vendor: 0, product: 0, version: 0 },
2405                    "keyboard_10".to_string(),
2406                ),
2407                inspector.root(),
2408            ));
2409            open_files.lock().push(Arc::downgrade(&device_id_10_file));
2410            let root_namespace_node = current_task
2411                .lookup_path_from_root(".".into())
2412                .expect("failed to get namespace node for root");
2413            let device_id_10_file_object = FileObject::new(
2414                &current_task,
2415                Box::new(crate::input_file::ArcInputFile(device_id_10_file)),
2416                root_namespace_node,
2417                OpenFlags::empty(),
2418            )
2419            .expect("FileObject::new failed");
2420
2421            let _ = keyboard_listener.on_key_event(&key_event).await;
2422
2423            let events = read_uapi_events(&keyboard_file, &current_task);
2424            // Default device should not receive events because they matched device id 10.
2425            assert_eq!(events.len(), 0);
2426
2427            let events = read_uapi_events(&device_id_10_file_object, &current_task);
2428            // file of device id 10 should receive events.
2429            assert_ne!(events.len(), 0);
2430
2431            std::mem::drop(keyboard_listener); // Close Zircon channel.
2432        })
2433        .await;
2434    }
2435
2436    #[::fuchsia::test]
2437    async fn route_media_button_event_by_device_id() {
2438        spawn_kernel_and_run(async move |current_task| {
2439            // Set up resources.
2440
2441            let (
2442                input_relay,
2443                _touch_device,
2444                _keyboard_device,
2445                _mouse_device,
2446                _touch_file,
2447                keyboard_file,
2448                _mouse_file,
2449                _touch_source_stream,
2450                _mouse_source_stream,
2451                _keyboard_listener,
2452                media_buttons_listener,
2453                _touch_buttons_listener,
2454            ) = start_input_relays_for_test(&current_task, EventProxyMode::None).await;
2455
2456            const DEVICE_ID: u32 = 10;
2457
2458            let power_pressed_event = MediaButtonsEvent {
2459                volume: Some(0),
2460                mic_mute: Some(false),
2461                pause: Some(false),
2462                camera_disable: Some(false),
2463                power: Some(true),
2464                function: Some(false),
2465                device_id: Some(DEVICE_ID),
2466                ..Default::default()
2467            };
2468
2469            let _ = media_buttons_listener.on_event(power_pressed_event).await;
2470
2471            let events = read_uapi_events(&keyboard_file, &current_task);
2472            // Default device should receive events because device id 10 falls back to default.
2473            assert_ne!(events.len(), 0);
2474            assert_eq!(input_relay.num_unregistered_device_events(), 0);
2475
2476            // add a device, mock uinput.
2477            let open_files: OpenedFiles = Default::default();
2478            input_relay.add_keyboard_device(DEVICE_ID, open_files.clone(), None);
2479            let inspector = fuchsia_inspect::Inspector::default();
2480            let device_id_10_file = Arc::new(InputFile::new_keyboard(
2481                InputDeviceInfo::new(
2482                    input_id { bustype: 0, vendor: 0, product: 0, version: 0 },
2483                    "keyboard_10".to_string(),
2484                ),
2485                inspector.root(),
2486            ));
2487            open_files.lock().push(Arc::downgrade(&device_id_10_file));
2488            let root_namespace_node = current_task
2489                .lookup_path_from_root(".".into())
2490                .expect("failed to get namespace node for root");
2491            let device_id_10_file_object = FileObject::new(
2492                &current_task,
2493                Box::new(crate::input_file::ArcInputFile(device_id_10_file)),
2494                root_namespace_node,
2495                OpenFlags::empty(),
2496            )
2497            .expect("FileObject::new failed");
2498
2499            let power_released_event = MediaButtonsEvent {
2500                volume: Some(0),
2501                mic_mute: Some(false),
2502                pause: Some(false),
2503                camera_disable: Some(false),
2504                power: Some(false),
2505                function: Some(false),
2506                device_id: Some(DEVICE_ID),
2507                ..Default::default()
2508            };
2509
2510            let _ = media_buttons_listener.on_event(power_released_event).await;
2511
2512            let events = read_uapi_events(&keyboard_file, &current_task);
2513            // Default device should not receive events because they matched device id 10.
2514            assert_eq!(events.len(), 0);
2515
2516            let events = read_uapi_events(&device_id_10_file_object, &current_task);
2517            // file of device id 10 should receive events.
2518            assert_ne!(events.len(), 0);
2519
2520            std::mem::drop(media_buttons_listener); // Close Zircon channel.
2521        })
2522        .await;
2523    }
2524
2525    #[::fuchsia::test]
2526    async fn route_touch_button_event_by_device_id() {
2527        spawn_kernel_and_run(async move |current_task| {
2528            // Set up resources.
2529
2530            let (
2531                input_relay,
2532                _touch_device,
2533                _keyboard_device,
2534                _mouse_device,
2535                touch_file,
2536                _keyboard_file,
2537                _mouse_file,
2538                _touch_source_stream,
2539                _mouse_source_stream,
2540                _keyboard_listener,
2541                _media_buttons_listener,
2542                touch_buttons_listener,
2543            ) = start_input_relays_for_test(&current_task, EventProxyMode::None).await;
2544
2545            const DEVICE_ID: u32 = 10;
2546
2547            let palm_pressed_event: TouchButtonsEvent = TouchButtonsEvent {
2548                pressed_buttons: Some(vec![TouchButton::Palm]),
2549                device_info: Some(TouchDeviceInfo { id: Some(DEVICE_ID), ..Default::default() }),
2550                ..Default::default()
2551            };
2552
2553            let _ = touch_buttons_listener.on_event(palm_pressed_event).await;
2554
2555            let events = read_uapi_events(&touch_file, &current_task);
2556            // Default device should receive events because device id 10 falls back to default.
2557            assert_ne!(events.len(), 0);
2558            assert_eq!(input_relay.num_unregistered_device_events(), 0);
2559
2560            // add a device, mock uinput.
2561            let device_id_10_file =
2562                create_test_touch_device(&current_task, input_relay.clone(), DEVICE_ID);
2563
2564            let palm_released_event: TouchButtonsEvent = TouchButtonsEvent {
2565                pressed_buttons: Some(vec![]),
2566                device_info: Some(TouchDeviceInfo { id: Some(DEVICE_ID), ..Default::default() }),
2567                ..Default::default()
2568            };
2569
2570            let _ = touch_buttons_listener.on_event(palm_released_event).await;
2571
2572            let events = read_uapi_events(&touch_file, &current_task);
2573            // Default device should not receive events because they matched device id 10.
2574            assert_eq!(events.len(), 0);
2575
2576            let events = read_uapi_events(&device_id_10_file, &current_task);
2577            // file of device id 10 should receive events.
2578            assert_ne!(events.len(), 0);
2579
2580            std::mem::drop(touch_buttons_listener); // Close Zircon channel.
2581        })
2582        .await;
2583    }
2584
2585    #[::fuchsia::test]
2586    async fn touch_device_multi_reader() {
2587        spawn_kernel_and_run(async move |current_task| {
2588            // Set up resources.
2589
2590            let (
2591                _input_relay,
2592                touch_device,
2593                _keyboard_device,
2594                _mouse_device,
2595                touch_reader1,
2596                _keyboard_file,
2597                _mouse_file,
2598                mut touch_source_stream,
2599                _mouse_source_stream,
2600                _keyboard_listener,
2601                _media_buttons_listener,
2602                _touch_buttons_listener,
2603            ) = start_input_relays_for_test(&current_task, EventProxyMode::None).await;
2604
2605            let touch_reader2 =
2606                touch_device.open_test(&current_task).expect("Failed to create input file");
2607
2608            const DEVICE_ID: u32 = DEFAULT_TOUCH_DEVICE_ID;
2609
2610            answer_next_touch_watch_request(
2611                &mut touch_source_stream,
2612                vec![make_touch_event_with_phase_device_id(EventPhase::Add, 1, DEVICE_ID)],
2613            )
2614            .await;
2615
2616            // Wait for another `Watch` to ensure input_file done processing the first reply.
2617            // Use an empty `TouchEvent`, to minimize the chance that this event creates unexpected
2618            // `uapi::input_event`s.
2619            answer_next_touch_watch_request(
2620                &mut touch_source_stream,
2621                vec![make_empty_touch_event(DEVICE_ID)],
2622            )
2623            .await;
2624
2625            // Consume all of the `uapi::input_event`s that are available.
2626            let events_from_reader1 = read_uapi_events(&touch_reader1, &current_task);
2627            let events_from_reader2 = read_uapi_events(&touch_reader2, &current_task);
2628            assert_ne!(events_from_reader1.len(), 0);
2629            assert_eq!(events_from_reader1.len(), events_from_reader2.len());
2630        })
2631        .await;
2632    }
2633
2634    #[::fuchsia::test]
2635    async fn keyboard_device_multi_reader() {
2636        spawn_kernel_and_run(async move |current_task| {
2637            // Set up resources.
2638
2639            let (
2640                _input_relay,
2641                _touch_device,
2642                keyboard_device,
2643                _mouse_device,
2644                _touch_file,
2645                keyboard_reader1,
2646                _mouse_file,
2647                _touch_source_stream,
2648                _mouse_source_stream,
2649                keyboard_listener,
2650                _media_buttons_listener,
2651                _touch_buttons_listener,
2652            ) = start_input_relays_for_test(&current_task, EventProxyMode::None).await;
2653
2654            let keyboard_reader2 =
2655                keyboard_device.open_test(&current_task).expect("Failed to create input file");
2656
2657            const DEVICE_ID: u32 = DEFAULT_KEYBOARD_DEVICE_ID;
2658
2659            let key_event = fuiinput::KeyEvent {
2660                timestamp: Some(0),
2661                type_: Some(fuiinput::KeyEventType::Pressed),
2662                key: Some(fidl_fuchsia_input::Key::A),
2663                device_id: Some(DEVICE_ID),
2664                ..Default::default()
2665            };
2666
2667            let _ = keyboard_listener.on_key_event(&key_event).await;
2668
2669            // Consume all of the `uapi::input_event`s that are available.
2670            let events_from_reader1 = read_uapi_events(&keyboard_reader1, &current_task);
2671            let events_from_reader2 = read_uapi_events(&keyboard_reader2, &current_task);
2672            assert_ne!(events_from_reader1.len(), 0);
2673            assert_eq!(events_from_reader1.len(), events_from_reader2.len());
2674        })
2675        .await;
2676    }
2677
2678    #[::fuchsia::test]
2679    async fn button_device_multi_reader() {
2680        spawn_kernel_and_run(async move |current_task| {
2681            // Set up resources.
2682
2683            let (
2684                _input_relay,
2685                _touch_device,
2686                keyboard_device,
2687                _mouse_device,
2688                _touch_file,
2689                keyboard_reader1,
2690                _mouse_file,
2691                _touch_source_stream,
2692                _mouse_source_stream,
2693                _keyboard_listener,
2694                media_buttons_listener,
2695                _touch_buttons_listener,
2696            ) = start_input_relays_for_test(&current_task, EventProxyMode::None).await;
2697
2698            let keyboard_reader2 =
2699                keyboard_device.open_test(&current_task).expect("Failed to create input file");
2700
2701            const DEVICE_ID: u32 = DEFAULT_KEYBOARD_DEVICE_ID;
2702
2703            let power_pressed_event = MediaButtonsEvent {
2704                volume: Some(0),
2705                mic_mute: Some(false),
2706                pause: Some(false),
2707                camera_disable: Some(false),
2708                power: Some(true),
2709                function: Some(false),
2710                device_id: Some(DEVICE_ID),
2711                ..Default::default()
2712            };
2713
2714            let _ = media_buttons_listener.on_event(power_pressed_event).await;
2715
2716            // Consume all of the `uapi::input_event`s that are available.
2717            let events_from_reader1 = read_uapi_events(&keyboard_reader1, &current_task);
2718            let events_from_reader2 = read_uapi_events(&keyboard_reader2, &current_task);
2719            assert_ne!(events_from_reader1.len(), 0);
2720            assert_eq!(events_from_reader1.len(), events_from_reader2.len());
2721        })
2722        .await;
2723    }
2724
2725    #[::fuchsia::test]
2726    async fn mouse_device_multi_reader() {
2727        spawn_kernel_and_run(async move |current_task| {
2728            // Set up resources.
2729
2730            let (
2731                _input_relay,
2732                _touch_device,
2733                _keyboard_device,
2734                mouse_device,
2735                _touch_file,
2736                _keyboard_file,
2737                mouse_reader1,
2738                _touch_stream,
2739                mut mouse_stream,
2740                _keyboard_listener,
2741                _media_buttons_listener,
2742                _touch_buttons_listener,
2743            ) = start_input_relays_for_test(&current_task, EventProxyMode::None).await;
2744
2745            let mouse_reader2 =
2746                mouse_device.open_test(&current_task).expect("Failed to create input file");
2747
2748            const DEVICE_ID: u32 = DEFAULT_MOUSE_DEVICE_ID;
2749
2750            answer_next_mouse_watch_request(
2751                &mut mouse_stream,
2752                vec![make_mouse_wheel_event(1, DEVICE_ID)],
2753            )
2754            .await;
2755
2756            // Wait for another `Watch` to ensure input_file done processing the first reply.
2757            // Use an empty `MouseEvent`, to minimize the chance that this event creates unexpected
2758            // `uapi::input_event`s.
2759            answer_next_mouse_watch_request(
2760                &mut mouse_stream,
2761                vec![make_mouse_wheel_event(0, DEVICE_ID)],
2762            )
2763            .await;
2764
2765            // Consume all of the `uapi::input_event`s that are available.
2766            let events_from_reader1 = read_uapi_events(&mouse_reader1, &current_task);
2767            let events_from_reader2 = read_uapi_events(&mouse_reader2, &current_task);
2768            assert_ne!(events_from_reader1.len(), 0);
2769            assert_eq!(events_from_reader1.len(), events_from_reader2.len());
2770        })
2771        .await;
2772    }
2773
2774    #[::fuchsia::test]
2775    async fn input_message_counters() {
2776        spawn_kernel_and_run(async move |current_task| {
2777            // Set up resources.
2778            let kernel = current_task.kernel().clone();
2779            let (
2780                _input_relay,
2781                _touch_device,
2782                _keyboard_device,
2783                _mouse_device,
2784                _touch_file,
2785                keyboard_file,
2786                _mouse_file,
2787                _touch_source_stream,
2788                _mouse_source_stream,
2789                keyboard_listener,
2790                _media_buttons_listener,
2791                _touch_buttons_listener,
2792            ) = start_input_relays_for_test(&current_task, EventProxyMode::WakeContainer).await;
2793
2794            const DEVICE_ID: u32 = DEFAULT_KEYBOARD_DEVICE_ID;
2795
2796            let key_event = fuiinput::KeyEvent {
2797                timestamp: Some(0),
2798                type_: Some(fuiinput::KeyEventType::Pressed),
2799                key: Some(fidl_fuchsia_input::Key::A),
2800                device_id: Some(DEVICE_ID),
2801                ..Default::default()
2802            };
2803
2804            let _ = keyboard_listener.on_key_event(&key_event).await;
2805
2806            let events = read_uapi_events(&keyboard_file, &current_task);
2807            assert_ne!(events.len(), 0);
2808
2809            assert!(!kernel.suspend_resume_manager.has_nonzero_message_counter());
2810        })
2811        .await;
2812    }
2813
2814    #[::fuchsia::test]
2815    async fn mouse_device_lazily_registered_on_first_mouse_event() {
2816        spawn_kernel_and_run(async move |current_task| {
2817            let kernel = current_task.kernel().clone();
2818            let inspector = fuchsia_inspect::Inspector::default();
2819
2820            let touch_device = crate::InputDevice::new_touch(
2821                700,
2822                1200,
2823                crate::InputDeviceInfo::new(TOUCH_INPUT_ID, "starnix_touch".to_string()),
2824                "touch_device",
2825                inspector.root(),
2826            );
2827            let keyboard_device = crate::InputDevice::new_keyboard(
2828                crate::InputDeviceInfo::new(KEYBOARD_INPUT_ID, "starnix_buttons".to_string()),
2829                "keyboard_device",
2830                inspector.root(),
2831            );
2832            // Do not open `mouse_device` before registration so we test production ordering:
2833            // userspace can only open `/dev/input/event2` after `DeviceRegistry` registration.
2834            let mouse_device = crate::InputDevice::new_mouse(
2835                crate::InputDeviceInfo::new(MOUSE_INPUT_ID, "starnix_mouse".to_string()),
2836                "mouse_device",
2837                inspector.root(),
2838            );
2839
2840            let (touch_source_client_end, _touch_source_stream) =
2841                fidl::endpoints::create_request_stream::<fuipointer::TouchSourceV2Marker>();
2842            let (mouse_source_client_end, mut mouse_stream) =
2843                fidl::endpoints::create_request_stream::<fuipointer::MouseSourceV2Marker>();
2844            let (keyboard_proxy, mut keyboard_stream) =
2845                fidl::endpoints::create_sync_proxy_and_stream::<fuiinput::KeyboardMarker>();
2846            let view_ref_pair =
2847                fuchsia_scenic::ViewRefPair::new().expect("Failed to create ViewRefPair");
2848            let (device_registry_proxy, mut device_listener_stream) =
2849                fidl::endpoints::create_sync_proxy_and_stream::<
2850                    fuipolicy::DeviceListenerRegistryMarker,
2851                >();
2852
2853            let (mut relay, _relay_handle) = new_input_relay();
2854            relay.add_touch_device(
2855                DEFAULT_TOUCH_DEVICE_ID,
2856                touch_device.open_files.clone(),
2857                Some(touch_device.inspect_status.clone()),
2858            );
2859            relay.add_keyboard_device(
2860                DEFAULT_KEYBOARD_DEVICE_ID,
2861                keyboard_device.open_files.clone(),
2862                Some(keyboard_device.inspect_status.clone()),
2863            );
2864            relay.add_pending_mouse_device(
2865                kernel.clone(),
2866                mouse_device.clone(),
2867                DEFAULT_MOUSE_DEVICE_ID,
2868            );
2869            relay.start_relays(
2870                &kernel,
2871                StartRelaysArgs {
2872                    event_proxy_mode: EventProxyMode::None,
2873                    touch_source_client_end,
2874                    keyboard_proxy,
2875                    mouse_source_client_end,
2876                    view_ref: view_ref_pair.view_ref,
2877                    registry_proxy: device_registry_proxy,
2878                    device_listener_registry: None,
2879                    display_width: 700,
2880                    display_height: 1200,
2881                },
2882            );
2883
2884            if let Some(Ok(fuiinput::KeyboardRequest::AddListener { responder, .. })) =
2885                keyboard_stream.next().await
2886            {
2887                let _ = responder.send();
2888            }
2889            if let Some(Ok(fuipolicy::DeviceListenerRegistryRequest::RegisterListener {
2890                responder,
2891                ..
2892            })) = device_listener_stream.next().await
2893            {
2894                let _ = responder.send();
2895            }
2896            if let Some(Ok(
2897                fuipolicy::DeviceListenerRegistryRequest::RegisterTouchButtonsListener {
2898                    responder,
2899                    ..
2900                },
2901            )) = device_listener_stream.next().await
2902            {
2903                let _ = responder.send();
2904            }
2905
2906            let mouse_dev_id = starnix_uapi::device_id::DeviceId::new(
2907                starnix_uapi::device_id::INPUT_MAJOR,
2908                DEFAULT_MOUSE_DEVICE_ID,
2909            );
2910            let next_dev_id = starnix_uapi::device_id::DeviceId::new(
2911                starnix_uapi::device_id::INPUT_MAJOR,
2912                DEFAULT_MOUSE_DEVICE_ID + 1,
2913            );
2914
2915            // Before any mouse event occurs, the mouse device should not be registered in
2916            // DeviceRegistry.
2917            assert!(
2918                kernel
2919                    .device_registry
2920                    .list_minor_devices(
2921                        starnix_core::device::DeviceMode::Char,
2922                        mouse_dev_id..next_dev_id,
2923                    )
2924                    .is_empty()
2925            );
2926
2927            // Send an empty/no-op mouse event (wheel delta 0) that produces no uapi input_events.
2928            answer_next_mouse_watch_request(
2929                &mut mouse_stream,
2930                vec![make_mouse_wheel_event(0, DEFAULT_MOUSE_DEVICE_ID)],
2931            )
2932            .await;
2933
2934            // Still should not be registered.
2935            assert!(
2936                kernel
2937                    .device_registry
2938                    .list_minor_devices(
2939                        starnix_core::device::DeviceMode::Char,
2940                        mouse_dev_id..next_dev_id,
2941                    )
2942                    .is_empty()
2943            );
2944
2945            // Send a real mouse event (wheel delta 1) to trigger Pending -> Registered, followed by
2946            // a second real mouse event (wheel delta 1) to synchronize the stream and exercise the
2947            // DeviceRegistration::Registered idempotency path.
2948            answer_next_mouse_watch_request(
2949                &mut mouse_stream,
2950                vec![make_mouse_wheel_event(1, DEFAULT_MOUSE_DEVICE_ID)],
2951            )
2952            .await;
2953            answer_next_mouse_watch_request(
2954                &mut mouse_stream,
2955                vec![make_mouse_wheel_event(1, DEFAULT_MOUSE_DEVICE_ID)],
2956            )
2957            .await;
2958            answer_next_mouse_watch_request(
2959                &mut mouse_stream,
2960                vec![make_mouse_wheel_event(0, DEFAULT_MOUSE_DEVICE_ID)],
2961            )
2962            .await;
2963
2964            // The mouse device should now be registered in DeviceRegistry.
2965            let registered = kernel.device_registry.list_minor_devices(
2966                starnix_core::device::DeviceMode::Char,
2967                mouse_dev_id..next_dev_id,
2968            );
2969            assert_eq!(registered.len(), 1);
2970            assert_eq!(registered[0].0, mouse_dev_id);
2971
2972            // Open the mouse device *after* registration (matching production ordering) and verify
2973            // that the converted events from the pre-open batches were buffered and flushed on
2974            // first open (2 wheel events * 2 uapi events [EV_REL, EV_SYN] each = 4 events).
2975            let mouse_file =
2976                mouse_device.open_test(&current_task).expect("Failed to open mouse file");
2977            let events = read_uapi_events(&mouse_file, &current_task);
2978            assert_eq!(events.len(), 4);
2979        })
2980        .await;
2981    }
2982
2983    #[::fuchsia::test]
2984    async fn events_dropped_and_counted_when_no_default_device_registered() {
2985        spawn_kernel_and_run(async move |current_task| {
2986            let kernel = current_task.kernel().clone();
2987            let (touch_source_client_end, mut touch_source_stream) =
2988                fidl::endpoints::create_request_stream::<fuipointer::TouchSourceV2Marker>();
2989            let (mouse_source_client_end, mut mouse_stream) =
2990                fidl::endpoints::create_request_stream::<fuipointer::MouseSourceV2Marker>();
2991            let (keyboard_proxy, mut keyboard_stream) =
2992                fidl::endpoints::create_sync_proxy_and_stream::<
2993                    fidl_fuchsia_ui_input3::KeyboardMarker,
2994                >();
2995            let view_ref_pair =
2996                fuchsia_scenic::ViewRefPair::new().expect("Failed to create ViewRefPair");
2997            let (device_registry_proxy, mut device_listener_stream) =
2998                fidl::endpoints::create_sync_proxy_and_stream::<
2999                    fuipolicy::DeviceListenerRegistryMarker,
3000                >();
3001
3002            let inspector = fuchsia_inspect::Inspector::default();
3003            let (relay, relay_handle) = new_input_relay();
3004            let relay = relay.with_inspect_node(inspector.root());
3005            relay.start_relays(
3006                &kernel,
3007                StartRelaysArgs {
3008                    event_proxy_mode: EventProxyMode::None,
3009                    touch_source_client_end,
3010                    keyboard_proxy,
3011                    mouse_source_client_end,
3012                    view_ref: view_ref_pair.view_ref,
3013                    registry_proxy: device_registry_proxy,
3014                    device_listener_registry: None,
3015                    display_width: 0,
3016                    display_height: 0,
3017                },
3018            );
3019
3020            let keyboard_listener = match keyboard_stream.next().await {
3021                Some(Ok(fidl_fuchsia_ui_input3::KeyboardRequest::AddListener {
3022                    listener,
3023                    responder,
3024                    ..
3025                })) => {
3026                    let _ = responder.send();
3027                    listener.into_proxy()
3028                }
3029                _ => panic!("Failed to get AddListener event"),
3030            };
3031            let media_buttons_listener = match device_listener_stream.next().await {
3032                Some(Ok(fuipolicy::DeviceListenerRegistryRequest::RegisterListener {
3033                    listener,
3034                    responder,
3035                })) => {
3036                    let _ = responder.send();
3037                    listener.into_proxy()
3038                }
3039                _ => panic!("Failed to get RegisterListener event"),
3040            };
3041            let touch_buttons_listener = match device_listener_stream.next().await {
3042                Some(Ok(
3043                    fuipolicy::DeviceListenerRegistryRequest::RegisterTouchButtonsListener {
3044                        listener,
3045                        responder,
3046                    },
3047                )) => {
3048                    let _ = responder.send();
3049                    listener.into_proxy()
3050                }
3051                _ => panic!("Failed to get RegisterTouchButtonsListener event"),
3052            };
3053
3054            const UNREGISTERED_ID: u32 = 42;
3055
3056            // 1. Key event with unregistered ID and no default keyboard device.
3057            let key_event = fidl_fuchsia_ui_input3::KeyEvent {
3058                timestamp: Some(0),
3059                type_: Some(fidl_fuchsia_ui_input3::KeyEventType::Pressed),
3060                key: Some(fidl_fuchsia_input::Key::A),
3061                device_id: Some(UNREGISTERED_ID),
3062                ..Default::default()
3063            };
3064            let status = keyboard_listener.on_key_event(&key_event).await.unwrap();
3065            assert_eq!(status, KeyEventStatus::NotHandled);
3066            assert_eq!(relay_handle.num_unregistered_device_events(), 1);
3067
3068            // 2. Media button event with unregistered ID and no default keyboard device.
3069            let media_event = MediaButtonsEvent {
3070                volume: Some(0),
3071                power: Some(true),
3072                device_id: Some(UNREGISTERED_ID),
3073                ..Default::default()
3074            };
3075            let _ = media_buttons_listener.on_event(media_event).await;
3076            assert_eq!(relay_handle.num_unregistered_device_events(), 2);
3077
3078            // 3. Touch button event with unregistered ID and no default touch device.
3079            let touch_btn_event = TouchButtonsEvent {
3080                pressed_buttons: Some(vec![TouchButton::Palm]),
3081                device_info: Some(TouchDeviceInfo {
3082                    id: Some(UNREGISTERED_ID),
3083                    ..Default::default()
3084                }),
3085                ..Default::default()
3086            };
3087            let _ = touch_buttons_listener.on_event(touch_btn_event).await;
3088            assert_eq!(relay_handle.num_unregistered_device_events(), 3);
3089
3090            // 4. Touch event with unregistered ID and no default touch device.
3091            answer_next_touch_watch_request(
3092                &mut touch_source_stream,
3093                vec![make_touch_event_with_phase_device_id(EventPhase::Add, 1, UNREGISTERED_ID)],
3094            )
3095            .await;
3096            answer_next_touch_watch_request(&mut touch_source_stream, vec![]).await;
3097            assert_eq!(relay_handle.num_unregistered_device_events(), 4);
3098
3099            // 5. Mouse event with unregistered ID and no default mouse device.
3100            answer_next_mouse_watch_request(
3101                &mut mouse_stream,
3102                vec![make_mouse_wheel_event(1, UNREGISTERED_ID)],
3103            )
3104            .await;
3105            assert_eq!(relay_handle.num_unregistered_device_events(), 5);
3106
3107            assert_data_tree!(inspector, root: contains {
3108                input_events_relay: {
3109                    num_unregistered_device_events: 5u64,
3110                    num_devices: 0u64,
3111                    device_listener_registered: false,
3112                }
3113            });
3114        })
3115        .await;
3116    }
3117}