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::{InputDeviceStatus, InputFile, uinput};
6use fidl::endpoints::{ClientEnd, RequestStream};
7use fidl_fuchsia_ui_input::TouchDeviceInfo;
8use fidl_fuchsia_ui_input3::{
9    KeyEventStatus, KeyboardListenerMarker, KeyboardListenerRequest, KeyboardListenerRequestStream,
10    KeyboardSynchronousProxy,
11};
12use fidl_fuchsia_ui_pointer::{
13    MouseEvent as FidlMouseEvent, TouchEvent as FidlTouchEvent, TouchPointerSample,
14    TouchResponse as FidlTouchResponse, TouchResponseType, {self as fuipointer},
15};
16use fidl_fuchsia_ui_policy as fuipolicy;
17use fidl_fuchsia_ui_views as fuiviews;
18use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender, unbounded};
19use futures::channel::oneshot::{self, Sender};
20use futures::executor::block_on;
21use futures::{FutureExt, StreamExt as _};
22use sorted_vec_map::SortedVecMap;
23use starnix_core::power::{
24    ContainerWakingProxy, ContainerWakingStream, create_proxy_for_wake_events_counter,
25};
26use starnix_core::task::dynamic_thread_spawner::SpawnRequestBuilder;
27use starnix_core::task::{Kernel, LockedAndTask};
28use starnix_logging::{
29    log_warn, trace_duration, trace_duration_begin, trace_duration_end, trace_flow_end,
30};
31use starnix_modules_input_event_conversion::button_fuchsia_to_linux::{
32    new_touch_buttons_bitvec, parse_fidl_media_button_event, parse_fidl_touch_button_event,
33};
34use starnix_modules_input_event_conversion::key_fuchsia_to_linux::parse_fidl_keyboard_event_to_linux_input_event;
35use starnix_modules_input_event_conversion::mouse_fuchsia_to_linux::parse_fidl_mouse_events;
36use starnix_modules_input_event_conversion::touch_fuchsia_to_linux::FuchsiaTouchEventToLinuxTouchEventConverter;
37use starnix_sync::Mutex;
38use starnix_uapi::uapi;
39use std::cell::RefCell;
40use std::collections::VecDeque;
41use std::rc::Rc;
42use std::sync::{Arc, Weak};
43
44const INPUT_RELAY_ROLE_NAME: &str = "fuchsia.starnix.kthread.input_relay";
45
46#[derive(Clone, Copy)]
47pub enum EventProxyMode {
48    /// Don't proxy input events at all.
49    None,
50
51    /// Have the Starnix runner proxy events such that the container
52    /// will wake up if events are received while the container is
53    /// suspended.
54    WakeContainer,
55}
56
57pub type OpenedFiles = Arc<Mutex<Vec<Weak<InputFile>>>>;
58
59pub enum InputDeviceType {
60    Touch(FuchsiaTouchEventToLinuxTouchEventConverter),
61    Keyboard,
62    Mouse,
63}
64
65impl std::fmt::Display for InputDeviceType {
66    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67        match self {
68            InputDeviceType::Touch(_) => write!(f, "touch"),
69            InputDeviceType::Keyboard => write!(f, "keyboard"),
70            InputDeviceType::Mouse => write!(f, "mouse"),
71        }
72    }
73}
74
75pub struct DeviceState {
76    device_type: InputDeviceType,
77    open_files: OpenedFiles,
78    inspect_status: Option<Arc<InputDeviceStatus>>,
79}
80
81pub struct TrackedWakeLease {
82    _lease: fidl::EventPair,
83    device_status: Arc<InputDeviceStatus>,
84}
85
86impl TrackedWakeLease {
87    pub fn new(lease: fidl::EventPair, device_status: Arc<InputDeviceStatus>) -> Self {
88        device_status.increment_active_wake_leases(1);
89        device_status.count_events_with_wake_lease(1);
90        Self { _lease: lease, device_status }
91    }
92}
93
94impl Drop for TrackedWakeLease {
95    fn drop(&mut self) {
96        self.device_status.decrement_active_wake_leases(1);
97    }
98}
99
100pub type DeviceId = u32;
101
102pub const DEFAULT_TOUCH_DEVICE_ID: DeviceId = 0;
103pub const DEFAULT_KEYBOARD_DEVICE_ID: DeviceId = 1;
104pub const DEFAULT_MOUSE_DEVICE_ID: DeviceId = 2;
105
106enum DeviceStateChange {
107    Add(DeviceId, DeviceState, Sender<()>),
108    Remove(DeviceId, Sender<()>),
109}
110
111pub fn new_input_relay() -> (InputEventsRelay, Arc<InputEventsRelayHandle>) {
112    let (sender, receiver) = unbounded();
113
114    (
115        InputEventsRelay { devices: SortedVecMap::new(), receiver },
116        Arc::new(InputEventsRelayHandle { sender }),
117    )
118}
119
120pub struct InputEventsRelayHandle {
121    sender: UnboundedSender<DeviceStateChange>,
122}
123
124impl InputEventsRelayHandle {
125    pub fn add_touch_device(
126        self: &Arc<Self>,
127        device_id: DeviceId,
128        open_files: OpenedFiles,
129        inspect_status: Option<Arc<InputDeviceStatus>>,
130    ) {
131        let (sender, receiver) = oneshot::channel();
132        let _ = self.sender.unbounded_send(DeviceStateChange::Add(
133            device_id,
134            DeviceState {
135                device_type: InputDeviceType::Touch(
136                    FuchsiaTouchEventToLinuxTouchEventConverter::create(),
137                ),
138                open_files,
139                inspect_status,
140            },
141            sender,
142        ));
143        let _ = block_on(receiver);
144    }
145
146    pub fn add_keyboard_device(
147        &self,
148        device_id: DeviceId,
149        open_files: OpenedFiles,
150        inspect_status: Option<Arc<InputDeviceStatus>>,
151    ) {
152        let (sender, receiver) = oneshot::channel();
153        let _ = self.sender.unbounded_send(DeviceStateChange::Add(
154            device_id,
155            DeviceState { device_type: InputDeviceType::Keyboard, open_files, inspect_status },
156            sender,
157        ));
158        let _ = block_on(receiver);
159    }
160
161    pub fn remove_device(&self, device_id: DeviceId) {
162        let (sender, receiver) = oneshot::channel();
163        let _ = self.sender.unbounded_send(DeviceStateChange::Remove(device_id, sender));
164        let _ = block_on(receiver);
165    }
166}
167
168pub struct InputEventsRelay {
169    devices: SortedVecMap<DeviceId, DeviceState>,
170    receiver: UnboundedReceiver<DeviceStateChange>,
171}
172
173impl InputEventsRelay {
174    // TODO(https://fxbug.dev/371602479): Use `fuchsia.ui.SupportedInputDevices` to create
175    // relays.
176    // start_relays will take over the ownership of InputEventsRelay.
177    pub fn start_relays(
178        mut self: Self,
179        kernel: &Kernel,
180        event_proxy_mode: EventProxyMode,
181        touch_source_client_end: ClientEnd<fuipointer::TouchSourceMarker>,
182        keyboard: KeyboardSynchronousProxy,
183        mouse_source_client_end: ClientEnd<fuipointer::MouseSourceMarker>,
184        view_ref: fuiviews::ViewRef,
185        registry_proxy: fuipolicy::DeviceListenerRegistrySynchronousProxy,
186        default_touch_device_opened_files: OpenedFiles,
187        default_keyboard_device_opened_files: OpenedFiles,
188        default_mouse_device_opened_files: OpenedFiles,
189        default_touch_device_inspect: Option<Arc<InputDeviceStatus>>,
190        default_keyboard_device_inspect: Option<Arc<InputDeviceStatus>>,
191        default_mouse_device_inspect: Option<Arc<InputDeviceStatus>>,
192    ) {
193        let f = async move |locked_and_task: LockedAndTask<'_>| {
194            let kernel = locked_and_task.current_task().kernel();
195            // touch
196            let previous_touch_event_disposition: Rc<RefCell<Vec<FidlTouchResponse>>> =
197                Default::default();
198            let touch_waking_fn = |p: &fuipointer::TouchSourceProxy| {
199                p.watch(&previous_touch_event_disposition.borrow_mut())
200            };
201            let (mut default_touch_device, touch_waking_proxy) = setup_touch_relay(
202                kernel,
203                event_proxy_mode,
204                touch_source_client_end,
205                default_touch_device_opened_files,
206                default_touch_device_inspect,
207            );
208            let mut touch_future = touch_waking_proxy.call(touch_waking_fn.clone()).fuse();
209
210            // mouse
211            let (mut default_mouse_device, mouse_waking_proxy) = setup_mouse_relay(
212                kernel,
213                event_proxy_mode,
214                mouse_source_client_end,
215                default_mouse_device_opened_files,
216                default_mouse_device_inspect,
217            );
218            let mut mouse_future =
219                mouse_waking_proxy.call(fuipointer::MouseSourceProxy::watch).fuse();
220
221            // keyboard
222            let (mut default_keyboard_device, mut keyboard_event_stream) = setup_keyboard_relay(
223                keyboard,
224                view_ref,
225                default_keyboard_device_opened_files.clone(),
226                default_keyboard_device_inspect.clone(),
227            );
228
229            // button
230            let (
231                mut default_button_device,
232                mut media_buttons_waking_stream,
233                mut touch_buttons_waking_stream,
234            ) = setup_button_relay(
235                kernel,
236                registry_proxy,
237                event_proxy_mode,
238                default_keyboard_device_opened_files,
239                default_keyboard_device_inspect,
240            );
241            let mut media_buttons_future = media_buttons_waking_stream.next();
242            let mut touch_buttons_future = touch_buttons_waking_stream.next();
243
244            let mut power_was_pressed = false;
245            let mut function_was_pressed = false;
246            let mut touch_buttons_were_pressed = new_touch_buttons_bitvec();
247
248            loop {
249                futures::select! {
250                    touch_future_res = touch_future => {
251                        match touch_future_res {
252                            Ok(touch_events) => {
253                                *previous_touch_event_disposition.borrow_mut() =
254                                    self.process_touch_event(
255                                        &mut default_touch_device,
256                                        touch_events,
257                                    );
258                                touch_future = touch_waking_proxy
259                                    .call(touch_waking_fn.clone())
260                                    .fuse();
261                            }
262                            Err(e) => {
263                                log_warn!(
264                                    "error {:?} reading from TouchSourceProxy; input is stopped",
265                                    e
266                                );
267                            }
268                        }
269                    }
270                    mouse_future_res = mouse_future => {
271                        match mouse_future_res {
272                            Ok(mouse_events) => {
273                                self.process_mouse_event(&mut default_mouse_device, mouse_events);
274                                mouse_future = mouse_waking_proxy
275                                    .call(fuipointer::MouseSourceProxy::watch)
276                                    .fuse();
277                            }
278                            Err(e) => {
279                                log_warn!(
280                                    "error {:?} reading from MouseSourceProxy; input is stopped",
281                                    e
282                                );
283                            }
284                        }
285                    }
286                    media_buttons_res = media_buttons_future => {
287                        match media_buttons_res {
288                            Some(Ok(event)) => {
289                                (power_was_pressed, function_was_pressed) =
290                                    self.process_media_button_event(
291                                        &mut default_button_device,
292                                        event,
293                                        power_was_pressed,
294                                        function_was_pressed,
295                                    );
296                            }
297                            _ => {}
298                        }
299                        media_buttons_future = media_buttons_waking_stream.next();
300                    }
301                    touch_buttons_res = touch_buttons_future => {
302                        match touch_buttons_res {
303                            Some(Ok(event)) => {
304                                touch_buttons_were_pressed = self.process_touch_button_event(
305                                    &mut default_touch_device,
306                                    event,
307                                    &touch_buttons_were_pressed,
308                                );
309                            }
310                            _ => {}
311                        }
312                        touch_buttons_future = touch_buttons_waking_stream.next();
313                    }
314                    e = keyboard_event_stream.next() => {
315                        match e  {
316                            Some(Ok(request)) => {
317                                self.process_keyboard(&mut default_keyboard_device, request);
318                            }
319                            _ => {}
320                        }
321                    }
322                    e = self.receiver.next() => {
323                        match e {
324                            Some(event) => {
325                                match event {
326                                    DeviceStateChange::Add(id, device_state, sender) => {
327                                        self.devices.insert(id, device_state);
328                                        let _ = sender.send(());
329                                    }
330                                    DeviceStateChange::Remove(id, sender) => {
331                                        self.devices.remove(&id);
332                                        let _ = sender.send(());
333                                    }
334                                }
335                            }
336                            _ => {}
337                        }
338                    }
339                    complete => break,
340                }
341            }
342        };
343        let req = SpawnRequestBuilder::new()
344            .with_debug_name("input-event-relay")
345            .with_role(INPUT_RELAY_ROLE_NAME)
346            .with_async_closure(f)
347            .build();
348        kernel.kthreads.spawner().spawn_from_request(req);
349    }
350
351    fn process_touch_event(
352        self: &mut Self,
353        default_touch_device: &mut DeviceState,
354        touch_events: Vec<FidlTouchEvent>,
355    ) -> Vec<FidlTouchResponse> {
356        trace_duration!("input", "starnix_process_touch_event");
357        for e in &touch_events {
358            match e.trace_flow_id {
359                Some(trace_flow_id) => {
360                    trace_flow_end!("input", "dispatch_event_to_client", trace_flow_id.into());
361                }
362                None => {
363                    log_warn!("touch event has not tracing id");
364                }
365            }
366        }
367        let num_received_events: u64 = touch_events.len().try_into().unwrap();
368
369        let previous_event_disposition =
370            touch_events.iter().map(make_response_for_fidl_event).collect();
371
372        let mut num_ignored_events: u64 = 0;
373
374        // 1 vec may contains events from different device.
375        let (events_by_device, ignored_events) = group_touch_events_by_device_id(touch_events);
376        num_ignored_events += ignored_events;
377
378        for (device_id, mut events) in events_by_device {
379            trace_duration_begin!("input", "starnix_process_per_device_touch_event");
380
381            let dev = self.devices.get_mut(&device_id).unwrap_or(default_touch_device);
382
383            let mut num_converted_events: u64 = 0;
384            let mut num_unexpected_events: u64 = 0;
385            let mut new_events: VecDeque<uapi::input_event> = VecDeque::new();
386
387            #[allow(clippy::collection_is_never_read)]
388            let mut tracked_leases = vec![];
389            for event in &mut events {
390                if let Some(lease) = event.wake_lease.take() {
391                    if let Some(status) = &dev.inspect_status {
392                        tracked_leases.push(TrackedWakeLease::new(lease, status.clone()));
393                    }
394                }
395            }
396
397            let last_event_time_ns: i64;
398            if let InputDeviceType::Touch(ref mut converter) = dev.device_type {
399                let mut batch = converter.handle(events);
400                new_events.append(&mut batch.events);
401                num_converted_events += batch.count_converted_fidl_events;
402                num_ignored_events += batch.count_ignored_fidl_events;
403                num_unexpected_events += batch.count_unexpected_fidl_events;
404                last_event_time_ns = batch.last_event_time_ns;
405            } else {
406                trace_duration_end!("input", "starnix_process_per_device_touch_event");
407                log_warn!(
408                    "Non touch device received touch events: device_id = {}, device_type = {}",
409                    device_id,
410                    dev.device_type
411                );
412                continue;
413            }
414
415            if let Some(dev_inspect_status) = &dev.inspect_status {
416                dev_inspect_status.count_total_received_events(num_received_events);
417                dev_inspect_status.count_total_ignored_events(num_ignored_events);
418                dev_inspect_status.count_total_unexpected_events(num_unexpected_events);
419                dev_inspect_status.count_total_converted_events(num_converted_events);
420                dev_inspect_status.count_total_generated_events(
421                    new_events.len().try_into().unwrap(),
422                    last_event_time_ns,
423                );
424            } else {
425                log_warn!(
426                    "unable to record inspect for device_id: {}, device_type: {}",
427                    device_id,
428                    dev.device_type
429                );
430            }
431
432            trace_duration_end!("input", "starnix_process_per_device_touch_event");
433            dev.open_files.lock().retain(|f| {
434                let Some(file) = f.upgrade() else {
435                    log_warn!("Dropping input file for touch that failed to upgrade");
436                    return false;
437                };
438                match &file.inspect_status {
439                    Some(file_inspect_status) => {
440                        file_inspect_status.count_received_events(num_received_events);
441                        file_inspect_status.count_ignored_events(num_ignored_events);
442                        file_inspect_status.count_unexpected_events(num_unexpected_events);
443                        file_inspect_status.count_converted_events(num_converted_events);
444                    }
445                    None => {
446                        log_warn!("unable to record inspect within the input file")
447                    }
448                }
449                if !new_events.is_empty() {
450                    // TODO(https://fxbug.dev/42075438): Reading from an `InputFile` should
451                    // not provide access to events that occurred before the file was
452                    // opened.
453                    if let Some(file_inspect_status) = &file.inspect_status {
454                        file_inspect_status.count_generated_events(
455                            new_events.len().try_into().unwrap(),
456                            last_event_time_ns,
457                        );
458                    }
459                    file.add_events(new_events.clone().into_iter().collect());
460                }
461
462                true
463            });
464        }
465
466        previous_event_disposition
467    }
468
469    fn process_keyboard(
470        self: &mut Self,
471        default_keyboard_device: &mut DeviceState,
472        request: KeyboardListenerRequest,
473    ) {
474        match request {
475            KeyboardListenerRequest::OnKeyEvent { event, responder } => {
476                trace_duration!("input", "starnix_process_keyboard_event");
477
478                let new_events = parse_fidl_keyboard_event_to_linux_input_event(
479                    &event,
480                    uinput::uinput_running(),
481                );
482
483                let dev = match event.device_id {
484                    Some(device_id) => {
485                        self.devices.get_mut(&device_id).unwrap_or(default_keyboard_device)
486                    }
487                    None => default_keyboard_device,
488                };
489
490                dev.open_files.lock().retain(|f| {
491                    let Some(file) = f.upgrade() else {
492                        log_warn!("Dropping input file for keyboard that failed to upgrade");
493                        return false;
494                    };
495                    if !new_events.is_empty() {
496                        file.add_events(new_events.clone().into_iter().collect());
497                    }
498
499                    true
500                });
501
502                responder.send(KeyEventStatus::Handled).expect("");
503            }
504        }
505    }
506
507    fn process_media_button_event(
508        &mut self,
509        default_button_device: &mut DeviceState,
510        button_event: fuipolicy::MediaButtonsListenerRequest,
511        power_was_pressed: bool,
512        function_was_pressed: bool,
513    ) -> (bool, bool) {
514        let mut power_was_pressed_after = false;
515        let mut function_was_pressed_after = false;
516        match button_event {
517            fuipolicy::MediaButtonsListenerRequest::OnEvent { mut event, responder } => {
518                if let Some(trace_flow_id) = event.trace_flow_id {
519                    trace_flow_end!(
520                        "input",
521                        "dispatch_media_buttons_to_listeners",
522                        trace_flow_id.into()
523                    );
524                }
525                trace_duration!("input", "starnix_process_media_button_event");
526
527                let batch =
528                    parse_fidl_media_button_event(&event, power_was_pressed, function_was_pressed);
529
530                power_was_pressed_after = batch.power_is_pressed;
531                function_was_pressed_after = batch.function_is_pressed;
532
533                let (converted_events, ignored_events, generated_events) = match batch.events.len()
534                {
535                    0 => (0u64, 1u64, 0u64),
536                    len => {
537                        if len % 2 == 1 {
538                            log_warn!(
539                                "unexpectedly received {} events: there should always be an even number of non-empty events.",
540                                len
541                            );
542                        }
543                        (1u64, 0u64, len as u64)
544                    }
545                };
546
547                let dev = match event.device_id {
548                    Some(device_id) => {
549                        self.devices.get_mut(&device_id).unwrap_or(default_button_device)
550                    }
551                    None => default_button_device,
552                };
553
554                #[allow(clippy::collection_is_never_read)]
555                let mut tracked_leases = vec![];
556                if let Some(lease) = event.wake_lease.take() {
557                    if let Some(status) = &dev.inspect_status {
558                        tracked_leases.push(TrackedWakeLease::new(lease, status.clone()));
559                    }
560                }
561
562                if let Some(dev_inspect_status) = &dev.inspect_status {
563                    dev_inspect_status.count_total_received_events(1);
564                    dev_inspect_status.count_total_ignored_events(ignored_events);
565                    dev_inspect_status.count_total_converted_events(converted_events);
566                    dev_inspect_status.count_total_generated_events(
567                        generated_events,
568                        batch.event_time.into_nanos().try_into().unwrap(),
569                    );
570                } else {
571                    log_warn!("unable to record inspect for button device");
572                }
573
574                dev.open_files.lock().retain(|f| {
575                    let Some(file) = f.upgrade() else {
576                        log_warn!("Dropping input file for buttons that failed to upgrade");
577                        return false;
578                    };
579                    match &file.inspect_status {
580                        Some(file_inspect_status) => {
581                            file_inspect_status.count_received_events(1);
582                            file_inspect_status.count_ignored_events(ignored_events);
583                            file_inspect_status.count_converted_events(converted_events);
584                        }
585                        None => {
586                            log_warn!("unable to record inspect within the input file")
587                        }
588                    }
589                    if !batch.events.is_empty() {
590                        if let Some(file_inspect_status) = &file.inspect_status {
591                            file_inspect_status.count_generated_events(
592                                generated_events,
593                                batch.event_time.into_nanos().try_into().unwrap(),
594                            );
595                        }
596                        file.add_events(batch.events.clone());
597                    }
598
599                    true
600                });
601
602                responder.send().expect("media buttons responder failed to respond");
603            }
604            _ => { /* Ignore deprecated OnMediaButtonsEvent */ }
605        }
606
607        (power_was_pressed_after, function_was_pressed_after)
608    }
609
610    fn process_touch_button_event(
611        &mut self,
612        default_touch_device: &mut DeviceState,
613        button_event: fuipolicy::TouchButtonsListenerRequest,
614        touch_buttons_were_pressed: &bit_vec::BitVec,
615    ) -> bit_vec::BitVec {
616        trace_duration!("input", "starnix_process_touch_button_event");
617        match button_event {
618            fuipolicy::TouchButtonsListenerRequest::OnEvent { mut event, responder } => {
619                if let Some(trace_flow_id) = event.trace_flow_id {
620                    trace_flow_end!(
621                        "input",
622                        "dispatch_touch_button_to_listeners",
623                        trace_flow_id.into()
624                    );
625                }
626                let batch = parse_fidl_touch_button_event(&event, touch_buttons_were_pressed);
627
628                let (converted_events, ignored_events, generated_events) = match batch.events.len()
629                {
630                    0 => (0u64, 1u64, 0u64),
631                    len => {
632                        if len % 2 == 1 {
633                            log_warn!(
634                                "unexpectedly received {} events: there should always be an even number of non-empty events.",
635                                len
636                            );
637                        }
638                        (1u64, 0u64, len as u64)
639                    }
640                };
641
642                let device_id = match &event.device_info {
643                    Some(TouchDeviceInfo { id: Some(id), .. }) => Some(*id),
644                    _ => None,
645                };
646
647                let dev = match device_id {
648                    Some(id) => self.devices.get_mut(&id).unwrap_or(default_touch_device),
649                    None => default_touch_device,
650                };
651
652                #[allow(clippy::collection_is_never_read)]
653                let mut tracked_leases = vec![];
654                if let Some(lease) = event.wake_lease.take() {
655                    if let Some(status) = &dev.inspect_status {
656                        tracked_leases.push(TrackedWakeLease::new(lease, status.clone()));
657                    }
658                }
659
660                if let Some(dev_inspect_status) = &dev.inspect_status {
661                    dev_inspect_status.count_total_received_events(1);
662                    dev_inspect_status.count_total_ignored_events(ignored_events);
663                    dev_inspect_status.count_total_converted_events(converted_events);
664                    dev_inspect_status.count_total_generated_events(
665                        generated_events,
666                        batch.event_time.into_nanos().try_into().unwrap(),
667                    );
668                } else {
669                    log_warn!("unable to record inspect for touch device");
670                }
671
672                dev.open_files.lock().retain(|f| {
673                    let Some(file) = f.upgrade() else {
674                        log_warn!("Dropping input file for touch that failed to upgrade");
675                        return false;
676                    };
677                    match &file.inspect_status {
678                        Some(file_inspect_status) => {
679                            file_inspect_status.count_received_events(1);
680                            file_inspect_status.count_ignored_events(ignored_events);
681                            file_inspect_status.count_converted_events(converted_events);
682                        }
683                        None => {
684                            log_warn!("unable to record inspect within the input file")
685                        }
686                    }
687                    if !batch.events.is_empty() {
688                        if let Some(file_inspect_status) = &file.inspect_status {
689                            file_inspect_status.count_generated_events(
690                                generated_events,
691                                batch.event_time.into_nanos().try_into().unwrap(),
692                            );
693                        }
694                        file.add_events(batch.events.clone());
695                    }
696
697                    true
698                });
699
700                responder.send().expect("touch buttons responder failed to respond");
701
702                batch.touch_buttons
703            }
704            fuipolicy::TouchButtonsListenerRequest::_UnknownMethod { ordinal, .. } => {
705                log_warn!("Received an unknown method with ordinal {ordinal}");
706                touch_buttons_were_pressed.clone()
707            }
708        }
709    }
710
711    fn process_mouse_event(
712        self: &Self,
713        default_mouse_device: &mut DeviceState,
714        mut mouse_events: Vec<FidlMouseEvent>,
715    ) {
716        let num_received_events: u64 = mouse_events.len().try_into().unwrap();
717        #[allow(clippy::collection_is_never_read)]
718        let mut tracked_leases = vec![];
719        for event in &mut mouse_events {
720            if let Some(lease) = event.wake_lease.take() {
721                if let Some(status) = &default_mouse_device.inspect_status {
722                    tracked_leases.push(TrackedWakeLease::new(lease, status.clone()));
723                }
724            }
725        }
726
727        let batch = parse_fidl_mouse_events(mouse_events);
728
729        if let Some(dev_inspect_status) = &default_mouse_device.inspect_status {
730            dev_inspect_status.count_total_received_events(num_received_events);
731            dev_inspect_status.count_total_ignored_events(batch.count_ignored_events);
732            dev_inspect_status.count_total_unexpected_events(batch.count_unexpected_events);
733            dev_inspect_status.count_total_converted_events(batch.count_converted_events);
734            if !batch.events.is_empty() {
735                dev_inspect_status.count_total_generated_events(
736                    batch.events.len().try_into().unwrap(),
737                    batch.last_event_time_ns.try_into().unwrap(),
738                );
739            }
740        } else {
741            log_warn!("unable to record inspect for mouse device");
742        }
743
744        default_mouse_device.open_files.lock().retain(|f| {
745            let Some(file) = f.upgrade() else {
746                log_warn!("Dropping input file for mouse that failed to upgrade");
747                return false;
748            };
749            match &file.inspect_status {
750                Some(file_inspect_status) => {
751                    file_inspect_status.count_received_events(num_received_events);
752                    file_inspect_status.count_ignored_events(batch.count_ignored_events);
753                    file_inspect_status.count_unexpected_events(batch.count_unexpected_events);
754                    file_inspect_status.count_converted_events(batch.count_converted_events);
755                }
756                None => {
757                    log_warn!("unable to record inspect within the input file")
758                }
759            }
760            if !batch.events.is_empty() {
761                if let Some(file_inspect_status) = &file.inspect_status {
762                    file_inspect_status.count_generated_events(
763                        batch.events.len().try_into().unwrap(),
764                        batch.last_event_time_ns.try_into().unwrap(),
765                    );
766                }
767                file.add_events(batch.events.clone().into_iter().collect());
768            }
769            true
770        });
771    }
772}
773
774fn setup_touch_relay(
775    kernel: &Arc<Kernel>,
776    event_proxy_mode: EventProxyMode,
777    touch_source_client_end: ClientEnd<fuipointer::TouchSourceMarker>,
778    default_touch_device_opened_files: OpenedFiles,
779    device_inspect_status: Option<Arc<InputDeviceStatus>>,
780) -> (DeviceState, ContainerWakingProxy<fuipointer::TouchSourceProxy>) {
781    let touch_counter_name = "touch";
782    let default_touch_device = DeviceState {
783        device_type: InputDeviceType::Touch(FuchsiaTouchEventToLinuxTouchEventConverter::create()),
784        open_files: default_touch_device_opened_files,
785        inspect_status: device_inspect_status,
786    };
787    let (touch_source_proxy, counter) = match event_proxy_mode {
788        EventProxyMode::WakeContainer => {
789            // Proxy the touch events through the Starnix runner. This allows touch events to
790            // wake the container when it is suspended.
791            let (touch_source_channel, counter) = create_proxy_for_wake_events_counter(
792                touch_source_client_end.into_channel(),
793                touch_counter_name.to_string(),
794            );
795            (
796                fuipointer::TouchSourceProxy::new(fidl::AsyncChannel::from_channel(
797                    touch_source_channel,
798                )),
799                Some(counter),
800            )
801        }
802        EventProxyMode::None => (touch_source_client_end.into_proxy(), None),
803    };
804    (
805        default_touch_device,
806        ContainerWakingProxy::new(
807            kernel.suspend_resume_manager.add_message_counter(touch_counter_name, counter),
808            touch_source_proxy,
809        ),
810    )
811}
812
813fn setup_keyboard_relay(
814    keyboard: KeyboardSynchronousProxy,
815    view_ref: fuiviews::ViewRef,
816    default_keyboard_device_opened_files: OpenedFiles,
817    device_inspect_status: Option<Arc<InputDeviceStatus>>,
818) -> (DeviceState, KeyboardListenerRequestStream) {
819    let default_keyboard_device = DeviceState {
820        device_type: InputDeviceType::Keyboard,
821        open_files: default_keyboard_device_opened_files,
822        inspect_status: device_inspect_status,
823    };
824    let (keyboard_listener, event_stream) =
825        fidl::endpoints::create_request_stream::<KeyboardListenerMarker>();
826    if keyboard.add_listener(view_ref, keyboard_listener, zx::MonotonicInstant::INFINITE).is_err() {
827        log_warn!("Could not register keyboard listener");
828    }
829
830    (default_keyboard_device, event_stream)
831}
832
833fn setup_button_relay(
834    kernel: &Arc<Kernel>,
835    registry_proxy: fuipolicy::DeviceListenerRegistrySynchronousProxy,
836    event_proxy_mode: EventProxyMode,
837    default_keyboard_device_opened_files: OpenedFiles,
838    device_inspect_status: Option<Arc<InputDeviceStatus>>,
839) -> (
840    DeviceState,
841    ContainerWakingStream<fuipolicy::MediaButtonsListenerRequestStream>,
842    ContainerWakingStream<fuipolicy::TouchButtonsListenerRequestStream>,
843) {
844    let default_keyboard_device = DeviceState {
845        device_type: InputDeviceType::Keyboard,
846        open_files: default_keyboard_device_opened_files,
847        inspect_status: device_inspect_status,
848    };
849    let media_buttons_name = "media buttons";
850    let touch_buttons_name = "touch buttons";
851
852    let (remote_media_button_client, remote_media_button_server) =
853        fidl::endpoints::create_endpoints::<fuipolicy::MediaButtonsListenerMarker>();
854    if let Err(e) =
855        registry_proxy.register_listener(remote_media_button_client, zx::MonotonicInstant::INFINITE)
856    {
857        log_warn!("Failed to register media buttons listener: {:?}", e);
858    }
859
860    let (remote_touch_button_client, remote_touch_button_server) =
861        fidl::endpoints::create_endpoints::<fuipolicy::TouchButtonsListenerMarker>();
862    if let Err(e) = registry_proxy
863        .register_touch_buttons_listener(remote_touch_button_client, zx::MonotonicInstant::INFINITE)
864    {
865        log_warn!("Failed to register touch buttons listener: {:?}", e);
866    }
867
868    let (
869        local_media_buttons_listener_stream,
870        media_buttons_counter,
871        local_touch_buttons_listener_stream,
872        touch_buttons_counter,
873    ) = match event_proxy_mode {
874        EventProxyMode::WakeContainer => {
875            let (local_media_buttons_channel, media_buttons_counter) =
876                create_proxy_for_wake_events_counter(
877                    remote_media_button_server.into_channel(),
878                    media_buttons_name.to_string(),
879                );
880            let local_media_buttons_listener_stream =
881                fuipolicy::MediaButtonsListenerRequestStream::from_channel(
882                    fidl::AsyncChannel::from_channel(local_media_buttons_channel),
883                );
884
885            let (local_touch_buttons_channel, touch_buttons_counter) =
886                create_proxy_for_wake_events_counter(
887                    remote_touch_button_server.into_channel(),
888                    touch_buttons_name.to_string(),
889                );
890            let local_touch_buttons_listener_stream =
891                fuipolicy::TouchButtonsListenerRequestStream::from_channel(
892                    fidl::AsyncChannel::from_channel(local_touch_buttons_channel),
893                );
894            (
895                local_media_buttons_listener_stream,
896                Some(media_buttons_counter),
897                local_touch_buttons_listener_stream,
898                Some(touch_buttons_counter),
899            )
900        }
901        EventProxyMode::None => (
902            remote_media_button_server.into_stream(),
903            None,
904            remote_touch_button_server.into_stream(),
905            None,
906        ),
907    };
908
909    (
910        default_keyboard_device,
911        ContainerWakingStream::new(
912            kernel
913                .suspend_resume_manager
914                .add_message_counter(media_buttons_name, media_buttons_counter),
915            local_media_buttons_listener_stream,
916        ),
917        ContainerWakingStream::new(
918            kernel
919                .suspend_resume_manager
920                .add_message_counter(touch_buttons_name, touch_buttons_counter),
921            local_touch_buttons_listener_stream,
922        ),
923    )
924}
925
926fn setup_mouse_relay(
927    kernel: &Arc<Kernel>,
928    event_proxy_mode: EventProxyMode,
929    mouse_source_client_end: ClientEnd<fuipointer::MouseSourceMarker>,
930    default_mouse_device_opened_files: OpenedFiles,
931    device_inspect_status: Option<Arc<InputDeviceStatus>>,
932) -> (DeviceState, ContainerWakingProxy<fuipointer::MouseSourceProxy>) {
933    let mouse_counter_name = "mouse";
934    let default_mouse_device = DeviceState {
935        device_type: InputDeviceType::Mouse,
936        open_files: default_mouse_device_opened_files,
937        inspect_status: device_inspect_status,
938    };
939    let (mouse_source_proxy, counter) = match event_proxy_mode {
940        EventProxyMode::WakeContainer => {
941            // Proxy the mouse events through the Starnix runner. This allows mouse events to
942            // wake the container when it is suspended.
943            let (mouse_source_channel, resume_event) = create_proxy_for_wake_events_counter(
944                mouse_source_client_end.into_channel(),
945                "mouse".to_string(),
946            );
947            (
948                fuipointer::MouseSourceProxy::new(fidl::AsyncChannel::from_channel(
949                    mouse_source_channel,
950                )),
951                Some(resume_event),
952            )
953        }
954        EventProxyMode::None => (mouse_source_client_end.into_proxy(), None),
955    };
956
957    (
958        default_mouse_device,
959        ContainerWakingProxy::new(
960            kernel.suspend_resume_manager.add_message_counter(mouse_counter_name, counter),
961            mouse_source_proxy,
962        ),
963    )
964}
965
966/// Returns a FIDL response for `fidl_event`.
967fn make_response_for_fidl_event(fidl_event: &FidlTouchEvent) -> FidlTouchResponse {
968    match fidl_event {
969        FidlTouchEvent { pointer_sample: Some(_), .. } => FidlTouchResponse {
970            response_type: Some(TouchResponseType::Yes), // Event consumed by Starnix.
971            trace_flow_id: fidl_event.trace_flow_id,
972            ..Default::default()
973        },
974        _ => FidlTouchResponse::default(),
975    }
976}
977
978fn group_touch_events_by_device_id(
979    events: Vec<FidlTouchEvent>,
980) -> (SortedVecMap<DeviceId, Vec<FidlTouchEvent>>, u64) {
981    let mut events_by_device: SortedVecMap<u32, Vec<FidlTouchEvent>> = SortedVecMap::new();
982    let mut ignored_events: u64 = 0;
983    for e in events {
984        match e {
985            FidlTouchEvent {
986                pointer_sample: Some(TouchPointerSample { interaction: Some(id), .. }),
987                ..
988            } => {
989                if let Some(vec) = events_by_device.get_mut(&id.device_id) {
990                    vec.push(e);
991                } else {
992                    events_by_device.insert(id.device_id, vec![e]);
993                }
994            }
995            _ => {
996                ignored_events += 1;
997            }
998        }
999    }
1000
1001    (events_by_device, ignored_events)
1002}
1003
1004#[cfg(test)]
1005pub async fn start_input_relays_for_test(
1006    locked: &mut starnix_sync::Locked<starnix_sync::Unlocked>,
1007    current_task: &starnix_core::task::CurrentTask,
1008    event_proxy_mode: EventProxyMode,
1009) -> (
1010    Arc<InputEventsRelayHandle>,
1011    crate::InputDevice,
1012    crate::InputDevice,
1013    crate::InputDevice,
1014    starnix_core::vfs::FileHandle,
1015    starnix_core::vfs::FileHandle,
1016    starnix_core::vfs::FileHandle,
1017    fuipointer::TouchSourceRequestStream,
1018    fuipointer::MouseSourceRequestStream,
1019    fidl_fuchsia_ui_input3::KeyboardListenerProxy,
1020    fuipolicy::MediaButtonsListenerProxy,
1021    fuipolicy::TouchButtonsListenerProxy,
1022) {
1023    let inspector = fuchsia_inspect::Inspector::default();
1024
1025    let touch_device = crate::InputDevice::new_touch(700, 1200, inspector.root());
1026    let touch_file =
1027        touch_device.open_test(locked, current_task).expect("Failed to create input file");
1028
1029    let keyboard_device = crate::InputDevice::new_keyboard(inspector.root());
1030    let keyboard_file =
1031        keyboard_device.open_test(locked, current_task).expect("Failed to create input file");
1032
1033    let mouse_device = crate::InputDevice::new_mouse(inspector.root());
1034    let mouse_file =
1035        mouse_device.open_test(locked, current_task).expect("Failed to create input file");
1036
1037    let (touch_source_client_end, touch_source_stream) =
1038        fidl::endpoints::create_request_stream::<fuipointer::TouchSourceMarker>();
1039    let (mouse_source_client_end, mouse_stream) =
1040        fidl::endpoints::create_request_stream::<fuipointer::MouseSourceMarker>();
1041    let (keyboard_proxy, mut keyboard_stream) =
1042        fidl::endpoints::create_sync_proxy_and_stream::<fidl_fuchsia_ui_input3::KeyboardMarker>();
1043    let view_ref_pair = fuchsia_scenic::ViewRefPair::new().expect("Failed to create ViewRefPair");
1044    let (device_registry_proxy, mut device_listener_stream) =
1045        fidl::endpoints::create_sync_proxy_and_stream::<fuipolicy::DeviceListenerRegistryMarker>();
1046
1047    let (relay, relay_handle) = new_input_relay();
1048    relay.start_relays(
1049        &current_task.kernel(),
1050        event_proxy_mode,
1051        touch_source_client_end,
1052        keyboard_proxy,
1053        mouse_source_client_end,
1054        view_ref_pair.view_ref,
1055        device_registry_proxy,
1056        touch_device.open_files.clone(),
1057        keyboard_device.open_files.clone(),
1058        mouse_device.open_files.clone(),
1059        Some(touch_device.inspect_status.clone()),
1060        Some(keyboard_device.inspect_status.clone()),
1061        Some(mouse_device.inspect_status.clone()),
1062    );
1063
1064    let keyboard_listener = match keyboard_stream.next().await {
1065        Some(Ok(fidl_fuchsia_ui_input3::KeyboardRequest::AddListener {
1066            view_ref: _,
1067            listener,
1068            responder,
1069        })) => {
1070            let _ = responder.send();
1071            listener.into_proxy()
1072        }
1073        _ => {
1074            panic!("Failed to get event");
1075        }
1076    };
1077
1078    let media_buttons_listener = match device_listener_stream.next().await {
1079        Some(Ok(fuipolicy::DeviceListenerRegistryRequest::RegisterListener {
1080            listener,
1081            responder,
1082        })) => {
1083            let _ = responder.send();
1084            listener.into_proxy()
1085        }
1086        _ => {
1087            panic!("Failed to get event");
1088        }
1089    };
1090
1091    let touch_buttons_listener = match device_listener_stream.next().await {
1092        Some(Ok(fuipolicy::DeviceListenerRegistryRequest::RegisterTouchButtonsListener {
1093            listener,
1094            responder,
1095        })) => {
1096            let _ = responder.send();
1097            listener.into_proxy()
1098        }
1099        _ => {
1100            panic!("Failed to get event");
1101        }
1102    };
1103
1104    (
1105        relay_handle,
1106        touch_device,
1107        keyboard_device,
1108        mouse_device,
1109        touch_file,
1110        keyboard_file,
1111        mouse_file,
1112        touch_source_stream,
1113        mouse_stream,
1114        keyboard_listener,
1115        media_buttons_listener,
1116        touch_buttons_listener,
1117    )
1118}
1119
1120#[cfg(test)]
1121mod test {
1122    use super::*;
1123    use anyhow::anyhow;
1124    use fidl_fuchsia_ui_input::{
1125        MediaButtonsEvent, TouchButton, TouchButtonsEvent, TouchDeviceInfo,
1126    };
1127    use fidl_fuchsia_ui_input3 as fuiinput;
1128    use fuipointer::{
1129        EventPhase, MouseEvent, MousePointerSample, TouchEvent, TouchInteractionId,
1130        TouchPointerSample, TouchResponse, TouchSourceRequest, TouchSourceRequestStream,
1131    };
1132    use starnix_core::task::CurrentTask;
1133    #[allow(deprecated, reason = "pre-existing usage")]
1134    use starnix_core::testing::create_kernel_task_and_unlocked;
1135    use starnix_core::vfs::{FileHandle, FileObject, VecOutputBuffer};
1136    use starnix_sync::{FileOpsCore, LockEqualOrBefore, Locked, Unlocked};
1137    use starnix_types::time::timeval_from_time;
1138    use starnix_uapi::errors::{EAGAIN, Errno};
1139    use starnix_uapi::input_id;
1140    use starnix_uapi::open_flags::OpenFlags;
1141    use zerocopy::FromBytes as _;
1142
1143    const INPUT_EVENT_SIZE: usize = std::mem::size_of::<uapi::input_event>();
1144
1145    // Waits for a `Watch()` request to arrive on `request_stream`, and responds with
1146    // `touch_event`. Returns the arguments to the `Watch()` call.
1147    async fn answer_next_touch_watch_request(
1148        request_stream: &mut TouchSourceRequestStream,
1149        touch_events: Vec<TouchEvent>,
1150    ) -> Vec<TouchResponse> {
1151        match request_stream.next().await {
1152            Some(Ok(TouchSourceRequest::Watch { responses, responder })) => {
1153                responder.send(touch_events).expect("failure sending Watch reply");
1154                responses
1155            }
1156            unexpected_request => panic!("unexpected request {:?}", unexpected_request),
1157        }
1158    }
1159
1160    // Waits for a `Watch()` request to arrive on `request_stream`, and responds with
1161    // `mouse_events`.
1162    async fn answer_next_mouse_watch_request(
1163        request_stream: &mut fuipointer::MouseSourceRequestStream,
1164        mouse_events: Vec<MouseEvent>,
1165    ) {
1166        match request_stream.next().await {
1167            Some(Ok(fuipointer::MouseSourceRequest::Watch { responder })) => {
1168                responder.send(mouse_events).expect("failure sending Watch reply");
1169            }
1170            unexpected_request => panic!("unexpected request {:?}", unexpected_request),
1171        }
1172    }
1173
1174    fn make_empty_touch_event(device_id: u32) -> TouchEvent {
1175        TouchEvent {
1176            pointer_sample: Some(TouchPointerSample {
1177                interaction: Some(TouchInteractionId {
1178                    pointer_id: 0,
1179                    device_id,
1180                    interaction_id: 0,
1181                }),
1182                ..Default::default()
1183            }),
1184            ..Default::default()
1185        }
1186    }
1187
1188    fn make_touch_event_with_phase_device_id(
1189        phase: EventPhase,
1190        pointer_id: u32,
1191        device_id: u32,
1192    ) -> TouchEvent {
1193        make_touch_event_with_phase_device_id_position(phase, pointer_id, device_id, 0.0, 0.0)
1194    }
1195
1196    fn make_touch_event_with_phase_device_id_position(
1197        phase: EventPhase,
1198        pointer_id: u32,
1199        device_id: u32,
1200        x: f32,
1201        y: f32,
1202    ) -> TouchEvent {
1203        TouchEvent {
1204            timestamp: Some(0),
1205            pointer_sample: Some(TouchPointerSample {
1206                position_in_viewport: Some([x, y]),
1207                phase: Some(phase),
1208                interaction: Some(TouchInteractionId { pointer_id, device_id, interaction_id: 0 }),
1209                ..Default::default()
1210            }),
1211            ..Default::default()
1212        }
1213    }
1214
1215    fn make_mouse_wheel_event(scroll_v_ticks: i64, device_id: u32) -> MouseEvent {
1216        MouseEvent {
1217            timestamp: Some(0),
1218            pointer_sample: Some(MousePointerSample {
1219                device_id: Some(device_id),
1220                scroll_v: Some(scroll_v_ticks),
1221                ..Default::default()
1222            }),
1223            ..Default::default()
1224        }
1225    }
1226
1227    fn read_uapi_events<L>(
1228        locked: &mut Locked<L>,
1229        file: &FileHandle,
1230        current_task: &CurrentTask,
1231    ) -> Vec<uapi::input_event>
1232    where
1233        L: LockEqualOrBefore<FileOpsCore>,
1234    {
1235        std::iter::from_fn(|| {
1236            let locked = locked.cast_locked::<FileOpsCore>();
1237            let mut event_bytes = VecOutputBuffer::new(INPUT_EVENT_SIZE);
1238            match file.read(locked, current_task, &mut event_bytes) {
1239                Ok(INPUT_EVENT_SIZE) => Some(
1240                    uapi::input_event::read_from_bytes(Vec::from(event_bytes).as_slice())
1241                        .map_err(|_| anyhow!("failed to read input_event from buffer")),
1242                ),
1243                Ok(other_size) => {
1244                    Some(Err(anyhow!("got {} bytes (expected {})", other_size, INPUT_EVENT_SIZE)))
1245                }
1246                Err(Errno { code: EAGAIN, .. }) => None,
1247                Err(other_error) => Some(Err(anyhow!("read failed: {:?}", other_error))),
1248            }
1249        })
1250        .enumerate()
1251        .map(|(i, read_res)| match read_res {
1252            Ok(event) => event,
1253            Err(e) => panic!("unexpected result {:?} on iteration {}", e, i),
1254        })
1255        .collect()
1256    }
1257
1258    fn create_test_touch_device(
1259        locked: &mut Locked<Unlocked>,
1260        current_task: &CurrentTask,
1261        input_relay: Arc<InputEventsRelayHandle>,
1262        device_id: u32,
1263    ) -> FileHandle {
1264        let open_files: OpenedFiles = Arc::new(Mutex::new(vec![]));
1265        input_relay.add_touch_device(device_id, open_files.clone(), None);
1266        let inspector = fuchsia_inspect::Inspector::default();
1267        let device_file = Arc::new(InputFile::new_touch(
1268            input_id { bustype: 0, vendor: 0, product: 0, version: 0 },
1269            1000,
1270            1000,
1271            inspector.root(),
1272        ));
1273        open_files.lock().push(Arc::downgrade(&device_file));
1274
1275        let root_namespace_node = current_task
1276            .lookup_path_from_root(locked, ".".into())
1277            .expect("failed to get namespace node for root");
1278
1279        FileObject::new(
1280            locked,
1281            &current_task,
1282            Box::new(crate::input_file::ArcInputFile(device_file)),
1283            root_namespace_node,
1284            OpenFlags::empty(),
1285        )
1286        .expect("FileObject::new failed")
1287    }
1288
1289    fn make_uapi_input_event(ty: u32, code: u32, value: i32) -> uapi::input_event {
1290        uapi::input_event {
1291            time: timeval_from_time(zx::MonotonicInstant::from_nanos(0)),
1292            type_: ty as u16,
1293            code: code as u16,
1294            value,
1295        }
1296    }
1297
1298    #[::fuchsia::test]
1299    async fn route_touch_event_by_device_id() {
1300        // Set up resources.
1301        #[allow(deprecated, reason = "pre-existing usage")]
1302        let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1303        let (
1304            input_relay,
1305            _touch_device,
1306            _keyboard_device,
1307            _mouse_device,
1308            input_file,
1309            _keyboard_file,
1310            _mouse_file,
1311            mut touch_source_stream,
1312            _mouse_source_stream,
1313            _keyboard_listener,
1314            _media_buttons_listener,
1315            _touch_buttons_listener,
1316        ) = start_input_relays_for_test(locked, &current_task, EventProxyMode::None).await;
1317
1318        const DEVICE_ID: u32 = 10;
1319
1320        answer_next_touch_watch_request(
1321            &mut touch_source_stream,
1322            vec![make_touch_event_with_phase_device_id(EventPhase::Add, 1, DEVICE_ID)],
1323        )
1324        .await;
1325
1326        // Wait for another `Watch` to ensure input_file done processing the first reply.
1327        // Use an empty `TouchEvent`, to minimize the chance that this event creates unexpected
1328        // `uapi::input_event`s.
1329        answer_next_touch_watch_request(
1330            &mut touch_source_stream,
1331            vec![make_empty_touch_event(DEVICE_ID)],
1332        )
1333        .await;
1334
1335        // Consume all of the `uapi::input_event`s that are available.
1336        let events = read_uapi_events(locked, &input_file, &current_task);
1337        // Default device receive events because no matched device.
1338        assert_ne!(events.len(), 0);
1339
1340        // add a device, mock uinput.
1341        let device_id_10_file =
1342            create_test_touch_device(locked, &current_task, input_relay.clone(), DEVICE_ID);
1343
1344        answer_next_touch_watch_request(
1345            &mut touch_source_stream,
1346            vec![make_touch_event_with_phase_device_id(EventPhase::Add, 1, DEVICE_ID)],
1347        )
1348        .await;
1349
1350        answer_next_touch_watch_request(
1351            &mut touch_source_stream,
1352            vec![make_empty_touch_event(DEVICE_ID)],
1353        )
1354        .await;
1355
1356        let events = read_uapi_events(locked, &input_file, &current_task);
1357        // Default device should not receive events because they matched device id 10.
1358        assert_eq!(events.len(), 0);
1359
1360        let events = read_uapi_events(locked, &device_id_10_file, &current_task);
1361        // file of device id 10 should receive events.
1362        assert_ne!(events.len(), 0);
1363    }
1364
1365    #[::fuchsia::test]
1366    async fn route_touch_event_with_wake_lease() {
1367        #[allow(deprecated, reason = "pre-existing usage")]
1368        let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1369        let (
1370            _input_relay,
1371            touch_device,
1372            _keyboard_device,
1373            _mouse_device,
1374            _input_file,
1375            _keyboard_file,
1376            _mouse_file,
1377            mut touch_source_stream,
1378            _mouse_source_stream,
1379            _keyboard_listener,
1380            _media_buttons_listener,
1381            _touch_buttons_listener,
1382        ) = start_input_relays_for_test(locked, &current_task, EventProxyMode::None).await;
1383
1384        const DEVICE_ID: u32 = 10;
1385        let mut event = make_touch_event_with_phase_device_id(EventPhase::Add, 1, DEVICE_ID);
1386        let (p1, _p2) = fidl::EventPair::create();
1387        event.wake_lease = Some(p1);
1388
1389        answer_next_touch_watch_request(&mut touch_source_stream, vec![event]).await;
1390
1391        // Wait for another `Watch` to ensure input_file done processing the first reply.
1392        answer_next_touch_watch_request(
1393            &mut touch_source_stream,
1394            vec![make_empty_touch_event(DEVICE_ID)],
1395        )
1396        .await;
1397
1398        let status = &touch_device.inspect_status;
1399        assert_eq!(
1400            status.total_events_with_wake_lease_count.load(std::sync::atomic::Ordering::Relaxed),
1401            1
1402        );
1403        assert_eq!(status.active_wake_leases_count.load(std::sync::atomic::Ordering::Relaxed), 0);
1404    }
1405
1406    #[::fuchsia::test]
1407    async fn route_touch_event_by_device_id_multi_device_events_in_one_sequence() {
1408        #[allow(deprecated, reason = "pre-existing usage")]
1409        let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1410        let (
1411            input_relay,
1412            _touch_device,
1413            _keyboard_device,
1414            _mouse_device,
1415            _input_file,
1416            _keyboard_file,
1417            _mouse_file,
1418            mut touch_source_stream,
1419            _mouse_source_stream,
1420            _keyboard_listener,
1421            _media_buttons_listener,
1422            _touch_buttons_listener,
1423        ) = start_input_relays_for_test(locked, &current_task, EventProxyMode::None).await;
1424
1425        const DEVICE_ID_10: u32 = 10;
1426        const DEVICE_ID_11: u32 = 11;
1427
1428        let device_id_10_file =
1429            create_test_touch_device(locked, &current_task, input_relay.clone(), DEVICE_ID_10);
1430
1431        let device_id_11_file =
1432            create_test_touch_device(locked, &current_task, input_relay.clone(), DEVICE_ID_11);
1433
1434        // 2 pointer down on different touch device.
1435        answer_next_touch_watch_request(
1436            &mut touch_source_stream,
1437            vec![
1438                make_touch_event_with_phase_device_id_position(
1439                    EventPhase::Add,
1440                    1,
1441                    DEVICE_ID_10,
1442                    10.0,
1443                    20.0,
1444                ),
1445                make_touch_event_with_phase_device_id_position(
1446                    EventPhase::Add,
1447                    2,
1448                    DEVICE_ID_11,
1449                    30.0,
1450                    40.0,
1451                ),
1452            ],
1453        )
1454        .await;
1455
1456        answer_next_touch_watch_request(&mut touch_source_stream, vec![]).await;
1457
1458        let events_10 = read_uapi_events(locked, &device_id_10_file, &current_task);
1459        let events_11 = read_uapi_events(locked, &device_id_11_file, &current_task);
1460        assert_eq!(events_10.len(), events_11.len());
1461
1462        assert_eq!(
1463            events_10,
1464            vec![
1465                make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0),
1466                make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 1),
1467                make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 10),
1468                make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 20),
1469                make_uapi_input_event(uapi::EV_KEY, uapi::BTN_TOUCH, 1),
1470                make_uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0),
1471            ]
1472        );
1473
1474        assert_eq!(
1475            events_11,
1476            vec![
1477                make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0),
1478                make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 2),
1479                make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 30),
1480                make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 40),
1481                make_uapi_input_event(uapi::EV_KEY, uapi::BTN_TOUCH, 1),
1482                make_uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0),
1483            ]
1484        );
1485    }
1486
1487    #[::fuchsia::test]
1488    async fn route_key_event_by_device_id() {
1489        // Set up resources.
1490        #[allow(deprecated, reason = "pre-existing usage")]
1491        let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1492        let (
1493            input_relay,
1494            _touch_device,
1495            _keyboard_device,
1496            _mouse_device,
1497            _touch_file,
1498            keyboard_file,
1499            _mouse_file,
1500            _touch_source_stream,
1501            _mouse_source_stream,
1502            keyboard_listener,
1503            _media_buttons_listener,
1504            _touch_buttons_listener,
1505        ) = start_input_relays_for_test(locked, &current_task, EventProxyMode::None).await;
1506
1507        const DEVICE_ID: u32 = 10;
1508
1509        let key_event = fuiinput::KeyEvent {
1510            timestamp: Some(0),
1511            type_: Some(fuiinput::KeyEventType::Pressed),
1512            key: Some(fidl_fuchsia_input::Key::A),
1513            device_id: Some(DEVICE_ID),
1514            ..Default::default()
1515        };
1516
1517        let _ = keyboard_listener.on_key_event(&key_event).await;
1518
1519        let events = read_uapi_events(locked, &keyboard_file, &current_task);
1520        // Default device should receive events because no device device id is 10.
1521        assert_ne!(events.len(), 0);
1522
1523        // add a device, mock uinput.
1524        let open_files: OpenedFiles = Arc::new(Mutex::new(vec![]));
1525        input_relay.add_keyboard_device(DEVICE_ID, open_files.clone(), None);
1526        let inspector = fuchsia_inspect::Inspector::default();
1527        let device_id_10_file = Arc::new(InputFile::new_keyboard(
1528            input_id { bustype: 0, vendor: 0, product: 0, version: 0 },
1529            inspector.root(),
1530        ));
1531        open_files.lock().push(Arc::downgrade(&device_id_10_file));
1532        let root_namespace_node = current_task
1533            .lookup_path_from_root(locked, ".".into())
1534            .expect("failed to get namespace node for root");
1535        let device_id_10_file_object = FileObject::new(
1536            locked,
1537            &current_task,
1538            Box::new(crate::input_file::ArcInputFile(device_id_10_file)),
1539            root_namespace_node,
1540            OpenFlags::empty(),
1541        )
1542        .expect("FileObject::new failed");
1543
1544        let _ = keyboard_listener.on_key_event(&key_event).await;
1545
1546        let events = read_uapi_events(locked, &keyboard_file, &current_task);
1547        // Default device should not receive events because they matched device id 10.
1548        assert_eq!(events.len(), 0);
1549
1550        let events = read_uapi_events(locked, &device_id_10_file_object, &current_task);
1551        // file of device id 10 should receive events.
1552        assert_ne!(events.len(), 0);
1553
1554        std::mem::drop(keyboard_listener); // Close Zircon channel.
1555    }
1556
1557    #[::fuchsia::test]
1558    async fn route_media_button_event_by_device_id() {
1559        // Set up resources.
1560        #[allow(deprecated, reason = "pre-existing usage")]
1561        let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1562        let (
1563            input_relay,
1564            _touch_device,
1565            _keyboard_device,
1566            _mouse_device,
1567            _touch_file,
1568            keyboard_file,
1569            _mouse_file,
1570            _touch_source_stream,
1571            _mouse_source_stream,
1572            _keyboard_listener,
1573            media_buttons_listener,
1574            _touch_buttons_listener,
1575        ) = start_input_relays_for_test(locked, &current_task, EventProxyMode::None).await;
1576
1577        const DEVICE_ID: u32 = 10;
1578
1579        let power_pressed_event = MediaButtonsEvent {
1580            volume: Some(0),
1581            mic_mute: Some(false),
1582            pause: Some(false),
1583            camera_disable: Some(false),
1584            power: Some(true),
1585            function: Some(false),
1586            device_id: Some(DEVICE_ID),
1587            ..Default::default()
1588        };
1589
1590        let _ = media_buttons_listener.on_event(power_pressed_event).await;
1591
1592        let events = read_uapi_events(locked, &keyboard_file, &current_task);
1593        // Default device should receive events because no device device id is 10.
1594        assert_ne!(events.len(), 0);
1595
1596        // add a device, mock uinput.
1597        let open_files: OpenedFiles = Arc::new(Mutex::new(vec![]));
1598        input_relay.add_keyboard_device(DEVICE_ID, open_files.clone(), None);
1599        let inspector = fuchsia_inspect::Inspector::default();
1600        let device_id_10_file = Arc::new(InputFile::new_keyboard(
1601            input_id { bustype: 0, vendor: 0, product: 0, version: 0 },
1602            inspector.root(),
1603        ));
1604        open_files.lock().push(Arc::downgrade(&device_id_10_file));
1605        let root_namespace_node = current_task
1606            .lookup_path_from_root(locked, ".".into())
1607            .expect("failed to get namespace node for root");
1608        let device_id_10_file_object = FileObject::new(
1609            locked,
1610            &current_task,
1611            Box::new(crate::input_file::ArcInputFile(device_id_10_file)),
1612            root_namespace_node,
1613            OpenFlags::empty(),
1614        )
1615        .expect("FileObject::new failed");
1616
1617        let power_released_event = MediaButtonsEvent {
1618            volume: Some(0),
1619            mic_mute: Some(false),
1620            pause: Some(false),
1621            camera_disable: Some(false),
1622            power: Some(false),
1623            function: Some(false),
1624            device_id: Some(DEVICE_ID),
1625            ..Default::default()
1626        };
1627
1628        let _ = media_buttons_listener.on_event(power_released_event).await;
1629
1630        let events = read_uapi_events(locked, &keyboard_file, &current_task);
1631        // Default device should not receive events because they matched device id 10.
1632        assert_eq!(events.len(), 0);
1633
1634        let events = read_uapi_events(locked, &device_id_10_file_object, &current_task);
1635        // file of device id 10 should receive events.
1636        assert_ne!(events.len(), 0);
1637
1638        std::mem::drop(media_buttons_listener); // Close Zircon channel.
1639    }
1640
1641    #[::fuchsia::test]
1642    async fn route_touch_button_event_by_device_id() {
1643        // Set up resources.
1644        #[allow(deprecated, reason = "pre-existing usage")]
1645        let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1646        let (
1647            input_relay,
1648            _touch_device,
1649            _keyboard_device,
1650            _mouse_device,
1651            touch_file,
1652            _keyboard_file,
1653            _mouse_file,
1654            _touch_source_stream,
1655            _mouse_source_stream,
1656            _keyboard_listener,
1657            _media_buttons_listener,
1658            touch_buttons_listener,
1659        ) = start_input_relays_for_test(locked, &current_task, EventProxyMode::None).await;
1660
1661        const DEVICE_ID: u32 = 10;
1662
1663        let palm_pressed_event: TouchButtonsEvent = TouchButtonsEvent {
1664            pressed_buttons: Some(vec![TouchButton::Palm]),
1665            device_info: Some(TouchDeviceInfo { id: Some(DEVICE_ID), ..Default::default() }),
1666            ..Default::default()
1667        };
1668
1669        let _ = touch_buttons_listener.on_event(palm_pressed_event).await;
1670
1671        let events = read_uapi_events(locked, &touch_file, &current_task);
1672        // Default device should receive events because no device device id is 10.
1673        assert_ne!(events.len(), 0);
1674
1675        // add a device, mock uinput.
1676        let open_files: OpenedFiles = Arc::new(Mutex::new(vec![]));
1677        input_relay.add_touch_device(DEVICE_ID, open_files.clone(), None);
1678        let device_id_10_file =
1679            create_test_touch_device(locked, &current_task, input_relay.clone(), DEVICE_ID);
1680
1681        let palm_released_event: TouchButtonsEvent = TouchButtonsEvent {
1682            pressed_buttons: Some(vec![]),
1683            device_info: Some(TouchDeviceInfo { id: Some(DEVICE_ID), ..Default::default() }),
1684            ..Default::default()
1685        };
1686
1687        let _ = touch_buttons_listener.on_event(palm_released_event).await;
1688
1689        let events = read_uapi_events(locked, &touch_file, &current_task);
1690        // Default device should not receive events because they matched device id 10.
1691        assert_eq!(events.len(), 0);
1692
1693        let events = read_uapi_events(locked, &device_id_10_file, &current_task);
1694        // file of device id 10 should receive events.
1695        assert_ne!(events.len(), 0);
1696
1697        std::mem::drop(touch_buttons_listener); // Close Zircon channel.
1698    }
1699
1700    #[::fuchsia::test]
1701    async fn touch_device_multi_reader() {
1702        // Set up resources.
1703        #[allow(deprecated, reason = "pre-existing usage")]
1704        let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1705        let (
1706            _input_relay,
1707            touch_device,
1708            _keyboard_device,
1709            _mouse_device,
1710            touch_reader1,
1711            _keyboard_file,
1712            _mouse_file,
1713            mut touch_source_stream,
1714            _mouse_source_stream,
1715            _keyboard_listener,
1716            _media_buttons_listener,
1717            _touch_buttons_listener,
1718        ) = start_input_relays_for_test(locked, &current_task, EventProxyMode::None).await;
1719
1720        let touch_reader2 =
1721            touch_device.open_test(locked, &current_task).expect("Failed to create input file");
1722
1723        const DEVICE_ID: u32 = 10;
1724
1725        answer_next_touch_watch_request(
1726            &mut touch_source_stream,
1727            vec![make_touch_event_with_phase_device_id(EventPhase::Add, 1, DEVICE_ID)],
1728        )
1729        .await;
1730
1731        // Wait for another `Watch` to ensure input_file done processing the first reply.
1732        // Use an empty `TouchEvent`, to minimize the chance that this event creates unexpected
1733        // `uapi::input_event`s.
1734        answer_next_touch_watch_request(
1735            &mut touch_source_stream,
1736            vec![make_empty_touch_event(DEVICE_ID)],
1737        )
1738        .await;
1739
1740        // Consume all of the `uapi::input_event`s that are available.
1741        let events_from_reader1 = read_uapi_events(locked, &touch_reader1, &current_task);
1742        let events_from_reader2 = read_uapi_events(locked, &touch_reader2, &current_task);
1743        assert_ne!(events_from_reader1.len(), 0);
1744        assert_eq!(events_from_reader1.len(), events_from_reader2.len());
1745    }
1746
1747    #[::fuchsia::test]
1748    async fn keyboard_device_multi_reader() {
1749        // Set up resources.
1750        #[allow(deprecated, reason = "pre-existing usage")]
1751        let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1752        let (
1753            _input_relay,
1754            _touch_device,
1755            keyboard_device,
1756            _mouse_device,
1757            _touch_file,
1758            keyboard_reader1,
1759            _mouse_file,
1760            _touch_source_stream,
1761            _mouse_source_stream,
1762            keyboard_listener,
1763            _media_buttons_listener,
1764            _touch_buttons_listener,
1765        ) = start_input_relays_for_test(locked, &current_task, EventProxyMode::None).await;
1766
1767        let keyboard_reader2 =
1768            keyboard_device.open_test(locked, &current_task).expect("Failed to create input file");
1769
1770        const DEVICE_ID: u32 = 10;
1771
1772        let key_event = fuiinput::KeyEvent {
1773            timestamp: Some(0),
1774            type_: Some(fuiinput::KeyEventType::Pressed),
1775            key: Some(fidl_fuchsia_input::Key::A),
1776            device_id: Some(DEVICE_ID),
1777            ..Default::default()
1778        };
1779
1780        let _ = keyboard_listener.on_key_event(&key_event).await;
1781
1782        // Consume all of the `uapi::input_event`s that are available.
1783        let events_from_reader1 = read_uapi_events(locked, &keyboard_reader1, &current_task);
1784        let events_from_reader2 = read_uapi_events(locked, &keyboard_reader2, &current_task);
1785        assert_ne!(events_from_reader1.len(), 0);
1786        assert_eq!(events_from_reader1.len(), events_from_reader2.len());
1787    }
1788
1789    #[::fuchsia::test]
1790    async fn button_device_multi_reader() {
1791        // Set up resources.
1792        #[allow(deprecated, reason = "pre-existing usage")]
1793        let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1794        let (
1795            _input_relay,
1796            _touch_device,
1797            keyboard_device,
1798            _mouse_device,
1799            _touch_file,
1800            keyboard_reader1,
1801            _mouse_file,
1802            _touch_source_stream,
1803            _mouse_source_stream,
1804            _keyboard_listener,
1805            media_buttons_listener,
1806            _touch_buttons_listener,
1807        ) = start_input_relays_for_test(locked, &current_task, EventProxyMode::None).await;
1808
1809        let keyboard_reader2 =
1810            keyboard_device.open_test(locked, &current_task).expect("Failed to create input file");
1811
1812        const DEVICE_ID: u32 = 10;
1813
1814        let power_pressed_event = MediaButtonsEvent {
1815            volume: Some(0),
1816            mic_mute: Some(false),
1817            pause: Some(false),
1818            camera_disable: Some(false),
1819            power: Some(true),
1820            function: Some(false),
1821            device_id: Some(DEVICE_ID),
1822            ..Default::default()
1823        };
1824
1825        let _ = media_buttons_listener.on_event(power_pressed_event).await;
1826
1827        // Consume all of the `uapi::input_event`s that are available.
1828        let events_from_reader1 = read_uapi_events(locked, &keyboard_reader1, &current_task);
1829        let events_from_reader2 = read_uapi_events(locked, &keyboard_reader2, &current_task);
1830        assert_ne!(events_from_reader1.len(), 0);
1831        assert_eq!(events_from_reader1.len(), events_from_reader2.len());
1832    }
1833
1834    #[::fuchsia::test]
1835    async fn mouse_device_multi_reader() {
1836        // Set up resources.
1837        #[allow(deprecated, reason = "pre-existing usage")]
1838        let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1839        let (
1840            _input_relay,
1841            _touch_device,
1842            _keyboard_device,
1843            mouse_device,
1844            _touch_file,
1845            _keyboard_file,
1846            mouse_reader1,
1847            _touch_stream,
1848            mut mouse_stream,
1849            _keyboard_listener,
1850            _media_buttons_listener,
1851            _touch_buttons_listener,
1852        ) = start_input_relays_for_test(locked, &current_task, EventProxyMode::None).await;
1853
1854        let mouse_reader2 =
1855            mouse_device.open_test(locked, &current_task).expect("Failed to create input file");
1856
1857        const DEVICE_ID: u32 = 10;
1858
1859        answer_next_mouse_watch_request(
1860            &mut mouse_stream,
1861            vec![make_mouse_wheel_event(1, DEVICE_ID)],
1862        )
1863        .await;
1864
1865        // Wait for another `Watch` to ensure input_file done processing the first reply.
1866        // Use an empty `MouseEvent`, to minimize the chance that this event creates unexpected
1867        // `uapi::input_event`s.
1868        answer_next_mouse_watch_request(
1869            &mut mouse_stream,
1870            vec![make_mouse_wheel_event(0, DEVICE_ID)],
1871        )
1872        .await;
1873
1874        // Consume all of the `uapi::input_event`s that are available.
1875        let events_from_reader1 = read_uapi_events(locked, &mouse_reader1, &current_task);
1876        let events_from_reader2 = read_uapi_events(locked, &mouse_reader2, &current_task);
1877        assert_ne!(events_from_reader1.len(), 0);
1878        assert_eq!(events_from_reader1.len(), events_from_reader2.len());
1879    }
1880
1881    #[::fuchsia::test]
1882    async fn input_message_counters() {
1883        // Set up resources.
1884        #[allow(deprecated, reason = "pre-existing usage")]
1885        let (kernel, current_task, locked) = create_kernel_task_and_unlocked();
1886        let (
1887            _input_relay,
1888            _touch_device,
1889            _keyboard_device,
1890            _mouse_device,
1891            _touch_file,
1892            keyboard_file,
1893            _mouse_file,
1894            _touch_source_stream,
1895            _mouse_source_stream,
1896            keyboard_listener,
1897            _media_buttons_listener,
1898            _touch_buttons_listener,
1899        ) = start_input_relays_for_test(locked, &current_task, EventProxyMode::WakeContainer).await;
1900
1901        const DEVICE_ID: u32 = 10;
1902
1903        let key_event = fuiinput::KeyEvent {
1904            timestamp: Some(0),
1905            type_: Some(fuiinput::KeyEventType::Pressed),
1906            key: Some(fidl_fuchsia_input::Key::A),
1907            device_id: Some(DEVICE_ID),
1908            ..Default::default()
1909        };
1910
1911        let _ = keyboard_listener.on_key_event(&key_event).await;
1912
1913        let events = read_uapi_events(locked, &keyboard_file, &current_task);
1914        assert_ne!(events.len(), 0);
1915
1916        assert!(!kernel.suspend_resume_manager.has_nonzero_message_counter());
1917    }
1918}