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