1use 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 {self as fuipointer},
15};
16use fidl_fuchsia_ui_policy as fuipolicy;
17use fidl_fuchsia_ui_views as fuiviews;
18use futures::StreamExt as _;
19use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender, unbounded};
20use futures::channel::oneshot::{self, Sender};
21use futures::executor::block_on;
22use sorted_vec_map::SortedVecMap;
23use starnix_core::power::{ContainerWakingStream, create_proxy_for_wake_events_counter};
24use starnix_core::task::dynamic_thread_spawner::SpawnRequestBuilder;
25use starnix_core::task::{CurrentTask, Kernel};
26use starnix_logging::log_warn;
27use starnix_modules_input_event_conversion::button_fuchsia_to_linux::{
28 new_touch_buttons_bitvec, parse_fidl_media_button_event, parse_fidl_touch_button_event,
29};
30use starnix_modules_input_event_conversion::key_fuchsia_to_linux::parse_fidl_keyboard_event_to_linux_input_event;
31use starnix_modules_input_event_conversion::mouse_fuchsia_to_linux::FuchsiaMouseEventToLinuxMouseEventConverter;
32use starnix_modules_input_event_conversion::touch_fuchsia_to_linux::FuchsiaTouchEventToLinuxTouchEventConverter;
33use starnix_sync::{InputEventRelayOpenedFilesLock, LockDepMutex};
34use starnix_uapi::uapi;
35use std::collections::VecDeque;
36use std::sync::{Arc, Weak};
37
38const INPUT_RELAY_ROLE_NAME: &str = "fuchsia.starnix.kthread.input_relay";
39
40#[derive(Clone, Copy)]
41pub enum EventProxyMode {
42 None,
44
45 WakeContainer,
49}
50
51#[derive(Default)]
52pub struct OpenedFilesState {
53 files: Vec<Weak<InputFile>>,
54 has_been_opened: bool,
55 buffered_events: Vec<uapi::input_event>,
56}
57
58impl OpenedFilesState {
59 pub fn on_file_opened(&mut self, file: &Arc<InputFile>) {
60 if !self.has_been_opened {
61 self.has_been_opened = true;
62 if !self.buffered_events.is_empty() {
63 file.add_events(std::mem::take(&mut self.buffered_events));
64 }
65 }
66 self.files.push(Arc::downgrade(file));
67 }
68}
69
70impl std::ops::Deref for OpenedFilesState {
71 type Target = Vec<Weak<InputFile>>;
72 fn deref(&self) -> &Self::Target {
73 &self.files
74 }
75}
76
77impl std::ops::DerefMut for OpenedFilesState {
78 fn deref_mut(&mut self) -> &mut Self::Target {
79 &mut self.files
80 }
81}
82
83pub type OpenedFiles = Arc<LockDepMutex<OpenedFilesState, InputEventRelayOpenedFilesLock>>;
84
85pub enum InputDeviceType {
86 Touch(FuchsiaTouchEventToLinuxTouchEventConverter),
87 Keyboard,
88 Mouse(FuchsiaMouseEventToLinuxMouseEventConverter),
89}
90
91impl std::fmt::Display for InputDeviceType {
92 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93 match self {
94 InputDeviceType::Touch(_) => write!(f, "touch"),
95 InputDeviceType::Keyboard => write!(f, "keyboard"),
96 InputDeviceType::Mouse(_) => write!(f, "mouse"),
97 }
98 }
99}
100
101enum DeviceRegistration {
102 Pending { kernel: Arc<Kernel>, device: crate::InputDevice, device_id: DeviceId },
103 Registered,
104 Failed,
105}
106
107impl DeviceRegistration {
108 fn pending(kernel: Arc<Kernel>, device: crate::InputDevice, device_id: DeviceId) -> Self {
115 debug_assert!(
116 {
117 let devt = starnix_uapi::device_id::DeviceId::new(
118 starnix_uapi::device_id::INPUT_MAJOR,
119 device_id,
120 );
121 let next_devt = starnix_uapi::device_id::DeviceId::new(
122 starnix_uapi::device_id::INPUT_MAJOR,
123 device_id + 1,
124 );
125 kernel
126 .device_registry
127 .list_minor_devices(starnix_core::device::DeviceMode::Char, devt..next_devt)
128 .is_empty()
129 },
130 "input device {device_id} must not be registered before lazy registration",
131 );
132 Self::Pending { kernel, device, device_id }
133 }
134
135 fn ensure_registered(&mut self) {
136 let Self::Pending { kernel, device, device_id } = self else { return };
137 match device.clone().register(kernel, *device_id) {
138 Ok(()) => *self = Self::Registered,
139 Err(e) => {
140 log_warn!("unable to register input device {device_id:?}: {e:?}");
141 *self = Self::Failed;
144 }
145 }
146 }
147}
148
149pub struct DeviceState {
150 device_type: InputDeviceType,
151 open_files: OpenedFiles,
152 inspect_status: Option<Arc<InputDeviceStatus>>,
153 registration: DeviceRegistration,
154}
155
156pub struct TrackedWakeLease {
157 _lease: fidl::EventPair,
158 device_status: Arc<InputDeviceStatus>,
159}
160
161impl TrackedWakeLease {
162 pub fn new(lease: fidl::EventPair, device_status: Arc<InputDeviceStatus>) -> Self {
163 device_status.increment_active_wake_leases(1);
164 device_status.count_events_with_wake_lease(1);
165 Self { _lease: lease, device_status }
166 }
167}
168
169impl Drop for TrackedWakeLease {
170 fn drop(&mut self) {
171 self.device_status.decrement_active_wake_leases(1);
172 }
173}
174
175pub type DeviceId = u32;
176
177pub const DEFAULT_TOUCH_DEVICE_ID: DeviceId = 0;
178pub const DEFAULT_KEYBOARD_DEVICE_ID: DeviceId = 1;
179pub const DEFAULT_MOUSE_DEVICE_ID: DeviceId = 2;
180
181enum DeviceStateChange {
182 Add(DeviceId, DeviceState, Sender<()>),
183 Remove(DeviceId, Sender<()>),
184}
185
186pub fn new_input_relay() -> (InputEventsRelay, Arc<InputEventsRelayHandle>) {
187 let (sender, receiver) = unbounded();
188
189 (
190 InputEventsRelay { devices: SortedVecMap::new(), receiver },
191 Arc::new(InputEventsRelayHandle { sender }),
192 )
193}
194
195pub struct InputEventsRelayHandle {
196 sender: UnboundedSender<DeviceStateChange>,
197}
198
199impl InputEventsRelayHandle {
200 pub fn add_touch_device(
201 self: &Arc<Self>,
202 device_id: DeviceId,
203 open_files: OpenedFiles,
204 inspect_status: Option<Arc<InputDeviceStatus>>,
205 ) {
206 let (sender, receiver) = oneshot::channel();
207 let _ = self.sender.unbounded_send(DeviceStateChange::Add(
208 device_id,
209 DeviceState {
210 device_type: InputDeviceType::Touch(
211 FuchsiaTouchEventToLinuxTouchEventConverter::create(),
212 ),
213 open_files,
214 inspect_status,
215 registration: DeviceRegistration::Registered,
216 },
217 sender,
218 ));
219 let _ = block_on(receiver);
220 }
221
222 pub fn add_keyboard_device(
223 &self,
224 device_id: DeviceId,
225 open_files: OpenedFiles,
226 inspect_status: Option<Arc<InputDeviceStatus>>,
227 ) {
228 let (sender, receiver) = oneshot::channel();
229 let _ = self.sender.unbounded_send(DeviceStateChange::Add(
230 device_id,
231 DeviceState {
232 device_type: InputDeviceType::Keyboard,
233 open_files,
234 inspect_status,
235 registration: DeviceRegistration::Registered,
236 },
237 sender,
238 ));
239 let _ = block_on(receiver);
240 }
241
242 pub fn add_mouse_device(
243 &self,
244 device_id: DeviceId,
245 open_files: OpenedFiles,
246 inspect_status: Option<Arc<InputDeviceStatus>>,
247 ) {
248 let (sender, receiver) = oneshot::channel();
249 let _ = self.sender.unbounded_send(DeviceStateChange::Add(
250 device_id,
251 DeviceState {
252 device_type: InputDeviceType::Mouse(
253 FuchsiaMouseEventToLinuxMouseEventConverter::create(),
254 ),
255 open_files,
256 inspect_status,
257 registration: DeviceRegistration::Registered,
258 },
259 sender,
260 ));
261 let _ = block_on(receiver);
262 }
263
264 pub fn remove_device(&self, device_id: DeviceId) {
265 let (sender, receiver) = oneshot::channel();
266 let _ = self.sender.unbounded_send(DeviceStateChange::Remove(device_id, sender));
267 let _ = block_on(receiver);
268 }
269}
270
271pub struct InputEventsRelay {
272 devices: SortedVecMap<DeviceId, DeviceState>,
273 receiver: UnboundedReceiver<DeviceStateChange>,
274}
275
276impl InputEventsRelay {
277 pub fn start_relays(
283 mut self: Self,
284 kernel: &Kernel,
285 event_proxy_mode: EventProxyMode,
286 touch_source_client_end: ClientEnd<fuipointer::TouchSourceV2Marker>,
287 keyboard: KeyboardSynchronousProxy,
288 mouse_source_client_end: ClientEnd<fuipointer::MouseSourceV2Marker>,
289 view_ref: fuiviews::ViewRef,
290 registry_proxy: fuipolicy::DeviceListenerRegistrySynchronousProxy,
291 default_touch_device_opened_files: OpenedFiles,
292 default_keyboard_device_opened_files: OpenedFiles,
293 default_mouse_device: Option<crate::InputDevice>,
294 default_touch_device_inspect: Option<Arc<InputDeviceStatus>>,
295 default_keyboard_device_inspect: Option<Arc<InputDeviceStatus>>,
296 ) {
297 let f = async move |current_task: &CurrentTask| {
298 let kernel = current_task.kernel();
299 let (mut default_touch_device, touch_source_proxy, mut touch_waking_stream) =
301 setup_touch_relay(
302 kernel,
303 event_proxy_mode,
304 touch_source_client_end,
305 default_touch_device_opened_files,
306 default_touch_device_inspect,
307 );
308 let mut touch_future = touch_waking_stream.next();
309
310 let (mut default_mouse_device, mouse_source_proxy, mut mouse_waking_stream) =
312 setup_mouse_relay(
313 kernel,
314 event_proxy_mode,
315 mouse_source_client_end,
316 default_mouse_device,
317 );
318 let mut mouse_future = mouse_waking_stream.next();
319
320 let (mut default_keyboard_device, mut keyboard_event_stream, _keyboard_proxy) =
326 setup_keyboard_relay(
327 keyboard,
328 view_ref,
329 default_keyboard_device_opened_files.clone(),
330 default_keyboard_device_inspect.clone(),
331 );
332
333 let (
335 mut default_button_device,
336 mut media_buttons_waking_stream,
337 mut touch_buttons_waking_stream,
338 ) = setup_button_relay(
339 kernel,
340 registry_proxy,
341 event_proxy_mode,
342 default_keyboard_device_opened_files,
343 default_keyboard_device_inspect,
344 );
345 let mut media_buttons_future = media_buttons_waking_stream.next();
346 let mut touch_buttons_future = touch_buttons_waking_stream.next();
347
348 let mut power_was_pressed = false;
349 let mut function_was_pressed = false;
350 let mut volume_up_was_pressed = false;
351 let mut volume_down_was_pressed = false;
352 let mut touch_buttons_were_pressed = new_touch_buttons_bitvec();
353
354 loop {
355 futures::select! {
356 touch_res = touch_future => {
357 match touch_res {
358 Some(Ok(fuipointer::TouchSourceV2Event::OnTouchEvents {
359 events,
360 last_event_stamp,
361 })) => {
362 self.process_touch_event(
363 &mut default_touch_device,
364 events,
365 );
366 if let Err(e) = touch_source_proxy.acknowledge_events(last_event_stamp) {
367 log_warn!("error acknowledging touch events: {:?}", e);
368 }
369 touch_future = touch_waking_stream.next();
370 }
371 Some(Ok(fuipointer::TouchSourceV2Event::_UnknownEvent { ordinal, .. })) => {
372 log_warn!("unknown event on TouchSourceV2: {}", ordinal);
373 touch_future = touch_waking_stream.next();
374 }
375 Some(Err(e)) => {
376 log_warn!(
377 "error {:?} reading from TouchSourceV2Proxy; input is stopped",
378 e
379 );
380 }
381 None => {}
382 }
383 }
384 mouse_res = mouse_future => {
385 match mouse_res {
386 Some(Ok(fuipointer::MouseSourceV2Event::OnMouseEvents {
387 events,
388 last_event_stamp,
389 })) => {
390 self.process_mouse_event(&mut default_mouse_device, events);
391 if let Err(e) = mouse_source_proxy.acknowledge_events(last_event_stamp) {
392 log_warn!("error acknowledging mouse events: {:?}", e);
393 }
394 mouse_future = mouse_waking_stream.next();
395 }
396 Some(Ok(fuipointer::MouseSourceV2Event::_UnknownEvent { ordinal, .. })) => {
397 log_warn!("unknown event on MouseSourceV2: {}", ordinal);
398 mouse_future = mouse_waking_stream.next();
399 }
400 Some(Err(e)) => {
401 log_warn!(
402 "error {:?} reading from MouseSourceV2Proxy; input is stopped",
403 e
404 );
405 }
406 None => {}
407 }
408 }
409 media_buttons_res = media_buttons_future => {
410 match media_buttons_res {
411 Some(Ok(event)) => {
412 (
413 power_was_pressed,
414 function_was_pressed,
415 volume_up_was_pressed,
416 volume_down_was_pressed,
417 ) = self.process_media_button_event(
418 &mut default_button_device,
419 event,
420 power_was_pressed,
421 function_was_pressed,
422 volume_up_was_pressed,
423 volume_down_was_pressed,
424 );
425 media_buttons_future = media_buttons_waking_stream.next();
426 }
427 _ => {}
428 }
429 }
430 touch_buttons_res = touch_buttons_future => {
431 match touch_buttons_res {
432 Some(Ok(event)) => {
433 touch_buttons_were_pressed = self.process_touch_button_event(
434 &mut default_touch_device,
435 event,
436 &touch_buttons_were_pressed,
437 );
438 touch_buttons_future = touch_buttons_waking_stream.next();
439 }
440 _ => {}
441 }
442 }
443 e = keyboard_event_stream.next() => {
444 match e {
445 Some(Ok(request)) => {
446 self.process_keyboard(&mut default_keyboard_device, request);
447 }
448 _ => {}
449 }
450 }
451 e = self.receiver.next() => {
452 match e {
453 Some(event) => {
454 match event {
455 DeviceStateChange::Add(id, device_state, sender) => {
456 self.devices.insert(id, device_state);
457 let _ = sender.send(());
458 }
459 DeviceStateChange::Remove(id, sender) => {
460 self.devices.remove(&id);
461 let _ = sender.send(());
462 }
463 }
464 }
465 _ => {}
466 }
467 }
468 complete => break,
469 }
470 }
471 };
472 let req = SpawnRequestBuilder::new()
473 .with_debug_name("input-event-relay")
474 .with_role(INPUT_RELAY_ROLE_NAME)
475 .with_async_closure(f)
476 .build();
477 kernel.kthreads.spawner().spawn_from_request(req);
478 }
479
480 fn process_touch_event(
481 self: &mut Self,
482 default_touch_device: &mut DeviceState,
483 touch_events: Vec<FidlTouchEvent>,
484 ) {
485 fuchsia_trace::duration!("input", "starnix_process_touch_event");
486 for e in &touch_events {
487 match e.trace_flow_id {
488 Some(trace_flow_id) => {
489 fuchsia_trace::flow_end!(
490 "input",
491 "dispatch_event_to_client",
492 trace_flow_id.into()
493 );
494 }
495 None => {
496 log_warn!("touch event has not tracing id");
497 }
498 }
499 }
500 let num_received_events: u64 = touch_events.len().try_into().unwrap();
501
502 let mut num_ignored_events: u64 = 0;
503
504 let (events_by_device, ignored_events) = group_touch_events_by_device_id(touch_events);
506 num_ignored_events += ignored_events;
507
508 for (device_id, mut events) in events_by_device {
509 fuchsia_trace::duration_begin!("input", "starnix_process_per_device_touch_event");
510
511 let dev = self.devices.get_mut(&device_id).unwrap_or(default_touch_device);
512
513 let mut num_converted_events: u64 = 0;
514 let mut num_unexpected_events: u64 = 0;
515 let mut new_events: VecDeque<uapi::input_event> = VecDeque::new();
516
517 #[allow(clippy::collection_is_never_read)]
518 let mut tracked_leases = vec![];
519 for event in &mut events {
520 if let Some(lease) = event.wake_lease.take() {
521 if let Some(status) = &dev.inspect_status {
522 tracked_leases.push(TrackedWakeLease::new(lease, status.clone()));
523 }
524 }
525 }
526
527 let last_event_time_ns: i64;
528 if let InputDeviceType::Touch(ref mut converter) = dev.device_type {
529 let mut batch = converter.handle(events);
530 new_events.append(&mut batch.events);
531 num_converted_events += batch.count_converted_fidl_events;
532 num_ignored_events += batch.count_ignored_fidl_events;
533 num_unexpected_events += batch.count_unexpected_fidl_events;
534 last_event_time_ns = batch.last_event_time_ns;
535 } else {
536 fuchsia_trace::duration_end!("input", "starnix_process_per_device_touch_event");
537 log_warn!(
538 "Non touch device received touch events: device_id = {}, device_type = {}",
539 device_id,
540 dev.device_type
541 );
542 continue;
543 }
544
545 if let Some(dev_inspect_status) = &dev.inspect_status {
546 dev_inspect_status.count_total_received_events(num_received_events);
547 dev_inspect_status.count_total_ignored_events(num_ignored_events);
548 dev_inspect_status.count_total_unexpected_events(num_unexpected_events);
549 dev_inspect_status.count_total_converted_events(num_converted_events);
550 dev_inspect_status.count_total_generated_events(
551 new_events.len().try_into().unwrap(),
552 last_event_time_ns,
553 );
554 } else {
555 log_warn!(
556 "unable to record inspect for device_id: {}, device_type: {}",
557 device_id,
558 dev.device_type
559 );
560 }
561
562 fuchsia_trace::duration_end!("input", "starnix_process_per_device_touch_event");
563 dev.open_files.lock().retain(|f| {
564 let Some(file) = f.upgrade() else {
565 log_warn!("Dropping input file for touch that failed to upgrade");
566 return false;
567 };
568 match &file.inspect_status {
569 Some(file_inspect_status) => {
570 file_inspect_status.count_received_events(num_received_events);
571 file_inspect_status.count_ignored_events(num_ignored_events);
572 file_inspect_status.count_unexpected_events(num_unexpected_events);
573 file_inspect_status.count_converted_events(num_converted_events);
574 }
575 None => {
576 log_warn!("unable to record inspect within the input file")
577 }
578 }
579 if !new_events.is_empty() {
580 if let Some(file_inspect_status) = &file.inspect_status {
584 file_inspect_status.count_generated_events(
585 new_events.len().try_into().unwrap(),
586 last_event_time_ns,
587 );
588 }
589 file.add_events(new_events.clone().into_iter().collect());
590 }
591
592 true
593 });
594 }
595 }
596
597 fn process_keyboard(
598 self: &mut Self,
599 default_keyboard_device: &mut DeviceState,
600 request: KeyboardListenerRequest,
601 ) {
602 match request {
603 KeyboardListenerRequest::OnKeyEvent { event, responder } => {
604 fuchsia_trace::duration!("input", "starnix_process_keyboard_event");
605
606 let new_events = parse_fidl_keyboard_event_to_linux_input_event(
607 &event,
608 uinput::uinput_running(),
609 );
610
611 let dev = match event.device_id {
612 Some(device_id) => {
613 self.devices.get_mut(&device_id).unwrap_or(default_keyboard_device)
614 }
615 None => default_keyboard_device,
616 };
617
618 let (converted_events, ignored_events, generated_events) = match new_events.len() {
624 0 => (0u64, 1u64, 0u64),
625 len => (1u64, 0u64, len as u64),
626 };
627 let last_time = event.timestamp.unwrap_or(0);
628
629 if let Some(dev_inspect_status) = &dev.inspect_status {
630 dev_inspect_status.count_total_received_events(1);
631 dev_inspect_status.count_total_ignored_events(ignored_events);
632 dev_inspect_status.count_total_converted_events(converted_events);
633 if generated_events > 0 {
638 dev_inspect_status
639 .count_total_generated_events(generated_events, last_time);
640 }
641 } else {
642 log_warn!("unable to record inspect for keyboard device");
643 }
644
645 dev.open_files.lock().retain(|f| {
646 let Some(file) = f.upgrade() else {
647 log_warn!("Dropping input file for keyboard that failed to upgrade");
648 return false;
649 };
650 match &file.inspect_status {
651 Some(file_inspect_status) => {
652 file_inspect_status.count_received_events(1);
653 file_inspect_status.count_ignored_events(ignored_events);
654 file_inspect_status.count_converted_events(converted_events);
655 if generated_events > 0 {
656 file_inspect_status
657 .count_generated_events(generated_events, last_time);
658 }
659 }
660 None => {
661 log_warn!("unable to record inspect within the input file")
662 }
663 }
664 if !new_events.is_empty() {
665 file.add_events(new_events.clone().into_iter().collect());
666 }
667
668 true
669 });
670
671 responder.send(KeyEventStatus::Handled).expect("");
672 }
673 }
674 }
675
676 fn process_media_button_event(
677 &mut self,
678 default_button_device: &mut DeviceState,
679 button_event: fuipolicy::MediaButtonsListenerRequest,
680 power_was_pressed: bool,
681 function_was_pressed: bool,
682 volume_up_was_pressed: bool,
683 volume_down_was_pressed: bool,
684 ) -> (bool, bool, bool, bool) {
685 let mut power_was_pressed_after = false;
686 let mut function_was_pressed_after = false;
687 let mut volume_up_was_pressed_after = false;
688 let mut volume_down_was_pressed_after = false;
689 match button_event {
690 fuipolicy::MediaButtonsListenerRequest::OnEvent { mut event, responder } => {
691 if let Some(trace_flow_id) = event.trace_flow_id {
692 fuchsia_trace::flow_end!(
693 "input",
694 "dispatch_media_buttons_to_listeners",
695 trace_flow_id.into()
696 );
697 }
698 fuchsia_trace::duration!("input", "starnix_process_media_button_event");
699
700 let batch = parse_fidl_media_button_event(
701 &event,
702 power_was_pressed,
703 function_was_pressed,
704 volume_up_was_pressed,
705 volume_down_was_pressed,
706 );
707
708 power_was_pressed_after = batch.power_is_pressed;
709 function_was_pressed_after = batch.function_is_pressed;
710 volume_up_was_pressed_after = batch.volume_up_is_pressed;
711 volume_down_was_pressed_after = batch.volume_down_is_pressed;
712
713 let (converted_events, ignored_events, generated_events) = match batch.events.len()
714 {
715 0 => (0u64, 1u64, 0u64),
716 len => {
717 if len % 2 == 1 {
718 log_warn!(
719 "unexpectedly received {} events: there should always be an even number of non-empty events.",
720 len
721 );
722 }
723 (1u64, 0u64, len as u64)
724 }
725 };
726
727 let dev = match event.device_id {
728 Some(device_id) => {
729 self.devices.get_mut(&device_id).unwrap_or(default_button_device)
730 }
731 None => default_button_device,
732 };
733
734 #[allow(clippy::collection_is_never_read)]
735 let mut tracked_leases = vec![];
736 if let Some(lease) = event.wake_lease.take() {
737 if let Some(status) = &dev.inspect_status {
738 tracked_leases.push(TrackedWakeLease::new(lease, status.clone()));
739 }
740 }
741
742 if let Some(dev_inspect_status) = &dev.inspect_status {
743 dev_inspect_status.count_total_received_events(1);
744 dev_inspect_status.count_total_ignored_events(ignored_events);
745 dev_inspect_status.count_total_converted_events(converted_events);
746 dev_inspect_status.count_total_generated_events(
747 generated_events,
748 batch.event_time.into_nanos().try_into().unwrap(),
749 );
750 } else {
751 log_warn!("unable to record inspect for button device");
752 }
753
754 dev.open_files.lock().retain(|f| {
755 let Some(file) = f.upgrade() else {
756 log_warn!("Dropping input file for buttons that failed to upgrade");
757 return false;
758 };
759 match &file.inspect_status {
760 Some(file_inspect_status) => {
761 file_inspect_status.count_received_events(1);
762 file_inspect_status.count_ignored_events(ignored_events);
763 file_inspect_status.count_converted_events(converted_events);
764 }
765 None => {
766 log_warn!("unable to record inspect within the input file")
767 }
768 }
769 if !batch.events.is_empty() {
770 if let Some(file_inspect_status) = &file.inspect_status {
771 file_inspect_status.count_generated_events(
772 generated_events,
773 batch.event_time.into_nanos().try_into().unwrap(),
774 );
775 }
776 file.add_events(batch.events.clone());
777 }
778
779 true
780 });
781
782 responder.send().expect("media buttons responder failed to respond");
783 }
784 _ => { }
785 }
786
787 (
788 power_was_pressed_after,
789 function_was_pressed_after,
790 volume_up_was_pressed_after,
791 volume_down_was_pressed_after,
792 )
793 }
794
795 fn process_touch_button_event(
796 &mut self,
797 default_touch_device: &mut DeviceState,
798 button_event: fuipolicy::TouchButtonsListenerRequest,
799 touch_buttons_were_pressed: &bit_vec::BitVec,
800 ) -> bit_vec::BitVec {
801 fuchsia_trace::duration!("input", "starnix_process_touch_button_event");
802 match button_event {
803 fuipolicy::TouchButtonsListenerRequest::OnEvent { mut event, responder } => {
804 if let Some(trace_flow_id) = event.trace_flow_id {
805 fuchsia_trace::flow_end!(
806 "input",
807 "dispatch_touch_button_to_listeners",
808 trace_flow_id.into()
809 );
810 }
811 let batch = parse_fidl_touch_button_event(&event, touch_buttons_were_pressed);
812
813 let (converted_events, ignored_events, generated_events) = match batch.events.len()
814 {
815 0 => (0u64, 1u64, 0u64),
816 len => {
817 if len % 2 == 1 {
818 log_warn!(
819 "unexpectedly received {} events: there should always be an even number of non-empty events.",
820 len
821 );
822 }
823 (1u64, 0u64, len as u64)
824 }
825 };
826
827 let device_id = match &event.device_info {
828 Some(TouchDeviceInfo { id: Some(id), .. }) => Some(*id),
829 _ => None,
830 };
831
832 let dev = match device_id {
833 Some(id) => self.devices.get_mut(&id).unwrap_or(default_touch_device),
834 None => default_touch_device,
835 };
836
837 #[allow(clippy::collection_is_never_read)]
838 let mut tracked_leases = vec![];
839 if let Some(lease) = event.wake_lease.take() {
840 if let Some(status) = &dev.inspect_status {
841 tracked_leases.push(TrackedWakeLease::new(lease, status.clone()));
842 }
843 }
844
845 if let Some(dev_inspect_status) = &dev.inspect_status {
846 dev_inspect_status.count_total_received_events(1);
847 dev_inspect_status.count_total_ignored_events(ignored_events);
848 dev_inspect_status.count_total_converted_events(converted_events);
849 dev_inspect_status.count_total_generated_events(
850 generated_events,
851 batch.event_time.into_nanos().try_into().unwrap(),
852 );
853 } else {
854 log_warn!("unable to record inspect for touch device");
855 }
856
857 dev.open_files.lock().retain(|f| {
858 let Some(file) = f.upgrade() else {
859 log_warn!("Dropping input file for touch that failed to upgrade");
860 return false;
861 };
862 match &file.inspect_status {
863 Some(file_inspect_status) => {
864 file_inspect_status.count_received_events(1);
865 file_inspect_status.count_ignored_events(ignored_events);
866 file_inspect_status.count_converted_events(converted_events);
867 }
868 None => {
869 log_warn!("unable to record inspect within the input file")
870 }
871 }
872 if !batch.events.is_empty() {
873 if let Some(file_inspect_status) = &file.inspect_status {
874 file_inspect_status.count_generated_events(
875 generated_events,
876 batch.event_time.into_nanos().try_into().unwrap(),
877 );
878 }
879 file.add_events(batch.events.clone());
880 }
881
882 true
883 });
884
885 responder.send().expect("touch buttons responder failed to respond");
886
887 batch.touch_buttons
888 }
889 fuipolicy::TouchButtonsListenerRequest::_UnknownMethod { ordinal, .. } => {
890 log_warn!("Received an unknown method with ordinal {ordinal}");
891 touch_buttons_were_pressed.clone()
892 }
893 }
894 }
895
896 fn process_mouse_event(
897 self: &mut Self,
898 default_mouse_device: &mut DeviceState,
899 mouse_events: Vec<FidlMouseEvent>,
900 ) {
901 fuchsia_trace::duration!("input", "starnix_process_mouse_event");
902 for e in &mouse_events {
903 if let Some(trace_flow_id) = e.trace_flow_id {
904 fuchsia_trace::flow_end!("input", "dispatch_event_to_client", trace_flow_id.into());
905 }
906 }
907 let num_received_events: u64 = mouse_events.len().try_into().unwrap();
913 let mut num_ignored_events: u64 = 0;
914
915 let (events_by_device, ignored_events) = group_mouse_events_by_device_id(mouse_events);
916 num_ignored_events += ignored_events;
917
918 for (device_id, mut events) in events_by_device {
919 fuchsia_trace::duration_begin!("input", "starnix_process_per_device_mouse_event");
920
921 let dev = self.devices.get_mut(&device_id).unwrap_or(default_mouse_device);
922
923 let mut num_converted_events: u64 = 0;
924 let mut num_unexpected_events: u64 = 0;
925 let mut new_events: VecDeque<uapi::input_event> = VecDeque::new();
926
927 #[allow(clippy::collection_is_never_read)]
928 let mut tracked_leases = vec![];
929 for event in &mut events {
930 if let Some(lease) = event.wake_lease.take() {
931 if let Some(status) = &dev.inspect_status {
932 tracked_leases.push(TrackedWakeLease::new(lease, status.clone()));
933 }
934 }
935 }
936
937 let last_event_time_ns: i64;
938 if let InputDeviceType::Mouse(ref mut converter) = dev.device_type {
939 let mut batch = converter.handle(events);
940 new_events.append(&mut batch.events);
941 num_converted_events += batch.count_converted_events;
942 num_ignored_events += batch.count_ignored_events;
943 num_unexpected_events += batch.count_unexpected_events;
944 last_event_time_ns = batch.last_event_time_ns;
945 } else {
946 fuchsia_trace::duration_end!("input", "starnix_process_per_device_mouse_event");
947 log_warn!(
948 "Non mouse device received mouse events: device_id = {}, device_type = {}",
949 device_id,
950 dev.device_type
951 );
952 continue;
953 }
954
955 if !new_events.is_empty() {
956 dev.registration.ensure_registered();
957 }
958
959 if let Some(dev_inspect_status) = &dev.inspect_status {
960 dev_inspect_status.count_total_received_events(num_received_events);
961 dev_inspect_status.count_total_ignored_events(num_ignored_events);
962 dev_inspect_status.count_total_unexpected_events(num_unexpected_events);
963 dev_inspect_status.count_total_converted_events(num_converted_events);
964 if !new_events.is_empty() {
965 dev_inspect_status.count_total_generated_events(
966 new_events.len().try_into().unwrap(),
967 last_event_time_ns,
968 );
969 }
970 } else {
971 log_warn!(
972 "unable to record inspect for device_id: {}, device_type: {}",
973 device_id,
974 dev.device_type
975 );
976 }
977
978 fuchsia_trace::duration_end!("input", "starnix_process_per_device_mouse_event");
979 let mut open_files = dev.open_files.lock();
980 if !open_files.has_been_opened && !new_events.is_empty() {
981 open_files.buffered_events.extend(new_events.iter().copied());
982 }
983 open_files.retain(|f| {
984 let Some(file) = f.upgrade() else {
985 log_warn!("Dropping input file for mouse that failed to upgrade");
986 return false;
987 };
988 if let Some(file_inspect_status) = &file.inspect_status {
989 file_inspect_status.count_received_events(num_received_events);
990 file_inspect_status.count_ignored_events(num_ignored_events);
991 file_inspect_status.count_unexpected_events(num_unexpected_events);
992 file_inspect_status.count_converted_events(num_converted_events);
993 }
994 if !new_events.is_empty() {
995 if let Some(file_inspect_status) = &file.inspect_status {
996 file_inspect_status.count_generated_events(
997 new_events.len().try_into().unwrap(),
998 last_event_time_ns,
999 );
1000 }
1001 file.add_events(new_events.clone().into_iter().collect());
1002 }
1003 true
1004 });
1005 }
1006 }
1007}
1008
1009fn setup_touch_relay(
1010 kernel: &Arc<Kernel>,
1011 event_proxy_mode: EventProxyMode,
1012 touch_source_client_end: ClientEnd<fuipointer::TouchSourceV2Marker>,
1013 default_touch_device_opened_files: OpenedFiles,
1014 device_inspect_status: Option<Arc<InputDeviceStatus>>,
1015) -> (
1016 DeviceState,
1017 fuipointer::TouchSourceV2Proxy,
1018 ContainerWakingStream<fuipointer::TouchSourceV2EventStream>,
1019) {
1020 let touch_counter_name = "touch";
1021 let default_touch_device = DeviceState {
1022 device_type: InputDeviceType::Touch(FuchsiaTouchEventToLinuxTouchEventConverter::create()),
1023 open_files: default_touch_device_opened_files,
1024 inspect_status: device_inspect_status,
1025 registration: DeviceRegistration::Registered,
1026 };
1027 let (touch_source_proxy, counter) = match event_proxy_mode {
1028 EventProxyMode::WakeContainer => {
1029 let (touch_source_channel, counter) = create_proxy_for_wake_events_counter(
1032 touch_source_client_end.into_channel(),
1033 touch_counter_name.to_string(),
1034 );
1035 (
1036 fuipointer::TouchSourceV2Proxy::new(fidl::AsyncChannel::from_channel(
1037 touch_source_channel,
1038 )),
1039 Some(counter),
1040 )
1041 }
1042 EventProxyMode::None => (touch_source_client_end.into_proxy(), None),
1043 };
1044 let waking_stream = ContainerWakingStream::new(
1045 kernel.suspend_resume_manager.add_message_counter(touch_counter_name, counter),
1046 touch_source_proxy.take_event_stream(),
1047 );
1048 (default_touch_device, touch_source_proxy, waking_stream)
1049}
1050
1051fn setup_keyboard_relay(
1052 keyboard: KeyboardSynchronousProxy,
1053 view_ref: fuiviews::ViewRef,
1054 default_keyboard_device_opened_files: OpenedFiles,
1055 device_inspect_status: Option<Arc<InputDeviceStatus>>,
1056) -> (DeviceState, KeyboardListenerRequestStream, KeyboardSynchronousProxy) {
1057 let default_keyboard_device = DeviceState {
1058 device_type: InputDeviceType::Keyboard,
1059 open_files: default_keyboard_device_opened_files,
1060 inspect_status: device_inspect_status,
1061 registration: DeviceRegistration::Registered,
1062 };
1063 let (keyboard_listener, event_stream) =
1064 fidl::endpoints::create_request_stream::<KeyboardListenerMarker>();
1065 if let Err(e) =
1066 keyboard.add_listener(view_ref, keyboard_listener, zx::MonotonicInstant::INFINITE)
1067 {
1068 log_warn!("Could not register keyboard listener: {:?}", e);
1069 }
1070
1071 (default_keyboard_device, event_stream, keyboard)
1072}
1073
1074fn setup_button_relay(
1075 kernel: &Arc<Kernel>,
1076 registry_proxy: fuipolicy::DeviceListenerRegistrySynchronousProxy,
1077 event_proxy_mode: EventProxyMode,
1078 default_keyboard_device_opened_files: OpenedFiles,
1079 device_inspect_status: Option<Arc<InputDeviceStatus>>,
1080) -> (
1081 DeviceState,
1082 ContainerWakingStream<fuipolicy::MediaButtonsListenerRequestStream>,
1083 ContainerWakingStream<fuipolicy::TouchButtonsListenerRequestStream>,
1084) {
1085 let default_keyboard_device = DeviceState {
1086 device_type: InputDeviceType::Keyboard,
1087 open_files: default_keyboard_device_opened_files,
1088 inspect_status: device_inspect_status,
1089 registration: DeviceRegistration::Registered,
1090 };
1091 let media_buttons_name = "media buttons";
1092 let touch_buttons_name = "touch buttons";
1093
1094 let (remote_media_button_client, remote_media_button_server) =
1095 fidl::endpoints::create_endpoints::<fuipolicy::MediaButtonsListenerMarker>();
1096 if let Err(e) =
1097 registry_proxy.register_listener(remote_media_button_client, zx::MonotonicInstant::INFINITE)
1098 {
1099 log_warn!("Failed to register media buttons listener: {:?}", e);
1100 }
1101
1102 let (remote_touch_button_client, remote_touch_button_server) =
1103 fidl::endpoints::create_endpoints::<fuipolicy::TouchButtonsListenerMarker>();
1104 if let Err(e) = registry_proxy
1105 .register_touch_buttons_listener(remote_touch_button_client, zx::MonotonicInstant::INFINITE)
1106 {
1107 log_warn!("Failed to register touch buttons listener: {:?}", e);
1108 }
1109
1110 let (
1111 local_media_buttons_listener_stream,
1112 media_buttons_counter,
1113 local_touch_buttons_listener_stream,
1114 touch_buttons_counter,
1115 ) = match event_proxy_mode {
1116 EventProxyMode::WakeContainer => {
1117 let (local_media_buttons_channel, media_buttons_counter) =
1118 create_proxy_for_wake_events_counter(
1119 remote_media_button_server.into_channel(),
1120 media_buttons_name.to_string(),
1121 );
1122 let local_media_buttons_listener_stream =
1123 fuipolicy::MediaButtonsListenerRequestStream::from_channel(
1124 fidl::AsyncChannel::from_channel(local_media_buttons_channel),
1125 );
1126
1127 let (local_touch_buttons_channel, touch_buttons_counter) =
1128 create_proxy_for_wake_events_counter(
1129 remote_touch_button_server.into_channel(),
1130 touch_buttons_name.to_string(),
1131 );
1132 let local_touch_buttons_listener_stream =
1133 fuipolicy::TouchButtonsListenerRequestStream::from_channel(
1134 fidl::AsyncChannel::from_channel(local_touch_buttons_channel),
1135 );
1136 (
1137 local_media_buttons_listener_stream,
1138 Some(media_buttons_counter),
1139 local_touch_buttons_listener_stream,
1140 Some(touch_buttons_counter),
1141 )
1142 }
1143 EventProxyMode::None => (
1144 remote_media_button_server.into_stream(),
1145 None,
1146 remote_touch_button_server.into_stream(),
1147 None,
1148 ),
1149 };
1150
1151 (
1152 default_keyboard_device,
1153 ContainerWakingStream::new(
1154 kernel
1155 .suspend_resume_manager
1156 .add_message_counter(media_buttons_name, media_buttons_counter),
1157 local_media_buttons_listener_stream,
1158 ),
1159 ContainerWakingStream::new(
1160 kernel
1161 .suspend_resume_manager
1162 .add_message_counter(touch_buttons_name, touch_buttons_counter),
1163 local_touch_buttons_listener_stream,
1164 ),
1165 )
1166}
1167
1168fn setup_mouse_relay(
1169 kernel: &Arc<Kernel>,
1170 event_proxy_mode: EventProxyMode,
1171 mouse_source_client_end: ClientEnd<fuipointer::MouseSourceV2Marker>,
1172 default_mouse_device: Option<crate::InputDevice>,
1173) -> (
1174 DeviceState,
1175 fuipointer::MouseSourceV2Proxy,
1176 ContainerWakingStream<fuipointer::MouseSourceV2EventStream>,
1177) {
1178 let mouse_counter_name = "mouse";
1179 let (open_files, inspect_status, registration) = match default_mouse_device {
1180 Some(dev) => (
1181 dev.open_files.clone(),
1182 Some(dev.inspect_status.clone()),
1183 DeviceRegistration::pending(kernel.clone(), dev, DEFAULT_MOUSE_DEVICE_ID),
1184 ),
1185 None => (Default::default(), None, DeviceRegistration::Registered),
1186 };
1187 let default_mouse_device = DeviceState {
1188 device_type: InputDeviceType::Mouse(FuchsiaMouseEventToLinuxMouseEventConverter::create()),
1189 open_files,
1190 inspect_status,
1191 registration,
1192 };
1193 let (mouse_source_proxy, counter) = match event_proxy_mode {
1194 EventProxyMode::WakeContainer => {
1195 let (mouse_source_channel, resume_event) = create_proxy_for_wake_events_counter(
1198 mouse_source_client_end.into_channel(),
1199 "mouse".to_string(),
1200 );
1201 (
1202 fuipointer::MouseSourceV2Proxy::new(fidl::AsyncChannel::from_channel(
1203 mouse_source_channel,
1204 )),
1205 Some(resume_event),
1206 )
1207 }
1208 EventProxyMode::None => (mouse_source_client_end.into_proxy(), None),
1209 };
1210
1211 let waking_stream = ContainerWakingStream::new(
1212 kernel.suspend_resume_manager.add_message_counter(mouse_counter_name, counter),
1213 mouse_source_proxy.take_event_stream(),
1214 );
1215
1216 (default_mouse_device, mouse_source_proxy, waking_stream)
1217}
1218
1219fn group_mouse_events_by_device_id(
1220 events: Vec<FidlMouseEvent>,
1221) -> (SortedVecMap<DeviceId, Vec<FidlMouseEvent>>, u64) {
1222 let mut events_by_device: SortedVecMap<u32, Vec<FidlMouseEvent>> = SortedVecMap::new();
1223 let mut ignored_events: u64 = 0;
1224 for e in events {
1225 match e {
1226 FidlMouseEvent { pointer_sample: Some(ref sample), .. } => {
1227 let id = sample.device_id.unwrap_or(DEFAULT_MOUSE_DEVICE_ID);
1228 if let Some(vec) = events_by_device.get_mut(&id) {
1229 vec.push(e);
1230 } else {
1231 events_by_device.insert(id, vec![e]);
1232 }
1233 }
1234 _ => {
1235 ignored_events += 1;
1236 }
1237 }
1238 }
1239
1240 (events_by_device, ignored_events)
1241}
1242
1243fn group_touch_events_by_device_id(
1244 events: Vec<FidlTouchEvent>,
1245) -> (SortedVecMap<DeviceId, Vec<FidlTouchEvent>>, u64) {
1246 let mut events_by_device: SortedVecMap<u32, Vec<FidlTouchEvent>> = SortedVecMap::new();
1247 let mut ignored_events: u64 = 0;
1248 for e in events {
1249 match e {
1250 FidlTouchEvent {
1251 pointer_sample: Some(TouchPointerSample { interaction: Some(id), .. }),
1252 ..
1253 } => {
1254 if let Some(vec) = events_by_device.get_mut(&id.device_id) {
1255 vec.push(e);
1256 } else {
1257 events_by_device.insert(id.device_id, vec![e]);
1258 }
1259 }
1260 _ => {
1261 ignored_events += 1;
1262 }
1263 }
1264 }
1265
1266 (events_by_device, ignored_events)
1267}
1268
1269#[cfg(test)]
1270pub async fn start_input_relays_for_test(
1271 current_task: &starnix_core::task::CurrentTask,
1272 event_proxy_mode: EventProxyMode,
1273) -> (
1274 Arc<InputEventsRelayHandle>,
1275 crate::InputDevice,
1276 crate::InputDevice,
1277 crate::InputDevice,
1278 starnix_core::vfs::FileHandle,
1279 starnix_core::vfs::FileHandle,
1280 starnix_core::vfs::FileHandle,
1281 fuipointer::TouchSourceV2RequestStream,
1282 fuipointer::MouseSourceV2RequestStream,
1283 fidl_fuchsia_ui_input3::KeyboardListenerProxy,
1284 fuipolicy::MediaButtonsListenerProxy,
1285 fuipolicy::TouchButtonsListenerProxy,
1286) {
1287 let inspector = fuchsia_inspect::Inspector::default();
1288
1289 let touch_device = crate::InputDevice::new_touch(700, 1200, inspector.root());
1290 let touch_file = touch_device.open_test(current_task).expect("Failed to create input file");
1291
1292 let keyboard_device = crate::InputDevice::new_keyboard(inspector.root());
1293 let keyboard_file =
1294 keyboard_device.open_test(current_task).expect("Failed to create input file");
1295
1296 let mouse_device = crate::InputDevice::new_mouse(inspector.root());
1297 let mouse_file = mouse_device.open_test(current_task).expect("Failed to create input file");
1298
1299 let (touch_source_client_end, touch_source_stream) =
1300 fidl::endpoints::create_request_stream::<fuipointer::TouchSourceV2Marker>();
1301 let (mouse_source_client_end, mouse_stream) =
1302 fidl::endpoints::create_request_stream::<fuipointer::MouseSourceV2Marker>();
1303 let (keyboard_proxy, mut keyboard_stream) =
1304 fidl::endpoints::create_sync_proxy_and_stream::<fidl_fuchsia_ui_input3::KeyboardMarker>();
1305 let view_ref_pair = fuchsia_scenic::ViewRefPair::new().expect("Failed to create ViewRefPair");
1306 let (device_registry_proxy, mut device_listener_stream) =
1307 fidl::endpoints::create_sync_proxy_and_stream::<fuipolicy::DeviceListenerRegistryMarker>();
1308
1309 let (relay, relay_handle) = new_input_relay();
1310 relay.start_relays(
1311 ¤t_task.kernel(),
1312 event_proxy_mode,
1313 touch_source_client_end,
1314 keyboard_proxy,
1315 mouse_source_client_end,
1316 view_ref_pair.view_ref,
1317 device_registry_proxy,
1318 touch_device.open_files.clone(),
1319 keyboard_device.open_files.clone(),
1320 Some(mouse_device.clone()),
1321 Some(touch_device.inspect_status.clone()),
1322 Some(keyboard_device.inspect_status.clone()),
1323 );
1324
1325 let keyboard_listener = match keyboard_stream.next().await {
1326 Some(Ok(fidl_fuchsia_ui_input3::KeyboardRequest::AddListener {
1327 view_ref: _,
1328 listener,
1329 responder,
1330 })) => {
1331 let _ = responder.send();
1332 listener.into_proxy()
1333 }
1334 _ => {
1335 panic!("Failed to get event");
1336 }
1337 };
1338
1339 let media_buttons_listener = match device_listener_stream.next().await {
1340 Some(Ok(fuipolicy::DeviceListenerRegistryRequest::RegisterListener {
1341 listener,
1342 responder,
1343 })) => {
1344 let _ = responder.send();
1345 listener.into_proxy()
1346 }
1347 _ => {
1348 panic!("Failed to get event");
1349 }
1350 };
1351
1352 let touch_buttons_listener = match device_listener_stream.next().await {
1353 Some(Ok(fuipolicy::DeviceListenerRegistryRequest::RegisterTouchButtonsListener {
1354 listener,
1355 responder,
1356 })) => {
1357 let _ = responder.send();
1358 listener.into_proxy()
1359 }
1360 _ => {
1361 panic!("Failed to get event");
1362 }
1363 };
1364
1365 (
1366 relay_handle,
1367 touch_device,
1368 keyboard_device,
1369 mouse_device,
1370 touch_file,
1371 keyboard_file,
1372 mouse_file,
1373 touch_source_stream,
1374 mouse_stream,
1375 keyboard_listener,
1376 media_buttons_listener,
1377 touch_buttons_listener,
1378 )
1379}
1380
1381#[cfg(test)]
1382mod test {
1383 use super::*;
1384 use anyhow::anyhow;
1385 use fidl_fuchsia_ui_input::{
1386 MediaButtonsEvent, TouchButton, TouchButtonsEvent, TouchDeviceInfo,
1387 };
1388 use fidl_fuchsia_ui_input3 as fuiinput;
1389 use fuipointer::{
1390 EventPhase, MouseEvent, MousePointerSample, TouchEvent, TouchInteractionId,
1391 TouchPointerSample, TouchSourceV2Request, TouchSourceV2RequestStream,
1392 };
1393 use starnix_core::task::CurrentTask;
1394 use starnix_core::testing::spawn_kernel_and_run;
1395 use starnix_core::vfs::{FileHandle, FileObject, VecOutputBuffer};
1396
1397 use starnix_types::time::timeval_from_time;
1398 use starnix_uapi::errors::{EAGAIN, Errno};
1399 use starnix_uapi::input_id;
1400 use starnix_uapi::open_flags::OpenFlags;
1401 use zerocopy::FromBytes as _;
1402
1403 const INPUT_EVENT_SIZE: usize = std::mem::size_of::<uapi::input_event>();
1404
1405 async fn answer_next_touch_watch_request(
1407 request_stream: &mut TouchSourceV2RequestStream,
1408 touch_events: Vec<TouchEvent>,
1409 ) {
1410 let control_handle = request_stream.control_handle();
1411 control_handle
1412 .send_on_touch_events(touch_events, 1)
1413 .expect("failure sending OnTouchEvents");
1414 match request_stream.next().await {
1415 Some(Ok(TouchSourceV2Request::AcknowledgeEvents { .. })) => {}
1416 unexpected_request => panic!("unexpected request {:?}", unexpected_request),
1417 }
1418 }
1419
1420 async fn answer_next_mouse_watch_request(
1422 request_stream: &mut fuipointer::MouseSourceV2RequestStream,
1423 mouse_events: Vec<MouseEvent>,
1424 ) {
1425 let control_handle = request_stream.control_handle();
1426 control_handle
1427 .send_on_mouse_events(mouse_events, 1)
1428 .expect("failure sending OnMouseEvents");
1429 match request_stream.next().await {
1430 Some(Ok(fuipointer::MouseSourceV2Request::AcknowledgeEvents { .. })) => {}
1431 unexpected_request => panic!("unexpected request {:?}", unexpected_request),
1432 }
1433 }
1434
1435 fn make_empty_touch_event(device_id: u32) -> TouchEvent {
1436 TouchEvent {
1437 pointer_sample: Some(TouchPointerSample {
1438 interaction: Some(TouchInteractionId {
1439 pointer_id: 0,
1440 device_id,
1441 interaction_id: 0,
1442 }),
1443 ..Default::default()
1444 }),
1445 ..Default::default()
1446 }
1447 }
1448
1449 fn make_touch_event_with_phase_device_id(
1450 phase: EventPhase,
1451 pointer_id: u32,
1452 device_id: u32,
1453 ) -> TouchEvent {
1454 make_touch_event_with_phase_device_id_position(phase, pointer_id, device_id, 0.0, 0.0)
1455 }
1456
1457 fn make_touch_event_with_phase_device_id_position(
1458 phase: EventPhase,
1459 pointer_id: u32,
1460 device_id: u32,
1461 x: f32,
1462 y: f32,
1463 ) -> TouchEvent {
1464 TouchEvent {
1465 timestamp: Some(0),
1466 pointer_sample: Some(TouchPointerSample {
1467 position_in_viewport: Some([x, y]),
1468 phase: Some(phase),
1469 interaction: Some(TouchInteractionId { pointer_id, device_id, interaction_id: 0 }),
1470 ..Default::default()
1471 }),
1472 ..Default::default()
1473 }
1474 }
1475
1476 fn make_mouse_wheel_event(scroll_v_ticks: i64, device_id: u32) -> MouseEvent {
1477 MouseEvent {
1478 timestamp: Some(0),
1479 pointer_sample: Some(MousePointerSample {
1480 device_id: Some(device_id),
1481 scroll_v: Some(scroll_v_ticks),
1482 ..Default::default()
1483 }),
1484 ..Default::default()
1485 }
1486 }
1487
1488 fn read_uapi_events(file: &FileHandle, current_task: &CurrentTask) -> Vec<uapi::input_event> {
1489 std::iter::from_fn(|| {
1490 let mut event_bytes = VecOutputBuffer::new(INPUT_EVENT_SIZE);
1491 match file.read(current_task, &mut event_bytes) {
1492 Ok(INPUT_EVENT_SIZE) => Some(
1493 uapi::input_event::read_from_bytes(Vec::from(event_bytes).as_slice())
1494 .map_err(|_| anyhow!("failed to read input_event from buffer")),
1495 ),
1496 Ok(other_size) => {
1497 Some(Err(anyhow!("got {} bytes (expected {})", other_size, INPUT_EVENT_SIZE)))
1498 }
1499 Err(Errno { code: EAGAIN, .. }) => None,
1500 Err(other_error) => Some(Err(anyhow!("read failed: {:?}", other_error))),
1501 }
1502 })
1503 .enumerate()
1504 .map(|(i, read_res)| match read_res {
1505 Ok(event) => event,
1506 Err(e) => panic!("unexpected result {:?} on iteration {}", e, i),
1507 })
1508 .collect()
1509 }
1510
1511 fn create_test_touch_device(
1512 current_task: &CurrentTask,
1513 input_relay: Arc<InputEventsRelayHandle>,
1514 device_id: u32,
1515 ) -> FileHandle {
1516 let open_files: OpenedFiles = Default::default();
1517 input_relay.add_touch_device(device_id, open_files.clone(), None);
1518 let inspector = fuchsia_inspect::Inspector::default();
1519 let device_file = Arc::new(InputFile::new_touch(
1520 input_id { bustype: 0, vendor: 0, product: 0, version: 0 },
1521 1000,
1522 1000,
1523 inspector.root(),
1524 ));
1525 open_files.lock().push(Arc::downgrade(&device_file));
1526
1527 let root_namespace_node = current_task
1528 .lookup_path_from_root(".".into())
1529 .expect("failed to get namespace node for root");
1530
1531 FileObject::new(
1532 ¤t_task,
1533 Box::new(crate::input_file::ArcInputFile(device_file)),
1534 root_namespace_node,
1535 OpenFlags::empty(),
1536 )
1537 .expect("FileObject::new failed")
1538 }
1539
1540 fn make_uapi_input_event(ty: u32, code: u32, value: i32) -> uapi::input_event {
1541 uapi::input_event {
1542 time: timeval_from_time(zx::MonotonicInstant::from_nanos(0)),
1543 type_: ty as u16,
1544 code: code as u16,
1545 value,
1546 }
1547 }
1548
1549 #[::fuchsia::test]
1550 async fn route_touch_event_by_device_id() {
1551 spawn_kernel_and_run(async move |current_task| {
1552 let (
1555 input_relay,
1556 _touch_device,
1557 _keyboard_device,
1558 _mouse_device,
1559 input_file,
1560 _keyboard_file,
1561 _mouse_file,
1562 mut touch_source_stream,
1563 _mouse_source_stream,
1564 _keyboard_listener,
1565 _media_buttons_listener,
1566 _touch_buttons_listener,
1567 ) = start_input_relays_for_test(¤t_task, EventProxyMode::None).await;
1568
1569 const DEVICE_ID: u32 = 10;
1570
1571 answer_next_touch_watch_request(
1572 &mut touch_source_stream,
1573 vec![make_touch_event_with_phase_device_id(EventPhase::Add, 1, DEVICE_ID)],
1574 )
1575 .await;
1576
1577 answer_next_touch_watch_request(
1581 &mut touch_source_stream,
1582 vec![make_empty_touch_event(DEVICE_ID)],
1583 )
1584 .await;
1585
1586 let events = read_uapi_events(&input_file, ¤t_task);
1588 assert_ne!(events.len(), 0);
1590
1591 let device_id_10_file =
1593 create_test_touch_device(¤t_task, input_relay.clone(), DEVICE_ID);
1594
1595 answer_next_touch_watch_request(
1596 &mut touch_source_stream,
1597 vec![make_touch_event_with_phase_device_id(EventPhase::Add, 1, DEVICE_ID)],
1598 )
1599 .await;
1600
1601 answer_next_touch_watch_request(
1602 &mut touch_source_stream,
1603 vec![make_empty_touch_event(DEVICE_ID)],
1604 )
1605 .await;
1606
1607 let events = read_uapi_events(&input_file, ¤t_task);
1608 assert_eq!(events.len(), 0);
1610
1611 let events = read_uapi_events(&device_id_10_file, ¤t_task);
1612 assert_ne!(events.len(), 0);
1614 })
1615 .await;
1616 }
1617
1618 #[::fuchsia::test]
1619 async fn route_touch_event_with_wake_lease() {
1620 spawn_kernel_and_run(async move |current_task| {
1621 let (
1622 _input_relay,
1623 touch_device,
1624 _keyboard_device,
1625 _mouse_device,
1626 _input_file,
1627 _keyboard_file,
1628 _mouse_file,
1629 mut touch_source_stream,
1630 _mouse_source_stream,
1631 _keyboard_listener,
1632 _media_buttons_listener,
1633 _touch_buttons_listener,
1634 ) = start_input_relays_for_test(¤t_task, EventProxyMode::None).await;
1635
1636 const DEVICE_ID: u32 = 10;
1637 let mut event = make_touch_event_with_phase_device_id(EventPhase::Add, 1, DEVICE_ID);
1638 let (p1, _p2) = fidl::EventPair::create();
1639 event.wake_lease = Some(p1);
1640
1641 answer_next_touch_watch_request(&mut touch_source_stream, vec![event]).await;
1642
1643 answer_next_touch_watch_request(
1645 &mut touch_source_stream,
1646 vec![make_empty_touch_event(DEVICE_ID)],
1647 )
1648 .await;
1649
1650 let status = &touch_device.inspect_status;
1651 assert_eq!(
1652 status
1653 .total_events_with_wake_lease_count
1654 .load(std::sync::atomic::Ordering::Relaxed),
1655 1
1656 );
1657 assert_eq!(
1658 status.active_wake_leases_count.load(std::sync::atomic::Ordering::Relaxed),
1659 0
1660 );
1661 })
1662 .await;
1663 }
1664
1665 #[::fuchsia::test]
1666 async fn route_touch_event_by_device_id_multi_device_events_in_one_sequence() {
1667 spawn_kernel_and_run(async move |current_task| {
1668 let (
1669 input_relay,
1670 _touch_device,
1671 _keyboard_device,
1672 _mouse_device,
1673 _input_file,
1674 _keyboard_file,
1675 _mouse_file,
1676 mut touch_source_stream,
1677 _mouse_source_stream,
1678 _keyboard_listener,
1679 _media_buttons_listener,
1680 _touch_buttons_listener,
1681 ) = start_input_relays_for_test(¤t_task, EventProxyMode::None).await;
1682
1683 const DEVICE_ID_10: u32 = 10;
1684 const DEVICE_ID_11: u32 = 11;
1685
1686 let device_id_10_file =
1687 create_test_touch_device(¤t_task, input_relay.clone(), DEVICE_ID_10);
1688
1689 let device_id_11_file =
1690 create_test_touch_device(¤t_task, input_relay.clone(), DEVICE_ID_11);
1691
1692 answer_next_touch_watch_request(
1694 &mut touch_source_stream,
1695 vec![
1696 make_touch_event_with_phase_device_id_position(
1697 EventPhase::Add,
1698 1,
1699 DEVICE_ID_10,
1700 10.0,
1701 20.0,
1702 ),
1703 make_touch_event_with_phase_device_id_position(
1704 EventPhase::Add,
1705 2,
1706 DEVICE_ID_11,
1707 30.0,
1708 40.0,
1709 ),
1710 ],
1711 )
1712 .await;
1713
1714 answer_next_touch_watch_request(&mut touch_source_stream, vec![]).await;
1715
1716 let events_10 = read_uapi_events(&device_id_10_file, ¤t_task);
1717 let events_11 = read_uapi_events(&device_id_11_file, ¤t_task);
1718 assert_eq!(events_10.len(), events_11.len());
1719
1720 assert_eq!(
1721 events_10,
1722 vec![
1723 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0),
1724 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 1),
1725 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 10),
1726 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 20),
1727 make_uapi_input_event(uapi::EV_KEY, uapi::BTN_TOUCH, 1),
1728 make_uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0),
1729 ]
1730 );
1731
1732 assert_eq!(
1733 events_11,
1734 vec![
1735 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0),
1736 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 2),
1737 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 30),
1738 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 40),
1739 make_uapi_input_event(uapi::EV_KEY, uapi::BTN_TOUCH, 1),
1740 make_uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0),
1741 ]
1742 );
1743 })
1744 .await;
1745 }
1746
1747 #[::fuchsia::test]
1748 async fn route_key_event_by_device_id() {
1749 spawn_kernel_and_run(async move |current_task| {
1750 let (
1753 input_relay,
1754 _touch_device,
1755 _keyboard_device,
1756 _mouse_device,
1757 _touch_file,
1758 keyboard_file,
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(¤t_task, EventProxyMode::None).await;
1766
1767 const DEVICE_ID: u32 = 10;
1768
1769 let key_event = fuiinput::KeyEvent {
1770 timestamp: Some(0),
1771 type_: Some(fuiinput::KeyEventType::Pressed),
1772 key: Some(fidl_fuchsia_input::Key::A),
1773 device_id: Some(DEVICE_ID),
1774 ..Default::default()
1775 };
1776
1777 let _ = keyboard_listener.on_key_event(&key_event).await;
1778
1779 let events = read_uapi_events(&keyboard_file, ¤t_task);
1780 assert_ne!(events.len(), 0);
1782
1783 let open_files: OpenedFiles = Default::default();
1785 input_relay.add_keyboard_device(DEVICE_ID, open_files.clone(), None);
1786 let inspector = fuchsia_inspect::Inspector::default();
1787 let device_id_10_file = Arc::new(InputFile::new_keyboard(
1788 input_id { bustype: 0, vendor: 0, product: 0, version: 0 },
1789 inspector.root(),
1790 ));
1791 open_files.lock().push(Arc::downgrade(&device_id_10_file));
1792 let root_namespace_node = current_task
1793 .lookup_path_from_root(".".into())
1794 .expect("failed to get namespace node for root");
1795 let device_id_10_file_object = FileObject::new(
1796 ¤t_task,
1797 Box::new(crate::input_file::ArcInputFile(device_id_10_file)),
1798 root_namespace_node,
1799 OpenFlags::empty(),
1800 )
1801 .expect("FileObject::new failed");
1802
1803 let _ = keyboard_listener.on_key_event(&key_event).await;
1804
1805 let events = read_uapi_events(&keyboard_file, ¤t_task);
1806 assert_eq!(events.len(), 0);
1808
1809 let events = read_uapi_events(&device_id_10_file_object, ¤t_task);
1810 assert_ne!(events.len(), 0);
1812
1813 std::mem::drop(keyboard_listener); })
1815 .await;
1816 }
1817
1818 #[::fuchsia::test]
1819 async fn route_media_button_event_by_device_id() {
1820 spawn_kernel_and_run(async move |current_task| {
1821 let (
1824 input_relay,
1825 _touch_device,
1826 _keyboard_device,
1827 _mouse_device,
1828 _touch_file,
1829 keyboard_file,
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(¤t_task, EventProxyMode::None).await;
1837
1838 const DEVICE_ID: u32 = 10;
1839
1840 let power_pressed_event = MediaButtonsEvent {
1841 volume: Some(0),
1842 mic_mute: Some(false),
1843 pause: Some(false),
1844 camera_disable: Some(false),
1845 power: Some(true),
1846 function: Some(false),
1847 device_id: Some(DEVICE_ID),
1848 ..Default::default()
1849 };
1850
1851 let _ = media_buttons_listener.on_event(power_pressed_event).await;
1852
1853 let events = read_uapi_events(&keyboard_file, ¤t_task);
1854 assert_ne!(events.len(), 0);
1856
1857 let open_files: OpenedFiles = Default::default();
1859 input_relay.add_keyboard_device(DEVICE_ID, open_files.clone(), None);
1860 let inspector = fuchsia_inspect::Inspector::default();
1861 let device_id_10_file = Arc::new(InputFile::new_keyboard(
1862 input_id { bustype: 0, vendor: 0, product: 0, version: 0 },
1863 inspector.root(),
1864 ));
1865 open_files.lock().push(Arc::downgrade(&device_id_10_file));
1866 let root_namespace_node = current_task
1867 .lookup_path_from_root(".".into())
1868 .expect("failed to get namespace node for root");
1869 let device_id_10_file_object = FileObject::new(
1870 ¤t_task,
1871 Box::new(crate::input_file::ArcInputFile(device_id_10_file)),
1872 root_namespace_node,
1873 OpenFlags::empty(),
1874 )
1875 .expect("FileObject::new failed");
1876
1877 let power_released_event = MediaButtonsEvent {
1878 volume: Some(0),
1879 mic_mute: Some(false),
1880 pause: Some(false),
1881 camera_disable: Some(false),
1882 power: Some(false),
1883 function: Some(false),
1884 device_id: Some(DEVICE_ID),
1885 ..Default::default()
1886 };
1887
1888 let _ = media_buttons_listener.on_event(power_released_event).await;
1889
1890 let events = read_uapi_events(&keyboard_file, ¤t_task);
1891 assert_eq!(events.len(), 0);
1893
1894 let events = read_uapi_events(&device_id_10_file_object, ¤t_task);
1895 assert_ne!(events.len(), 0);
1897
1898 std::mem::drop(media_buttons_listener); })
1900 .await;
1901 }
1902
1903 #[::fuchsia::test]
1904 async fn route_touch_button_event_by_device_id() {
1905 spawn_kernel_and_run(async move |current_task| {
1906 let (
1909 input_relay,
1910 _touch_device,
1911 _keyboard_device,
1912 _mouse_device,
1913 touch_file,
1914 _keyboard_file,
1915 _mouse_file,
1916 _touch_source_stream,
1917 _mouse_source_stream,
1918 _keyboard_listener,
1919 _media_buttons_listener,
1920 touch_buttons_listener,
1921 ) = start_input_relays_for_test(¤t_task, EventProxyMode::None).await;
1922
1923 const DEVICE_ID: u32 = 10;
1924
1925 let palm_pressed_event: TouchButtonsEvent = TouchButtonsEvent {
1926 pressed_buttons: Some(vec![TouchButton::Palm]),
1927 device_info: Some(TouchDeviceInfo { id: Some(DEVICE_ID), ..Default::default() }),
1928 ..Default::default()
1929 };
1930
1931 let _ = touch_buttons_listener.on_event(palm_pressed_event).await;
1932
1933 let events = read_uapi_events(&touch_file, ¤t_task);
1934 assert_ne!(events.len(), 0);
1936
1937 let open_files: OpenedFiles = Default::default();
1939 input_relay.add_touch_device(DEVICE_ID, open_files.clone(), None);
1940 let device_id_10_file =
1941 create_test_touch_device(¤t_task, input_relay.clone(), DEVICE_ID);
1942
1943 let palm_released_event: TouchButtonsEvent = TouchButtonsEvent {
1944 pressed_buttons: Some(vec![]),
1945 device_info: Some(TouchDeviceInfo { id: Some(DEVICE_ID), ..Default::default() }),
1946 ..Default::default()
1947 };
1948
1949 let _ = touch_buttons_listener.on_event(palm_released_event).await;
1950
1951 let events = read_uapi_events(&touch_file, ¤t_task);
1952 assert_eq!(events.len(), 0);
1954
1955 let events = read_uapi_events(&device_id_10_file, ¤t_task);
1956 assert_ne!(events.len(), 0);
1958
1959 std::mem::drop(touch_buttons_listener); })
1961 .await;
1962 }
1963
1964 #[::fuchsia::test]
1965 async fn touch_device_multi_reader() {
1966 spawn_kernel_and_run(async move |current_task| {
1967 let (
1970 _input_relay,
1971 touch_device,
1972 _keyboard_device,
1973 _mouse_device,
1974 touch_reader1,
1975 _keyboard_file,
1976 _mouse_file,
1977 mut touch_source_stream,
1978 _mouse_source_stream,
1979 _keyboard_listener,
1980 _media_buttons_listener,
1981 _touch_buttons_listener,
1982 ) = start_input_relays_for_test(¤t_task, EventProxyMode::None).await;
1983
1984 let touch_reader2 =
1985 touch_device.open_test(¤t_task).expect("Failed to create input file");
1986
1987 const DEVICE_ID: u32 = 10;
1988
1989 answer_next_touch_watch_request(
1990 &mut touch_source_stream,
1991 vec![make_touch_event_with_phase_device_id(EventPhase::Add, 1, DEVICE_ID)],
1992 )
1993 .await;
1994
1995 answer_next_touch_watch_request(
1999 &mut touch_source_stream,
2000 vec![make_empty_touch_event(DEVICE_ID)],
2001 )
2002 .await;
2003
2004 let events_from_reader1 = read_uapi_events(&touch_reader1, ¤t_task);
2006 let events_from_reader2 = read_uapi_events(&touch_reader2, ¤t_task);
2007 assert_ne!(events_from_reader1.len(), 0);
2008 assert_eq!(events_from_reader1.len(), events_from_reader2.len());
2009 })
2010 .await;
2011 }
2012
2013 #[::fuchsia::test]
2014 async fn keyboard_device_multi_reader() {
2015 spawn_kernel_and_run(async move |current_task| {
2016 let (
2019 _input_relay,
2020 _touch_device,
2021 keyboard_device,
2022 _mouse_device,
2023 _touch_file,
2024 keyboard_reader1,
2025 _mouse_file,
2026 _touch_source_stream,
2027 _mouse_source_stream,
2028 keyboard_listener,
2029 _media_buttons_listener,
2030 _touch_buttons_listener,
2031 ) = start_input_relays_for_test(¤t_task, EventProxyMode::None).await;
2032
2033 let keyboard_reader2 =
2034 keyboard_device.open_test(¤t_task).expect("Failed to create input file");
2035
2036 const DEVICE_ID: u32 = 10;
2037
2038 let key_event = fuiinput::KeyEvent {
2039 timestamp: Some(0),
2040 type_: Some(fuiinput::KeyEventType::Pressed),
2041 key: Some(fidl_fuchsia_input::Key::A),
2042 device_id: Some(DEVICE_ID),
2043 ..Default::default()
2044 };
2045
2046 let _ = keyboard_listener.on_key_event(&key_event).await;
2047
2048 let events_from_reader1 = read_uapi_events(&keyboard_reader1, ¤t_task);
2050 let events_from_reader2 = read_uapi_events(&keyboard_reader2, ¤t_task);
2051 assert_ne!(events_from_reader1.len(), 0);
2052 assert_eq!(events_from_reader1.len(), events_from_reader2.len());
2053 })
2054 .await;
2055 }
2056
2057 #[::fuchsia::test]
2058 async fn button_device_multi_reader() {
2059 spawn_kernel_and_run(async move |current_task| {
2060 let (
2063 _input_relay,
2064 _touch_device,
2065 keyboard_device,
2066 _mouse_device,
2067 _touch_file,
2068 keyboard_reader1,
2069 _mouse_file,
2070 _touch_source_stream,
2071 _mouse_source_stream,
2072 _keyboard_listener,
2073 media_buttons_listener,
2074 _touch_buttons_listener,
2075 ) = start_input_relays_for_test(¤t_task, EventProxyMode::None).await;
2076
2077 let keyboard_reader2 =
2078 keyboard_device.open_test(¤t_task).expect("Failed to create input file");
2079
2080 const DEVICE_ID: u32 = 10;
2081
2082 let power_pressed_event = MediaButtonsEvent {
2083 volume: Some(0),
2084 mic_mute: Some(false),
2085 pause: Some(false),
2086 camera_disable: Some(false),
2087 power: Some(true),
2088 function: Some(false),
2089 device_id: Some(DEVICE_ID),
2090 ..Default::default()
2091 };
2092
2093 let _ = media_buttons_listener.on_event(power_pressed_event).await;
2094
2095 let events_from_reader1 = read_uapi_events(&keyboard_reader1, ¤t_task);
2097 let events_from_reader2 = read_uapi_events(&keyboard_reader2, ¤t_task);
2098 assert_ne!(events_from_reader1.len(), 0);
2099 assert_eq!(events_from_reader1.len(), events_from_reader2.len());
2100 })
2101 .await;
2102 }
2103
2104 #[::fuchsia::test]
2105 async fn mouse_device_multi_reader() {
2106 spawn_kernel_and_run(async move |current_task| {
2107 let (
2110 _input_relay,
2111 _touch_device,
2112 _keyboard_device,
2113 mouse_device,
2114 _touch_file,
2115 _keyboard_file,
2116 mouse_reader1,
2117 _touch_stream,
2118 mut mouse_stream,
2119 _keyboard_listener,
2120 _media_buttons_listener,
2121 _touch_buttons_listener,
2122 ) = start_input_relays_for_test(¤t_task, EventProxyMode::None).await;
2123
2124 let mouse_reader2 =
2125 mouse_device.open_test(¤t_task).expect("Failed to create input file");
2126
2127 const DEVICE_ID: u32 = 10;
2128
2129 answer_next_mouse_watch_request(
2130 &mut mouse_stream,
2131 vec![make_mouse_wheel_event(1, DEVICE_ID)],
2132 )
2133 .await;
2134
2135 answer_next_mouse_watch_request(
2139 &mut mouse_stream,
2140 vec![make_mouse_wheel_event(0, DEVICE_ID)],
2141 )
2142 .await;
2143
2144 let events_from_reader1 = read_uapi_events(&mouse_reader1, ¤t_task);
2146 let events_from_reader2 = read_uapi_events(&mouse_reader2, ¤t_task);
2147 assert_ne!(events_from_reader1.len(), 0);
2148 assert_eq!(events_from_reader1.len(), events_from_reader2.len());
2149 })
2150 .await;
2151 }
2152
2153 #[::fuchsia::test]
2154 async fn input_message_counters() {
2155 spawn_kernel_and_run(async move |current_task| {
2156 let kernel = current_task.kernel().clone();
2158 let (
2159 _input_relay,
2160 _touch_device,
2161 _keyboard_device,
2162 _mouse_device,
2163 _touch_file,
2164 keyboard_file,
2165 _mouse_file,
2166 _touch_source_stream,
2167 _mouse_source_stream,
2168 keyboard_listener,
2169 _media_buttons_listener,
2170 _touch_buttons_listener,
2171 ) = start_input_relays_for_test(¤t_task, EventProxyMode::WakeContainer).await;
2172
2173 const DEVICE_ID: u32 = 10;
2174
2175 let key_event = fuiinput::KeyEvent {
2176 timestamp: Some(0),
2177 type_: Some(fuiinput::KeyEventType::Pressed),
2178 key: Some(fidl_fuchsia_input::Key::A),
2179 device_id: Some(DEVICE_ID),
2180 ..Default::default()
2181 };
2182
2183 let _ = keyboard_listener.on_key_event(&key_event).await;
2184
2185 let events = read_uapi_events(&keyboard_file, ¤t_task);
2186 assert_ne!(events.len(), 0);
2187
2188 assert!(!kernel.suspend_resume_manager.has_nonzero_message_counter());
2189 })
2190 .await;
2191 }
2192
2193 #[::fuchsia::test]
2194 async fn mouse_device_lazily_registered_on_first_mouse_event() {
2195 spawn_kernel_and_run(async move |current_task| {
2196 let kernel = current_task.kernel().clone();
2197 let inspector = fuchsia_inspect::Inspector::default();
2198
2199 let touch_device = crate::InputDevice::new_touch(700, 1200, inspector.root());
2200 let keyboard_device = crate::InputDevice::new_keyboard(inspector.root());
2201 let mouse_device = crate::InputDevice::new_mouse(inspector.root());
2204
2205 let (touch_source_client_end, _touch_source_stream) =
2206 fidl::endpoints::create_request_stream::<fuipointer::TouchSourceV2Marker>();
2207 let (mouse_source_client_end, mut mouse_stream) =
2208 fidl::endpoints::create_request_stream::<fuipointer::MouseSourceV2Marker>();
2209 let (keyboard_proxy, mut keyboard_stream) =
2210 fidl::endpoints::create_sync_proxy_and_stream::<fuiinput::KeyboardMarker>();
2211 let view_ref_pair =
2212 fuchsia_scenic::ViewRefPair::new().expect("Failed to create ViewRefPair");
2213 let (device_registry_proxy, mut device_listener_stream) =
2214 fidl::endpoints::create_sync_proxy_and_stream::<
2215 fuipolicy::DeviceListenerRegistryMarker,
2216 >();
2217
2218 let (relay, _relay_handle) = new_input_relay();
2219 relay.start_relays(
2220 &kernel,
2221 EventProxyMode::None,
2222 touch_source_client_end,
2223 keyboard_proxy,
2224 mouse_source_client_end,
2225 view_ref_pair.view_ref,
2226 device_registry_proxy,
2227 touch_device.open_files.clone(),
2228 keyboard_device.open_files.clone(),
2229 Some(mouse_device.clone()),
2230 Some(touch_device.inspect_status.clone()),
2231 Some(keyboard_device.inspect_status.clone()),
2232 );
2233
2234 if let Some(Ok(fuiinput::KeyboardRequest::AddListener { responder, .. })) =
2235 keyboard_stream.next().await
2236 {
2237 let _ = responder.send();
2238 }
2239 if let Some(Ok(fuipolicy::DeviceListenerRegistryRequest::RegisterListener {
2240 responder,
2241 ..
2242 })) = device_listener_stream.next().await
2243 {
2244 let _ = responder.send();
2245 }
2246 if let Some(Ok(
2247 fuipolicy::DeviceListenerRegistryRequest::RegisterTouchButtonsListener {
2248 responder,
2249 ..
2250 },
2251 )) = device_listener_stream.next().await
2252 {
2253 let _ = responder.send();
2254 }
2255
2256 let mouse_dev_id = starnix_uapi::device_id::DeviceId::new(
2257 starnix_uapi::device_id::INPUT_MAJOR,
2258 DEFAULT_MOUSE_DEVICE_ID,
2259 );
2260 let next_dev_id = starnix_uapi::device_id::DeviceId::new(
2261 starnix_uapi::device_id::INPUT_MAJOR,
2262 DEFAULT_MOUSE_DEVICE_ID + 1,
2263 );
2264
2265 assert!(
2268 kernel
2269 .device_registry
2270 .list_minor_devices(
2271 starnix_core::device::DeviceMode::Char,
2272 mouse_dev_id..next_dev_id,
2273 )
2274 .is_empty()
2275 );
2276
2277 answer_next_mouse_watch_request(
2279 &mut mouse_stream,
2280 vec![make_mouse_wheel_event(0, DEFAULT_MOUSE_DEVICE_ID)],
2281 )
2282 .await;
2283
2284 assert!(
2286 kernel
2287 .device_registry
2288 .list_minor_devices(
2289 starnix_core::device::DeviceMode::Char,
2290 mouse_dev_id..next_dev_id,
2291 )
2292 .is_empty()
2293 );
2294
2295 answer_next_mouse_watch_request(
2299 &mut mouse_stream,
2300 vec![make_mouse_wheel_event(1, DEFAULT_MOUSE_DEVICE_ID)],
2301 )
2302 .await;
2303 answer_next_mouse_watch_request(
2304 &mut mouse_stream,
2305 vec![make_mouse_wheel_event(1, DEFAULT_MOUSE_DEVICE_ID)],
2306 )
2307 .await;
2308 answer_next_mouse_watch_request(
2309 &mut mouse_stream,
2310 vec![make_mouse_wheel_event(0, DEFAULT_MOUSE_DEVICE_ID)],
2311 )
2312 .await;
2313
2314 let registered = kernel.device_registry.list_minor_devices(
2316 starnix_core::device::DeviceMode::Char,
2317 mouse_dev_id..next_dev_id,
2318 );
2319 assert_eq!(registered.len(), 1);
2320 assert_eq!(registered[0].0, mouse_dev_id);
2321
2322 let mouse_file =
2326 mouse_device.open_test(¤t_task).expect("Failed to open mouse file");
2327 let events = read_uapi_events(&mouse_file, ¤t_task);
2328 assert_eq!(events.len(), 4);
2329 })
2330 .await;
2331 }
2332}