input_pipeline/
display_ownership.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::input_device::{self, InputEvent, UnhandledInputEvent};
6use crate::input_handler::{InputHandlerStatus, UnhandledInputHandler};
7use crate::keyboard_binding::{KeyboardDeviceDescriptor, KeyboardEvent};
8use anyhow::{Context, Result};
9use async_trait::async_trait;
10use fidl_fuchsia_ui_composition_internal as fcomp;
11use fidl_fuchsia_ui_input3::KeyEventType;
12use fuchsia_async::{OnSignals, Task};
13use fuchsia_inspect::health::Reporter;
14use futures::StreamExt;
15use futures::channel::mpsc::{self, UnboundedReceiver, UnboundedSender};
16use keymaps::KeyState;
17use std::cell::RefCell;
18use std::rc::Rc;
19use std::sync::LazyLock;
20use zx::{AsHandleRef, MonotonicDuration, MonotonicInstant, Signals, Status};
21
22// The signal value corresponding to the `DISPLAY_OWNED_SIGNAL`.  Same as zircon's signal
23// USER_0.
24static DISPLAY_OWNED: LazyLock<Signals> = LazyLock::new(|| {
25    Signals::from_bits(fcomp::SIGNAL_DISPLAY_OWNED).expect("static init should not fail")
26});
27
28// The signal value corresponding to the `DISPLAY_NOT_OWNED_SIGNAL`.  Same as zircon's signal
29// USER_1.
30static DISPLAY_UNOWNED: LazyLock<Signals> = LazyLock::new(|| {
31    Signals::from_bits(fcomp::SIGNAL_DISPLAY_NOT_OWNED).expect("static init should not fail")
32});
33
34// Any display-related signal.
35static ANY_DISPLAY_EVENT: LazyLock<Signals> = LazyLock::new(|| *DISPLAY_OWNED | *DISPLAY_UNOWNED);
36
37// Stores the last received ownership signals.
38#[derive(Debug, Clone, PartialEq)]
39struct Ownership {
40    signals: Signals,
41}
42
43impl std::convert::From<Signals> for Ownership {
44    fn from(signals: Signals) -> Self {
45        Ownership { signals }
46    }
47}
48
49impl Ownership {
50    // Returns true if the display is currently indicated to be not owned by
51    // Scenic.
52    fn is_display_ownership_lost(&self) -> bool {
53        self.signals.contains(*DISPLAY_UNOWNED)
54    }
55
56    // Returns the mask of the next signal to watch.
57    //
58    // Since the ownership alternates, so does the next signal to wait on.
59    fn next_signal(&self) -> Signals {
60        match self.is_display_ownership_lost() {
61            true => *DISPLAY_OWNED,
62            false => *DISPLAY_UNOWNED,
63        }
64    }
65
66    /// Waits for the next signal change.
67    ///
68    /// If the display is owned, it will wait for display to become unowned.
69    /// If the display is unowned, it will wait for the display to become owned.
70    async fn wait_ownership_change<'a, T: AsHandleRef>(
71        &self,
72        event: &'a T,
73    ) -> Result<Signals, Status> {
74        OnSignals::new(event, self.next_signal()).await
75    }
76}
77
78/// A handler that turns the input pipeline off or on based on whether
79/// the Scenic owns the display.
80///
81/// This allows us to turn off keyboard processing when the user switches away
82/// from the product (e.g. terminal) into virtual console.
83///
84/// See the `README.md` file in this crate for details.
85///
86/// # Safety and Concurrency
87///
88/// This struct uses `RefCell` to manage internal state. While `DisplayOwnership`
89/// logic is split between multiple tasks (`handle_ownership_change` and
90/// `handle_unhandled_input_event`), safety is maintained because:
91/// 1. The pipeline runs on a single-threaded `LocalExecutor`.
92/// 2. Borrows of `RefCell`s (like `ownership` and `key_state`) are never held
93///    across `await` points.
94///
95/// If asynchronous calls are added to critical sections in the future,
96/// ensure that all borrows are dropped before the `await`.
97pub struct DisplayOwnership {
98    /// The current view of the display ownership.  It is mutated by the
99    /// display ownership task when appropriate signals arrive.
100    ownership: Rc<RefCell<Ownership>>,
101
102    /// The registry of currently pressed keys.
103    key_state: RefCell<KeyState>,
104
105    /// The source of ownership change events for the main loop.
106    display_ownership_change_receiver: RefCell<Option<UnboundedReceiver<Ownership>>>,
107
108    /// A background task that watches for display ownership changes.  We keep
109    /// it alive to ensure that it keeps running.
110    _display_ownership_task: Task<()>,
111
112    /// The inventory of this handler's Inspect status.
113    inspect_status: InputHandlerStatus,
114
115    /// The event processing loop will do an `unbounded_send(())` on this
116    /// channel once at the end of each loop pass, in test configurations only.
117    /// The test fixture uses this channel to execute test fixture in
118    /// lock-step with the event processing loop for test cases where the
119    /// precise event sequencing is relevant.
120    #[cfg(test)]
121    loop_done: RefCell<Option<UnboundedSender<()>>>,
122}
123
124impl DisplayOwnership {
125    /// Creates a new handler that watches `display_ownership_event` for events.
126    ///
127    /// The `display_ownership_event` is assumed to be an [Event] obtained from
128    /// `fuchsia.ui.composition.internal.DisplayOwnership/GetEvent`.  There
129    /// isn't really a way for this code to know here whether this is true or
130    /// not, so implementor beware.
131    pub fn new(
132        display_ownership_event: impl AsHandleRef + 'static,
133        input_handlers_node: &fuchsia_inspect::Node,
134    ) -> Rc<Self> {
135        DisplayOwnership::new_internal(display_ownership_event, None, input_handlers_node)
136    }
137
138    #[cfg(test)]
139    pub fn new_for_test(
140        display_ownership_event: impl AsHandleRef + 'static,
141        loop_done: UnboundedSender<()>,
142    ) -> Rc<Self> {
143        let inspector = fuchsia_inspect::Inspector::default();
144        let fake_handlers_node = inspector.root().create_child("input_handlers_node");
145        DisplayOwnership::new_internal(
146            display_ownership_event,
147            Some(loop_done),
148            &fake_handlers_node,
149        )
150    }
151
152    fn new_internal(
153        display_ownership_event: impl AsHandleRef + 'static,
154        _loop_done: Option<UnboundedSender<()>>,
155        input_handlers_node: &fuchsia_inspect::Node,
156    ) -> Rc<Self> {
157        let initial_state = display_ownership_event
158            // scenic guarantees that ANY_DISPLAY_EVENT is asserted. If it is
159            // not, this will fail with a timeout error.
160            .as_handle_ref()
161            .wait_one(*ANY_DISPLAY_EVENT, MonotonicInstant::INFINITE_PAST)
162            .expect("unable to set the initial display state");
163        log::debug!("setting initial display ownership to: {:?}", &initial_state);
164        let initial_ownership: Ownership = initial_state.into();
165        let ownership = Rc::new(RefCell::new(initial_ownership.clone()));
166
167        let mut ownership_clone = initial_ownership;
168        let (ownership_sender, ownership_receiver) = mpsc::unbounded();
169        let display_ownership_task = Task::local(async move {
170            loop {
171                let signals = ownership_clone.wait_ownership_change(&display_ownership_event).await;
172                match signals {
173                    Err(e) => {
174                        log::warn!("could not read display state: {:?}", e);
175                        break;
176                    }
177                    Ok(signals) => {
178                        log::debug!("setting display ownership to: {:?}", &signals);
179                        ownership_sender.unbounded_send(signals.into()).unwrap();
180                        ownership_clone = signals.into();
181                    }
182                }
183            }
184            log::warn!(
185                "display loop exiting and will no longer monitor display changes - this is not expected"
186            );
187        });
188        log::info!("Display ownership handler installed");
189        let inspect_status = InputHandlerStatus::new(
190            input_handlers_node,
191            "display_ownership",
192            /* generates_events */ false,
193        );
194        Rc::new(Self {
195            ownership,
196            key_state: RefCell::new(KeyState::new()),
197            display_ownership_change_receiver: RefCell::new(Some(ownership_receiver)),
198            _display_ownership_task: display_ownership_task,
199            inspect_status,
200            #[cfg(test)]
201            loop_done: RefCell::new(_loop_done),
202        })
203    }
204
205    /// Returns true if the display is currently *not* owned by Scenic.
206    fn is_display_ownership_lost(&self) -> bool {
207        self.ownership.borrow().is_display_ownership_lost()
208    }
209
210    /// Watches for display ownership changes and sends cancel/sync events.
211    ///
212    /// NOTE: RefCell safety relies on the single-threaded nature of the executor.
213    /// No borrows of `ownership` or `key_state` must be held across the `await`
214    /// below to avoid panics if `handle_unhandled_input_event` runs while this
215    /// task is suspended.
216    pub async fn handle_ownership_change(
217        self: &Rc<Self>,
218        output: UnboundedSender<InputEvent>,
219    ) -> Result<()> {
220        let mut ownership_source = self
221            .display_ownership_change_receiver
222            .borrow_mut()
223            .take()
224            .context("display_ownership_change_receiver already taken")?;
225        while let Some(new_ownership) = ownership_source.next().await {
226            let is_display_ownership_lost = new_ownership.is_display_ownership_lost();
227            // When the ownership is modified, float a set of cancel or sync
228            // events to scoop up stale keyboard state, treating it the same
229            // as loss of focus.
230            let event_type = match is_display_ownership_lost {
231                true => KeyEventType::Cancel,
232                false => KeyEventType::Sync,
233            };
234            let keys = self.key_state.borrow().get_set();
235            let mut event_time = MonotonicInstant::get();
236            for key in keys.into_iter() {
237                let key_event = KeyboardEvent::new(key, event_type);
238                output
239                    .unbounded_send(into_input_event(key_event, event_time))
240                    .context("unable to send display updates")?;
241                event_time = event_time + MonotonicDuration::from_nanos(1);
242            }
243            *(self.ownership.borrow_mut()) = new_ownership;
244            #[cfg(test)]
245            {
246                if let Some(loop_done) = self.loop_done.borrow().as_ref() {
247                    loop_done.unbounded_send(()).unwrap();
248                }
249            }
250        }
251        Ok(())
252    }
253}
254
255#[async_trait(?Send)]
256impl UnhandledInputHandler for DisplayOwnership {
257    async fn handle_unhandled_input_event(
258        self: Rc<Self>,
259        unhandled_input_event: UnhandledInputEvent,
260    ) -> Vec<input_device::InputEvent> {
261        fuchsia_trace::duration!("input", "display_ownership");
262        self.inspect_status.count_received_event(&unhandled_input_event.event_time);
263        match unhandled_input_event.device_event {
264            input_device::InputDeviceEvent::Keyboard(ref e) => {
265                self.key_state.borrow_mut().update(e.get_event_type(), e.get_key());
266            }
267            _ => {}
268        }
269        let is_display_ownership_lost = self.is_display_ownership_lost();
270        if is_display_ownership_lost {
271            self.inspect_status.count_handled_event();
272        }
273
274        #[cfg(test)]
275        {
276            if let Some(loop_done) = self.loop_done.borrow().as_ref() {
277                loop_done.unbounded_send(()).unwrap();
278            }
279        }
280
281        vec![
282            input_device::InputEvent::from(unhandled_input_event)
283                .into_handled_if(is_display_ownership_lost),
284        ]
285    }
286
287    fn set_handler_healthy(self: std::rc::Rc<Self>) {
288        self.inspect_status.health_node.borrow_mut().set_ok();
289    }
290
291    fn set_handler_unhealthy(self: std::rc::Rc<Self>, msg: &str) {
292        self.inspect_status.health_node.borrow_mut().set_unhealthy(msg);
293    }
294
295    fn get_name(&self) -> &'static str {
296        "DisplayOwnership"
297    }
298}
299
300fn empty_keyboard_device_descriptor() -> input_device::InputDeviceDescriptor {
301    input_device::InputDeviceDescriptor::Keyboard(
302        // Should descriptor be something sensible?
303        KeyboardDeviceDescriptor {
304            keys: vec![],
305            device_information: fidl_fuchsia_input_report::DeviceInformation {
306                vendor_id: Some(0),
307                product_id: Some(0),
308                version: Some(0),
309                polling_rate: Some(0),
310                ..Default::default()
311            },
312            device_id: 0,
313        },
314    )
315}
316
317fn into_input_event(
318    keyboard_event: KeyboardEvent,
319    event_time: MonotonicInstant,
320) -> input_device::InputEvent {
321    input_device::InputEvent {
322        device_event: input_device::InputDeviceEvent::Keyboard(keyboard_event),
323        device_descriptor: empty_keyboard_device_descriptor(),
324        event_time,
325        handled: input_device::Handled::No,
326        trace_id: None,
327    }
328}
329
330#[cfg(test)]
331mod tests {
332    use super::*;
333    use crate::testing_utilities::{create_fake_input_event, create_input_event};
334    use fidl_fuchsia_input::Key;
335    use fuchsia_async as fasync;
336    use pretty_assertions::assert_eq;
337    use std::convert::TryFrom as _;
338    use zx::{EventPair, Peered};
339
340    // Manages losing and regaining display, since manual management is error-prone:
341    // if signal_peer does not change the signal state, the waiting process will block
342    // forever, which makes tests run longer than needed.
343    struct DisplayWrangler {
344        event: EventPair,
345        last: Signals,
346    }
347
348    impl DisplayWrangler {
349        fn new(event: EventPair) -> Self {
350            let mut instance = DisplayWrangler { event, last: *DISPLAY_OWNED };
351            // Signal needs to be initialized before the handlers attempts to read it.
352            // This is normally always the case in production.
353            // Else, the `new_for_test` below will panic with a TIMEOUT error.
354            instance.set_unowned();
355            instance
356        }
357
358        fn set_unowned(&mut self) {
359            assert!(self.last != *DISPLAY_UNOWNED, "display is already unowned");
360            self.event.signal_peer(*DISPLAY_OWNED, *DISPLAY_UNOWNED).unwrap();
361            self.last = *DISPLAY_UNOWNED;
362        }
363
364        fn set_owned(&mut self) {
365            assert!(self.last != *DISPLAY_OWNED, "display is already owned");
366            self.event.signal_peer(*DISPLAY_UNOWNED, *DISPLAY_OWNED).unwrap();
367            self.last = *DISPLAY_OWNED;
368        }
369    }
370
371    #[fuchsia::test]
372    async fn display_ownership_change() {
373        // handler_event is the event that the unit under test will examine for
374        // display ownership changes.  test_event is used to set the appropriate
375        // signals.
376        let (test_event, handler_event) = EventPair::create();
377
378        // test_sender is used to pipe input events into the handler.
379        let (test_sender, handler_receiver) = mpsc::unbounded::<InputEvent>();
380
381        // test_receiver is used to pipe input events out of the handler.
382        let (handler_sender, test_receiver) = mpsc::unbounded::<InputEvent>();
383
384        // The unit under test adds a () each time it completes one pass through
385        // its event loop.  Use to ensure synchronization.
386        let (loop_done_sender, mut loop_done) = mpsc::unbounded::<()>();
387
388        // We use a wrapper to signal test_event correctly, since doing it wrong
389        // by hand causes tests to hang, which isn't the best dev experience.
390        let mut wrangler = DisplayWrangler::new(test_event);
391        let handler = DisplayOwnership::new_for_test(handler_event, loop_done_sender);
392
393        let handler_clone = handler.clone();
394        let handler_sender_clone = handler_sender.clone();
395        let _task = fasync::Task::local(async move {
396            handler_clone.handle_ownership_change(handler_sender_clone).await.unwrap();
397        });
398
399        let handler_clone_2 = handler.clone();
400        let _input_task = fasync::Task::local(async move {
401            let mut receiver = handler_receiver;
402            while let Some(event) = receiver.next().await {
403                let unhandled_event = UnhandledInputEvent::try_from(event).unwrap();
404                let out_events =
405                    handler_clone_2.clone().handle_unhandled_input_event(unhandled_event).await;
406                for out_event in out_events {
407                    handler_sender.unbounded_send(out_event).unwrap();
408                }
409            }
410        });
411
412        let fake_time = MonotonicInstant::from_nanos(42);
413
414        // Go two full circles of signaling.
415
416        // 1
417        wrangler.set_owned();
418        loop_done.next().await;
419        test_sender.unbounded_send(create_fake_input_event(fake_time)).unwrap();
420        loop_done.next().await;
421
422        // 2
423        wrangler.set_unowned();
424        loop_done.next().await;
425        test_sender.unbounded_send(create_fake_input_event(fake_time)).unwrap();
426        loop_done.next().await;
427
428        // 3
429        wrangler.set_owned();
430        loop_done.next().await;
431        test_sender.unbounded_send(create_fake_input_event(fake_time)).unwrap();
432        loop_done.next().await;
433
434        // 4
435        wrangler.set_unowned();
436        loop_done.next().await;
437        test_sender.unbounded_send(create_fake_input_event(fake_time)).unwrap();
438        loop_done.next().await;
439
440        let actual: Vec<InputEvent> =
441            test_receiver.take(4).map(|e| e.into_with_event_time(fake_time)).collect().await;
442
443        assert_eq!(
444            actual,
445            vec![
446                // Event received while we owned the display.
447                create_fake_input_event(fake_time),
448                // Event received when we lost the display.
449                create_fake_input_event(fake_time).into_handled(),
450                // Display ownership regained.
451                create_fake_input_event(fake_time),
452                // Display ownership lost.
453                create_fake_input_event(fake_time).into_handled(),
454            ]
455        );
456    }
457
458    fn new_keyboard_input_event(key: Key, event_type: KeyEventType) -> InputEvent {
459        let fake_time = MonotonicInstant::from_nanos(42);
460        create_input_event(
461            KeyboardEvent::new(key, event_type),
462            &input_device::InputDeviceDescriptor::Fake,
463            fake_time,
464            input_device::Handled::No,
465        )
466    }
467
468    #[fuchsia::test]
469    async fn basic_key_state_handling() {
470        let (test_event, handler_event) = EventPair::create();
471        let (test_sender, handler_receiver) = mpsc::unbounded::<InputEvent>();
472        let (handler_sender, test_receiver) = mpsc::unbounded::<InputEvent>();
473        let (loop_done_sender, mut loop_done) = mpsc::unbounded::<()>();
474        let mut wrangler = DisplayWrangler::new(test_event);
475        let handler = DisplayOwnership::new_for_test(handler_event, loop_done_sender);
476
477        let handler_clone = handler.clone();
478        let handler_sender_clone = handler_sender.clone();
479        let _task = fasync::Task::local(async move {
480            handler_clone.handle_ownership_change(handler_sender_clone).await.unwrap();
481        });
482
483        let handler_clone_2 = handler.clone();
484        let _input_task = fasync::Task::local(async move {
485            let mut receiver = handler_receiver;
486            while let Some(event) = receiver.next().await {
487                let unhandled_event = UnhandledInputEvent::try_from(event).unwrap();
488                let out_events =
489                    handler_clone_2.clone().handle_unhandled_input_event(unhandled_event).await;
490                for out_event in out_events {
491                    handler_sender.unbounded_send(out_event).unwrap();
492                }
493            }
494        });
495
496        let fake_time = MonotonicInstant::from_nanos(42);
497
498        // Gain the display, and press a key.
499        wrangler.set_owned();
500        loop_done.next().await;
501        test_sender
502            .unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Pressed))
503            .unwrap();
504        loop_done.next().await;
505
506        // Lose display.
507        wrangler.set_unowned();
508        loop_done.next().await;
509
510        // Regain display
511        wrangler.set_owned();
512        loop_done.next().await;
513
514        // Key event after regaining.
515        test_sender
516            .unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Released))
517            .unwrap();
518        loop_done.next().await;
519
520        let actual: Vec<InputEvent> =
521            test_receiver.take(4).map(|e| e.into_with_event_time(fake_time)).collect().await;
522
523        assert_eq!(
524            actual,
525            vec![
526                new_keyboard_input_event(Key::A, KeyEventType::Pressed),
527                new_keyboard_input_event(Key::A, KeyEventType::Cancel)
528                    .into_with_device_descriptor(empty_keyboard_device_descriptor()),
529                new_keyboard_input_event(Key::A, KeyEventType::Sync)
530                    .into_with_device_descriptor(empty_keyboard_device_descriptor()),
531                new_keyboard_input_event(Key::A, KeyEventType::Released),
532            ]
533        );
534    }
535
536    #[fuchsia::test]
537    async fn more_key_state_handling() {
538        let (test_event, handler_event) = EventPair::create();
539        let (test_sender, handler_receiver) = mpsc::unbounded::<InputEvent>();
540        let (handler_sender, test_receiver) = mpsc::unbounded::<InputEvent>();
541        let (loop_done_sender, mut loop_done) = mpsc::unbounded::<()>();
542        let mut wrangler = DisplayWrangler::new(test_event);
543        let handler = DisplayOwnership::new_for_test(handler_event, loop_done_sender);
544
545        let handler_clone = handler.clone();
546        let handler_sender_clone = handler_sender.clone();
547        let _task = fasync::Task::local(async move {
548            handler_clone.handle_ownership_change(handler_sender_clone).await.unwrap();
549        });
550
551        let handler_clone_2 = handler.clone();
552        let _input_task = fasync::Task::local(async move {
553            let mut receiver = handler_receiver;
554            while let Some(event) = receiver.next().await {
555                let unhandled_event = UnhandledInputEvent::try_from(event).unwrap();
556                let out_events =
557                    handler_clone_2.clone().handle_unhandled_input_event(unhandled_event).await;
558                for out_event in out_events {
559                    handler_sender.unbounded_send(out_event).unwrap();
560                }
561            }
562        });
563
564        let fake_time = MonotonicInstant::from_nanos(42);
565
566        wrangler.set_owned();
567        loop_done.next().await;
568        test_sender
569            .unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Pressed))
570            .unwrap();
571        loop_done.next().await;
572        test_sender
573            .unbounded_send(new_keyboard_input_event(Key::B, KeyEventType::Pressed))
574            .unwrap();
575        loop_done.next().await;
576
577        // Lose display, release a key, press a key.
578        wrangler.set_unowned();
579        loop_done.next().await;
580        test_sender
581            .unbounded_send(new_keyboard_input_event(Key::B, KeyEventType::Released))
582            .unwrap();
583        loop_done.next().await;
584        test_sender
585            .unbounded_send(new_keyboard_input_event(Key::C, KeyEventType::Pressed))
586            .unwrap();
587        loop_done.next().await;
588
589        // Regain display
590        wrangler.set_owned();
591        loop_done.next().await;
592
593        // Key event after regaining.
594        test_sender
595            .unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Released))
596            .unwrap();
597        loop_done.next().await;
598        test_sender
599            .unbounded_send(new_keyboard_input_event(Key::C, KeyEventType::Released))
600            .unwrap();
601        loop_done.next().await;
602
603        let actual: Vec<InputEvent> =
604            test_receiver.take(10).map(|e| e.into_with_event_time(fake_time)).collect().await;
605
606        assert_eq!(
607            actual,
608            vec![
609                new_keyboard_input_event(Key::A, KeyEventType::Pressed),
610                new_keyboard_input_event(Key::B, KeyEventType::Pressed),
611                new_keyboard_input_event(Key::A, KeyEventType::Cancel)
612                    .into_with_device_descriptor(empty_keyboard_device_descriptor()),
613                new_keyboard_input_event(Key::B, KeyEventType::Cancel)
614                    .into_with_device_descriptor(empty_keyboard_device_descriptor()),
615                new_keyboard_input_event(Key::B, KeyEventType::Released).into_handled(),
616                new_keyboard_input_event(Key::C, KeyEventType::Pressed).into_handled(),
617                // The CANCEL and SYNC events are emitted in the sort ordering of the
618                // `Key` enum values. Perhaps they should be emitted instead in the order
619                // they have been received for SYNC, and in reverse order for CANCEL.
620                new_keyboard_input_event(Key::A, KeyEventType::Sync)
621                    .into_with_device_descriptor(empty_keyboard_device_descriptor()),
622                new_keyboard_input_event(Key::C, KeyEventType::Sync)
623                    .into_with_device_descriptor(empty_keyboard_device_descriptor()),
624                new_keyboard_input_event(Key::A, KeyEventType::Released),
625                new_keyboard_input_event(Key::C, KeyEventType::Released),
626            ]
627        );
628    }
629
630    #[fuchsia::test]
631    async fn display_ownership_initialized_with_inspect_node() {
632        let (test_event, handler_event) = EventPair::create();
633        let (loop_done_sender, _) = mpsc::unbounded::<()>();
634        let inspector = fuchsia_inspect::Inspector::default();
635        let fake_handlers_node = inspector.root().create_child("input_handlers_node");
636        // Signal needs to be initialized first so DisplayOwnership::new doesn't panic with a TIMEOUT error
637        let _ = DisplayWrangler::new(test_event);
638        let _handler = DisplayOwnership::new_internal(
639            handler_event,
640            Some(loop_done_sender),
641            &fake_handlers_node,
642        );
643        diagnostics_assertions::assert_data_tree!(inspector, root: {
644            input_handlers_node: {
645                display_ownership: {
646                    events_received_count: 0u64,
647                    events_handled_count: 0u64,
648                    last_received_timestamp_ns: 0u64,
649                    "fuchsia.inspect.Health": {
650                        status: "STARTING_UP",
651                        // Timestamp value is unpredictable and not relevant in this context,
652                        // so we only assert that the property is present.
653                        start_timestamp_nanos: diagnostics_assertions::AnyProperty
654                    },
655                }
656            }
657        });
658    }
659
660    #[fuchsia::test]
661    async fn display_ownership_inspect_counts_events() {
662        let (test_event, handler_event) = EventPair::create();
663        let (test_sender, handler_receiver) = mpsc::unbounded::<InputEvent>();
664        let (handler_sender, _test_receiver) = mpsc::unbounded::<InputEvent>();
665        let (loop_done_sender, mut loop_done) = mpsc::unbounded::<()>();
666        let mut wrangler = DisplayWrangler::new(test_event);
667        let inspector = fuchsia_inspect::Inspector::default();
668        let fake_handlers_node = inspector.root().create_child("input_handlers_node");
669        let handler = DisplayOwnership::new_internal(
670            handler_event,
671            Some(loop_done_sender),
672            &fake_handlers_node,
673        );
674        let handler_clone = handler.clone();
675        let handler_sender_clone = handler_sender.clone();
676        let _task = fasync::Task::local(async move {
677            handler_clone.handle_ownership_change(handler_sender_clone).await.unwrap();
678        });
679
680        let handler_clone_2 = handler.clone();
681        let _input_task = fasync::Task::local(async move {
682            let mut receiver = handler_receiver;
683            while let Some(event) = receiver.next().await {
684                let unhandled_event = UnhandledInputEvent::try_from(event).unwrap();
685                let out_events =
686                    handler_clone_2.clone().handle_unhandled_input_event(unhandled_event).await;
687                for out_event in out_events {
688                    handler_sender.unbounded_send(out_event).unwrap();
689                }
690            }
691        });
692
693        // Gain the display, and press a key.
694        wrangler.set_owned();
695        loop_done.next().await;
696        test_sender
697            .unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Pressed))
698            .unwrap();
699        loop_done.next().await;
700
701        // Lose display
702        // Input event is marked `Handled` if received after display ownership is lost
703        wrangler.set_unowned();
704        loop_done.next().await;
705        test_sender
706            .unbounded_send(new_keyboard_input_event(Key::B, KeyEventType::Pressed))
707            .unwrap();
708        loop_done.next().await;
709
710        // Regain display
711        wrangler.set_owned();
712        loop_done.next().await;
713
714        // Key event after regaining.
715        test_sender
716            .unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Released))
717            .unwrap();
718        loop_done.next().await;
719
720        diagnostics_assertions::assert_data_tree!(inspector, root: {
721            input_handlers_node: {
722                display_ownership: {
723                    events_received_count: 3u64,
724                    events_handled_count: 1u64,
725                    last_received_timestamp_ns: 42u64,
726                    "fuchsia.inspect.Health": {
727                        status: "STARTING_UP",
728                        // Timestamp value is unpredictable and not relevant in this context,
729                        // so we only assert that the property is present.
730                        start_timestamp_nanos: diagnostics_assertions::AnyProperty
731                    },
732                }
733            }
734        });
735    }
736}