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