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, RawWheelDelta,
372 WheelDelta,
373 };
374 use crate::testing_utilities::{
375 consumer_controls_device_descriptor, create_consumer_controls_event,
376 create_fake_handled_input_event, create_fake_input_event, create_keyboard_event,
377 create_mouse_event, create_touch_contact, create_touch_screen_event, create_touchpad_event,
378 next_client_old_stream,
379 };
380 use crate::touch_binding::{TouchScreenDeviceDescriptor, TouchpadDeviceDescriptor};
381 use crate::utils::Position;
382 use diagnostics_assertions::{AnyProperty, assert_data_tree};
383 use fidl_fuchsia_input_report::InputDeviceMarker;
384 use fuchsia_async as fasync;
385 use sorted_vec_map::SortedVecMap;
386 use test_case::test_case;
387
388 fn fixed_now() -> zx::MonotonicInstant {
389 zx::MonotonicInstant::ZERO + zx::MonotonicDuration::from_nanos(42)
390 }
391
392 #[fasync::run_singlethreaded(test)]
393 async fn circular_buffer_no_overflow() {
394 let mut circular_buffer = CircularBuffer::new(MAX_RECENT_EVENT_LOG_SIZE);
395 assert_eq!(circular_buffer._size, MAX_RECENT_EVENT_LOG_SIZE);
396
397 let first_event_time = zx::MonotonicInstant::get();
398 circular_buffer.push(create_fake_input_event(first_event_time));
399 let second_event_time = zx::MonotonicInstant::get();
400 circular_buffer.push(create_fake_input_event(second_event_time));
401
402 for _i in 2..MAX_RECENT_EVENT_LOG_SIZE {
404 let curr_event_time = zx::MonotonicInstant::get();
405 circular_buffer.push(create_fake_input_event(curr_event_time));
406 match circular_buffer._events.back() {
407 Some(event) => assert_eq!(event.event_time, curr_event_time),
408 None => assert!(false),
409 }
410 }
411
412 match circular_buffer._events.front() {
414 Some(event) => assert_eq!(event.event_time, first_event_time),
415 None => assert!(false),
416 }
417
418 let last_event_time = zx::MonotonicInstant::get();
420 circular_buffer.push(create_fake_input_event(last_event_time));
421 match circular_buffer._events.front() {
422 Some(event) => assert_eq!(event.event_time, second_event_time),
423 None => assert!(false),
424 }
425 match circular_buffer._events.back() {
426 Some(event) => assert_eq!(event.event_time, last_event_time),
427 None => assert!(false),
428 }
429 }
430
431 #[fasync::run_singlethreaded(test)]
432 async fn recent_events_log_records_inspect() {
433 let inspector = fuchsia_inspect::Inspector::default();
434
435 let recent_events_log =
436 Arc::new(Mutex::new(CircularBuffer::new(MAX_RECENT_EVENT_LOG_SIZE)));
437 record_lazy_recent_events(inspector.root(), Arc::clone(&recent_events_log));
438
439 let keyboard_descriptor = InputDeviceDescriptor::Keyboard(KeyboardDeviceDescriptor {
440 keys: vec![fidl_fuchsia_input::Key::A, fidl_fuchsia_input::Key::B],
441 ..Default::default()
442 });
443 let mouse_descriptor = InputDeviceDescriptor::Mouse(MouseDeviceDescriptor {
444 device_id: 1u32,
445 absolute_x_range: None,
446 absolute_y_range: None,
447 wheel_v_range: None,
448 wheel_h_range: None,
449 buttons: None,
450 counts_per_mm: 12u32,
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_report::ConsumerControlButton::VolumeUp,
484 fidl_fuchsia_input_report::ConsumerControlButton::VolumeUp,
485 fidl_fuchsia_input_report::ConsumerControlButton::Pause,
486 fidl_fuchsia_input_report::ConsumerControlButton::VolumeDown,
487 fidl_fuchsia_input_report::ConsumerControlButton::MicMute,
488 fidl_fuchsia_input_report::ConsumerControlButton::CameraDisable,
489 fidl_fuchsia_input_report::ConsumerControlButton::FactoryReset,
490 fidl_fuchsia_input_report::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 {
498 raw_data: RawWheelDelta::Ticks(5i64),
499 physical_pixel: Some(8.0f32),
500 }),
501 Some(WheelDelta {
502 raw_data: RawWheelDelta::Millimeters(10.0f32),
503 physical_pixel: Some(8.0f32),
504 }),
505 Some(PrecisionScroll::Yes),
506 MousePhase::Move,
507 SortedVecSet::from(vec![1u8]),
508 pressed_buttons.clone(),
509 zx::MonotonicInstant::get(),
510 &mouse_descriptor,
511 ),
512 create_touch_screen_event(
513 SortedVecMap::from_iter(vec![
514 (
515 fidl_fuchsia_ui_input::PointerEventPhase::Add,
516 vec![create_touch_contact(1u32, Position { x: 10.0, y: 30.0 })],
517 ),
518 (
519 fidl_fuchsia_ui_input::PointerEventPhase::Move,
520 vec![create_touch_contact(1u32, Position { x: 11.0, y: 31.0 })],
521 ),
522 ]),
523 zx::MonotonicInstant::get(),
524 &touch_screen_descriptor,
525 ),
526 create_touchpad_event(
527 vec![
528 create_touch_contact(1u32, Position { x: 0.0, y: 0.0 }),
529 create_touch_contact(2u32, Position { x: 10.0, y: 10.0 }),
530 ],
531 SortedVecSet::new(),
532 zx::MonotonicInstant::get(),
533 &touchpad_descriptor,
534 ),
535 InputEvent {
536 device_event: InputDeviceEvent::LightSensor(LightSensorEvent {
537 device_proxy: light_sensor_proxy,
538 rgbc: Rgbc { red: 1, green: 2, blue: 3, clear: 14747 },
539 }),
540 device_descriptor: InputDeviceDescriptor::LightSensor(
541 LightSensorDeviceDescriptor {
542 vendor_id: 1,
543 product_id: 2,
544 device_id: 3,
545 sensor_layout: Rgbc { red: 1, green: 2, blue: 3, clear: 4 },
546 },
547 ),
548 event_time: zx::MonotonicInstant::get(),
549 handled: input_device::Handled::No,
550 trace_id: None,
551 },
552 create_keyboard_event(
553 fidl_fuchsia_input::Key::B,
554 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
555 None,
556 &keyboard_descriptor,
557 None,
558 ),
559 ];
560
561 for event in recent_events.into_iter() {
562 recent_events_log.lock().await.push(event);
563 }
564
565 assert_data_tree!(inspector, root: {
566 recent_events_log: {
567 "000_keyboard_event": {
568 event_time: AnyProperty,
569 },
570 "001_consumer_controls_event": {
571 event_time: AnyProperty,
572 pressed_buttons: vec!["volume_up", "volume_up", "pause", "volume_down", "mic_mute", "camera_disable", "factory_reset", "reboot"],
573 },
574 "002_mouse_event": {
575 event_time: AnyProperty,
576 location_absolute: { x: 7.0f64, y: 15.0f64},
577 wheel_delta_v: {
578 ticks: 5i64,
579 physical_pixel: 8.0f64,
580 },
581 wheel_delta_h: {
582 millimeters: 10.0f64,
583 physical_pixel: 8.0f64,
584 },
585 is_precision_scroll: "yes",
586 phase: "move",
587 affected_buttons: vec![1u64],
588 pressed_buttons: pressed_buttons_vec.clone(),
589 },
590 "003_touch_screen_event": {
591 event_time: AnyProperty,
592 injector_contacts: {
593 add: {
594 "1": {
595 position_x_mm: 10.0f64,
596 position_y_mm: 30.0f64,
597 },
598 },
599 change: {
600 "1": {
601 position_x_mm: 11.0f64,
602 position_y_mm: 31.0f64,
603 },
604 },
605 remove: {},
606 },
607 pressed_buttons: Vec::<String>::new(),
608 },
609 "004_touchpad_event": {
610 event_time: AnyProperty,
611 pressed_buttons: Vec::<u64>::new(),
612 injector_contacts: {
613 "1": {
614 position_x_mm: 0.0f64,
615 position_y_mm: 0.0f64,
616 },
617 "2": {
618 position_x_mm: 10.0f64,
619 position_y_mm: 10.0f64,
620 },
621 },
622 },
623 "005_light_sensor_event": {
624 event_time: AnyProperty,
625 red: 1u64,
626 green: 2u64,
627 blue: 3u64,
628 clear: 14747u64,
629 },
630 "006_keyboard_event": {
631 event_time: AnyProperty,
632 },
633 }
634 });
635 }
636
637 #[fasync::run_singlethreaded(test)]
638 async fn verify_inspect_no_recent_events_log() {
639 let inspector = inspect::Inspector::default();
640 let root = inspector.root();
641 let test_node = root.create_child("test_node");
642 let supported_input_devices: SortedVecSet<&InputDeviceType> = SortedVecSet::from([
643 &input_device::InputDeviceType::Keyboard,
644 &input_device::InputDeviceType::ConsumerControls,
645 &input_device::InputDeviceType::LightSensor,
646 &input_device::InputDeviceType::Mouse,
647 &input_device::InputDeviceType::Touch,
648 ]);
649
650 let handler = super::InspectHandler::new_internal(
651 test_node,
652 fixed_now,
653 &supported_input_devices,
654 false,
655 );
656 assert_data_tree!(inspector, root: {
657 test_node: contains {
658 events_count: 0u64,
659 last_seen_timestamp_ns: 0i64,
660 last_generated_timestamp_ns: 0i64,
661 consumer_controls: {
662 events_count: 0u64,
663 events_with_wake_lease_count: 0u64,
664 handled_events_count: 0u64,
665 last_generated_timestamp_ns: 0i64,
666 last_seen_timestamp_ns: 0i64,
667 },
668 fake: {
669 events_count: 0u64,
670 events_with_wake_lease_count: 0u64,
671 handled_events_count: 0u64,
672 last_generated_timestamp_ns: 0i64,
673 last_seen_timestamp_ns: 0i64,
674 },
675 keyboard: {
676 events_count: 0u64,
677 events_with_wake_lease_count: 0u64,
678 handled_events_count: 0u64,
679 last_generated_timestamp_ns: 0i64,
680 last_seen_timestamp_ns: 0i64,
681 },
682 light_sensor: {
683 events_count: 0u64,
684 events_with_wake_lease_count: 0u64,
685 handled_events_count: 0u64,
686 last_generated_timestamp_ns: 0i64,
687 last_seen_timestamp_ns: 0i64,
688 },
689 mouse: {
690 events_count: 0u64,
691 events_with_wake_lease_count: 0u64,
692 handled_events_count: 0u64,
693 last_generated_timestamp_ns: 0i64,
694 last_seen_timestamp_ns: 0i64,
695 },
696 touch_screen: {
697 events_count: 0u64,
698 events_with_wake_lease_count: 0u64,
699 handled_events_count: 0u64,
700 last_generated_timestamp_ns: 0i64,
701 last_seen_timestamp_ns: 0i64,
702 },
703 touchpad: {
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 }
711 });
712
713 handler
714 .clone()
715 .handle_input_event(create_fake_input_event(zx::MonotonicInstant::from_nanos(43i64)))
716 .await;
717 assert_data_tree!(inspector, root: {
718 test_node: contains {
719 events_count: 1u64,
720 last_seen_timestamp_ns: 42i64,
721 last_generated_timestamp_ns: 43i64,
722 consumer_controls: {
723 events_count: 0u64,
724 events_with_wake_lease_count: 0u64,
725 handled_events_count: 0u64,
726 last_generated_timestamp_ns: 0i64,
727 last_seen_timestamp_ns: 0i64,
728 },
729 fake: {
730 events_count: 1u64,
731 events_with_wake_lease_count: 0u64, handled_events_count: 0u64,
733 last_generated_timestamp_ns: 43i64,
734 last_seen_timestamp_ns: 42i64,
735 },
736 keyboard: {
737 events_count: 0u64,
738 events_with_wake_lease_count: 0u64,
739 handled_events_count: 0u64,
740 last_generated_timestamp_ns: 0i64,
741 last_seen_timestamp_ns: 0i64,
742 },
743 light_sensor: {
744 events_count: 0u64,
745 events_with_wake_lease_count: 0u64,
746 handled_events_count: 0u64,
747 last_generated_timestamp_ns: 0i64,
748 last_seen_timestamp_ns: 0i64,
749 },
750 mouse: {
751 events_count: 0u64,
752 events_with_wake_lease_count: 0u64,
753 handled_events_count: 0u64,
754 last_generated_timestamp_ns: 0i64,
755 last_seen_timestamp_ns: 0i64,
756 },
757 touch_screen: {
758 events_count: 0u64,
759 events_with_wake_lease_count: 0u64,
760 handled_events_count: 0u64,
761 last_generated_timestamp_ns: 0i64,
762 last_seen_timestamp_ns: 0i64,
763 },
764 touchpad: {
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 }
772 });
773
774 handler
775 .clone()
776 .handle_input_event(create_fake_input_event(zx::MonotonicInstant::from_nanos(44i64)))
777 .await;
778 assert_data_tree!(inspector, root: {
779 test_node: contains {
780 events_count: 2u64,
781 last_seen_timestamp_ns: 42i64,
782 last_generated_timestamp_ns: 44i64,
783 consumer_controls: {
784 events_count: 0u64,
785 events_with_wake_lease_count: 0u64,
786 handled_events_count: 0u64,
787 last_generated_timestamp_ns: 0i64,
788 last_seen_timestamp_ns: 0i64,
789 },
790 fake: {
791 events_count: 2u64,
792 events_with_wake_lease_count: 0u64,
793 handled_events_count: 0u64,
794 last_generated_timestamp_ns: 44i64,
795 last_seen_timestamp_ns: 42i64,
796 },
797 keyboard: {
798 events_count: 0u64,
799 events_with_wake_lease_count: 0u64,
800 handled_events_count: 0u64,
801 last_generated_timestamp_ns: 0i64,
802 last_seen_timestamp_ns: 0i64,
803 },
804 light_sensor: {
805 events_count: 0u64,
806 events_with_wake_lease_count: 0u64,
807 handled_events_count: 0u64,
808 last_generated_timestamp_ns: 0i64,
809 last_seen_timestamp_ns: 0i64,
810 },
811 mouse: {
812 events_count: 0u64,
813 events_with_wake_lease_count: 0u64,
814 handled_events_count: 0u64,
815 last_generated_timestamp_ns: 0i64,
816 last_seen_timestamp_ns: 0i64,
817 },
818 touch_screen: {
819 events_count: 0u64,
820 events_with_wake_lease_count: 0u64,
821 handled_events_count: 0u64,
822 last_generated_timestamp_ns: 0i64,
823 last_seen_timestamp_ns: 0i64,
824 },
825 touchpad: {
826 events_count: 0u64,
827 events_with_wake_lease_count: 0u64,
828 handled_events_count: 0u64,
829 last_generated_timestamp_ns: 0i64,
830 last_seen_timestamp_ns: 0i64,
831 },
832 }
833 });
834
835 handler
836 .clone()
837 .handle_input_event(create_fake_handled_input_event(zx::MonotonicInstant::from_nanos(
838 44,
839 )))
840 .await;
841 assert_data_tree!(inspector, root: {
842 test_node: contains {
843 events_count: 3u64,
844 last_seen_timestamp_ns: 42i64,
845 last_generated_timestamp_ns: 44i64,
846 consumer_controls: {
847 events_count: 0u64,
848 events_with_wake_lease_count: 0u64,
849 handled_events_count: 0u64,
850 last_generated_timestamp_ns: 0i64,
851 last_seen_timestamp_ns: 0i64,
852 },
853 fake: {
854 events_count: 3u64,
855 events_with_wake_lease_count: 0u64,
856 handled_events_count: 1u64,
857 last_generated_timestamp_ns: 44i64,
858 last_seen_timestamp_ns: 42i64,
859 },
860 keyboard: {
861 events_count: 0u64,
862 events_with_wake_lease_count: 0u64,
863 handled_events_count: 0u64,
864 last_generated_timestamp_ns: 0i64,
865 last_seen_timestamp_ns: 0i64,
866 },
867 light_sensor: {
868 events_count: 0u64,
869 events_with_wake_lease_count: 0u64,
870 handled_events_count: 0u64,
871 last_generated_timestamp_ns: 0i64,
872 last_seen_timestamp_ns: 0i64,
873 },
874 mouse: {
875 events_count: 0u64,
876 events_with_wake_lease_count: 0u64,
877 handled_events_count: 0u64,
878 last_generated_timestamp_ns: 0i64,
879 last_seen_timestamp_ns: 0i64,
880 },
881 touch_screen: {
882 events_count: 0u64,
883 events_with_wake_lease_count: 0u64,
884 handled_events_count: 0u64,
885 last_generated_timestamp_ns: 0i64,
886 last_seen_timestamp_ns: 0i64,
887 },
888 touchpad: {
889 events_count: 0u64,
890 events_with_wake_lease_count: 0u64,
891 handled_events_count: 0u64,
892 last_generated_timestamp_ns: 0i64,
893 last_seen_timestamp_ns: 0i64,
894 },
895 }
896 });
897 }
898
899 #[fasync::run_singlethreaded(test)]
900 async fn verify_inspect_with_recent_events_log() {
901 let inspector = inspect::Inspector::default();
902 let root = inspector.root();
903 let test_node = root.create_child("test_node");
904 let supported_input_devices: SortedVecSet<&InputDeviceType> = SortedVecSet::from([
905 &input_device::InputDeviceType::Keyboard,
906 &input_device::InputDeviceType::ConsumerControls,
907 &input_device::InputDeviceType::LightSensor,
908 &input_device::InputDeviceType::Mouse,
909 &input_device::InputDeviceType::Touch,
910 ]);
911
912 let handler = super::InspectHandler::new_internal(
913 test_node,
914 fixed_now,
915 &supported_input_devices,
916 true,
917 );
918 assert_data_tree!(inspector, root: {
919 test_node: contains {
920 events_count: 0u64,
921 last_seen_timestamp_ns: 0i64,
922 last_generated_timestamp_ns: 0i64,
923 recent_events_log: {},
924 consumer_controls: {
925 events_count: 0u64,
926 events_with_wake_lease_count: 0u64,
927 handled_events_count: 0u64,
928 last_generated_timestamp_ns: 0i64,
929 last_seen_timestamp_ns: 0i64,
930 },
931 fake: {
932 events_count: 0u64,
933 events_with_wake_lease_count: 0u64,
934 handled_events_count: 0u64,
935 last_generated_timestamp_ns: 0i64,
936 last_seen_timestamp_ns: 0i64,
937 },
938 keyboard: {
939 events_count: 0u64,
940 events_with_wake_lease_count: 0u64,
941 handled_events_count: 0u64,
942 last_generated_timestamp_ns: 0i64,
943 last_seen_timestamp_ns: 0i64,
944 },
945 light_sensor: {
946 events_count: 0u64,
947 events_with_wake_lease_count: 0u64,
948 handled_events_count: 0u64,
949 last_generated_timestamp_ns: 0i64,
950 last_seen_timestamp_ns: 0i64,
951 },
952 mouse: {
953 events_count: 0u64,
954 events_with_wake_lease_count: 0u64,
955 handled_events_count: 0u64,
956 last_generated_timestamp_ns: 0i64,
957 last_seen_timestamp_ns: 0i64,
958 },
959 touch_screen: {
960 events_count: 0u64,
961 events_with_wake_lease_count: 0u64,
962 handled_events_count: 0u64,
963 last_generated_timestamp_ns: 0i64,
964 last_seen_timestamp_ns: 0i64,
965 },
966 touchpad: {
967 events_count: 0u64,
968 events_with_wake_lease_count: 0u64,
969 handled_events_count: 0u64,
970 last_generated_timestamp_ns: 0i64,
971 last_seen_timestamp_ns: 0i64,
972 },
973 }
974 });
975
976 handler
977 .clone()
978 .handle_input_event(create_fake_input_event(zx::MonotonicInstant::from_nanos(43i64)))
979 .await;
980 assert_data_tree!(inspector, root: {
981 test_node: contains {
982 events_count: 1u64,
983 last_seen_timestamp_ns: 42i64,
984 last_generated_timestamp_ns: 43i64,
985 recent_events_log: {
986 "000_fake_event": {
987 event_time: 43i64,
988 },
989 },
990 consumer_controls: {
991 events_count: 0u64,
992 events_with_wake_lease_count: 0u64,
993 handled_events_count: 0u64,
994 last_generated_timestamp_ns: 0i64,
995 last_seen_timestamp_ns: 0i64,
996 },
997 fake: {
998 events_count: 1u64,
999 events_with_wake_lease_count: 0u64,
1000 handled_events_count: 0u64,
1001 last_generated_timestamp_ns: 43i64,
1002 last_seen_timestamp_ns: 42i64,
1003 },
1004 keyboard: {
1005 events_count: 0u64,
1006 events_with_wake_lease_count: 0u64,
1007 handled_events_count: 0u64,
1008 last_generated_timestamp_ns: 0i64,
1009 last_seen_timestamp_ns: 0i64,
1010 },
1011 light_sensor: {
1012 events_count: 0u64,
1013 events_with_wake_lease_count: 0u64,
1014 handled_events_count: 0u64,
1015 last_generated_timestamp_ns: 0i64,
1016 last_seen_timestamp_ns: 0i64,
1017 },
1018 mouse: {
1019 events_count: 0u64,
1020 events_with_wake_lease_count: 0u64,
1021 handled_events_count: 0u64,
1022 last_generated_timestamp_ns: 0i64,
1023 last_seen_timestamp_ns: 0i64,
1024 },
1025 touch_screen: {
1026 events_count: 0u64,
1027 events_with_wake_lease_count: 0u64,
1028 handled_events_count: 0u64,
1029 last_generated_timestamp_ns: 0i64,
1030 last_seen_timestamp_ns: 0i64,
1031 },
1032 touchpad: {
1033 events_count: 0u64,
1034 events_with_wake_lease_count: 0u64,
1035 handled_events_count: 0u64,
1036 last_generated_timestamp_ns: 0i64,
1037 last_seen_timestamp_ns: 0i64,
1038 },
1039 }
1040 });
1041
1042 handler
1043 .clone()
1044 .handle_input_event(create_fake_input_event(zx::MonotonicInstant::from_nanos(44i64)))
1045 .await;
1046 assert_data_tree!(inspector, root: {
1047 test_node: contains {
1048 events_count: 2u64,
1049 last_seen_timestamp_ns: 42i64,
1050 last_generated_timestamp_ns: 44i64,
1051 recent_events_log: {
1052 "000_fake_event": {
1053 event_time: 43i64,
1054 },
1055 "001_fake_event": {
1056 event_time: 44i64,
1057 },
1058 },
1059 consumer_controls: {
1060 events_count: 0u64,
1061 events_with_wake_lease_count: 0u64,
1062 handled_events_count: 0u64,
1063 last_generated_timestamp_ns: 0i64,
1064 last_seen_timestamp_ns: 0i64,
1065 },
1066 fake: {
1067 events_count: 2u64,
1068 events_with_wake_lease_count: 0u64,
1069 handled_events_count: 0u64,
1070 last_generated_timestamp_ns: 44i64,
1071 last_seen_timestamp_ns: 42i64,
1072 },
1073 keyboard: {
1074 events_count: 0u64,
1075 events_with_wake_lease_count: 0u64,
1076 handled_events_count: 0u64,
1077 last_generated_timestamp_ns: 0i64,
1078 last_seen_timestamp_ns: 0i64,
1079 },
1080 light_sensor: {
1081 events_count: 0u64,
1082 events_with_wake_lease_count: 0u64,
1083 handled_events_count: 0u64,
1084 last_generated_timestamp_ns: 0i64,
1085 last_seen_timestamp_ns: 0i64,
1086 },
1087 mouse: {
1088 events_count: 0u64,
1089 events_with_wake_lease_count: 0u64,
1090 handled_events_count: 0u64,
1091 last_generated_timestamp_ns: 0i64,
1092 last_seen_timestamp_ns: 0i64,
1093 },
1094 touch_screen: {
1095 events_count: 0u64,
1096 events_with_wake_lease_count: 0u64,
1097 handled_events_count: 0u64,
1098 last_generated_timestamp_ns: 0i64,
1099 last_seen_timestamp_ns: 0i64,
1100 },
1101 touchpad: {
1102 events_count: 0u64,
1103 events_with_wake_lease_count: 0u64,
1104 handled_events_count: 0u64,
1105 last_generated_timestamp_ns: 0i64,
1106 last_seen_timestamp_ns: 0i64,
1107 },
1108 }
1109 });
1110
1111 handler
1112 .clone()
1113 .handle_input_event(create_fake_handled_input_event(zx::MonotonicInstant::from_nanos(
1114 44,
1115 )))
1116 .await;
1117 assert_data_tree!(inspector, root: {
1118 test_node: contains {
1119 events_count: 3u64,
1120 last_seen_timestamp_ns: 42i64,
1121 last_generated_timestamp_ns: 44i64,
1122 recent_events_log: {
1123 "000_fake_event": {
1124 event_time: 43i64,
1125 },
1126 "001_fake_event": {
1127 event_time: 44i64,
1128 },
1129 "002_fake_event": {
1130 event_time: 44i64,
1131 },
1132 },
1133 consumer_controls: {
1134 events_count: 0u64,
1135 events_with_wake_lease_count: 0u64,
1136 handled_events_count: 0u64,
1137 last_generated_timestamp_ns: 0i64,
1138 last_seen_timestamp_ns: 0i64,
1139 },
1140 fake: {
1141 events_count: 3u64,
1142 events_with_wake_lease_count: 0u64,
1143 handled_events_count: 1u64,
1144 last_generated_timestamp_ns: 44i64,
1145 last_seen_timestamp_ns: 42i64,
1146 },
1147 keyboard: {
1148 events_count: 0u64,
1149 events_with_wake_lease_count: 0u64,
1150 handled_events_count: 0u64,
1151 last_generated_timestamp_ns: 0i64,
1152 last_seen_timestamp_ns: 0i64,
1153 },
1154 light_sensor: {
1155 events_count: 0u64,
1156 events_with_wake_lease_count: 0u64,
1157 handled_events_count: 0u64,
1158 last_generated_timestamp_ns: 0i64,
1159 last_seen_timestamp_ns: 0i64,
1160 },
1161 mouse: {
1162 events_count: 0u64,
1163 events_with_wake_lease_count: 0u64,
1164 handled_events_count: 0u64,
1165 last_generated_timestamp_ns: 0i64,
1166 last_seen_timestamp_ns: 0i64,
1167 },
1168 touch_screen: {
1169 events_count: 0u64,
1170 events_with_wake_lease_count: 0u64,
1171 handled_events_count: 0u64,
1172 last_generated_timestamp_ns: 0i64,
1173 last_seen_timestamp_ns: 0i64,
1174 },
1175 touchpad: {
1176 events_count: 0u64,
1177 events_with_wake_lease_count: 0u64,
1178 handled_events_count: 0u64,
1179 last_generated_timestamp_ns: 0i64,
1180 last_seen_timestamp_ns: 0i64,
1181 },
1182 }
1183 });
1184 }
1185
1186 #[test_case([i64::MIN]; "min value")]
1187 #[test_case([-1]; "negative value")]
1188 #[test_case([0]; "zero")]
1189 #[test_case([1]; "positive value")]
1190 #[test_case([i64::MAX]; "max value")]
1191 #[test_case([1_000_000, 10_000_000, 100_000_000, 1000_000_000]; "multiple values")]
1192 #[fuchsia::test(allow_stalls = false)]
1193 async fn updates_latency_histogram(
1194 latencies_nsec: impl IntoIterator<Item = i64> + Clone + 'static,
1195 ) {
1196 let inspector = inspect::Inspector::default();
1197 let root = inspector.root();
1198 let test_node = root.create_child("test_node");
1199
1200 let mut seen_timestamps =
1201 latencies_nsec.clone().into_iter().map(zx::MonotonicInstant::from_nanos);
1202 let now = move || {
1203 seen_timestamps.next().expect("internal error: test has more events than latencies")
1204 };
1205 let handler = super::InspectHandler::new_internal(
1206 test_node,
1207 now,
1208 &SortedVecSet::new(),
1209 false,
1210 );
1211 for _latency in latencies_nsec.clone() {
1212 handler
1213 .clone()
1214 .handle_input_event(create_fake_input_event(zx::MonotonicInstant::ZERO))
1215 .await;
1216 }
1217
1218 let mut histogram_assertion = diagnostics_assertions::HistogramAssertion::exponential(
1219 super::LATENCY_HISTOGRAM_PROPERTIES,
1220 );
1221 histogram_assertion
1222 .insert_values(latencies_nsec.into_iter().map(|nsec| nsec / 1000 / 1000));
1223 assert_data_tree!(inspector, root: {
1224 test_node: contains {
1225 pipeline_latency_ms: histogram_assertion
1226 }
1227 })
1228 }
1229}