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