1use crate::input_device::{Handled, InputDeviceEvent, InputDeviceType, InputEvent, InputEventType};
6use crate::input_handler::{Handler, InputHandler};
7use async_trait::async_trait;
8use fuchsia_inspect::health::Reporter;
9use fuchsia_inspect::{
10 self as inspect, ExponentialHistogramParams, HistogramProperty, Inspector, NumericProperty,
11 Property,
12};
13
14use futures::FutureExt;
15use futures::lock::Mutex;
16use inspect::Node;
17use sorted_vec_map::SortedVecSet;
18use std::cell::RefCell;
19use std::collections::VecDeque;
20use std::fmt::Debug;
21use std::rc::Rc;
22use std::sync::Arc;
23use strum::EnumCount;
24
25const MAX_RECENT_EVENT_LOG_SIZE: usize = 125;
26const LATENCY_HISTOGRAM_PROPERTIES: ExponentialHistogramParams<i64> = ExponentialHistogramParams {
27 floor: 0,
28 initial_step: 1,
29 step_multiplier: 10,
30 buckets: 7,
41};
42
43#[derive(Debug)]
44struct EventCounters {
45 _node: inspect::Node,
47 events_count: inspect::UintProperty,
49 events_with_wake_lease_count: inspect::UintProperty,
51 handled_events_count: inspect::UintProperty,
53 last_seen_timestamp_ns: inspect::IntProperty,
56 last_generated_timestamp_ns: inspect::IntProperty,
59}
60
61impl EventCounters {
62 fn create(root: &inspect::Node, event_type: InputEventType) -> EventCounters {
63 let node = root.create_child(format!("{}", event_type));
64 let events_count = node.create_uint("events_count", 0);
65 let events_with_wake_lease_count = node.create_uint("events_with_wake_lease_count", 0);
66 let handled_events_count = node.create_uint("handled_events_count", 0);
67 let last_seen_timestamp_ns = node.create_int("last_seen_timestamp_ns", 0);
68 let last_generated_timestamp_ns = node.create_int("last_generated_timestamp_ns", 0);
69 EventCounters {
70 _node: node,
71 events_count,
72 events_with_wake_lease_count,
73 handled_events_count,
74 last_seen_timestamp_ns,
75 last_generated_timestamp_ns,
76 }
77 }
78
79 pub fn count_event(
80 &self,
81 time: zx::MonotonicInstant,
82 event_time: zx::MonotonicInstant,
83 handled: &Handled,
84 has_wake_lease: bool,
85 ) {
86 self.events_count.add(1);
87 if has_wake_lease {
88 self.events_with_wake_lease_count.add(1);
89 }
90 if *handled == Handled::Yes {
91 self.handled_events_count.add(1);
92 }
93 self.last_seen_timestamp_ns.set(time.into_nanos());
94 self.last_generated_timestamp_ns.set(event_time.into_nanos());
95 }
96}
97
98pub(crate) struct CircularBuffer<T> {
99 _size: usize,
101 _events: VecDeque<T>,
103}
104
105pub(crate) trait BufferNode {
106 fn get_name(&self) -> &'static str;
107 fn record_inspect(&self, node: &Node);
108}
109
110impl<T> CircularBuffer<T>
111where
112 T: BufferNode,
113{
114 pub(crate) fn new(size: usize) -> Self {
115 let events = VecDeque::with_capacity(size);
116 CircularBuffer { _size: size, _events: events }
117 }
118
119 pub(crate) fn push(&mut self, event: T) {
120 if self._events.len() >= self._size {
121 std::mem::drop(self._events.pop_front());
122 }
123 self._events.push_back(event);
124 }
125
126 pub(crate) fn record_all_lazy_inspect(
127 &self,
128 inspector: inspect::Inspector,
129 ) -> inspect::Inspector {
130 self._events.iter().enumerate().for_each(|(i, event)| {
131 inspector.root().record_child(format!("{:03}_{}", i, event.get_name()), move |node| {
134 event.record_inspect(node)
135 });
136 });
137 inspector
138 }
139}
140
141impl BufferNode for InputEvent {
142 fn get_name(&self) -> &'static str {
143 self.get_event_type()
144 }
145
146 fn record_inspect(&self, node: &Node) {
147 InputEvent::record_inspect(self, node);
148 }
149}
150
151pub struct InspectHandler<F> {
156 now: RefCell<F>,
158 node: inspect::Node,
160 events_count: inspect::UintProperty,
162 events_with_wake_lease_count: inspect::UintProperty,
164 last_seen_timestamp_ns: inspect::IntProperty,
167 last_generated_timestamp_ns: inspect::IntProperty,
170 events_by_type: [Option<EventCounters>; InputEventType::COUNT],
172 recent_events_log: Option<Arc<Mutex<CircularBuffer<InputEvent>>>>,
174 pipeline_latency_ms: inspect::IntExponentialHistogramProperty,
178 health_node: RefCell<fuchsia_inspect::health::Node>,
180}
181
182impl<F: FnMut() -> zx::MonotonicInstant + 'static> Debug for InspectHandler<F> {
183 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
184 f.debug_struct("InspectHandler")
185 .field("node", &self.node)
186 .field("events_count", &self.events_count)
187 .field("events_with_wake_lease_count", &self.events_with_wake_lease_count)
188 .field("last_seen_timestamp_ns", &self.last_seen_timestamp_ns)
189 .field("last_generated_timestamp_ns", &self.last_generated_timestamp_ns)
190 .field("events_by_type", &self.events_by_type)
191 .field("recent_events_log", &self.recent_events_log)
192 .field("pipeline_latency_ms", &self.pipeline_latency_ms)
193 .finish()
194 }
195}
196
197impl<F: FnMut() -> zx::MonotonicInstant + 'static> Handler for InspectHandler<F> {
198 fn set_handler_healthy(self: std::rc::Rc<Self>) {
199 self.health_node.borrow_mut().set_ok();
200 }
201
202 fn set_handler_unhealthy(self: std::rc::Rc<Self>, msg: &str) {
203 self.health_node.borrow_mut().set_unhealthy(msg);
204 }
205
206 fn get_name(&self) -> &'static str {
207 "InspectHandler"
208 }
209
210 fn interest(&self) -> Vec<InputEventType> {
211 vec![
212 InputEventType::Keyboard,
213 InputEventType::LightSensor,
214 InputEventType::ConsumerControls,
215 InputEventType::Mouse,
216 InputEventType::TouchScreen,
217 InputEventType::Touchpad,
218 #[cfg(test)]
219 InputEventType::Fake,
220 ]
221 }
222}
223
224#[async_trait(?Send)]
225impl<F: FnMut() -> zx::MonotonicInstant + 'static> InputHandler for InspectHandler<F> {
226 async fn handle_input_event(self: Rc<Self>, input_event: InputEvent) -> Vec<InputEvent> {
227 fuchsia_trace::duration!("input", "inspect_handler");
228 let tracing_id = input_event.trace_id.unwrap_or_else(|| 0.into());
229 fuchsia_trace::flow_step!("input", "event_in_input_pipeline", tracing_id);
230
231 let event_time = input_event.event_time;
232 let now = (self.now.borrow_mut())();
233 self.events_count.add(1);
234
235 let has_wake_lease = match &input_event.device_event {
236 InputDeviceEvent::ConsumerControls(e) => e.wake_lease.is_some(),
237 InputDeviceEvent::Mouse(e) => e.wake_lease.lock().is_some(),
238 InputDeviceEvent::TouchScreen(e) => e.wake_lease.is_some(),
239 _ => false,
240 };
241 if has_wake_lease {
242 self.events_with_wake_lease_count.add(1);
243 }
244 self.last_seen_timestamp_ns.set(now.into_nanos());
245 self.last_generated_timestamp_ns.set(event_time.into_nanos());
246 let event_type = InputEventType::from(&input_event.device_event);
247 self.events_by_type[event_type as usize]
248 .as_ref()
249 .unwrap_or_else(|| panic!("no event counters for {}", event_type))
250 .count_event(now, event_time, &input_event.handled, has_wake_lease);
251 if let Some(recent_events_log) = &self.recent_events_log {
252 recent_events_log.lock().await.push(input_event.clone());
253 }
254 self.pipeline_latency_ms.insert((now - event_time).into_millis());
255 vec![input_event]
256 }
257}
258
259pub fn make_inspect_handler(
263 node: inspect::Node,
264 supported_input_devices: &SortedVecSet<&InputDeviceType>,
265 displays_recent_events: bool,
266) -> Rc<InspectHandler<fn() -> zx::MonotonicInstant>> {
267 InspectHandler::new_internal(
268 node,
269 zx::MonotonicInstant::get,
270 supported_input_devices,
271 displays_recent_events,
272 )
273}
274
275impl<F> InspectHandler<F> {
276 fn new_internal(
279 node: inspect::Node,
280 now: F,
281 supported_input_devices: &SortedVecSet<&InputDeviceType>,
282 displays_recent_events: bool,
283 ) -> Rc<Self> {
284 let event_count = node.create_uint("events_count", 0);
285 let events_with_wake_lease_count_node = node.create_uint("events_with_wake_lease_count", 0);
286 let last_seen_timestamp_ns = node.create_int("last_seen_timestamp_ns", 0);
287 let last_generated_timestamp_ns = node.create_int("last_generated_timestamp_ns", 0);
288
289 let recent_events_log = match displays_recent_events {
290 true => {
291 let recent_events =
292 Arc::new(Mutex::new(CircularBuffer::new(MAX_RECENT_EVENT_LOG_SIZE)));
293 record_lazy_recent_events(&node, Arc::clone(&recent_events));
294 Some(recent_events)
295 }
296 false => None,
297 };
298
299 let pipeline_latency_ms = node
300 .create_int_exponential_histogram("pipeline_latency_ms", LATENCY_HISTOGRAM_PROPERTIES);
301
302 let mut health_node = fuchsia_inspect::health::Node::new(&node);
303 health_node.set_starting_up();
304
305 let mut events_by_type: [Option<EventCounters>; InputEventType::COUNT] = Default::default();
306 if supported_input_devices.contains(&InputDeviceType::Keyboard) {
307 events_by_type[InputEventType::Keyboard as usize] =
308 Some(EventCounters::create(&node, InputEventType::Keyboard));
309 }
310 if supported_input_devices.contains(&InputDeviceType::ConsumerControls) {
311 events_by_type[InputEventType::ConsumerControls as usize] =
312 Some(EventCounters::create(&node, InputEventType::ConsumerControls));
313 }
314 if supported_input_devices.contains(&InputDeviceType::LightSensor) {
315 events_by_type[InputEventType::LightSensor as usize] =
316 Some(EventCounters::create(&node, InputEventType::LightSensor));
317 }
318 if supported_input_devices.contains(&InputDeviceType::Mouse) {
319 events_by_type[InputEventType::Mouse as usize] =
320 Some(EventCounters::create(&node, InputEventType::Mouse));
321 }
322 if supported_input_devices.contains(&InputDeviceType::Touch) {
323 events_by_type[InputEventType::TouchScreen as usize] =
324 Some(EventCounters::create(&node, InputEventType::TouchScreen));
325 events_by_type[InputEventType::Touchpad as usize] =
326 Some(EventCounters::create(&node, InputEventType::Touchpad));
327 }
328 #[cfg(test)]
329 {
330 events_by_type[InputEventType::Fake as usize] =
331 Some(EventCounters::create(&node, InputEventType::Fake));
332 }
333
334 Rc::new(Self {
335 now: RefCell::new(now),
336 node,
337 events_count: event_count,
338 events_with_wake_lease_count: events_with_wake_lease_count_node,
339 last_seen_timestamp_ns,
340 last_generated_timestamp_ns,
341 events_by_type,
342 recent_events_log,
343 pipeline_latency_ms,
344 health_node: RefCell::new(health_node),
345 })
346 }
347}
348
349fn record_lazy_recent_events(
350 node: &inspect::Node,
351 recent_events: Arc<Mutex<CircularBuffer<InputEvent>>>,
352) {
353 node.record_lazy_child("recent_events_log", move || {
354 let recent_events_clone = Arc::clone(&recent_events);
355 async move {
356 let inspector = Inspector::default();
357 Ok(recent_events_clone.lock().await.record_all_lazy_inspect(inspector))
358 }
359 .boxed()
360 });
361}
362
363#[cfg(test)]
364mod tests {
365 use super::*;
366 use crate::input_device::{self, InputDeviceDescriptor, InputDeviceEvent};
367 use crate::keyboard_binding::KeyboardDeviceDescriptor;
368 use crate::light_sensor::types::Rgbc;
369 use crate::light_sensor_binding::{LightSensorDeviceDescriptor, LightSensorEvent};
370 use crate::mouse_binding::{
371 MouseDeviceDescriptor, MouseLocation, MousePhase, PrecisionScroll, WheelDelta,
372 };
373 use crate::testing_utilities::{
374 consumer_controls_device_descriptor, create_consumer_controls_event,
375 create_fake_handled_input_event, create_fake_input_event, create_keyboard_event,
376 create_mouse_event, create_touch_contact, create_touch_screen_event, create_touchpad_event,
377 next_client_old_stream,
378 };
379 use crate::touch_binding::{TouchScreenDeviceDescriptor, TouchpadDeviceDescriptor};
380 use crate::utils::Position;
381 use diagnostics_assertions::{AnyProperty, assert_data_tree};
382 use fidl_fuchsia_input_report::InputDeviceMarker;
383 use fuchsia_async as fasync;
384 use sorted_vec_map::SortedVecMap;
385 use test_case::test_case;
386
387 fn fixed_now() -> zx::MonotonicInstant {
388 zx::MonotonicInstant::ZERO + zx::MonotonicDuration::from_nanos(42)
389 }
390
391 #[fasync::run_singlethreaded(test)]
392 async fn circular_buffer_no_overflow() {
393 let mut circular_buffer = CircularBuffer::new(MAX_RECENT_EVENT_LOG_SIZE);
394 assert_eq!(circular_buffer._size, MAX_RECENT_EVENT_LOG_SIZE);
395
396 let first_event_time = zx::MonotonicInstant::get();
397 circular_buffer.push(create_fake_input_event(first_event_time));
398 let second_event_time = zx::MonotonicInstant::get();
399 circular_buffer.push(create_fake_input_event(second_event_time));
400
401 for _i in 2..MAX_RECENT_EVENT_LOG_SIZE {
403 let curr_event_time = zx::MonotonicInstant::get();
404 circular_buffer.push(create_fake_input_event(curr_event_time));
405 match circular_buffer._events.back() {
406 Some(event) => assert_eq!(event.event_time, curr_event_time),
407 None => assert!(false),
408 }
409 }
410
411 match circular_buffer._events.front() {
413 Some(event) => assert_eq!(event.event_time, first_event_time),
414 None => assert!(false),
415 }
416
417 let last_event_time = zx::MonotonicInstant::get();
419 circular_buffer.push(create_fake_input_event(last_event_time));
420 match circular_buffer._events.front() {
421 Some(event) => assert_eq!(event.event_time, second_event_time),
422 None => assert!(false),
423 }
424 match circular_buffer._events.back() {
425 Some(event) => assert_eq!(event.event_time, last_event_time),
426 None => assert!(false),
427 }
428 }
429
430 #[fasync::run_singlethreaded(test)]
431 async fn recent_events_log_records_inspect() {
432 let inspector = fuchsia_inspect::Inspector::default();
433
434 let recent_events_log =
435 Arc::new(Mutex::new(CircularBuffer::new(MAX_RECENT_EVENT_LOG_SIZE)));
436 record_lazy_recent_events(inspector.root(), Arc::clone(&recent_events_log));
437
438 let keyboard_descriptor = InputDeviceDescriptor::Keyboard(KeyboardDeviceDescriptor {
439 keys: vec![fidl_fuchsia_input::Key::A, fidl_fuchsia_input::Key::B],
440 ..Default::default()
441 });
442 let mouse_descriptor = InputDeviceDescriptor::Mouse(MouseDeviceDescriptor {
443 device_id: 1u32,
444 absolute_x_range: None,
445 absolute_y_range: None,
446 wheel_v_range: None,
447 wheel_h_range: None,
448 buttons: None,
449 });
450 let touch_screen_descriptor =
451 InputDeviceDescriptor::TouchScreen(TouchScreenDeviceDescriptor {
452 device_id: 1,
453 contacts: vec![],
454 });
455 let touchpad_descriptor = InputDeviceDescriptor::Touchpad(TouchpadDeviceDescriptor {
456 device_id: 1,
457 contacts: vec![],
458 });
459
460 let pressed_buttons = SortedVecSet::from(vec![1u8, 21u8, 15u8]);
461 let mut pressed_buttons_vec: Vec<u64> = vec![];
462 pressed_buttons.iter().for_each(|button| {
463 pressed_buttons_vec.push(*button as u64);
464 });
465
466 let (light_sensor_proxy, _) = next_client_old_stream::<
467 InputDeviceMarker,
468 fidl_next_fuchsia_input_report::InputDevice,
469 >();
470
471 let recent_events = vec![
472 create_keyboard_event(
473 fidl_fuchsia_input::Key::A,
474 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
475 None,
476 &keyboard_descriptor,
477 None,
478 ),
479 create_consumer_controls_event(
480 vec![
481 fidl_fuchsia_input_report::ConsumerControlButton::VolumeUp,
482 fidl_fuchsia_input_report::ConsumerControlButton::VolumeUp,
483 fidl_fuchsia_input_report::ConsumerControlButton::Pause,
484 fidl_fuchsia_input_report::ConsumerControlButton::VolumeDown,
485 fidl_fuchsia_input_report::ConsumerControlButton::MicMute,
486 fidl_fuchsia_input_report::ConsumerControlButton::CameraDisable,
487 fidl_fuchsia_input_report::ConsumerControlButton::FactoryReset,
488 fidl_fuchsia_input_report::ConsumerControlButton::Reboot,
489 ],
490 zx::MonotonicInstant::get(),
491 &consumer_controls_device_descriptor(),
492 ),
493 create_mouse_event(
494 MouseLocation::Absolute(Position { x: 7.0f32, y: 15.0f32 }),
495 Some(WheelDelta { ticks: 5i64, physical_pixel: Some(8.0f32) }),
496 Some(WheelDelta { ticks: 10i64, physical_pixel: Some(8.0f32) }),
497 Some(PrecisionScroll::Yes),
498 MousePhase::Move,
499 SortedVecSet::from(vec![1u8]),
500 pressed_buttons.clone(),
501 zx::MonotonicInstant::get(),
502 &mouse_descriptor,
503 ),
504 create_touch_screen_event(
505 SortedVecMap::from_iter(vec![
506 (
507 fidl_fuchsia_ui_input::PointerEventPhase::Add,
508 vec![create_touch_contact(1u32, Position { x: 10.0, y: 30.0 })],
509 ),
510 (
511 fidl_fuchsia_ui_input::PointerEventPhase::Move,
512 vec![create_touch_contact(1u32, Position { x: 11.0, y: 31.0 })],
513 ),
514 ]),
515 zx::MonotonicInstant::get(),
516 &touch_screen_descriptor,
517 ),
518 create_touchpad_event(
519 vec![
520 create_touch_contact(1u32, Position { x: 0.0, y: 0.0 }),
521 create_touch_contact(2u32, Position { x: 10.0, y: 10.0 }),
522 ],
523 SortedVecSet::new(),
524 zx::MonotonicInstant::get(),
525 &touchpad_descriptor,
526 ),
527 InputEvent {
528 device_event: InputDeviceEvent::LightSensor(LightSensorEvent {
529 device_proxy: light_sensor_proxy,
530 rgbc: Rgbc { red: 1, green: 2, blue: 3, clear: 14747 },
531 }),
532 device_descriptor: InputDeviceDescriptor::LightSensor(
533 LightSensorDeviceDescriptor {
534 vendor_id: 1,
535 product_id: 2,
536 device_id: 3,
537 sensor_layout: Rgbc { red: 1, green: 2, blue: 3, clear: 4 },
538 },
539 ),
540 event_time: zx::MonotonicInstant::get(),
541 handled: input_device::Handled::No,
542 trace_id: None,
543 },
544 create_keyboard_event(
545 fidl_fuchsia_input::Key::B,
546 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
547 None,
548 &keyboard_descriptor,
549 None,
550 ),
551 ];
552
553 for event in recent_events.into_iter() {
554 recent_events_log.lock().await.push(event);
555 }
556
557 assert_data_tree!(inspector, root: {
558 recent_events_log: {
559 "000_keyboard_event": {
560 event_time: AnyProperty,
561 },
562 "001_consumer_controls_event": {
563 event_time: AnyProperty,
564 pressed_buttons: vec!["volume_up", "volume_up", "pause", "volume_down", "mic_mute", "camera_disable", "factory_reset", "reboot"],
565 },
566 "002_mouse_event": {
567 event_time: AnyProperty,
568 location_absolute: { x: 7.0f64, y: 15.0f64},
569 wheel_delta_v: {
570 ticks: 5i64,
571 physical_pixel: 8.0f64,
572 },
573 wheel_delta_h: {
574 ticks: 10i64,
575 physical_pixel: 8.0f64,
576 },
577 is_precision_scroll: "yes",
578 phase: "move",
579 affected_buttons: vec![1u64],
580 pressed_buttons: pressed_buttons_vec.clone(),
581 },
582 "003_touch_screen_event": {
583 event_time: AnyProperty,
584 injector_contacts: {
585 add: {
586 "1": {
587 position_x_mm: 10.0f64,
588 position_y_mm: 30.0f64,
589 },
590 },
591 change: {
592 "1": {
593 position_x_mm: 11.0f64,
594 position_y_mm: 31.0f64,
595 },
596 },
597 remove: {},
598 },
599 pressed_buttons: Vec::<String>::new(),
600 },
601 "004_touchpad_event": {
602 event_time: AnyProperty,
603 pressed_buttons: Vec::<u64>::new(),
604 injector_contacts: {
605 "1": {
606 position_x_mm: 0.0f64,
607 position_y_mm: 0.0f64,
608 },
609 "2": {
610 position_x_mm: 10.0f64,
611 position_y_mm: 10.0f64,
612 },
613 },
614 },
615 "005_light_sensor_event": {
616 event_time: AnyProperty,
617 red: 1u64,
618 green: 2u64,
619 blue: 3u64,
620 clear: 14747u64,
621 },
622 "006_keyboard_event": {
623 event_time: AnyProperty,
624 },
625 }
626 });
627 }
628
629 #[fasync::run_singlethreaded(test)]
630 async fn verify_inspect_no_recent_events_log() {
631 let inspector = inspect::Inspector::default();
632 let root = inspector.root();
633 let test_node = root.create_child("test_node");
634 let supported_input_devices: SortedVecSet<&InputDeviceType> = SortedVecSet::from([
635 &input_device::InputDeviceType::Keyboard,
636 &input_device::InputDeviceType::ConsumerControls,
637 &input_device::InputDeviceType::LightSensor,
638 &input_device::InputDeviceType::Mouse,
639 &input_device::InputDeviceType::Touch,
640 ]);
641
642 let handler = super::InspectHandler::new_internal(
643 test_node,
644 fixed_now,
645 &supported_input_devices,
646 false,
647 );
648 assert_data_tree!(inspector, root: {
649 test_node: contains {
650 events_count: 0u64,
651 last_seen_timestamp_ns: 0i64,
652 last_generated_timestamp_ns: 0i64,
653 consumer_controls: {
654 events_count: 0u64,
655 events_with_wake_lease_count: 0u64,
656 handled_events_count: 0u64,
657 last_generated_timestamp_ns: 0i64,
658 last_seen_timestamp_ns: 0i64,
659 },
660 fake: {
661 events_count: 0u64,
662 events_with_wake_lease_count: 0u64,
663 handled_events_count: 0u64,
664 last_generated_timestamp_ns: 0i64,
665 last_seen_timestamp_ns: 0i64,
666 },
667 keyboard: {
668 events_count: 0u64,
669 events_with_wake_lease_count: 0u64,
670 handled_events_count: 0u64,
671 last_generated_timestamp_ns: 0i64,
672 last_seen_timestamp_ns: 0i64,
673 },
674 light_sensor: {
675 events_count: 0u64,
676 events_with_wake_lease_count: 0u64,
677 handled_events_count: 0u64,
678 last_generated_timestamp_ns: 0i64,
679 last_seen_timestamp_ns: 0i64,
680 },
681 mouse: {
682 events_count: 0u64,
683 events_with_wake_lease_count: 0u64,
684 handled_events_count: 0u64,
685 last_generated_timestamp_ns: 0i64,
686 last_seen_timestamp_ns: 0i64,
687 },
688 touch_screen: {
689 events_count: 0u64,
690 events_with_wake_lease_count: 0u64,
691 handled_events_count: 0u64,
692 last_generated_timestamp_ns: 0i64,
693 last_seen_timestamp_ns: 0i64,
694 },
695 touchpad: {
696 events_count: 0u64,
697 events_with_wake_lease_count: 0u64,
698 handled_events_count: 0u64,
699 last_generated_timestamp_ns: 0i64,
700 last_seen_timestamp_ns: 0i64,
701 },
702 }
703 });
704
705 handler
706 .clone()
707 .handle_input_event(create_fake_input_event(zx::MonotonicInstant::from_nanos(43i64)))
708 .await;
709 assert_data_tree!(inspector, root: {
710 test_node: contains {
711 events_count: 1u64,
712 last_seen_timestamp_ns: 42i64,
713 last_generated_timestamp_ns: 43i64,
714 consumer_controls: {
715 events_count: 0u64,
716 events_with_wake_lease_count: 0u64,
717 handled_events_count: 0u64,
718 last_generated_timestamp_ns: 0i64,
719 last_seen_timestamp_ns: 0i64,
720 },
721 fake: {
722 events_count: 1u64,
723 events_with_wake_lease_count: 0u64, handled_events_count: 0u64,
725 last_generated_timestamp_ns: 43i64,
726 last_seen_timestamp_ns: 42i64,
727 },
728 keyboard: {
729 events_count: 0u64,
730 events_with_wake_lease_count: 0u64,
731 handled_events_count: 0u64,
732 last_generated_timestamp_ns: 0i64,
733 last_seen_timestamp_ns: 0i64,
734 },
735 light_sensor: {
736 events_count: 0u64,
737 events_with_wake_lease_count: 0u64,
738 handled_events_count: 0u64,
739 last_generated_timestamp_ns: 0i64,
740 last_seen_timestamp_ns: 0i64,
741 },
742 mouse: {
743 events_count: 0u64,
744 events_with_wake_lease_count: 0u64,
745 handled_events_count: 0u64,
746 last_generated_timestamp_ns: 0i64,
747 last_seen_timestamp_ns: 0i64,
748 },
749 touch_screen: {
750 events_count: 0u64,
751 events_with_wake_lease_count: 0u64,
752 handled_events_count: 0u64,
753 last_generated_timestamp_ns: 0i64,
754 last_seen_timestamp_ns: 0i64,
755 },
756 touchpad: {
757 events_count: 0u64,
758 events_with_wake_lease_count: 0u64,
759 handled_events_count: 0u64,
760 last_generated_timestamp_ns: 0i64,
761 last_seen_timestamp_ns: 0i64,
762 },
763 }
764 });
765
766 handler
767 .clone()
768 .handle_input_event(create_fake_input_event(zx::MonotonicInstant::from_nanos(44i64)))
769 .await;
770 assert_data_tree!(inspector, root: {
771 test_node: contains {
772 events_count: 2u64,
773 last_seen_timestamp_ns: 42i64,
774 last_generated_timestamp_ns: 44i64,
775 consumer_controls: {
776 events_count: 0u64,
777 events_with_wake_lease_count: 0u64,
778 handled_events_count: 0u64,
779 last_generated_timestamp_ns: 0i64,
780 last_seen_timestamp_ns: 0i64,
781 },
782 fake: {
783 events_count: 2u64,
784 events_with_wake_lease_count: 0u64,
785 handled_events_count: 0u64,
786 last_generated_timestamp_ns: 44i64,
787 last_seen_timestamp_ns: 42i64,
788 },
789 keyboard: {
790 events_count: 0u64,
791 events_with_wake_lease_count: 0u64,
792 handled_events_count: 0u64,
793 last_generated_timestamp_ns: 0i64,
794 last_seen_timestamp_ns: 0i64,
795 },
796 light_sensor: {
797 events_count: 0u64,
798 events_with_wake_lease_count: 0u64,
799 handled_events_count: 0u64,
800 last_generated_timestamp_ns: 0i64,
801 last_seen_timestamp_ns: 0i64,
802 },
803 mouse: {
804 events_count: 0u64,
805 events_with_wake_lease_count: 0u64,
806 handled_events_count: 0u64,
807 last_generated_timestamp_ns: 0i64,
808 last_seen_timestamp_ns: 0i64,
809 },
810 touch_screen: {
811 events_count: 0u64,
812 events_with_wake_lease_count: 0u64,
813 handled_events_count: 0u64,
814 last_generated_timestamp_ns: 0i64,
815 last_seen_timestamp_ns: 0i64,
816 },
817 touchpad: {
818 events_count: 0u64,
819 events_with_wake_lease_count: 0u64,
820 handled_events_count: 0u64,
821 last_generated_timestamp_ns: 0i64,
822 last_seen_timestamp_ns: 0i64,
823 },
824 }
825 });
826
827 handler
828 .clone()
829 .handle_input_event(create_fake_handled_input_event(zx::MonotonicInstant::from_nanos(
830 44,
831 )))
832 .await;
833 assert_data_tree!(inspector, root: {
834 test_node: contains {
835 events_count: 3u64,
836 last_seen_timestamp_ns: 42i64,
837 last_generated_timestamp_ns: 44i64,
838 consumer_controls: {
839 events_count: 0u64,
840 events_with_wake_lease_count: 0u64,
841 handled_events_count: 0u64,
842 last_generated_timestamp_ns: 0i64,
843 last_seen_timestamp_ns: 0i64,
844 },
845 fake: {
846 events_count: 3u64,
847 events_with_wake_lease_count: 0u64,
848 handled_events_count: 1u64,
849 last_generated_timestamp_ns: 44i64,
850 last_seen_timestamp_ns: 42i64,
851 },
852 keyboard: {
853 events_count: 0u64,
854 events_with_wake_lease_count: 0u64,
855 handled_events_count: 0u64,
856 last_generated_timestamp_ns: 0i64,
857 last_seen_timestamp_ns: 0i64,
858 },
859 light_sensor: {
860 events_count: 0u64,
861 events_with_wake_lease_count: 0u64,
862 handled_events_count: 0u64,
863 last_generated_timestamp_ns: 0i64,
864 last_seen_timestamp_ns: 0i64,
865 },
866 mouse: {
867 events_count: 0u64,
868 events_with_wake_lease_count: 0u64,
869 handled_events_count: 0u64,
870 last_generated_timestamp_ns: 0i64,
871 last_seen_timestamp_ns: 0i64,
872 },
873 touch_screen: {
874 events_count: 0u64,
875 events_with_wake_lease_count: 0u64,
876 handled_events_count: 0u64,
877 last_generated_timestamp_ns: 0i64,
878 last_seen_timestamp_ns: 0i64,
879 },
880 touchpad: {
881 events_count: 0u64,
882 events_with_wake_lease_count: 0u64,
883 handled_events_count: 0u64,
884 last_generated_timestamp_ns: 0i64,
885 last_seen_timestamp_ns: 0i64,
886 },
887 }
888 });
889 }
890
891 #[fasync::run_singlethreaded(test)]
892 async fn verify_inspect_with_recent_events_log() {
893 let inspector = inspect::Inspector::default();
894 let root = inspector.root();
895 let test_node = root.create_child("test_node");
896 let supported_input_devices: SortedVecSet<&InputDeviceType> = SortedVecSet::from([
897 &input_device::InputDeviceType::Keyboard,
898 &input_device::InputDeviceType::ConsumerControls,
899 &input_device::InputDeviceType::LightSensor,
900 &input_device::InputDeviceType::Mouse,
901 &input_device::InputDeviceType::Touch,
902 ]);
903
904 let handler = super::InspectHandler::new_internal(
905 test_node,
906 fixed_now,
907 &supported_input_devices,
908 true,
909 );
910 assert_data_tree!(inspector, root: {
911 test_node: contains {
912 events_count: 0u64,
913 last_seen_timestamp_ns: 0i64,
914 last_generated_timestamp_ns: 0i64,
915 recent_events_log: {},
916 consumer_controls: {
917 events_count: 0u64,
918 events_with_wake_lease_count: 0u64,
919 handled_events_count: 0u64,
920 last_generated_timestamp_ns: 0i64,
921 last_seen_timestamp_ns: 0i64,
922 },
923 fake: {
924 events_count: 0u64,
925 events_with_wake_lease_count: 0u64,
926 handled_events_count: 0u64,
927 last_generated_timestamp_ns: 0i64,
928 last_seen_timestamp_ns: 0i64,
929 },
930 keyboard: {
931 events_count: 0u64,
932 events_with_wake_lease_count: 0u64,
933 handled_events_count: 0u64,
934 last_generated_timestamp_ns: 0i64,
935 last_seen_timestamp_ns: 0i64,
936 },
937 light_sensor: {
938 events_count: 0u64,
939 events_with_wake_lease_count: 0u64,
940 handled_events_count: 0u64,
941 last_generated_timestamp_ns: 0i64,
942 last_seen_timestamp_ns: 0i64,
943 },
944 mouse: {
945 events_count: 0u64,
946 events_with_wake_lease_count: 0u64,
947 handled_events_count: 0u64,
948 last_generated_timestamp_ns: 0i64,
949 last_seen_timestamp_ns: 0i64,
950 },
951 touch_screen: {
952 events_count: 0u64,
953 events_with_wake_lease_count: 0u64,
954 handled_events_count: 0u64,
955 last_generated_timestamp_ns: 0i64,
956 last_seen_timestamp_ns: 0i64,
957 },
958 touchpad: {
959 events_count: 0u64,
960 events_with_wake_lease_count: 0u64,
961 handled_events_count: 0u64,
962 last_generated_timestamp_ns: 0i64,
963 last_seen_timestamp_ns: 0i64,
964 },
965 }
966 });
967
968 handler
969 .clone()
970 .handle_input_event(create_fake_input_event(zx::MonotonicInstant::from_nanos(43i64)))
971 .await;
972 assert_data_tree!(inspector, root: {
973 test_node: contains {
974 events_count: 1u64,
975 last_seen_timestamp_ns: 42i64,
976 last_generated_timestamp_ns: 43i64,
977 recent_events_log: {
978 "000_fake_event": {
979 event_time: 43i64,
980 },
981 },
982 consumer_controls: {
983 events_count: 0u64,
984 events_with_wake_lease_count: 0u64,
985 handled_events_count: 0u64,
986 last_generated_timestamp_ns: 0i64,
987 last_seen_timestamp_ns: 0i64,
988 },
989 fake: {
990 events_count: 1u64,
991 events_with_wake_lease_count: 0u64,
992 handled_events_count: 0u64,
993 last_generated_timestamp_ns: 43i64,
994 last_seen_timestamp_ns: 42i64,
995 },
996 keyboard: {
997 events_count: 0u64,
998 events_with_wake_lease_count: 0u64,
999 handled_events_count: 0u64,
1000 last_generated_timestamp_ns: 0i64,
1001 last_seen_timestamp_ns: 0i64,
1002 },
1003 light_sensor: {
1004 events_count: 0u64,
1005 events_with_wake_lease_count: 0u64,
1006 handled_events_count: 0u64,
1007 last_generated_timestamp_ns: 0i64,
1008 last_seen_timestamp_ns: 0i64,
1009 },
1010 mouse: {
1011 events_count: 0u64,
1012 events_with_wake_lease_count: 0u64,
1013 handled_events_count: 0u64,
1014 last_generated_timestamp_ns: 0i64,
1015 last_seen_timestamp_ns: 0i64,
1016 },
1017 touch_screen: {
1018 events_count: 0u64,
1019 events_with_wake_lease_count: 0u64,
1020 handled_events_count: 0u64,
1021 last_generated_timestamp_ns: 0i64,
1022 last_seen_timestamp_ns: 0i64,
1023 },
1024 touchpad: {
1025 events_count: 0u64,
1026 events_with_wake_lease_count: 0u64,
1027 handled_events_count: 0u64,
1028 last_generated_timestamp_ns: 0i64,
1029 last_seen_timestamp_ns: 0i64,
1030 },
1031 }
1032 });
1033
1034 handler
1035 .clone()
1036 .handle_input_event(create_fake_input_event(zx::MonotonicInstant::from_nanos(44i64)))
1037 .await;
1038 assert_data_tree!(inspector, root: {
1039 test_node: contains {
1040 events_count: 2u64,
1041 last_seen_timestamp_ns: 42i64,
1042 last_generated_timestamp_ns: 44i64,
1043 recent_events_log: {
1044 "000_fake_event": {
1045 event_time: 43i64,
1046 },
1047 "001_fake_event": {
1048 event_time: 44i64,
1049 },
1050 },
1051 consumer_controls: {
1052 events_count: 0u64,
1053 events_with_wake_lease_count: 0u64,
1054 handled_events_count: 0u64,
1055 last_generated_timestamp_ns: 0i64,
1056 last_seen_timestamp_ns: 0i64,
1057 },
1058 fake: {
1059 events_count: 2u64,
1060 events_with_wake_lease_count: 0u64,
1061 handled_events_count: 0u64,
1062 last_generated_timestamp_ns: 44i64,
1063 last_seen_timestamp_ns: 42i64,
1064 },
1065 keyboard: {
1066 events_count: 0u64,
1067 events_with_wake_lease_count: 0u64,
1068 handled_events_count: 0u64,
1069 last_generated_timestamp_ns: 0i64,
1070 last_seen_timestamp_ns: 0i64,
1071 },
1072 light_sensor: {
1073 events_count: 0u64,
1074 events_with_wake_lease_count: 0u64,
1075 handled_events_count: 0u64,
1076 last_generated_timestamp_ns: 0i64,
1077 last_seen_timestamp_ns: 0i64,
1078 },
1079 mouse: {
1080 events_count: 0u64,
1081 events_with_wake_lease_count: 0u64,
1082 handled_events_count: 0u64,
1083 last_generated_timestamp_ns: 0i64,
1084 last_seen_timestamp_ns: 0i64,
1085 },
1086 touch_screen: {
1087 events_count: 0u64,
1088 events_with_wake_lease_count: 0u64,
1089 handled_events_count: 0u64,
1090 last_generated_timestamp_ns: 0i64,
1091 last_seen_timestamp_ns: 0i64,
1092 },
1093 touchpad: {
1094 events_count: 0u64,
1095 events_with_wake_lease_count: 0u64,
1096 handled_events_count: 0u64,
1097 last_generated_timestamp_ns: 0i64,
1098 last_seen_timestamp_ns: 0i64,
1099 },
1100 }
1101 });
1102
1103 handler
1104 .clone()
1105 .handle_input_event(create_fake_handled_input_event(zx::MonotonicInstant::from_nanos(
1106 44,
1107 )))
1108 .await;
1109 assert_data_tree!(inspector, root: {
1110 test_node: contains {
1111 events_count: 3u64,
1112 last_seen_timestamp_ns: 42i64,
1113 last_generated_timestamp_ns: 44i64,
1114 recent_events_log: {
1115 "000_fake_event": {
1116 event_time: 43i64,
1117 },
1118 "001_fake_event": {
1119 event_time: 44i64,
1120 },
1121 "002_fake_event": {
1122 event_time: 44i64,
1123 },
1124 },
1125 consumer_controls: {
1126 events_count: 0u64,
1127 events_with_wake_lease_count: 0u64,
1128 handled_events_count: 0u64,
1129 last_generated_timestamp_ns: 0i64,
1130 last_seen_timestamp_ns: 0i64,
1131 },
1132 fake: {
1133 events_count: 3u64,
1134 events_with_wake_lease_count: 0u64,
1135 handled_events_count: 1u64,
1136 last_generated_timestamp_ns: 44i64,
1137 last_seen_timestamp_ns: 42i64,
1138 },
1139 keyboard: {
1140 events_count: 0u64,
1141 events_with_wake_lease_count: 0u64,
1142 handled_events_count: 0u64,
1143 last_generated_timestamp_ns: 0i64,
1144 last_seen_timestamp_ns: 0i64,
1145 },
1146 light_sensor: {
1147 events_count: 0u64,
1148 events_with_wake_lease_count: 0u64,
1149 handled_events_count: 0u64,
1150 last_generated_timestamp_ns: 0i64,
1151 last_seen_timestamp_ns: 0i64,
1152 },
1153 mouse: {
1154 events_count: 0u64,
1155 events_with_wake_lease_count: 0u64,
1156 handled_events_count: 0u64,
1157 last_generated_timestamp_ns: 0i64,
1158 last_seen_timestamp_ns: 0i64,
1159 },
1160 touch_screen: {
1161 events_count: 0u64,
1162 events_with_wake_lease_count: 0u64,
1163 handled_events_count: 0u64,
1164 last_generated_timestamp_ns: 0i64,
1165 last_seen_timestamp_ns: 0i64,
1166 },
1167 touchpad: {
1168 events_count: 0u64,
1169 events_with_wake_lease_count: 0u64,
1170 handled_events_count: 0u64,
1171 last_generated_timestamp_ns: 0i64,
1172 last_seen_timestamp_ns: 0i64,
1173 },
1174 }
1175 });
1176 }
1177
1178 #[test_case([i64::MIN]; "min value")]
1179 #[test_case([-1]; "negative value")]
1180 #[test_case([0]; "zero")]
1181 #[test_case([1]; "positive value")]
1182 #[test_case([i64::MAX]; "max value")]
1183 #[test_case([1_000_000, 10_000_000, 100_000_000, 1000_000_000]; "multiple values")]
1184 #[fuchsia::test(allow_stalls = false)]
1185 async fn updates_latency_histogram(
1186 latencies_nsec: impl IntoIterator<Item = i64> + Clone + 'static,
1187 ) {
1188 let inspector = inspect::Inspector::default();
1189 let root = inspector.root();
1190 let test_node = root.create_child("test_node");
1191
1192 let mut seen_timestamps =
1193 latencies_nsec.clone().into_iter().map(zx::MonotonicInstant::from_nanos);
1194 let now = move || {
1195 seen_timestamps.next().expect("internal error: test has more events than latencies")
1196 };
1197 let handler = super::InspectHandler::new_internal(
1198 test_node,
1199 now,
1200 &SortedVecSet::new(),
1201 false,
1202 );
1203 for _latency in latencies_nsec.clone() {
1204 handler
1205 .clone()
1206 .handle_input_event(create_fake_input_event(zx::MonotonicInstant::ZERO))
1207 .await;
1208 }
1209
1210 let mut histogram_assertion = diagnostics_assertions::HistogramAssertion::exponential(
1211 super::LATENCY_HISTOGRAM_PROPERTIES,
1212 );
1213 histogram_assertion
1214 .insert_values(latencies_nsec.into_iter().map(|nsec| nsec / 1000 / 1000));
1215 assert_data_tree!(inspector, root: {
1216 test_node: contains {
1217 pipeline_latency_ms: histogram_assertion
1218 }
1219 })
1220 }
1221}