1use crate::{
6 Dispatcher, Incoming, Transport, consumer_controls_binding, keyboard_binding,
7 light_sensor_binding, metrics, mouse_binding, touch_binding,
8};
9use anyhow::{Error, format_err};
10use async_trait::async_trait;
11use fidl_next_fuchsia_input_report::{InputDevice, InputReport};
12use fuchsia_inspect::health::Reporter;
13use fuchsia_inspect::{
14 ExponentialHistogramParams, HistogramProperty as _, NumericProperty, Property,
15};
16use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
17use futures::stream::StreamExt;
18use metrics_registry::*;
19use std::path::PathBuf;
20use {
21 fidl_fuchsia_io as fio, fidl_next_fuchsia_input_report as fidl_next_input_report,
22 fuchsia_trace as ftrace,
23};
24
25pub use input_device_constants::InputDeviceType;
26
27#[derive(Debug, Clone, Default)]
28pub struct InputPipelineFeatureFlags {
29 pub enable_merge_touch_events: bool,
31}
32
33pub static INPUT_REPORT_PATH: &str = "/dev/class/input-report";
35
36const LATENCY_HISTOGRAM_PROPERTIES: ExponentialHistogramParams<i64> = ExponentialHistogramParams {
37 floor: 0,
38 initial_step: 1,
39 step_multiplier: 10,
40 buckets: 7,
51};
52
53pub struct InputDeviceStatus {
56 now: Box<dyn Fn() -> zx::MonotonicInstant>,
59
60 _node: fuchsia_inspect::Node,
62
63 reports_received_count: fuchsia_inspect::UintProperty,
65
66 reports_filtered_count: fuchsia_inspect::UintProperty,
69
70 events_generated: fuchsia_inspect::UintProperty,
73
74 last_received_timestamp_ns: fuchsia_inspect::UintProperty,
76
77 last_generated_timestamp_ns: fuchsia_inspect::UintProperty,
79
80 pub health_node: fuchsia_inspect::health::Node,
82
83 driver_to_binding_latency_ms: fuchsia_inspect::IntExponentialHistogramProperty,
88
89 wake_lease_leak_count: fuchsia_inspect::UintProperty,
91}
92
93impl InputDeviceStatus {
94 pub fn new(device_node: fuchsia_inspect::Node) -> Self {
95 Self::new_internal(device_node, Box::new(zx::MonotonicInstant::get))
96 }
97
98 fn new_internal(
99 device_node: fuchsia_inspect::Node,
100 now: Box<dyn Fn() -> zx::MonotonicInstant>,
101 ) -> Self {
102 let mut health_node = fuchsia_inspect::health::Node::new(&device_node);
103 health_node.set_starting_up();
104
105 let reports_received_count = device_node.create_uint("reports_received_count", 0);
106 let reports_filtered_count = device_node.create_uint("reports_filtered_count", 0);
107 let events_generated = device_node.create_uint("events_generated", 0);
108 let last_received_timestamp_ns = device_node.create_uint("last_received_timestamp_ns", 0);
109 let last_generated_timestamp_ns = device_node.create_uint("last_generated_timestamp_ns", 0);
110 let driver_to_binding_latency_ms = device_node.create_int_exponential_histogram(
111 "driver_to_binding_latency_ms",
112 LATENCY_HISTOGRAM_PROPERTIES,
113 );
114 let wake_lease_leak_count = device_node.create_uint("wake_lease_leak_count", 0);
115
116 Self {
117 now,
118 _node: device_node,
119 reports_received_count,
120 reports_filtered_count,
121 events_generated,
122 last_received_timestamp_ns,
123 last_generated_timestamp_ns,
124 health_node,
125 driver_to_binding_latency_ms,
126 wake_lease_leak_count,
127 }
128 }
129
130 pub fn count_received_report(&self, report: &InputReport) {
131 self.reports_received_count.add(1);
132 match report.event_time {
133 Some(event_time) => {
134 self.driver_to_binding_latency_ms.insert(
135 ((self.now)() - zx::MonotonicInstant::from_nanos(event_time)).into_millis(),
136 );
137 self.last_received_timestamp_ns.set(event_time.try_into().unwrap());
138 }
139 None => (),
140 }
141 }
142
143 pub fn count_filtered_report(&self) {
144 self.reports_filtered_count.add(1);
145 }
146
147 pub fn count_generated_event(&self, event: InputEvent) {
148 self.events_generated.add(1);
149 self.last_generated_timestamp_ns.set(event.event_time.into_nanos().try_into().unwrap());
150 }
151
152 pub fn count_generated_events(&self, events: &Vec<InputEvent>) {
153 self.events_generated.add(events.len() as u64);
154 if let Some(last_event) = events.last() {
155 self.last_generated_timestamp_ns
156 .set(last_event.event_time.into_nanos().try_into().unwrap());
157 }
158 }
159
160 pub fn count_wake_lease_leak(&self) {
161 self.wake_lease_leak_count.add(1);
162 }
163}
164
165#[derive(Clone, Debug, PartialEq)]
167pub struct InputEvent {
168 pub device_event: InputDeviceEvent,
170
171 pub device_descriptor: InputDeviceDescriptor,
174
175 pub event_time: zx::MonotonicInstant,
177
178 pub handled: Handled,
180
181 pub trace_id: Option<ftrace::Id>,
182}
183
184#[derive(Clone, Debug, PartialEq)]
190pub struct UnhandledInputEvent {
191 pub device_event: InputDeviceEvent,
193
194 pub device_descriptor: InputDeviceDescriptor,
197
198 pub event_time: zx::MonotonicInstant,
200
201 pub trace_id: Option<ftrace::Id>,
202}
203
204impl UnhandledInputEvent {
205 pub fn get_event_type(&self) -> &'static str {
207 match self.device_event {
208 InputDeviceEvent::Keyboard(_) => "keyboard_event",
209 InputDeviceEvent::LightSensor(_) => "light_sensor_event",
210 InputDeviceEvent::ConsumerControls(_) => "consumer_controls_event",
211 InputDeviceEvent::Mouse(_) => "mouse_event",
212 InputDeviceEvent::TouchScreen(_) => "touch_screen_event",
213 InputDeviceEvent::Touchpad(_) => "touchpad_event",
214 #[cfg(test)]
215 InputDeviceEvent::Fake => "fake_event",
216 }
217 }
218}
219
220#[derive(Clone, Debug, PartialEq)]
229pub enum InputDeviceEvent {
230 Keyboard(keyboard_binding::KeyboardEvent),
231 LightSensor(light_sensor_binding::LightSensorEvent),
232 ConsumerControls(consumer_controls_binding::ConsumerControlsEvent),
233 Mouse(mouse_binding::MouseEvent),
234 TouchScreen(touch_binding::TouchScreenEvent),
235 Touchpad(touch_binding::TouchpadEvent),
236 #[cfg(test)]
237 Fake,
238}
239
240#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
242pub enum InputEventType {
243 Keyboard,
244 LightSensor,
245 ConsumerControls,
246 Mouse,
247 TouchScreen,
248 Touchpad,
249 #[cfg(test)]
250 Fake,
251}
252
253impl std::fmt::Display for InputEventType {
254 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
255 match &*self {
256 InputEventType::Keyboard => write!(f, "keyboard"),
257 InputEventType::LightSensor => write!(f, "light_sensor"),
258 InputEventType::ConsumerControls => write!(f, "consumer_controls"),
259 InputEventType::Mouse => write!(f, "mouse"),
260 InputEventType::TouchScreen => write!(f, "touch_screen"),
261 InputEventType::Touchpad => write!(f, "touchpad"),
262 #[cfg(test)]
263 InputEventType::Fake => write!(f, "fake"),
264 }
265 }
266}
267
268impl From<&InputDeviceEvent> for InputEventType {
269 fn from(event: &InputDeviceEvent) -> Self {
270 match event {
271 InputDeviceEvent::Keyboard(_) => InputEventType::Keyboard,
272 InputDeviceEvent::LightSensor(_) => InputEventType::LightSensor,
273 InputDeviceEvent::ConsumerControls(_) => InputEventType::ConsumerControls,
274 InputDeviceEvent::Mouse(_) => InputEventType::Mouse,
275 InputDeviceEvent::TouchScreen(_) => InputEventType::TouchScreen,
276 InputDeviceEvent::Touchpad(_) => InputEventType::Touchpad,
277 #[cfg(test)]
278 InputDeviceEvent::Fake => InputEventType::Fake,
279 }
280 }
281}
282
283#[derive(Clone, Debug, PartialEq)]
293pub enum InputDeviceDescriptor {
294 Keyboard(keyboard_binding::KeyboardDeviceDescriptor),
295 LightSensor(light_sensor_binding::LightSensorDeviceDescriptor),
296 ConsumerControls(consumer_controls_binding::ConsumerControlsDeviceDescriptor),
297 Mouse(mouse_binding::MouseDeviceDescriptor),
298 TouchScreen(touch_binding::TouchScreenDeviceDescriptor),
299 Touchpad(touch_binding::TouchpadDeviceDescriptor),
300 #[cfg(test)]
301 Fake,
302}
303
304impl From<keyboard_binding::KeyboardDeviceDescriptor> for InputDeviceDescriptor {
305 fn from(b: keyboard_binding::KeyboardDeviceDescriptor) -> Self {
306 InputDeviceDescriptor::Keyboard(b)
307 }
308}
309
310impl InputDeviceDescriptor {
311 pub fn device_id(&self) -> u32 {
312 match self {
313 InputDeviceDescriptor::Keyboard(b) => b.device_id,
314 InputDeviceDescriptor::LightSensor(b) => b.device_id,
315 InputDeviceDescriptor::ConsumerControls(b) => b.device_id,
316 InputDeviceDescriptor::Mouse(b) => b.device_id,
317 InputDeviceDescriptor::TouchScreen(b) => b.device_id,
318 InputDeviceDescriptor::Touchpad(b) => b.device_id,
319 #[cfg(test)]
320 InputDeviceDescriptor::Fake => 0,
321 }
322 }
323}
324
325#[derive(Copy, Clone, Debug, PartialEq)]
327pub enum Handled {
328 Yes,
330 No,
332}
333
334#[async_trait]
343pub trait InputDeviceBinding: Send {
344 fn get_device_descriptor(&self) -> InputDeviceDescriptor;
346
347 fn input_event_sender(&self) -> UnboundedSender<Vec<InputEvent>>;
349}
350
351pub fn initialize_report_stream<InputDeviceProcessReportsFn>(
368 device_proxy: fidl_next::Client<InputDevice, Transport>,
369 device_descriptor: InputDeviceDescriptor,
370 mut event_sender: UnboundedSender<Vec<InputEvent>>,
371 inspect_status: InputDeviceStatus,
372 metrics_logger: metrics::MetricsLogger,
373 feature_flags: InputPipelineFeatureFlags,
374 mut process_reports: InputDeviceProcessReportsFn,
375) where
376 InputDeviceProcessReportsFn: 'static
377 + Send
378 + FnMut(
379 Vec<InputReport>,
380 Option<InputReport>,
381 &InputDeviceDescriptor,
382 &mut UnboundedSender<Vec<InputEvent>>,
383 &InputDeviceStatus,
384 &metrics::MetricsLogger,
385 &InputPipelineFeatureFlags,
386 ) -> (Option<InputReport>, Option<UnboundedReceiver<InputEvent>>),
387{
388 Dispatcher::spawn_local(async move {
389 let mut previous_report: Option<InputReport> = None;
390 let (report_reader, server_end) = fidl_next::fuchsia::create_channel();
391 let report_reader = Dispatcher::client_from_zx_channel(report_reader);
392 let result = device_proxy.get_input_reports_reader(server_end).await;
393 if result.is_err() {
394 metrics_logger.log_error(
395 InputPipelineErrorMetricDimensionEvent::InputDeviceGetInputReportsReaderError,
396 std::format!("error on GetInputReportsReader: {:?}", &result),
397 );
398 return; }
400 let report_reader = report_reader.spawn();
401 loop {
402 match report_reader.read_input_reports().await {
403 Ok(Err(_service_error)) => break,
404 Err(_fidl_error) => break,
405 Ok(Ok(fidl_next_input_report::InputReportsReaderReadInputReportsResponse {
406 reports,
407 })) => {
408 fuchsia_trace::duration!("input", "input-device-process-reports");
409 let (prev_report, inspect_receiver) = process_reports(
410 reports,
411 previous_report,
412 &device_descriptor,
413 &mut event_sender,
414 &inspect_status,
415 &metrics_logger,
416 &feature_flags,
417 );
418 previous_report = prev_report;
419
420 if let Some(previous_report) = previous_report.as_ref() {
421 if previous_report.wake_lease.is_some() {
422 inspect_status.count_wake_lease_leak();
423
424 let error_code = match device_descriptor {
425 InputDeviceDescriptor::TouchScreen(_) => {
426 Some(InputPipelineMetricDimensionEvent::TouchscreenPreviousReportHasWakeLease)
427 }
428 InputDeviceDescriptor::Touchpad(_) => {
429 Some(InputPipelineMetricDimensionEvent::TouchpadPreviousReportHasWakeLease)
430 }
431 InputDeviceDescriptor::Mouse(_) => {
432 Some(InputPipelineMetricDimensionEvent::MousePreviousReportHasWakeLease)
433 }
434 InputDeviceDescriptor::Keyboard(_) => {
435 Some(InputPipelineMetricDimensionEvent::KeyboardPreviousReportHasWakeLease)
436 }
437 InputDeviceDescriptor::ConsumerControls(_) => {
438 Some(InputPipelineMetricDimensionEvent::ButtonPreviousReportHasWakeLease)
439 }
440 InputDeviceDescriptor::LightSensor(_) => {
441 Some(InputPipelineMetricDimensionEvent::LightSensorPreviousReportHasWakeLease)
442 }
443 #[cfg(test)]
444 InputDeviceDescriptor::Fake => None,
445 };
446 if let Some(error_code) = error_code {
447 metrics_logger.log_error(error_code, std::format!("previous_report must not have a wake lease but does: {:?}", previous_report));
448 }
449 }
450 }
451
452 match inspect_receiver {
456 Some(mut receiver) => {
457 while let Some(event) = receiver.next().await {
458 inspect_status.count_generated_event(event);
459 }
460 }
461 None => (),
462 };
463 }
464 }
465 }
466 log::warn!("initialize_report_stream exited - device binding no longer works");
469 })
470 .detach();
471}
472
473pub async fn is_device_type(
479 device_descriptor: &fidl_next_fuchsia_input_report::DeviceDescriptor,
480 device_type: InputDeviceType,
481) -> bool {
482 match device_type {
484 InputDeviceType::ConsumerControls => device_descriptor.consumer_control.is_some(),
485 InputDeviceType::Mouse => device_descriptor.mouse.is_some(),
486 InputDeviceType::Touch => device_descriptor.touch.is_some(),
487 InputDeviceType::Keyboard => device_descriptor.keyboard.is_some(),
488 InputDeviceType::LightSensor => device_descriptor.sensor.is_some(),
489 }
490}
491
492pub async fn get_device_binding(
500 device_type: InputDeviceType,
501 device_proxy: fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
502 device_id: u32,
503 input_event_sender: UnboundedSender<Vec<InputEvent>>,
504 device_node: fuchsia_inspect::Node,
505 feature_flags: InputPipelineFeatureFlags,
506 metrics_logger: metrics::MetricsLogger,
507) -> Result<Box<dyn InputDeviceBinding>, Error> {
508 match device_type {
509 InputDeviceType::ConsumerControls => {
510 let binding = consumer_controls_binding::ConsumerControlsBinding::new(
511 device_proxy,
512 device_id,
513 input_event_sender,
514 device_node,
515 feature_flags.clone(),
516 metrics_logger,
517 )
518 .await?;
519 Ok(Box::new(binding))
520 }
521 InputDeviceType::Mouse => {
522 let binding = mouse_binding::MouseBinding::new(
523 device_proxy,
524 device_id,
525 input_event_sender,
526 device_node,
527 feature_flags.clone(),
528 metrics_logger,
529 )
530 .await?;
531 Ok(Box::new(binding))
532 }
533 InputDeviceType::Touch => {
534 let binding = touch_binding::TouchBinding::new(
535 device_proxy,
536 device_id,
537 input_event_sender,
538 device_node,
539 feature_flags.clone(),
540 metrics_logger,
541 )
542 .await?;
543 Ok(Box::new(binding))
544 }
545 InputDeviceType::Keyboard => {
546 let binding = keyboard_binding::KeyboardBinding::new(
547 device_proxy,
548 device_id,
549 input_event_sender,
550 device_node,
551 feature_flags.clone(),
552 metrics_logger,
553 )
554 .await?;
555 Ok(Box::new(binding))
556 }
557 InputDeviceType::LightSensor => {
558 let binding = light_sensor_binding::LightSensorBinding::new(
559 device_proxy,
560 device_id,
561 input_event_sender,
562 device_node,
563 feature_flags.clone(),
564 metrics_logger,
565 )
566 .await?;
567 Ok(Box::new(binding))
568 }
569 }
570}
571
572pub fn get_device_from_dir_entry_path(
581 dir_proxy: &fio::DirectoryProxy,
582 entry_path: &PathBuf,
583) -> Result<fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>, Error> {
584 let input_device_path = entry_path.to_str();
585 if input_device_path.is_none() {
586 return Err(format_err!("Failed to get entry path as a string."));
587 }
588
589 let input_device = Incoming::connect_protocol_next_at(dir_proxy, input_device_path.unwrap())
590 .expect("Failed to connect to InputDevice.");
591 Ok(input_device.spawn())
592}
593
594pub fn event_time_or_now(event_time: Option<i64>) -> zx::MonotonicInstant {
599 match event_time {
600 Some(time) => zx::MonotonicInstant::from_nanos(time),
601 None => zx::MonotonicInstant::get(),
602 }
603}
604
605impl std::convert::From<UnhandledInputEvent> for InputEvent {
606 fn from(event: UnhandledInputEvent) -> Self {
607 Self {
608 device_event: event.device_event,
609 device_descriptor: event.device_descriptor,
610 event_time: event.event_time,
611 handled: Handled::No,
612 trace_id: event.trace_id,
613 }
614 }
615}
616
617#[cfg(test)]
624impl std::convert::TryFrom<InputEvent> for UnhandledInputEvent {
625 type Error = anyhow::Error;
626 fn try_from(event: InputEvent) -> Result<UnhandledInputEvent, Self::Error> {
627 match event.handled {
628 Handled::Yes => {
629 Err(format_err!("Attempted to treat a handled InputEvent as unhandled"))
630 }
631 Handled::No => Ok(UnhandledInputEvent {
632 device_event: event.device_event,
633 device_descriptor: event.device_descriptor,
634 event_time: event.event_time,
635 trace_id: event.trace_id,
636 }),
637 }
638 }
639}
640
641impl InputEvent {
642 pub fn clone_with_wake_lease(&self) -> Self {
643 let device_event = match &self.device_event {
644 InputDeviceEvent::ConsumerControls(event) => {
645 InputDeviceEvent::ConsumerControls(event.clone_with_wake_lease())
646 }
647 InputDeviceEvent::Mouse(event) => {
648 InputDeviceEvent::Mouse(event.clone_with_wake_lease())
649 }
650 InputDeviceEvent::TouchScreen(event) => {
651 InputDeviceEvent::TouchScreen(event.clone_with_wake_lease())
652 }
653 _ => self.device_event.clone(),
654 };
655 Self {
656 device_event,
657 device_descriptor: self.device_descriptor.clone(),
658 event_time: self.event_time,
659 handled: self.handled,
660 trace_id: self.trace_id,
661 }
662 }
663
664 pub(crate) fn into_handled_if(self, predicate: bool) -> Self {
667 if predicate { Self { handled: Handled::Yes, ..self } } else { self }
668 }
669
670 pub(crate) fn into_handled(self) -> Self {
672 Self { handled: Handled::Yes, ..self }
673 }
674
675 pub fn into_with_event_time(self, event_time: zx::MonotonicInstant) -> Self {
677 Self { event_time, ..self }
678 }
679
680 #[cfg(test)]
682 pub fn into_with_device_descriptor(self, device_descriptor: InputDeviceDescriptor) -> Self {
683 Self { device_descriptor, ..self }
684 }
685
686 pub fn is_handled(&self) -> bool {
688 self.handled == Handled::Yes
689 }
690
691 pub fn get_event_type(&self) -> &'static str {
693 match self.device_event {
694 InputDeviceEvent::Keyboard(_) => "keyboard_event",
695 InputDeviceEvent::LightSensor(_) => "light_sensor_event",
696 InputDeviceEvent::ConsumerControls(_) => "consumer_controls_event",
697 InputDeviceEvent::Mouse(_) => "mouse_event",
698 InputDeviceEvent::TouchScreen(_) => "touch_screen_event",
699 InputDeviceEvent::Touchpad(_) => "touchpad_event",
700 #[cfg(test)]
701 InputDeviceEvent::Fake => "fake_event",
702 }
703 }
704
705 pub fn record_inspect(&self, node: &fuchsia_inspect::Node) {
706 node.record_int("event_time", self.event_time.into_nanos());
707 match &self.device_event {
708 InputDeviceEvent::LightSensor(e) => e.record_inspect(node),
709 InputDeviceEvent::ConsumerControls(e) => e.record_inspect(node),
710 InputDeviceEvent::Mouse(e) => e.record_inspect(node),
711 InputDeviceEvent::TouchScreen(e) => e.record_inspect(node),
712 InputDeviceEvent::Touchpad(e) => e.record_inspect(node),
713 InputDeviceEvent::Keyboard(_) => (),
715 #[cfg(test)] InputDeviceEvent::Fake => (),
717 }
718 }
719}
720
721#[cfg(test)]
722mod tests {
723 use super::*;
724 use crate::testing_utilities::spawn_input_stream_handler;
725 use assert_matches::assert_matches;
726 use diagnostics_assertions::AnyProperty;
727 use pretty_assertions::assert_eq;
728 use std::convert::TryFrom as _;
729 use test_case::test_case;
730 use {fidl_fuchsia_input_report as fidl_input_report, fuchsia_async as fasync};
731
732 #[test]
733 fn max_event_time() {
734 let event_time = event_time_or_now(Some(i64::MAX));
735 assert_eq!(event_time, zx::MonotonicInstant::INFINITE);
736 }
737
738 #[test]
739 fn min_event_time() {
740 let event_time = event_time_or_now(Some(std::i64::MIN));
741 assert_eq!(event_time, zx::MonotonicInstant::INFINITE_PAST);
742 }
743
744 #[fasync::run_singlethreaded(test)]
745 async fn input_device_status_initialized_with_correct_properties() {
746 let inspector = fuchsia_inspect::Inspector::default();
747 let input_pipeline_node = inspector.root().create_child("input_pipeline");
748 let input_devices_node = input_pipeline_node.create_child("input_devices");
749 let device_node = input_devices_node.create_child("001_keyboard");
750 let _input_device_status = InputDeviceStatus::new(device_node);
751 diagnostics_assertions::assert_data_tree!(inspector, root: {
752 input_pipeline: {
753 input_devices: {
754 "001_keyboard": {
755 reports_received_count: 0u64,
756 reports_filtered_count: 0u64,
757 events_generated: 0u64,
758 last_received_timestamp_ns: 0u64,
759 last_generated_timestamp_ns: 0u64,
760 "fuchsia.inspect.Health": {
761 status: "STARTING_UP",
762 start_timestamp_nanos: AnyProperty
765 },
766 driver_to_binding_latency_ms: diagnostics_assertions::HistogramAssertion::exponential(super::LATENCY_HISTOGRAM_PROPERTIES),
767 wake_lease_leak_count: 0u64,
768 }
769 }
770 }
771 });
772 }
773
774 #[test_case(i64::MIN; "min value")]
775 #[test_case(-1; "negative value")]
776 #[test_case(0; "zero")]
777 #[test_case(1; "positive value")]
778 #[test_case(i64::MAX; "max value")]
779 #[fuchsia::test(allow_stalls = false)]
780 async fn input_device_status_updates_latency_histogram_on_count_received_report(
781 latency_nsec: i64,
782 ) {
783 let mut expected_histogram = diagnostics_assertions::HistogramAssertion::exponential(
784 super::LATENCY_HISTOGRAM_PROPERTIES,
785 );
786 let inspector = fuchsia_inspect::Inspector::default();
787 let input_device_status = InputDeviceStatus::new_internal(
788 inspector.root().clone_weak(),
789 Box::new(move || zx::MonotonicInstant::from_nanos(latency_nsec)),
790 );
791 input_device_status
792 .count_received_report(&InputReport { event_time: Some(0), ..InputReport::default() });
793 expected_histogram.insert_values([latency_nsec / 1000 / 1000]);
794 diagnostics_assertions::assert_data_tree!(inspector, root: contains {
795 driver_to_binding_latency_ms: expected_histogram,
796 });
797 }
798
799 #[fasync::run_singlethreaded(test)]
802 async fn consumer_controls_input_device_exists() {
803 let input_device_proxy =
804 spawn_input_stream_handler(move |input_device_request| async move {
805 match input_device_request {
806 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
807 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
808 device_information: None,
809 mouse: None,
810 sensor: None,
811 touch: None,
812 keyboard: None,
813 consumer_control: Some(fidl_input_report::ConsumerControlDescriptor {
814 input: Some(fidl_input_report::ConsumerControlInputDescriptor {
815 buttons: Some(vec![
816 fidl_input_report::ConsumerControlButton::VolumeUp,
817 fidl_input_report::ConsumerControlButton::VolumeDown,
818 ]),
819 ..Default::default()
820 }),
821 ..Default::default()
822 }),
823 ..Default::default()
824 });
825 }
826 _ => panic!("InputDevice handler received an unexpected request"),
827 }
828 });
829
830 assert!(
831 is_device_type(
832 &input_device_proxy
833 .get_descriptor()
834 .await
835 .expect("Failed to get device descriptor")
836 .descriptor,
837 InputDeviceType::ConsumerControls
838 )
839 .await
840 );
841 }
842
843 #[fasync::run_singlethreaded(test)]
845 async fn mouse_input_device_exists() {
846 let input_device_proxy =
847 spawn_input_stream_handler(move |input_device_request| async move {
848 match input_device_request {
849 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
850 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
851 device_information: None,
852 mouse: Some(fidl_input_report::MouseDescriptor {
853 input: Some(fidl_input_report::MouseInputDescriptor {
854 movement_x: None,
855 movement_y: None,
856 position_x: None,
857 position_y: None,
858 scroll_v: None,
859 scroll_h: None,
860 buttons: None,
861 ..Default::default()
862 }),
863 ..Default::default()
864 }),
865 sensor: None,
866 touch: None,
867 keyboard: None,
868 consumer_control: None,
869 ..Default::default()
870 });
871 }
872 _ => panic!("InputDevice handler received an unexpected request"),
873 }
874 });
875
876 assert!(
877 is_device_type(
878 &input_device_proxy
879 .get_descriptor()
880 .await
881 .expect("Failed to get device descriptor")
882 .descriptor,
883 InputDeviceType::Mouse
884 )
885 .await
886 );
887 }
888
889 #[fasync::run_singlethreaded(test)]
892 async fn mouse_input_device_doesnt_exist() {
893 let input_device_proxy =
894 spawn_input_stream_handler(move |input_device_request| async move {
895 match input_device_request {
896 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
897 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
898 device_information: None,
899 mouse: None,
900 sensor: None,
901 touch: None,
902 keyboard: None,
903 consumer_control: None,
904 ..Default::default()
905 });
906 }
907 _ => panic!("InputDevice handler received an unexpected request"),
908 }
909 });
910
911 assert!(
912 !is_device_type(
913 &input_device_proxy
914 .get_descriptor()
915 .await
916 .expect("Failed to get device descriptor")
917 .descriptor,
918 InputDeviceType::Mouse
919 )
920 .await
921 );
922 }
923
924 #[fasync::run_singlethreaded(test)]
927 async fn touch_input_device_exists() {
928 let input_device_proxy =
929 spawn_input_stream_handler(move |input_device_request| async move {
930 match input_device_request {
931 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
932 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
933 device_information: None,
934 mouse: None,
935 sensor: None,
936 touch: Some(fidl_input_report::TouchDescriptor {
937 input: Some(fidl_input_report::TouchInputDescriptor {
938 contacts: None,
939 max_contacts: None,
940 touch_type: None,
941 buttons: None,
942 ..Default::default()
943 }),
944 ..Default::default()
945 }),
946 keyboard: None,
947 consumer_control: None,
948 ..Default::default()
949 });
950 }
951 _ => panic!("InputDevice handler received an unexpected request"),
952 }
953 });
954
955 assert!(
956 is_device_type(
957 &input_device_proxy
958 .get_descriptor()
959 .await
960 .expect("Failed to get device descriptor")
961 .descriptor,
962 InputDeviceType::Touch
963 )
964 .await
965 );
966 }
967
968 #[fasync::run_singlethreaded(test)]
971 async fn touch_input_device_doesnt_exist() {
972 let input_device_proxy =
973 spawn_input_stream_handler(move |input_device_request| async move {
974 match input_device_request {
975 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
976 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
977 device_information: None,
978 mouse: None,
979 sensor: None,
980 touch: None,
981 keyboard: None,
982 consumer_control: None,
983 ..Default::default()
984 });
985 }
986 _ => panic!("InputDevice handler received an unexpected request"),
987 }
988 });
989
990 assert!(
991 !is_device_type(
992 &input_device_proxy
993 .get_descriptor()
994 .await
995 .expect("Failed to get device descriptor")
996 .descriptor,
997 InputDeviceType::Touch
998 )
999 .await
1000 );
1001 }
1002
1003 #[fasync::run_singlethreaded(test)]
1006 async fn keyboard_input_device_exists() {
1007 let input_device_proxy =
1008 spawn_input_stream_handler(move |input_device_request| async move {
1009 match input_device_request {
1010 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
1011 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
1012 device_information: None,
1013 mouse: None,
1014 sensor: None,
1015 touch: None,
1016 keyboard: Some(fidl_input_report::KeyboardDescriptor {
1017 input: Some(fidl_input_report::KeyboardInputDescriptor {
1018 keys3: None,
1019 ..Default::default()
1020 }),
1021 output: None,
1022 ..Default::default()
1023 }),
1024 consumer_control: None,
1025 ..Default::default()
1026 });
1027 }
1028 _ => panic!("InputDevice handler received an unexpected request"),
1029 }
1030 });
1031
1032 assert!(
1033 is_device_type(
1034 &input_device_proxy
1035 .get_descriptor()
1036 .await
1037 .expect("Failed to get device descriptor")
1038 .descriptor,
1039 InputDeviceType::Keyboard
1040 )
1041 .await
1042 );
1043 }
1044
1045 #[fasync::run_singlethreaded(test)]
1048 async fn keyboard_input_device_doesnt_exist() {
1049 let input_device_proxy =
1050 spawn_input_stream_handler(move |input_device_request| async move {
1051 match input_device_request {
1052 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
1053 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
1054 device_information: None,
1055 mouse: None,
1056 sensor: None,
1057 touch: None,
1058 keyboard: None,
1059 consumer_control: None,
1060 ..Default::default()
1061 });
1062 }
1063 _ => panic!("InputDevice handler received an unexpected request"),
1064 }
1065 });
1066
1067 assert!(
1068 !is_device_type(
1069 &input_device_proxy
1070 .get_descriptor()
1071 .await
1072 .expect("Failed to get device descriptor")
1073 .descriptor,
1074 InputDeviceType::Keyboard
1075 )
1076 .await
1077 );
1078 }
1079
1080 #[fasync::run_singlethreaded(test)]
1082 async fn no_input_device_match() {
1083 let input_device_proxy =
1084 spawn_input_stream_handler(move |input_device_request| async move {
1085 match input_device_request {
1086 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
1087 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
1088 device_information: None,
1089 mouse: Some(fidl_input_report::MouseDescriptor {
1090 input: Some(fidl_input_report::MouseInputDescriptor {
1091 movement_x: None,
1092 movement_y: None,
1093 position_x: None,
1094 position_y: None,
1095 scroll_v: None,
1096 scroll_h: None,
1097 buttons: None,
1098 ..Default::default()
1099 }),
1100 ..Default::default()
1101 }),
1102 sensor: None,
1103 touch: Some(fidl_input_report::TouchDescriptor {
1104 input: Some(fidl_input_report::TouchInputDescriptor {
1105 contacts: None,
1106 max_contacts: None,
1107 touch_type: None,
1108 buttons: None,
1109 ..Default::default()
1110 }),
1111 ..Default::default()
1112 }),
1113 keyboard: Some(fidl_input_report::KeyboardDescriptor {
1114 input: Some(fidl_input_report::KeyboardInputDescriptor {
1115 keys3: None,
1116 ..Default::default()
1117 }),
1118 output: None,
1119 ..Default::default()
1120 }),
1121 consumer_control: Some(fidl_input_report::ConsumerControlDescriptor {
1122 input: Some(fidl_input_report::ConsumerControlInputDescriptor {
1123 buttons: Some(vec![
1124 fidl_input_report::ConsumerControlButton::VolumeUp,
1125 fidl_input_report::ConsumerControlButton::VolumeDown,
1126 ]),
1127 ..Default::default()
1128 }),
1129 ..Default::default()
1130 }),
1131 ..Default::default()
1132 });
1133 }
1134 _ => panic!("InputDevice handler received an unexpected request"),
1135 }
1136 });
1137
1138 let device_descriptor = &input_device_proxy
1139 .get_descriptor()
1140 .await
1141 .expect("Failed to get device descriptor")
1142 .descriptor;
1143 assert!(is_device_type(&device_descriptor, InputDeviceType::ConsumerControls).await);
1144 assert!(is_device_type(&device_descriptor, InputDeviceType::Mouse).await);
1145 assert!(is_device_type(&device_descriptor, InputDeviceType::Touch).await);
1146 assert!(is_device_type(&device_descriptor, InputDeviceType::Keyboard).await);
1147 }
1148
1149 #[fuchsia::test]
1150 fn unhandled_to_generic_conversion_sets_handled_flag_to_no() {
1151 assert_eq!(
1152 InputEvent::from(UnhandledInputEvent {
1153 device_event: InputDeviceEvent::Fake,
1154 device_descriptor: InputDeviceDescriptor::Fake,
1155 event_time: zx::MonotonicInstant::from_nanos(1),
1156 trace_id: None,
1157 })
1158 .handled,
1159 Handled::No
1160 );
1161 }
1162
1163 #[fuchsia::test]
1164 fn unhandled_to_generic_conversion_preserves_fields() {
1165 const EVENT_TIME: zx::MonotonicInstant = zx::MonotonicInstant::from_nanos(42);
1166 let expected_trace_id: Option<ftrace::Id> = Some(1234.into());
1167 assert_eq!(
1168 InputEvent::from(UnhandledInputEvent {
1169 device_event: InputDeviceEvent::Fake,
1170 device_descriptor: InputDeviceDescriptor::Fake,
1171 event_time: EVENT_TIME,
1172 trace_id: expected_trace_id,
1173 }),
1174 InputEvent {
1175 device_event: InputDeviceEvent::Fake,
1176 device_descriptor: InputDeviceDescriptor::Fake,
1177 event_time: EVENT_TIME,
1178 handled: Handled::No,
1179 trace_id: expected_trace_id,
1180 },
1181 );
1182 }
1183
1184 #[fuchsia::test]
1185 fn generic_to_unhandled_conversion_fails_for_handled_events() {
1186 assert_matches!(
1187 UnhandledInputEvent::try_from(InputEvent {
1188 device_event: InputDeviceEvent::Fake,
1189 device_descriptor: InputDeviceDescriptor::Fake,
1190 event_time: zx::MonotonicInstant::from_nanos(1),
1191 handled: Handled::Yes,
1192 trace_id: None,
1193 }),
1194 Err(_)
1195 )
1196 }
1197
1198 #[fuchsia::test]
1199 fn generic_to_unhandled_conversion_preserves_fields_for_unhandled_events() {
1200 const EVENT_TIME: zx::MonotonicInstant = zx::MonotonicInstant::from_nanos(42);
1201 let expected_trace_id: Option<ftrace::Id> = Some(1234.into());
1202 assert_eq!(
1203 UnhandledInputEvent::try_from(InputEvent {
1204 device_event: InputDeviceEvent::Fake,
1205 device_descriptor: InputDeviceDescriptor::Fake,
1206 event_time: EVENT_TIME,
1207 handled: Handled::No,
1208 trace_id: expected_trace_id,
1209 })
1210 .unwrap(),
1211 UnhandledInputEvent {
1212 device_event: InputDeviceEvent::Fake,
1213 device_descriptor: InputDeviceDescriptor::Fake,
1214 event_time: EVENT_TIME,
1215 trace_id: expected_trace_id,
1216 },
1217 )
1218 }
1219
1220 #[test_case(Handled::No; "initially not handled")]
1221 #[test_case(Handled::Yes; "initially handled")]
1222 fn into_handled_if_yields_handled_yes_on_true(initially_handled: Handled) {
1223 let event = InputEvent {
1224 device_event: InputDeviceEvent::Fake,
1225 device_descriptor: InputDeviceDescriptor::Fake,
1226 event_time: zx::MonotonicInstant::from_nanos(1),
1227 handled: initially_handled,
1228 trace_id: None,
1229 };
1230 pretty_assertions::assert_eq!(event.into_handled_if(true).handled, Handled::Yes);
1231 }
1232
1233 #[test_case(Handled::No; "initially not handled")]
1234 #[test_case(Handled::Yes; "initially handled")]
1235 fn into_handled_if_leaves_handled_unchanged_on_false(initially_handled: Handled) {
1236 let event = InputEvent {
1237 device_event: InputDeviceEvent::Fake,
1238 device_descriptor: InputDeviceDescriptor::Fake,
1239 event_time: zx::MonotonicInstant::from_nanos(1),
1240 handled: initially_handled.clone(),
1241 trace_id: None,
1242 };
1243 pretty_assertions::assert_eq!(event.into_handled_if(false).handled, initially_handled);
1244 }
1245
1246 #[test_case(Handled::No; "initially not handled")]
1247 #[test_case(Handled::Yes; "initially handled")]
1248 fn into_handled_yields_handled_yes(initially_handled: Handled) {
1249 let event = InputEvent {
1250 device_event: InputDeviceEvent::Fake,
1251 device_descriptor: InputDeviceDescriptor::Fake,
1252 event_time: zx::MonotonicInstant::from_nanos(1),
1253 handled: initially_handled,
1254 trace_id: None,
1255 };
1256 pretty_assertions::assert_eq!(event.into_handled().handled, Handled::Yes);
1257 }
1258}