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, MousePointerSample, TouchEvent as FidlTouchEvent,
14    TouchPointerSample, TouchResponse as FidlTouchResponse, TouchResponseType,
15    {self as fuipointer},
16};
17use fidl_fuchsia_ui_policy as fuipolicy;
18use fidl_fuchsia_ui_views as fuiviews;
19use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender, unbounded};
20use futures::channel::oneshot::{self, Sender};
21use futures::executor::block_on;
22use futures::{FutureExt, StreamExt as _};
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::touch_fuchsia_to_linux::FuchsiaTouchEventToLinuxTouchEventConverter;
36use starnix_sync::Mutex;
37use starnix_types::time::timeval_from_time;
38use starnix_uapi::uapi;
39use std::cell::RefCell;
40use std::collections::{HashMap, 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: HashMap::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: HashMap<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        mouse_events: Vec<FidlMouseEvent>,
715    ) {
716        let num_received_events: u64 = mouse_events.len().try_into().unwrap();
717        let mut num_ignored_events: u64 = 0;
718        let mut num_converted_events: u64 = 0;
719        let mut num_unexpected_events: u64 = 0;
720        let mut new_events: VecDeque<uapi::input_event> = VecDeque::new();
721        let mut last_event_time_ns = zx::MonotonicInstant::get();
722        #[allow(clippy::collection_is_never_read)]
723        let mut tracked_leases = vec![];
724        for mut event in mouse_events {
725            if let Some(lease) = event.wake_lease.take() {
726                if let Some(status) = &default_mouse_device.inspect_status {
727                    tracked_leases.push(TrackedWakeLease::new(lease, status.clone()));
728                }
729            }
730            match event {
731                FidlMouseEvent {
732                    timestamp: Some(time),
733                    pointer_sample: Some(MousePointerSample { scroll_v: Some(ticks), .. }),
734                    ..
735                } => {
736                    last_event_time_ns = zx::MonotonicInstant::from_nanos(time);
737                    // Ensure this is a mouse wheel event with delta, otherwise ignore.
738                    if ticks != 0 {
739                        new_events.push_back(uapi::input_event {
740                            time: timeval_from_time(last_event_time_ns),
741                            type_: uapi::EV_REL as u16,
742                            code: uapi::REL_WHEEL as u16,
743                            value: ticks as i32,
744                        });
745                        num_converted_events += 1;
746                    } else {
747                        num_ignored_events += 1;
748                    }
749                }
750                _ => {
751                    num_unexpected_events += 1;
752                }
753            }
754        }
755        if new_events.len() > 0 {
756            new_events.push_back(uapi::input_event {
757                // See https://www.kernel.org/doc/Documentation/input/event-codes.rst.
758                time: timeval_from_time(last_event_time_ns),
759                type_: uapi::EV_SYN as u16,
760                code: uapi::SYN_REPORT as u16,
761                value: 0,
762            });
763        }
764
765        if let Some(dev_inspect_status) = &default_mouse_device.inspect_status {
766            dev_inspect_status.count_total_received_events(num_received_events);
767            dev_inspect_status.count_total_ignored_events(num_ignored_events);
768            dev_inspect_status.count_total_unexpected_events(num_unexpected_events);
769            dev_inspect_status.count_total_converted_events(num_converted_events);
770            if !new_events.is_empty() {
771                dev_inspect_status.count_total_generated_events(
772                    new_events.len().try_into().unwrap(),
773                    last_event_time_ns.into_nanos().try_into().unwrap(),
774                );
775            }
776        } else {
777            log_warn!("unable to record inspect for mouse device");
778        }
779
780        default_mouse_device.open_files.lock().retain(|f| {
781            let Some(file) = f.upgrade() else {
782                log_warn!("Dropping input file for mouse that failed to upgrade");
783                return false;
784            };
785            match &file.inspect_status {
786                Some(file_inspect_status) => {
787                    file_inspect_status.count_received_events(num_received_events);
788                    file_inspect_status.count_ignored_events(num_ignored_events);
789                    file_inspect_status.count_unexpected_events(num_unexpected_events);
790                    file_inspect_status.count_converted_events(num_converted_events);
791                }
792                None => {
793                    log_warn!("unable to record inspect within the input file")
794                }
795            }
796            if !new_events.is_empty() {
797                if let Some(file_inspect_status) = &file.inspect_status {
798                    file_inspect_status.count_generated_events(
799                        new_events.len().try_into().unwrap(),
800                        last_event_time_ns.into_nanos().try_into().unwrap(),
801                    );
802                }
803                file.add_events(new_events.clone().into_iter().collect());
804            }
805            true
806        });
807    }
808}
809
810fn setup_touch_relay(
811    kernel: &Arc<Kernel>,
812    event_proxy_mode: EventProxyMode,
813    touch_source_client_end: ClientEnd<fuipointer::TouchSourceMarker>,
814    default_touch_device_opened_files: OpenedFiles,
815    device_inspect_status: Option<Arc<InputDeviceStatus>>,
816) -> (DeviceState, ContainerWakingProxy<fuipointer::TouchSourceProxy>) {
817    let touch_counter_name = "touch";
818    let default_touch_device = DeviceState {
819        device_type: InputDeviceType::Touch(FuchsiaTouchEventToLinuxTouchEventConverter::create()),
820        open_files: default_touch_device_opened_files,
821        inspect_status: device_inspect_status,
822    };
823    let (touch_source_proxy, counter) = match event_proxy_mode {
824        EventProxyMode::WakeContainer => {
825            // Proxy the touch events through the Starnix runner. This allows touch events to
826            // wake the container when it is suspended.
827            let (touch_source_channel, counter) = create_proxy_for_wake_events_counter(
828                touch_source_client_end.into_channel(),
829                touch_counter_name.to_string(),
830            );
831            (
832                fuipointer::TouchSourceProxy::new(fidl::AsyncChannel::from_channel(
833                    touch_source_channel,
834                )),
835                Some(counter),
836            )
837        }
838        EventProxyMode::None => (touch_source_client_end.into_proxy(), None),
839    };
840    (
841        default_touch_device,
842        ContainerWakingProxy::new(
843            kernel.suspend_resume_manager.add_message_counter(touch_counter_name, counter),
844            touch_source_proxy,
845        ),
846    )
847}
848
849fn setup_keyboard_relay(
850    keyboard: KeyboardSynchronousProxy,
851    view_ref: fuiviews::ViewRef,
852    default_keyboard_device_opened_files: OpenedFiles,
853    device_inspect_status: Option<Arc<InputDeviceStatus>>,
854) -> (DeviceState, KeyboardListenerRequestStream) {
855    let default_keyboard_device = DeviceState {
856        device_type: InputDeviceType::Keyboard,
857        open_files: default_keyboard_device_opened_files,
858        inspect_status: device_inspect_status,
859    };
860    let (keyboard_listener, event_stream) =
861        fidl::endpoints::create_request_stream::<KeyboardListenerMarker>();
862    if keyboard.add_listener(view_ref, keyboard_listener, zx::MonotonicInstant::INFINITE).is_err() {
863        log_warn!("Could not register keyboard listener");
864    }
865
866    (default_keyboard_device, event_stream)
867}
868
869fn setup_button_relay(
870    kernel: &Arc<Kernel>,
871    registry_proxy: fuipolicy::DeviceListenerRegistrySynchronousProxy,
872    event_proxy_mode: EventProxyMode,
873    default_keyboard_device_opened_files: OpenedFiles,
874    device_inspect_status: Option<Arc<InputDeviceStatus>>,
875) -> (
876    DeviceState,
877    ContainerWakingStream<fuipolicy::MediaButtonsListenerRequestStream>,
878    ContainerWakingStream<fuipolicy::TouchButtonsListenerRequestStream>,
879) {
880    let default_keyboard_device = DeviceState {
881        device_type: InputDeviceType::Keyboard,
882        open_files: default_keyboard_device_opened_files,
883        inspect_status: device_inspect_status,
884    };
885    let media_buttons_name = "media buttons";
886    let touch_buttons_name = "touch buttons";
887
888    let (remote_media_button_client, remote_media_button_server) =
889        fidl::endpoints::create_endpoints::<fuipolicy::MediaButtonsListenerMarker>();
890    if let Err(e) =
891        registry_proxy.register_listener(remote_media_button_client, zx::MonotonicInstant::INFINITE)
892    {
893        log_warn!("Failed to register media buttons listener: {:?}", e);
894    }
895
896    let (remote_touch_button_client, remote_touch_button_server) =
897        fidl::endpoints::create_endpoints::<fuipolicy::TouchButtonsListenerMarker>();
898    if let Err(e) = registry_proxy
899        .register_touch_buttons_listener(remote_touch_button_client, zx::MonotonicInstant::INFINITE)
900    {
901        log_warn!("Failed to register touch buttons listener: {:?}", e);
902    }
903
904    let (
905        local_media_buttons_listener_stream,
906        media_buttons_counter,
907        local_touch_buttons_listener_stream,
908        touch_buttons_counter,
909    ) = match event_proxy_mode {
910        EventProxyMode::WakeContainer => {
911            let (local_media_buttons_channel, media_buttons_counter) =
912                create_proxy_for_wake_events_counter(
913                    remote_media_button_server.into_channel(),
914                    media_buttons_name.to_string(),
915                );
916            let local_media_buttons_listener_stream =
917                fuipolicy::MediaButtonsListenerRequestStream::from_channel(
918                    fidl::AsyncChannel::from_channel(local_media_buttons_channel),
919                );
920
921            let (local_touch_buttons_channel, touch_buttons_counter) =
922                create_proxy_for_wake_events_counter(
923                    remote_touch_button_server.into_channel(),
924                    touch_buttons_name.to_string(),
925                );
926            let local_touch_buttons_listener_stream =
927                fuipolicy::TouchButtonsListenerRequestStream::from_channel(
928                    fidl::AsyncChannel::from_channel(local_touch_buttons_channel),
929                );
930            (
931                local_media_buttons_listener_stream,
932                Some(media_buttons_counter),
933                local_touch_buttons_listener_stream,
934                Some(touch_buttons_counter),
935            )
936        }
937        EventProxyMode::None => (
938            remote_media_button_server.into_stream(),
939            None,
940            remote_touch_button_server.into_stream(),
941            None,
942        ),
943    };
944
945    (
946        default_keyboard_device,
947        ContainerWakingStream::new(
948            kernel
949                .suspend_resume_manager
950                .add_message_counter(media_buttons_name, media_buttons_counter),
951            local_media_buttons_listener_stream,
952        ),
953        ContainerWakingStream::new(
954            kernel
955                .suspend_resume_manager
956                .add_message_counter(touch_buttons_name, touch_buttons_counter),
957            local_touch_buttons_listener_stream,
958        ),
959    )
960}
961
962fn setup_mouse_relay(
963    kernel: &Arc<Kernel>,
964    event_proxy_mode: EventProxyMode,
965    mouse_source_client_end: ClientEnd<fuipointer::MouseSourceMarker>,
966    default_mouse_device_opened_files: OpenedFiles,
967    device_inspect_status: Option<Arc<InputDeviceStatus>>,
968) -> (DeviceState, ContainerWakingProxy<fuipointer::MouseSourceProxy>) {
969    let mouse_counter_name = "mouse";
970    let default_mouse_device = DeviceState {
971        device_type: InputDeviceType::Mouse,
972        open_files: default_mouse_device_opened_files,
973        inspect_status: device_inspect_status,
974    };
975    let (mouse_source_proxy, counter) = match event_proxy_mode {
976        EventProxyMode::WakeContainer => {
977            // Proxy the mouse events through the Starnix runner. This allows mouse events to
978            // wake the container when it is suspended.
979            let (mouse_source_channel, resume_event) = create_proxy_for_wake_events_counter(
980                mouse_source_client_end.into_channel(),
981                "mouse".to_string(),
982            );
983            (
984                fuipointer::MouseSourceProxy::new(fidl::AsyncChannel::from_channel(
985                    mouse_source_channel,
986                )),
987                Some(resume_event),
988            )
989        }
990        EventProxyMode::None => (mouse_source_client_end.into_proxy(), None),
991    };
992
993    (
994        default_mouse_device,
995        ContainerWakingProxy::new(
996            kernel.suspend_resume_manager.add_message_counter(mouse_counter_name, counter),
997            mouse_source_proxy,
998        ),
999    )
1000}
1001
1002/// Returns a FIDL response for `fidl_event`.
1003fn make_response_for_fidl_event(fidl_event: &FidlTouchEvent) -> FidlTouchResponse {
1004    match fidl_event {
1005        FidlTouchEvent { pointer_sample: Some(_), .. } => FidlTouchResponse {
1006            response_type: Some(TouchResponseType::Yes), // Event consumed by Starnix.
1007            trace_flow_id: fidl_event.trace_flow_id,
1008            ..Default::default()
1009        },
1010        _ => FidlTouchResponse::default(),
1011    }
1012}
1013
1014fn group_touch_events_by_device_id(
1015    events: Vec<FidlTouchEvent>,
1016) -> (HashMap<DeviceId, Vec<FidlTouchEvent>>, u64) {
1017    let mut events_by_device: HashMap<u32, Vec<FidlTouchEvent>> = HashMap::new();
1018    let mut ignored_events: u64 = 0;
1019    for e in events {
1020        match e {
1021            FidlTouchEvent {
1022                pointer_sample: Some(TouchPointerSample { interaction: Some(id), .. }),
1023                ..
1024            } => {
1025                events_by_device.entry(id.device_id).or_default().push(e);
1026            }
1027            _ => {
1028                ignored_events += 1;
1029            }
1030        }
1031    }
1032
1033    (events_by_device, ignored_events)
1034}
1035
1036#[cfg(test)]
1037pub async fn start_input_relays_for_test(
1038    locked: &mut starnix_sync::Locked<starnix_sync::Unlocked>,
1039    current_task: &starnix_core::task::CurrentTask,
1040    event_proxy_mode: EventProxyMode,
1041) -> (
1042    Arc<InputEventsRelayHandle>,
1043    crate::InputDevice,
1044    crate::InputDevice,
1045    crate::InputDevice,
1046    starnix_core::vfs::FileHandle,
1047    starnix_core::vfs::FileHandle,
1048    starnix_core::vfs::FileHandle,
1049    fuipointer::TouchSourceRequestStream,
1050    fuipointer::MouseSourceRequestStream,
1051    fidl_fuchsia_ui_input3::KeyboardListenerProxy,
1052    fuipolicy::MediaButtonsListenerProxy,
1053    fuipolicy::TouchButtonsListenerProxy,
1054) {
1055    let inspector = fuchsia_inspect::Inspector::default();
1056
1057    let touch_device = crate::InputDevice::new_touch(700, 1200, inspector.root());
1058    let touch_file =
1059        touch_device.open_test(locked, current_task).expect("Failed to create input file");
1060
1061    let keyboard_device = crate::InputDevice::new_keyboard(inspector.root());
1062    let keyboard_file =
1063        keyboard_device.open_test(locked, current_task).expect("Failed to create input file");
1064
1065    let mouse_device = crate::InputDevice::new_mouse(inspector.root());
1066    let mouse_file =
1067        mouse_device.open_test(locked, current_task).expect("Failed to create input file");
1068
1069    let (touch_source_client_end, touch_source_stream) =
1070        fidl::endpoints::create_request_stream::<fuipointer::TouchSourceMarker>();
1071    let (mouse_source_client_end, mouse_stream) =
1072        fidl::endpoints::create_request_stream::<fuipointer::MouseSourceMarker>();
1073    let (keyboard_proxy, mut keyboard_stream) =
1074        fidl::endpoints::create_sync_proxy_and_stream::<fidl_fuchsia_ui_input3::KeyboardMarker>();
1075    let view_ref_pair = fuchsia_scenic::ViewRefPair::new().expect("Failed to create ViewRefPair");
1076    let (device_registry_proxy, mut device_listener_stream) =
1077        fidl::endpoints::create_sync_proxy_and_stream::<fuipolicy::DeviceListenerRegistryMarker>();
1078
1079    let (relay, relay_handle) = new_input_relay();
1080    relay.start_relays(
1081        &current_task.kernel(),
1082        event_proxy_mode,
1083        touch_source_client_end,
1084        keyboard_proxy,
1085        mouse_source_client_end,
1086        view_ref_pair.view_ref,
1087        device_registry_proxy,
1088        touch_device.open_files.clone(),
1089        keyboard_device.open_files.clone(),
1090        mouse_device.open_files.clone(),
1091        Some(touch_device.inspect_status.clone()),
1092        Some(keyboard_device.inspect_status.clone()),
1093        Some(mouse_device.inspect_status.clone()),
1094    );
1095
1096    let keyboard_listener = match keyboard_stream.next().await {
1097        Some(Ok(fidl_fuchsia_ui_input3::KeyboardRequest::AddListener {
1098            view_ref: _,
1099            listener,
1100            responder,
1101        })) => {
1102            let _ = responder.send();
1103            listener.into_proxy()
1104        }
1105        _ => {
1106            panic!("Failed to get event");
1107        }
1108    };
1109
1110    let media_buttons_listener = match device_listener_stream.next().await {
1111        Some(Ok(fuipolicy::DeviceListenerRegistryRequest::RegisterListener {
1112            listener,
1113            responder,
1114        })) => {
1115            let _ = responder.send();
1116            listener.into_proxy()
1117        }
1118        _ => {
1119            panic!("Failed to get event");
1120        }
1121    };
1122
1123    let touch_buttons_listener = match device_listener_stream.next().await {
1124        Some(Ok(fuipolicy::DeviceListenerRegistryRequest::RegisterTouchButtonsListener {
1125            listener,
1126            responder,
1127        })) => {
1128            let _ = responder.send();
1129            listener.into_proxy()
1130        }
1131        _ => {
1132            panic!("Failed to get event");
1133        }
1134    };
1135
1136    (
1137        relay_handle,
1138        touch_device,
1139        keyboard_device,
1140        mouse_device,
1141        touch_file,
1142        keyboard_file,
1143        mouse_file,
1144        touch_source_stream,
1145        mouse_stream,
1146        keyboard_listener,
1147        media_buttons_listener,
1148        touch_buttons_listener,
1149    )
1150}
1151
1152#[cfg(test)]
1153mod test {
1154    use super::*;
1155    use anyhow::anyhow;
1156    use fidl_fuchsia_ui_input::{
1157        MediaButtonsEvent, TouchButton, TouchButtonsEvent, TouchDeviceInfo,
1158    };
1159    use fidl_fuchsia_ui_input3 as fuiinput;
1160    use fuipointer::{
1161        EventPhase, MouseEvent, TouchEvent, TouchInteractionId, TouchPointerSample, TouchResponse,
1162        TouchSourceRequest, TouchSourceRequestStream,
1163    };
1164    use starnix_core::task::CurrentTask;
1165    #[allow(deprecated, reason = "pre-existing usage")]
1166    use starnix_core::testing::create_kernel_task_and_unlocked;
1167    use starnix_core::vfs::{FileHandle, FileObject, VecOutputBuffer};
1168    use starnix_sync::{FileOpsCore, LockEqualOrBefore, Locked, Unlocked};
1169    use starnix_types::time::timeval_from_time;
1170    use starnix_uapi::errors::{EAGAIN, Errno};
1171    use starnix_uapi::input_id;
1172    use starnix_uapi::open_flags::OpenFlags;
1173    use zerocopy::FromBytes as _;
1174
1175    const INPUT_EVENT_SIZE: usize = std::mem::size_of::<uapi::input_event>();
1176
1177    // Waits for a `Watch()` request to arrive on `request_stream`, and responds with
1178    // `touch_event`. Returns the arguments to the `Watch()` call.
1179    async fn answer_next_touch_watch_request(
1180        request_stream: &mut TouchSourceRequestStream,
1181        touch_events: Vec<TouchEvent>,
1182    ) -> Vec<TouchResponse> {
1183        match request_stream.next().await {
1184            Some(Ok(TouchSourceRequest::Watch { responses, responder })) => {
1185                responder.send(touch_events).expect("failure sending Watch reply");
1186                responses
1187            }
1188            unexpected_request => panic!("unexpected request {:?}", unexpected_request),
1189        }
1190    }
1191
1192    // Waits for a `Watch()` request to arrive on `request_stream`, and responds with
1193    // `mouse_events`.
1194    async fn answer_next_mouse_watch_request(
1195        request_stream: &mut fuipointer::MouseSourceRequestStream,
1196        mouse_events: Vec<MouseEvent>,
1197    ) {
1198        match request_stream.next().await {
1199            Some(Ok(fuipointer::MouseSourceRequest::Watch { responder })) => {
1200                responder.send(mouse_events).expect("failure sending Watch reply");
1201            }
1202            unexpected_request => panic!("unexpected request {:?}", unexpected_request),
1203        }
1204    }
1205
1206    fn make_empty_touch_event(device_id: u32) -> TouchEvent {
1207        TouchEvent {
1208            pointer_sample: Some(TouchPointerSample {
1209                interaction: Some(TouchInteractionId {
1210                    pointer_id: 0,
1211                    device_id,
1212                    interaction_id: 0,
1213                }),
1214                ..Default::default()
1215            }),
1216            ..Default::default()
1217        }
1218    }
1219
1220    fn make_touch_event_with_phase_device_id(
1221        phase: EventPhase,
1222        pointer_id: u32,
1223        device_id: u32,
1224    ) -> TouchEvent {
1225        make_touch_event_with_phase_device_id_position(phase, pointer_id, device_id, 0.0, 0.0)
1226    }
1227
1228    fn make_touch_event_with_phase_device_id_position(
1229        phase: EventPhase,
1230        pointer_id: u32,
1231        device_id: u32,
1232        x: f32,
1233        y: f32,
1234    ) -> TouchEvent {
1235        TouchEvent {
1236            timestamp: Some(0),
1237            pointer_sample: Some(TouchPointerSample {
1238                position_in_viewport: Some([x, y]),
1239                phase: Some(phase),
1240                interaction: Some(TouchInteractionId { pointer_id, device_id, interaction_id: 0 }),
1241                ..Default::default()
1242            }),
1243            ..Default::default()
1244        }
1245    }
1246
1247    fn make_mouse_wheel_event(scroll_v_ticks: i64, device_id: u32) -> MouseEvent {
1248        MouseEvent {
1249            timestamp: Some(0),
1250            pointer_sample: Some(MousePointerSample {
1251                device_id: Some(device_id),
1252                scroll_v: Some(scroll_v_ticks),
1253                ..Default::default()
1254            }),
1255            ..Default::default()
1256        }
1257    }
1258
1259    fn read_uapi_events<L>(
1260        locked: &mut Locked<L>,
1261        file: &FileHandle,
1262        current_task: &CurrentTask,
1263    ) -> Vec<uapi::input_event>
1264    where
1265        L: LockEqualOrBefore<FileOpsCore>,
1266    {
1267        std::iter::from_fn(|| {
1268            let locked = locked.cast_locked::<FileOpsCore>();
1269            let mut event_bytes = VecOutputBuffer::new(INPUT_EVENT_SIZE);
1270            match file.read(locked, current_task, &mut event_bytes) {
1271                Ok(INPUT_EVENT_SIZE) => Some(
1272                    uapi::input_event::read_from_bytes(Vec::from(event_bytes).as_slice())
1273                        .map_err(|_| anyhow!("failed to read input_event from buffer")),
1274                ),
1275                Ok(other_size) => {
1276                    Some(Err(anyhow!("got {} bytes (expected {})", other_size, INPUT_EVENT_SIZE)))
1277                }
1278                Err(Errno { code: EAGAIN, .. }) => None,
1279                Err(other_error) => Some(Err(anyhow!("read failed: {:?}", other_error))),
1280            }
1281        })
1282        .enumerate()
1283        .map(|(i, read_res)| match read_res {
1284            Ok(event) => event,
1285            Err(e) => panic!("unexpected result {:?} on iteration {}", e, i),
1286        })
1287        .collect()
1288    }
1289
1290    fn create_test_touch_device(
1291        locked: &mut Locked<Unlocked>,
1292        current_task: &CurrentTask,
1293        input_relay: Arc<InputEventsRelayHandle>,
1294        device_id: u32,
1295    ) -> FileHandle {
1296        let open_files: OpenedFiles = Arc::new(Mutex::new(vec![]));
1297        input_relay.add_touch_device(device_id, open_files.clone(), None);
1298        let device_file = Arc::new(InputFile::new_touch(
1299            input_id { bustype: 0, vendor: 0, product: 0, version: 0 },
1300            1000,
1301            1000,
1302            None,
1303        ));
1304        open_files.lock().push(Arc::downgrade(&device_file));
1305
1306        let root_namespace_node = current_task
1307            .lookup_path_from_root(locked, ".".into())
1308            .expect("failed to get namespace node for root");
1309
1310        FileObject::new(
1311            locked,
1312            &current_task,
1313            Box::new(device_file),
1314            root_namespace_node,
1315            OpenFlags::empty(),
1316        )
1317        .expect("FileObject::new failed")
1318    }
1319
1320    fn make_uapi_input_event(ty: u32, code: u32, value: i32) -> uapi::input_event {
1321        uapi::input_event {
1322            time: timeval_from_time(zx::MonotonicInstant::from_nanos(0)),
1323            type_: ty as u16,
1324            code: code as u16,
1325            value,
1326        }
1327    }
1328
1329    #[::fuchsia::test]
1330    async fn route_touch_event_by_device_id() {
1331        // Set up resources.
1332        #[allow(deprecated, reason = "pre-existing usage")]
1333        let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1334        let (
1335            input_relay,
1336            _touch_device,
1337            _keyboard_device,
1338            _mouse_device,
1339            input_file,
1340            _keyboard_file,
1341            _mouse_file,
1342            mut touch_source_stream,
1343            _mouse_source_stream,
1344            _keyboard_listener,
1345            _media_buttons_listener,
1346            _touch_buttons_listener,
1347        ) = start_input_relays_for_test(locked, &current_task, EventProxyMode::None).await;
1348
1349        const DEVICE_ID: u32 = 10;
1350
1351        answer_next_touch_watch_request(
1352            &mut touch_source_stream,
1353            vec![make_touch_event_with_phase_device_id(EventPhase::Add, 1, DEVICE_ID)],
1354        )
1355        .await;
1356
1357        // Wait for another `Watch` to ensure input_file done processing the first reply.
1358        // Use an empty `TouchEvent`, to minimize the chance that this event creates unexpected
1359        // `uapi::input_event`s.
1360        answer_next_touch_watch_request(
1361            &mut touch_source_stream,
1362            vec![make_empty_touch_event(DEVICE_ID)],
1363        )
1364        .await;
1365
1366        // Consume all of the `uapi::input_event`s that are available.
1367        let events = read_uapi_events(locked, &input_file, &current_task);
1368        // Default device receive events because no matched device.
1369        assert_ne!(events.len(), 0);
1370
1371        // add a device, mock uinput.
1372        let device_id_10_file =
1373            create_test_touch_device(locked, &current_task, input_relay.clone(), DEVICE_ID);
1374
1375        answer_next_touch_watch_request(
1376            &mut touch_source_stream,
1377            vec![make_touch_event_with_phase_device_id(EventPhase::Add, 1, DEVICE_ID)],
1378        )
1379        .await;
1380
1381        answer_next_touch_watch_request(
1382            &mut touch_source_stream,
1383            vec![make_empty_touch_event(DEVICE_ID)],
1384        )
1385        .await;
1386
1387        let events = read_uapi_events(locked, &input_file, &current_task);
1388        // Default device should not receive events because they matched device id 10.
1389        assert_eq!(events.len(), 0);
1390
1391        let events = read_uapi_events(locked, &device_id_10_file, &current_task);
1392        // file of device id 10 should receive events.
1393        assert_ne!(events.len(), 0);
1394    }
1395
1396    #[::fuchsia::test]
1397    async fn route_touch_event_with_wake_lease() {
1398        #[allow(deprecated, reason = "pre-existing usage")]
1399        let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1400        let (
1401            _input_relay,
1402            touch_device,
1403            _keyboard_device,
1404            _mouse_device,
1405            _input_file,
1406            _keyboard_file,
1407            _mouse_file,
1408            mut touch_source_stream,
1409            _mouse_source_stream,
1410            _keyboard_listener,
1411            _media_buttons_listener,
1412            _touch_buttons_listener,
1413        ) = start_input_relays_for_test(locked, &current_task, EventProxyMode::None).await;
1414
1415        const DEVICE_ID: u32 = 10;
1416        let mut event = make_touch_event_with_phase_device_id(EventPhase::Add, 1, DEVICE_ID);
1417        let (p1, _p2) = fidl::EventPair::create();
1418        event.wake_lease = Some(p1);
1419
1420        answer_next_touch_watch_request(&mut touch_source_stream, vec![event]).await;
1421
1422        // Wait for another `Watch` to ensure input_file done processing the first reply.
1423        answer_next_touch_watch_request(
1424            &mut touch_source_stream,
1425            vec![make_empty_touch_event(DEVICE_ID)],
1426        )
1427        .await;
1428
1429        let status = &touch_device.inspect_status;
1430        assert_eq!(
1431            status.total_events_with_wake_lease_count.load(std::sync::atomic::Ordering::Relaxed),
1432            1
1433        );
1434        assert_eq!(status.active_wake_leases_count.load(std::sync::atomic::Ordering::Relaxed), 0);
1435    }
1436
1437    #[::fuchsia::test]
1438    async fn route_touch_event_by_device_id_multi_device_events_in_one_sequence() {
1439        #[allow(deprecated, reason = "pre-existing usage")]
1440        let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1441        let (
1442            input_relay,
1443            _touch_device,
1444            _keyboard_device,
1445            _mouse_device,
1446            _input_file,
1447            _keyboard_file,
1448            _mouse_file,
1449            mut touch_source_stream,
1450            _mouse_source_stream,
1451            _keyboard_listener,
1452            _media_buttons_listener,
1453            _touch_buttons_listener,
1454        ) = start_input_relays_for_test(locked, &current_task, EventProxyMode::None).await;
1455
1456        const DEVICE_ID_10: u32 = 10;
1457        const DEVICE_ID_11: u32 = 11;
1458
1459        let device_id_10_file =
1460            create_test_touch_device(locked, &current_task, input_relay.clone(), DEVICE_ID_10);
1461
1462        let device_id_11_file =
1463            create_test_touch_device(locked, &current_task, input_relay.clone(), DEVICE_ID_11);
1464
1465        // 2 pointer down on different touch device.
1466        answer_next_touch_watch_request(
1467            &mut touch_source_stream,
1468            vec![
1469                make_touch_event_with_phase_device_id_position(
1470                    EventPhase::Add,
1471                    1,
1472                    DEVICE_ID_10,
1473                    10.0,
1474                    20.0,
1475                ),
1476                make_touch_event_with_phase_device_id_position(
1477                    EventPhase::Add,
1478                    2,
1479                    DEVICE_ID_11,
1480                    30.0,
1481                    40.0,
1482                ),
1483            ],
1484        )
1485        .await;
1486
1487        answer_next_touch_watch_request(&mut touch_source_stream, vec![]).await;
1488
1489        let events_10 = read_uapi_events(locked, &device_id_10_file, &current_task);
1490        let events_11 = read_uapi_events(locked, &device_id_11_file, &current_task);
1491        assert_eq!(events_10.len(), events_11.len());
1492
1493        assert_eq!(
1494            events_10,
1495            vec![
1496                make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0),
1497                make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 1),
1498                make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 10),
1499                make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 20),
1500                make_uapi_input_event(uapi::EV_KEY, uapi::BTN_TOUCH, 1),
1501                make_uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0),
1502            ]
1503        );
1504
1505        assert_eq!(
1506            events_11,
1507            vec![
1508                make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0),
1509                make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 2),
1510                make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 30),
1511                make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 40),
1512                make_uapi_input_event(uapi::EV_KEY, uapi::BTN_TOUCH, 1),
1513                make_uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0),
1514            ]
1515        );
1516    }
1517
1518    #[::fuchsia::test]
1519    async fn route_key_event_by_device_id() {
1520        // Set up resources.
1521        #[allow(deprecated, reason = "pre-existing usage")]
1522        let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1523        let (
1524            input_relay,
1525            _touch_device,
1526            _keyboard_device,
1527            _mouse_device,
1528            _touch_file,
1529            keyboard_file,
1530            _mouse_file,
1531            _touch_source_stream,
1532            _mouse_source_stream,
1533            keyboard_listener,
1534            _media_buttons_listener,
1535            _touch_buttons_listener,
1536        ) = start_input_relays_for_test(locked, &current_task, EventProxyMode::None).await;
1537
1538        const DEVICE_ID: u32 = 10;
1539
1540        let key_event = fuiinput::KeyEvent {
1541            timestamp: Some(0),
1542            type_: Some(fuiinput::KeyEventType::Pressed),
1543            key: Some(fidl_fuchsia_input::Key::A),
1544            device_id: Some(DEVICE_ID),
1545            ..Default::default()
1546        };
1547
1548        let _ = keyboard_listener.on_key_event(&key_event).await;
1549
1550        let events = read_uapi_events(locked, &keyboard_file, &current_task);
1551        // Default device should receive events because no device device id is 10.
1552        assert_ne!(events.len(), 0);
1553
1554        // add a device, mock uinput.
1555        let open_files: OpenedFiles = Arc::new(Mutex::new(vec![]));
1556        input_relay.add_keyboard_device(DEVICE_ID, open_files.clone(), None);
1557        let device_id_10_file = Arc::new(InputFile::new_keyboard(
1558            input_id { bustype: 0, vendor: 0, product: 0, version: 0 },
1559            None,
1560        ));
1561        open_files.lock().push(Arc::downgrade(&device_id_10_file));
1562        let root_namespace_node = current_task
1563            .lookup_path_from_root(locked, ".".into())
1564            .expect("failed to get namespace node for root");
1565        let device_id_10_file_object = FileObject::new(
1566            locked,
1567            &current_task,
1568            Box::new(device_id_10_file),
1569            root_namespace_node,
1570            OpenFlags::empty(),
1571        )
1572        .expect("FileObject::new failed");
1573
1574        let _ = keyboard_listener.on_key_event(&key_event).await;
1575
1576        let events = read_uapi_events(locked, &keyboard_file, &current_task);
1577        // Default device should not receive events because they matched device id 10.
1578        assert_eq!(events.len(), 0);
1579
1580        let events = read_uapi_events(locked, &device_id_10_file_object, &current_task);
1581        // file of device id 10 should receive events.
1582        assert_ne!(events.len(), 0);
1583
1584        std::mem::drop(keyboard_listener); // Close Zircon channel.
1585    }
1586
1587    #[::fuchsia::test]
1588    async fn route_media_button_event_by_device_id() {
1589        // Set up resources.
1590        #[allow(deprecated, reason = "pre-existing usage")]
1591        let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1592        let (
1593            input_relay,
1594            _touch_device,
1595            _keyboard_device,
1596            _mouse_device,
1597            _touch_file,
1598            keyboard_file,
1599            _mouse_file,
1600            _touch_source_stream,
1601            _mouse_source_stream,
1602            _keyboard_listener,
1603            media_buttons_listener,
1604            _touch_buttons_listener,
1605        ) = start_input_relays_for_test(locked, &current_task, EventProxyMode::None).await;
1606
1607        const DEVICE_ID: u32 = 10;
1608
1609        let power_pressed_event = MediaButtonsEvent {
1610            volume: Some(0),
1611            mic_mute: Some(false),
1612            pause: Some(false),
1613            camera_disable: Some(false),
1614            power: Some(true),
1615            function: Some(false),
1616            device_id: Some(DEVICE_ID),
1617            ..Default::default()
1618        };
1619
1620        let _ = media_buttons_listener.on_event(power_pressed_event).await;
1621
1622        let events = read_uapi_events(locked, &keyboard_file, &current_task);
1623        // Default device should receive events because no device device id is 10.
1624        assert_ne!(events.len(), 0);
1625
1626        // add a device, mock uinput.
1627        let open_files: OpenedFiles = Arc::new(Mutex::new(vec![]));
1628        input_relay.add_keyboard_device(DEVICE_ID, open_files.clone(), None);
1629        let device_id_10_file = Arc::new(InputFile::new_keyboard(
1630            input_id { bustype: 0, vendor: 0, product: 0, version: 0 },
1631            None,
1632        ));
1633        open_files.lock().push(Arc::downgrade(&device_id_10_file));
1634        let root_namespace_node = current_task
1635            .lookup_path_from_root(locked, ".".into())
1636            .expect("failed to get namespace node for root");
1637        let device_id_10_file_object = FileObject::new(
1638            locked,
1639            &current_task,
1640            Box::new(device_id_10_file),
1641            root_namespace_node,
1642            OpenFlags::empty(),
1643        )
1644        .expect("FileObject::new failed");
1645
1646        let power_released_event = MediaButtonsEvent {
1647            volume: Some(0),
1648            mic_mute: Some(false),
1649            pause: Some(false),
1650            camera_disable: Some(false),
1651            power: Some(false),
1652            function: Some(false),
1653            device_id: Some(DEVICE_ID),
1654            ..Default::default()
1655        };
1656
1657        let _ = media_buttons_listener.on_event(power_released_event).await;
1658
1659        let events = read_uapi_events(locked, &keyboard_file, &current_task);
1660        // Default device should not receive events because they matched device id 10.
1661        assert_eq!(events.len(), 0);
1662
1663        let events = read_uapi_events(locked, &device_id_10_file_object, &current_task);
1664        // file of device id 10 should receive events.
1665        assert_ne!(events.len(), 0);
1666
1667        std::mem::drop(media_buttons_listener); // Close Zircon channel.
1668    }
1669
1670    #[::fuchsia::test]
1671    async fn route_touch_button_event_by_device_id() {
1672        // Set up resources.
1673        #[allow(deprecated, reason = "pre-existing usage")]
1674        let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1675        let (
1676            input_relay,
1677            _touch_device,
1678            _keyboard_device,
1679            _mouse_device,
1680            touch_file,
1681            _keyboard_file,
1682            _mouse_file,
1683            _touch_source_stream,
1684            _mouse_source_stream,
1685            _keyboard_listener,
1686            _media_buttons_listener,
1687            touch_buttons_listener,
1688        ) = start_input_relays_for_test(locked, &current_task, EventProxyMode::None).await;
1689
1690        const DEVICE_ID: u32 = 10;
1691
1692        let palm_pressed_event: TouchButtonsEvent = TouchButtonsEvent {
1693            pressed_buttons: Some(vec![TouchButton::Palm]),
1694            device_info: Some(TouchDeviceInfo { id: Some(DEVICE_ID), ..Default::default() }),
1695            ..Default::default()
1696        };
1697
1698        let _ = touch_buttons_listener.on_event(palm_pressed_event).await;
1699
1700        let events = read_uapi_events(locked, &touch_file, &current_task);
1701        // Default device should receive events because no device device id is 10.
1702        assert_ne!(events.len(), 0);
1703
1704        // add a device, mock uinput.
1705        let open_files: OpenedFiles = Arc::new(Mutex::new(vec![]));
1706        input_relay.add_touch_device(DEVICE_ID, open_files.clone(), None);
1707        let device_id_10_file =
1708            create_test_touch_device(locked, &current_task, input_relay.clone(), DEVICE_ID);
1709
1710        let palm_released_event: TouchButtonsEvent = TouchButtonsEvent {
1711            pressed_buttons: Some(vec![]),
1712            device_info: Some(TouchDeviceInfo { id: Some(DEVICE_ID), ..Default::default() }),
1713            ..Default::default()
1714        };
1715
1716        let _ = touch_buttons_listener.on_event(palm_released_event).await;
1717
1718        let events = read_uapi_events(locked, &touch_file, &current_task);
1719        // Default device should not receive events because they matched device id 10.
1720        assert_eq!(events.len(), 0);
1721
1722        let events = read_uapi_events(locked, &device_id_10_file, &current_task);
1723        // file of device id 10 should receive events.
1724        assert_ne!(events.len(), 0);
1725
1726        std::mem::drop(touch_buttons_listener); // Close Zircon channel.
1727    }
1728
1729    #[::fuchsia::test]
1730    async fn touch_device_multi_reader() {
1731        // Set up resources.
1732        #[allow(deprecated, reason = "pre-existing usage")]
1733        let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1734        let (
1735            _input_relay,
1736            touch_device,
1737            _keyboard_device,
1738            _mouse_device,
1739            touch_reader1,
1740            _keyboard_file,
1741            _mouse_file,
1742            mut touch_source_stream,
1743            _mouse_source_stream,
1744            _keyboard_listener,
1745            _media_buttons_listener,
1746            _touch_buttons_listener,
1747        ) = start_input_relays_for_test(locked, &current_task, EventProxyMode::None).await;
1748
1749        let touch_reader2 =
1750            touch_device.open_test(locked, &current_task).expect("Failed to create input file");
1751
1752        const DEVICE_ID: u32 = 10;
1753
1754        answer_next_touch_watch_request(
1755            &mut touch_source_stream,
1756            vec![make_touch_event_with_phase_device_id(EventPhase::Add, 1, DEVICE_ID)],
1757        )
1758        .await;
1759
1760        // Wait for another `Watch` to ensure input_file done processing the first reply.
1761        // Use an empty `TouchEvent`, to minimize the chance that this event creates unexpected
1762        // `uapi::input_event`s.
1763        answer_next_touch_watch_request(
1764            &mut touch_source_stream,
1765            vec![make_empty_touch_event(DEVICE_ID)],
1766        )
1767        .await;
1768
1769        // Consume all of the `uapi::input_event`s that are available.
1770        let events_from_reader1 = read_uapi_events(locked, &touch_reader1, &current_task);
1771        let events_from_reader2 = read_uapi_events(locked, &touch_reader2, &current_task);
1772        assert_ne!(events_from_reader1.len(), 0);
1773        assert_eq!(events_from_reader1.len(), events_from_reader2.len());
1774    }
1775
1776    #[::fuchsia::test]
1777    async fn keyboard_device_multi_reader() {
1778        // Set up resources.
1779        #[allow(deprecated, reason = "pre-existing usage")]
1780        let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1781        let (
1782            _input_relay,
1783            _touch_device,
1784            keyboard_device,
1785            _mouse_device,
1786            _touch_file,
1787            keyboard_reader1,
1788            _mouse_file,
1789            _touch_source_stream,
1790            _mouse_source_stream,
1791            keyboard_listener,
1792            _media_buttons_listener,
1793            _touch_buttons_listener,
1794        ) = start_input_relays_for_test(locked, &current_task, EventProxyMode::None).await;
1795
1796        let keyboard_reader2 =
1797            keyboard_device.open_test(locked, &current_task).expect("Failed to create input file");
1798
1799        const DEVICE_ID: u32 = 10;
1800
1801        let key_event = fuiinput::KeyEvent {
1802            timestamp: Some(0),
1803            type_: Some(fuiinput::KeyEventType::Pressed),
1804            key: Some(fidl_fuchsia_input::Key::A),
1805            device_id: Some(DEVICE_ID),
1806            ..Default::default()
1807        };
1808
1809        let _ = keyboard_listener.on_key_event(&key_event).await;
1810
1811        // Consume all of the `uapi::input_event`s that are available.
1812        let events_from_reader1 = read_uapi_events(locked, &keyboard_reader1, &current_task);
1813        let events_from_reader2 = read_uapi_events(locked, &keyboard_reader2, &current_task);
1814        assert_ne!(events_from_reader1.len(), 0);
1815        assert_eq!(events_from_reader1.len(), events_from_reader2.len());
1816    }
1817
1818    #[::fuchsia::test]
1819    async fn button_device_multi_reader() {
1820        // Set up resources.
1821        #[allow(deprecated, reason = "pre-existing usage")]
1822        let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1823        let (
1824            _input_relay,
1825            _touch_device,
1826            keyboard_device,
1827            _mouse_device,
1828            _touch_file,
1829            keyboard_reader1,
1830            _mouse_file,
1831            _touch_source_stream,
1832            _mouse_source_stream,
1833            _keyboard_listener,
1834            media_buttons_listener,
1835            _touch_buttons_listener,
1836        ) = start_input_relays_for_test(locked, &current_task, EventProxyMode::None).await;
1837
1838        let keyboard_reader2 =
1839            keyboard_device.open_test(locked, &current_task).expect("Failed to create input file");
1840
1841        const DEVICE_ID: u32 = 10;
1842
1843        let power_pressed_event = MediaButtonsEvent {
1844            volume: Some(0),
1845            mic_mute: Some(false),
1846            pause: Some(false),
1847            camera_disable: Some(false),
1848            power: Some(true),
1849            function: Some(false),
1850            device_id: Some(DEVICE_ID),
1851            ..Default::default()
1852        };
1853
1854        let _ = media_buttons_listener.on_event(power_pressed_event).await;
1855
1856        // Consume all of the `uapi::input_event`s that are available.
1857        let events_from_reader1 = read_uapi_events(locked, &keyboard_reader1, &current_task);
1858        let events_from_reader2 = read_uapi_events(locked, &keyboard_reader2, &current_task);
1859        assert_ne!(events_from_reader1.len(), 0);
1860        assert_eq!(events_from_reader1.len(), events_from_reader2.len());
1861    }
1862
1863    #[::fuchsia::test]
1864    async fn mouse_device_multi_reader() {
1865        // Set up resources.
1866        #[allow(deprecated, reason = "pre-existing usage")]
1867        let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1868        let (
1869            _input_relay,
1870            _touch_device,
1871            _keyboard_device,
1872            mouse_device,
1873            _touch_file,
1874            _keyboard_file,
1875            mouse_reader1,
1876            _touch_stream,
1877            mut mouse_stream,
1878            _keyboard_listener,
1879            _media_buttons_listener,
1880            _touch_buttons_listener,
1881        ) = start_input_relays_for_test(locked, &current_task, EventProxyMode::None).await;
1882
1883        let mouse_reader2 =
1884            mouse_device.open_test(locked, &current_task).expect("Failed to create input file");
1885
1886        const DEVICE_ID: u32 = 10;
1887
1888        answer_next_mouse_watch_request(
1889            &mut mouse_stream,
1890            vec![make_mouse_wheel_event(1, DEVICE_ID)],
1891        )
1892        .await;
1893
1894        // Wait for another `Watch` to ensure input_file done processing the first reply.
1895        // Use an empty `MouseEvent`, to minimize the chance that this event creates unexpected
1896        // `uapi::input_event`s.
1897        answer_next_mouse_watch_request(
1898            &mut mouse_stream,
1899            vec![make_mouse_wheel_event(0, DEVICE_ID)],
1900        )
1901        .await;
1902
1903        // Consume all of the `uapi::input_event`s that are available.
1904        let events_from_reader1 = read_uapi_events(locked, &mouse_reader1, &current_task);
1905        let events_from_reader2 = read_uapi_events(locked, &mouse_reader2, &current_task);
1906        assert_ne!(events_from_reader1.len(), 0);
1907        assert_eq!(events_from_reader1.len(), events_from_reader2.len());
1908    }
1909
1910    #[::fuchsia::test]
1911    async fn input_message_counters() {
1912        // Set up resources.
1913        #[allow(deprecated, reason = "pre-existing usage")]
1914        let (kernel, current_task, locked) = create_kernel_task_and_unlocked();
1915        let (
1916            _input_relay,
1917            _touch_device,
1918            _keyboard_device,
1919            _mouse_device,
1920            _touch_file,
1921            keyboard_file,
1922            _mouse_file,
1923            _touch_source_stream,
1924            _mouse_source_stream,
1925            keyboard_listener,
1926            _media_buttons_listener,
1927            _touch_buttons_listener,
1928        ) = start_input_relays_for_test(locked, &current_task, EventProxyMode::WakeContainer).await;
1929
1930        const DEVICE_ID: u32 = 10;
1931
1932        let key_event = fuiinput::KeyEvent {
1933            timestamp: Some(0),
1934            type_: Some(fuiinput::KeyEventType::Pressed),
1935            key: Some(fidl_fuchsia_input::Key::A),
1936            device_id: Some(DEVICE_ID),
1937            ..Default::default()
1938        };
1939
1940        let _ = keyboard_listener.on_key_event(&key_event).await;
1941
1942        let events = read_uapi_events(locked, &keyboard_file, &current_task);
1943        assert_ne!(events.len(), 0);
1944
1945        assert!(!kernel.suspend_resume_manager.has_nonzero_message_counter());
1946    }
1947}