Skip to main content

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