1use crate::{
6 Dispatcher, Incoming, consumer_controls_binding, keyboard_binding, light_sensor_binding,
7 metrics, mouse_binding, touch_binding,
8};
9use anyhow::{Error, format_err};
10use async_trait::async_trait;
11use async_utils::hanging_get::client::HangingGetStream;
12use fidl_fuchsia_input_report as fidl_input_report;
13use fidl_fuchsia_input_report::InputReport;
14use fidl_fuchsia_io as fio;
15use fuchsia_inspect::health::Reporter;
16use fuchsia_inspect::{
17 ExponentialHistogramParams, HistogramProperty as _, NumericProperty, Property,
18};
19use fuchsia_trace as ftrace;
20use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
21use futures::stream::StreamExt;
22use metrics_registry::*;
23use std::path::PathBuf;
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_input_report::InputDeviceProxy,
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::endpoints::create_proxy();
391 let result = device_proxy.get_input_reports_reader(server_end);
392 if result.is_err() {
393 metrics_logger.log_error(
394 InputPipelineErrorMetricDimensionEvent::InputDeviceGetInputReportsReaderError,
395 std::format!("error on GetInputReportsReader: {:?}", &result),
396 );
397 return; }
399 let mut report_stream = HangingGetStream::new(
400 report_reader,
401 fidl_input_report::InputReportsReaderProxy::read_input_reports,
402 );
403 loop {
404 match report_stream.next().await {
405 Some(Ok(Ok(input_reports))) => {
406 fuchsia_trace::duration!("input", "input-device-process-reports");
407 let (prev_report, inspect_receiver) = process_reports(
408 input_reports,
409 previous_report,
410 &device_descriptor,
411 &mut event_sender,
412 &inspect_status,
413 &metrics_logger,
414 &feature_flags,
415 );
416 previous_report = prev_report;
417
418 if let Some(previous_report) = previous_report.as_ref() {
419 if previous_report.wake_lease.is_some() {
420 inspect_status.count_wake_lease_leak();
421
422 let error_code = match device_descriptor {
423 InputDeviceDescriptor::TouchScreen(_) => {
424 Some(InputPipelineMetricDimensionEvent::TouchscreenPreviousReportHasWakeLease)
425 }
426 InputDeviceDescriptor::Touchpad(_) => {
427 Some(InputPipelineMetricDimensionEvent::TouchpadPreviousReportHasWakeLease)
428 }
429 InputDeviceDescriptor::Mouse(_) => {
430 Some(InputPipelineMetricDimensionEvent::MousePreviousReportHasWakeLease)
431 }
432 InputDeviceDescriptor::Keyboard(_) => {
433 Some(InputPipelineMetricDimensionEvent::KeyboardPreviousReportHasWakeLease)
434 }
435 InputDeviceDescriptor::ConsumerControls(_) => {
436 Some(InputPipelineMetricDimensionEvent::ButtonPreviousReportHasWakeLease)
437 }
438 InputDeviceDescriptor::LightSensor(_) => {
439 Some(InputPipelineMetricDimensionEvent::LightSensorPreviousReportHasWakeLease)
440 }
441 #[cfg(test)]
442 InputDeviceDescriptor::Fake => None,
443 };
444 if let Some(error_code) = error_code {
445 metrics_logger.log_error(error_code, std::format!("previous_report must not have a wake lease but does: {:?}", previous_report));
446 }
447 }
448 }
449
450 match inspect_receiver {
454 Some(mut receiver) => {
455 while let Some(event) = receiver.next().await {
456 inspect_status.count_generated_event(event);
457 }
458 }
459 None => (),
460 };
461 }
462 Some(Ok(Err(_service_error))) => break,
463 Some(Err(_fidl_error)) => break,
464 None => break,
465 }
466 }
467 log::warn!("initialize_report_stream exited - device binding no longer works");
470 })
471 .detach();
472}
473
474pub async fn is_device_type(
480 device_descriptor: &fidl_input_report::DeviceDescriptor,
481 device_type: InputDeviceType,
482) -> bool {
483 match device_type {
485 InputDeviceType::ConsumerControls => device_descriptor.consumer_control.is_some(),
486 InputDeviceType::Mouse => device_descriptor.mouse.is_some(),
487 InputDeviceType::Touch => device_descriptor.touch.is_some(),
488 InputDeviceType::Keyboard => device_descriptor.keyboard.is_some(),
489 InputDeviceType::LightSensor => device_descriptor.sensor.is_some(),
490 }
491}
492
493pub async fn get_device_binding(
501 device_type: InputDeviceType,
502 device_proxy: fidl_input_report::InputDeviceProxy,
503 device_id: u32,
504 input_event_sender: UnboundedSender<Vec<InputEvent>>,
505 device_node: fuchsia_inspect::Node,
506 feature_flags: InputPipelineFeatureFlags,
507 metrics_logger: metrics::MetricsLogger,
508) -> Result<Box<dyn InputDeviceBinding>, Error> {
509 match device_type {
510 InputDeviceType::ConsumerControls => {
511 let binding = consumer_controls_binding::ConsumerControlsBinding::new(
512 device_proxy,
513 device_id,
514 input_event_sender,
515 device_node,
516 feature_flags.clone(),
517 metrics_logger,
518 )
519 .await?;
520 Ok(Box::new(binding))
521 }
522 InputDeviceType::Mouse => {
523 let binding = mouse_binding::MouseBinding::new(
524 device_proxy,
525 device_id,
526 input_event_sender,
527 device_node,
528 feature_flags.clone(),
529 metrics_logger,
530 )
531 .await?;
532 Ok(Box::new(binding))
533 }
534 InputDeviceType::Touch => {
535 let binding = touch_binding::TouchBinding::new(
536 device_proxy,
537 device_id,
538 input_event_sender,
539 device_node,
540 feature_flags.clone(),
541 metrics_logger,
542 )
543 .await?;
544 Ok(Box::new(binding))
545 }
546 InputDeviceType::Keyboard => {
547 let binding = keyboard_binding::KeyboardBinding::new(
548 device_proxy,
549 device_id,
550 input_event_sender,
551 device_node,
552 feature_flags.clone(),
553 metrics_logger,
554 )
555 .await?;
556 Ok(Box::new(binding))
557 }
558 InputDeviceType::LightSensor => {
559 let binding = light_sensor_binding::LightSensorBinding::new(
560 device_proxy,
561 device_id,
562 input_event_sender,
563 device_node,
564 feature_flags.clone(),
565 metrics_logger,
566 )
567 .await?;
568 Ok(Box::new(binding))
569 }
570 }
571}
572
573pub fn get_device_from_dir_entry_path(
582 dir_proxy: &fio::DirectoryProxy,
583 entry_path: &PathBuf,
584) -> Result<fidl_input_report::InputDeviceProxy, Error> {
585 let input_device_path = entry_path.to_str();
586 if input_device_path.is_none() {
587 return Err(format_err!("Failed to get entry path as a string."));
588 }
589
590 let input_device = Incoming::connect_protocol_at::<fidl_input_report::InputDeviceProxy>(
591 dir_proxy,
592 input_device_path.unwrap(),
593 )
594 .expect("Failed to connect to InputDevice.");
595 Ok(input_device)
596}
597
598pub fn event_time_or_now(event_time: Option<i64>) -> zx::MonotonicInstant {
603 match event_time {
604 Some(time) => zx::MonotonicInstant::from_nanos(time),
605 None => zx::MonotonicInstant::get(),
606 }
607}
608
609impl std::convert::From<UnhandledInputEvent> for InputEvent {
610 fn from(event: UnhandledInputEvent) -> Self {
611 Self {
612 device_event: event.device_event,
613 device_descriptor: event.device_descriptor,
614 event_time: event.event_time,
615 handled: Handled::No,
616 trace_id: event.trace_id,
617 }
618 }
619}
620
621#[cfg(test)]
628impl std::convert::TryFrom<InputEvent> for UnhandledInputEvent {
629 type Error = anyhow::Error;
630 fn try_from(event: InputEvent) -> Result<UnhandledInputEvent, Self::Error> {
631 match event.handled {
632 Handled::Yes => {
633 Err(format_err!("Attempted to treat a handled InputEvent as unhandled"))
634 }
635 Handled::No => Ok(UnhandledInputEvent {
636 device_event: event.device_event,
637 device_descriptor: event.device_descriptor,
638 event_time: event.event_time,
639 trace_id: event.trace_id,
640 }),
641 }
642 }
643}
644
645impl InputEvent {
646 pub fn clone_with_wake_lease(&self) -> Self {
647 let device_event = match &self.device_event {
648 InputDeviceEvent::ConsumerControls(event) => {
649 InputDeviceEvent::ConsumerControls(event.clone_with_wake_lease())
650 }
651 InputDeviceEvent::Mouse(event) => {
652 InputDeviceEvent::Mouse(event.clone_with_wake_lease())
653 }
654 InputDeviceEvent::TouchScreen(event) => {
655 InputDeviceEvent::TouchScreen(event.clone_with_wake_lease())
656 }
657 _ => self.device_event.clone(),
658 };
659 Self {
660 device_event,
661 device_descriptor: self.device_descriptor.clone(),
662 event_time: self.event_time,
663 handled: self.handled,
664 trace_id: self.trace_id,
665 }
666 }
667
668 pub(crate) fn into_handled_if(self, predicate: bool) -> Self {
671 if predicate { Self { handled: Handled::Yes, ..self } } else { self }
672 }
673
674 pub(crate) fn into_handled(self) -> Self {
676 Self { handled: Handled::Yes, ..self }
677 }
678
679 pub fn into_with_event_time(self, event_time: zx::MonotonicInstant) -> Self {
681 Self { event_time, ..self }
682 }
683
684 #[cfg(test)]
686 pub fn into_with_device_descriptor(self, device_descriptor: InputDeviceDescriptor) -> Self {
687 Self { device_descriptor, ..self }
688 }
689
690 pub fn is_handled(&self) -> bool {
692 self.handled == Handled::Yes
693 }
694
695 pub fn get_event_type(&self) -> &'static str {
697 match self.device_event {
698 InputDeviceEvent::Keyboard(_) => "keyboard_event",
699 InputDeviceEvent::LightSensor(_) => "light_sensor_event",
700 InputDeviceEvent::ConsumerControls(_) => "consumer_controls_event",
701 InputDeviceEvent::Mouse(_) => "mouse_event",
702 InputDeviceEvent::TouchScreen(_) => "touch_screen_event",
703 InputDeviceEvent::Touchpad(_) => "touchpad_event",
704 #[cfg(test)]
705 InputDeviceEvent::Fake => "fake_event",
706 }
707 }
708
709 pub fn record_inspect(&self, node: &fuchsia_inspect::Node) {
710 node.record_int("event_time", self.event_time.into_nanos());
711 match &self.device_event {
712 InputDeviceEvent::LightSensor(e) => e.record_inspect(node),
713 InputDeviceEvent::ConsumerControls(e) => e.record_inspect(node),
714 InputDeviceEvent::Mouse(e) => e.record_inspect(node),
715 InputDeviceEvent::TouchScreen(e) => e.record_inspect(node),
716 InputDeviceEvent::Touchpad(e) => e.record_inspect(node),
717 InputDeviceEvent::Keyboard(_) => (),
719 #[cfg(test)] InputDeviceEvent::Fake => (),
721 }
722 }
723}
724
725#[cfg(test)]
726mod tests {
727 use super::*;
728 use assert_matches::assert_matches;
729 use diagnostics_assertions::AnyProperty;
730 use fidl_test_util::spawn_stream_handler;
731 use fuchsia_async as fasync;
732
733 use pretty_assertions::assert_eq;
734 use std::convert::TryFrom as _;
735 use test_case::test_case;
736
737 #[test]
738 fn max_event_time() {
739 let event_time = event_time_or_now(Some(i64::MAX));
740 assert_eq!(event_time, zx::MonotonicInstant::INFINITE);
741 }
742
743 #[test]
744 fn min_event_time() {
745 let event_time = event_time_or_now(Some(std::i64::MIN));
746 assert_eq!(event_time, zx::MonotonicInstant::INFINITE_PAST);
747 }
748
749 #[fasync::run_singlethreaded(test)]
750 async fn input_device_status_initialized_with_correct_properties() {
751 let inspector = fuchsia_inspect::Inspector::default();
752 let input_pipeline_node = inspector.root().create_child("input_pipeline");
753 let input_devices_node = input_pipeline_node.create_child("input_devices");
754 let device_node = input_devices_node.create_child("001_keyboard");
755 let _input_device_status = InputDeviceStatus::new(device_node);
756 diagnostics_assertions::assert_data_tree!(inspector, root: {
757 input_pipeline: {
758 input_devices: {
759 "001_keyboard": {
760 reports_received_count: 0u64,
761 reports_filtered_count: 0u64,
762 events_generated: 0u64,
763 last_received_timestamp_ns: 0u64,
764 last_generated_timestamp_ns: 0u64,
765 "fuchsia.inspect.Health": {
766 status: "STARTING_UP",
767 start_timestamp_nanos: AnyProperty
770 },
771 driver_to_binding_latency_ms: diagnostics_assertions::HistogramAssertion::exponential(super::LATENCY_HISTOGRAM_PROPERTIES),
772 wake_lease_leak_count: 0u64,
773 }
774 }
775 }
776 });
777 }
778
779 #[test_case(i64::MIN; "min value")]
780 #[test_case(-1; "negative value")]
781 #[test_case(0; "zero")]
782 #[test_case(1; "positive value")]
783 #[test_case(i64::MAX; "max value")]
784 #[fuchsia::test(allow_stalls = false)]
785 async fn input_device_status_updates_latency_histogram_on_count_received_report(
786 latency_nsec: i64,
787 ) {
788 let mut expected_histogram = diagnostics_assertions::HistogramAssertion::exponential(
789 super::LATENCY_HISTOGRAM_PROPERTIES,
790 );
791 let inspector = fuchsia_inspect::Inspector::default();
792 let input_device_status = InputDeviceStatus::new_internal(
793 inspector.root().clone_weak(),
794 Box::new(move || zx::MonotonicInstant::from_nanos(latency_nsec)),
795 );
796 input_device_status
797 .count_received_report(&InputReport { event_time: Some(0), ..InputReport::default() });
798 expected_histogram.insert_values([latency_nsec / 1000 / 1000]);
799 diagnostics_assertions::assert_data_tree!(inspector, root: contains {
800 driver_to_binding_latency_ms: expected_histogram,
801 });
802 }
803
804 #[fasync::run_singlethreaded(test)]
807 async fn consumer_controls_input_device_exists() {
808 let input_device_proxy: fidl_input_report::InputDeviceProxy =
809 spawn_stream_handler(move |input_device_request| async move {
810 match input_device_request {
811 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
812 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
813 device_information: None,
814 mouse: None,
815 sensor: None,
816 touch: None,
817 keyboard: None,
818 consumer_control: Some(fidl_input_report::ConsumerControlDescriptor {
819 input: Some(fidl_input_report::ConsumerControlInputDescriptor {
820 buttons: Some(vec![
821 fidl_input_report::ConsumerControlButton::VolumeUp,
822 fidl_input_report::ConsumerControlButton::VolumeDown,
823 ]),
824 ..Default::default()
825 }),
826 ..Default::default()
827 }),
828 ..Default::default()
829 });
830 }
831 _ => panic!("InputDevice handler received an unexpected request"),
832 }
833 });
834
835 assert!(
836 is_device_type(
837 &input_device_proxy
838 .get_descriptor()
839 .await
840 .expect("Failed to get device descriptor"),
841 InputDeviceType::ConsumerControls
842 )
843 .await
844 );
845 }
846
847 #[fasync::run_singlethreaded(test)]
849 async fn mouse_input_device_exists() {
850 let input_device_proxy: fidl_input_report::InputDeviceProxy =
851 spawn_stream_handler(move |input_device_request| async move {
852 match input_device_request {
853 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
854 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
855 device_information: None,
856 mouse: Some(fidl_input_report::MouseDescriptor {
857 input: Some(fidl_input_report::MouseInputDescriptor {
858 movement_x: None,
859 movement_y: None,
860 position_x: None,
861 position_y: None,
862 scroll_v: None,
863 scroll_h: None,
864 buttons: None,
865 ..Default::default()
866 }),
867 ..Default::default()
868 }),
869 sensor: None,
870 touch: None,
871 keyboard: None,
872 consumer_control: None,
873 ..Default::default()
874 });
875 }
876 _ => panic!("InputDevice handler received an unexpected request"),
877 }
878 });
879
880 assert!(
881 is_device_type(
882 &input_device_proxy
883 .get_descriptor()
884 .await
885 .expect("Failed to get device descriptor"),
886 InputDeviceType::Mouse
887 )
888 .await
889 );
890 }
891
892 #[fasync::run_singlethreaded(test)]
895 async fn mouse_input_device_doesnt_exist() {
896 let input_device_proxy: fidl_input_report::InputDeviceProxy =
897 spawn_stream_handler(move |input_device_request| async move {
898 match input_device_request {
899 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
900 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
901 device_information: None,
902 mouse: None,
903 sensor: None,
904 touch: None,
905 keyboard: None,
906 consumer_control: None,
907 ..Default::default()
908 });
909 }
910 _ => panic!("InputDevice handler received an unexpected request"),
911 }
912 });
913
914 assert!(
915 !is_device_type(
916 &input_device_proxy
917 .get_descriptor()
918 .await
919 .expect("Failed to get device descriptor"),
920 InputDeviceType::Mouse
921 )
922 .await
923 );
924 }
925
926 #[fasync::run_singlethreaded(test)]
929 async fn touch_input_device_exists() {
930 let input_device_proxy: fidl_input_report::InputDeviceProxy =
931 spawn_stream_handler(move |input_device_request| async move {
932 match input_device_request {
933 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
934 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
935 device_information: None,
936 mouse: None,
937 sensor: None,
938 touch: Some(fidl_input_report::TouchDescriptor {
939 input: Some(fidl_input_report::TouchInputDescriptor {
940 contacts: None,
941 max_contacts: None,
942 touch_type: None,
943 buttons: None,
944 ..Default::default()
945 }),
946 ..Default::default()
947 }),
948 keyboard: None,
949 consumer_control: None,
950 ..Default::default()
951 });
952 }
953 _ => panic!("InputDevice handler received an unexpected request"),
954 }
955 });
956
957 assert!(
958 is_device_type(
959 &input_device_proxy
960 .get_descriptor()
961 .await
962 .expect("Failed to get device descriptor"),
963 InputDeviceType::Touch
964 )
965 .await
966 );
967 }
968
969 #[fasync::run_singlethreaded(test)]
972 async fn touch_input_device_doesnt_exist() {
973 let input_device_proxy: fidl_input_report::InputDeviceProxy =
974 spawn_stream_handler(move |input_device_request| async move {
975 match input_device_request {
976 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
977 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
978 device_information: None,
979 mouse: None,
980 sensor: None,
981 touch: None,
982 keyboard: None,
983 consumer_control: None,
984 ..Default::default()
985 });
986 }
987 _ => panic!("InputDevice handler received an unexpected request"),
988 }
989 });
990
991 assert!(
992 !is_device_type(
993 &input_device_proxy
994 .get_descriptor()
995 .await
996 .expect("Failed to get device 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: fidl_input_report::InputDeviceProxy =
1008 spawn_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 InputDeviceType::Keyboard
1039 )
1040 .await
1041 );
1042 }
1043
1044 #[fasync::run_singlethreaded(test)]
1047 async fn keyboard_input_device_doesnt_exist() {
1048 let input_device_proxy: fidl_input_report::InputDeviceProxy =
1049 spawn_stream_handler(move |input_device_request| async move {
1050 match input_device_request {
1051 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
1052 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
1053 device_information: None,
1054 mouse: None,
1055 sensor: None,
1056 touch: None,
1057 keyboard: None,
1058 consumer_control: None,
1059 ..Default::default()
1060 });
1061 }
1062 _ => panic!("InputDevice handler received an unexpected request"),
1063 }
1064 });
1065
1066 assert!(
1067 !is_device_type(
1068 &input_device_proxy
1069 .get_descriptor()
1070 .await
1071 .expect("Failed to get device descriptor"),
1072 InputDeviceType::Keyboard
1073 )
1074 .await
1075 );
1076 }
1077
1078 #[fasync::run_singlethreaded(test)]
1080 async fn no_input_device_match() {
1081 let input_device_proxy: fidl_input_report::InputDeviceProxy =
1082 spawn_stream_handler(move |input_device_request| async move {
1083 match input_device_request {
1084 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
1085 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
1086 device_information: None,
1087 mouse: Some(fidl_input_report::MouseDescriptor {
1088 input: Some(fidl_input_report::MouseInputDescriptor {
1089 movement_x: None,
1090 movement_y: None,
1091 position_x: None,
1092 position_y: None,
1093 scroll_v: None,
1094 scroll_h: None,
1095 buttons: None,
1096 ..Default::default()
1097 }),
1098 ..Default::default()
1099 }),
1100 sensor: None,
1101 touch: Some(fidl_input_report::TouchDescriptor {
1102 input: Some(fidl_input_report::TouchInputDescriptor {
1103 contacts: None,
1104 max_contacts: None,
1105 touch_type: None,
1106 buttons: None,
1107 ..Default::default()
1108 }),
1109 ..Default::default()
1110 }),
1111 keyboard: Some(fidl_input_report::KeyboardDescriptor {
1112 input: Some(fidl_input_report::KeyboardInputDescriptor {
1113 keys3: None,
1114 ..Default::default()
1115 }),
1116 output: None,
1117 ..Default::default()
1118 }),
1119 consumer_control: Some(fidl_input_report::ConsumerControlDescriptor {
1120 input: Some(fidl_input_report::ConsumerControlInputDescriptor {
1121 buttons: Some(vec![
1122 fidl_input_report::ConsumerControlButton::VolumeUp,
1123 fidl_input_report::ConsumerControlButton::VolumeDown,
1124 ]),
1125 ..Default::default()
1126 }),
1127 ..Default::default()
1128 }),
1129 ..Default::default()
1130 });
1131 }
1132 _ => panic!("InputDevice handler received an unexpected request"),
1133 }
1134 });
1135
1136 let device_descriptor =
1137 &input_device_proxy.get_descriptor().await.expect("Failed to get device descriptor");
1138 assert!(is_device_type(&device_descriptor, InputDeviceType::ConsumerControls).await);
1139 assert!(is_device_type(&device_descriptor, InputDeviceType::Mouse).await);
1140 assert!(is_device_type(&device_descriptor, InputDeviceType::Touch).await);
1141 assert!(is_device_type(&device_descriptor, InputDeviceType::Keyboard).await);
1142 }
1143
1144 #[fuchsia::test]
1145 fn unhandled_to_generic_conversion_sets_handled_flag_to_no() {
1146 assert_eq!(
1147 InputEvent::from(UnhandledInputEvent {
1148 device_event: InputDeviceEvent::Fake,
1149 device_descriptor: InputDeviceDescriptor::Fake,
1150 event_time: zx::MonotonicInstant::from_nanos(1),
1151 trace_id: None,
1152 })
1153 .handled,
1154 Handled::No
1155 );
1156 }
1157
1158 #[fuchsia::test]
1159 fn unhandled_to_generic_conversion_preserves_fields() {
1160 const EVENT_TIME: zx::MonotonicInstant = zx::MonotonicInstant::from_nanos(42);
1161 let expected_trace_id: Option<ftrace::Id> = Some(1234.into());
1162 assert_eq!(
1163 InputEvent::from(UnhandledInputEvent {
1164 device_event: InputDeviceEvent::Fake,
1165 device_descriptor: InputDeviceDescriptor::Fake,
1166 event_time: EVENT_TIME,
1167 trace_id: expected_trace_id,
1168 }),
1169 InputEvent {
1170 device_event: InputDeviceEvent::Fake,
1171 device_descriptor: InputDeviceDescriptor::Fake,
1172 event_time: EVENT_TIME,
1173 handled: Handled::No,
1174 trace_id: expected_trace_id,
1175 },
1176 );
1177 }
1178
1179 #[fuchsia::test]
1180 fn generic_to_unhandled_conversion_fails_for_handled_events() {
1181 assert_matches!(
1182 UnhandledInputEvent::try_from(InputEvent {
1183 device_event: InputDeviceEvent::Fake,
1184 device_descriptor: InputDeviceDescriptor::Fake,
1185 event_time: zx::MonotonicInstant::from_nanos(1),
1186 handled: Handled::Yes,
1187 trace_id: None,
1188 }),
1189 Err(_)
1190 )
1191 }
1192
1193 #[fuchsia::test]
1194 fn generic_to_unhandled_conversion_preserves_fields_for_unhandled_events() {
1195 const EVENT_TIME: zx::MonotonicInstant = zx::MonotonicInstant::from_nanos(42);
1196 let expected_trace_id: Option<ftrace::Id> = Some(1234.into());
1197 assert_eq!(
1198 UnhandledInputEvent::try_from(InputEvent {
1199 device_event: InputDeviceEvent::Fake,
1200 device_descriptor: InputDeviceDescriptor::Fake,
1201 event_time: EVENT_TIME,
1202 handled: Handled::No,
1203 trace_id: expected_trace_id,
1204 })
1205 .unwrap(),
1206 UnhandledInputEvent {
1207 device_event: InputDeviceEvent::Fake,
1208 device_descriptor: InputDeviceDescriptor::Fake,
1209 event_time: EVENT_TIME,
1210 trace_id: expected_trace_id,
1211 },
1212 )
1213 }
1214
1215 #[test_case(Handled::No; "initially not handled")]
1216 #[test_case(Handled::Yes; "initially handled")]
1217 fn into_handled_if_yields_handled_yes_on_true(initially_handled: Handled) {
1218 let event = InputEvent {
1219 device_event: InputDeviceEvent::Fake,
1220 device_descriptor: InputDeviceDescriptor::Fake,
1221 event_time: zx::MonotonicInstant::from_nanos(1),
1222 handled: initially_handled,
1223 trace_id: None,
1224 };
1225 pretty_assertions::assert_eq!(event.into_handled_if(true).handled, Handled::Yes);
1226 }
1227
1228 #[test_case(Handled::No; "initially not handled")]
1229 #[test_case(Handled::Yes; "initially handled")]
1230 fn into_handled_if_leaves_handled_unchanged_on_false(initially_handled: Handled) {
1231 let event = InputEvent {
1232 device_event: InputDeviceEvent::Fake,
1233 device_descriptor: InputDeviceDescriptor::Fake,
1234 event_time: zx::MonotonicInstant::from_nanos(1),
1235 handled: initially_handled.clone(),
1236 trace_id: None,
1237 };
1238 pretty_assertions::assert_eq!(event.into_handled_if(false).handled, initially_handled);
1239 }
1240
1241 #[test_case(Handled::No; "initially not handled")]
1242 #[test_case(Handled::Yes; "initially handled")]
1243 fn into_handled_yields_handled_yes(initially_handled: Handled) {
1244 let event = InputEvent {
1245 device_event: InputDeviceEvent::Fake,
1246 device_descriptor: InputDeviceDescriptor::Fake,
1247 event_time: zx::MonotonicInstant::from_nanos(1),
1248 handled: initially_handled,
1249 trace_id: None,
1250 };
1251 pretty_assertions::assert_eq!(event.into_handled().handled, Handled::Yes);
1252 }
1253}