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