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