input_pipeline/
media_buttons_handler.rs

1// Copyright 2021 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_handler::{Handler, InputHandlerStatus, UnhandledInputHandler};
6use crate::{consumer_controls_binding, input_device, metrics};
7use async_trait::async_trait;
8use fidl::HandleBased;
9use fidl::endpoints::Proxy;
10use fuchsia_inspect::health::Reporter;
11use futures::StreamExt;
12use futures::channel::mpsc;
13use metrics_registry::*;
14use std::cell::RefCell;
15use std::collections::HashMap;
16use std::rc::Rc;
17use zx::AsHandleRef;
18use {
19    fidl_fuchsia_input_report as fidl_input_report, fidl_fuchsia_ui_input as fidl_ui_input,
20    fidl_fuchsia_ui_policy as fidl_ui_policy, fuchsia_async as fasync,
21};
22
23/// A [`MediaButtonsHandler`] tracks MediaButtonListeners and sends media button events to them.
24pub struct MediaButtonsHandler {
25    /// The mutable fields of this handler.
26    inner: RefCell<MediaButtonsHandlerInner>,
27
28    /// The inventory of this handler's Inspect status.
29    pub inspect_status: InputHandlerStatus,
30
31    metrics_logger: metrics::MetricsLogger,
32}
33
34#[derive(Debug)]
35struct MediaButtonsHandlerInner {
36    /// The media button listeners, key referenced by proxy channel's raw handle.
37    pub listeners: HashMap<u32, fidl_ui_policy::MediaButtonsListenerProxy>,
38
39    /// The last MediaButtonsEvent sent to all listeners.
40    /// This is used to send new listeners the state of the media buttons.
41    pub last_event: Option<fidl_ui_input::MediaButtonsEvent>,
42
43    pub send_event_task_tracker: LocalTaskTracker,
44}
45
46impl Handler for MediaButtonsHandler {
47    fn set_handler_healthy(self: std::rc::Rc<Self>) {
48        self.inspect_status.health_node.borrow_mut().set_ok();
49    }
50
51    fn set_handler_unhealthy(self: std::rc::Rc<Self>, msg: &str) {
52        self.inspect_status.health_node.borrow_mut().set_unhealthy(msg);
53    }
54
55    fn get_name(&self) -> &'static str {
56        "MediaButtonsHandler"
57    }
58
59    fn interest(&self) -> Vec<input_device::InputEventType> {
60        vec![input_device::InputEventType::ConsumerControls]
61    }
62}
63
64#[async_trait(?Send)]
65impl UnhandledInputHandler for MediaButtonsHandler {
66    async fn handle_unhandled_input_event(
67        self: Rc<Self>,
68        mut unhandled_input_event: input_device::UnhandledInputEvent,
69    ) -> Vec<input_device::InputEvent> {
70        fuchsia_trace::duration!("input", "media_buttons_handler");
71        match unhandled_input_event {
72            input_device::UnhandledInputEvent {
73                device_event:
74                    input_device::InputDeviceEvent::ConsumerControls(ref mut consumer_controls_event),
75                device_descriptor:
76                    input_device::InputDeviceDescriptor::ConsumerControls(ref device_descriptor),
77                event_time,
78                trace_id,
79            } => {
80                fuchsia_trace::duration!("input", "media_buttons_handler[processing]");
81                if let Some(trace_id) = trace_id {
82                    fuchsia_trace::flow_end!("input", "event_in_input_pipeline", trace_id.into());
83                }
84
85                self.inspect_status.count_received_event(&event_time);
86                let mut media_buttons_event = Self::create_media_buttons_event(
87                    consumer_controls_event,
88                    device_descriptor.device_id,
89                );
90
91                // Send the event if the media buttons are supported.
92                self.send_event_to_listeners(&media_buttons_event).await;
93
94                // Store the sent event without any wake leases.
95                std::mem::drop(media_buttons_event.wake_lease.take());
96                self.inner.borrow_mut().last_event = Some(media_buttons_event);
97
98                // Consume the input event.
99                self.inspect_status.count_handled_event();
100                vec![input_device::InputEvent::from(unhandled_input_event).into_handled()]
101            }
102            _ => {
103                // TODO: b/478249522 - add cobalt logging
104                log::warn!("Unhandled input event: {:?}", unhandled_input_event.get_event_type());
105                vec![input_device::InputEvent::from(unhandled_input_event)]
106            }
107        }
108    }
109}
110
111impl MediaButtonsHandler {
112    /// Creates a new [`MediaButtonsHandler`] that sends media button events to listeners.
113    pub fn new(
114        input_handlers_node: &fuchsia_inspect::Node,
115        metrics_logger: metrics::MetricsLogger,
116    ) -> Rc<Self> {
117        let inspect_status =
118            InputHandlerStatus::new(input_handlers_node, "media_buttons_handler", false);
119        Self::new_internal(inspect_status, metrics_logger)
120    }
121
122    fn clone_event(event: &fidl_ui_input::MediaButtonsEvent) -> fidl_ui_input::MediaButtonsEvent {
123        fidl_ui_input::MediaButtonsEvent {
124            volume: event.volume,
125            mic_mute: event.mic_mute,
126            pause: event.pause,
127            camera_disable: event.camera_disable,
128            power: event.power,
129            function: event.function,
130            device_id: event.device_id,
131            wake_lease: event.wake_lease.as_ref().map(|lease| {
132                lease
133                    .duplicate_handle(zx::Rights::SAME_RIGHTS)
134                    .expect("failed to duplicate event pair")
135            }),
136            ..Default::default()
137        }
138    }
139
140    fn new_internal(
141        inspect_status: InputHandlerStatus,
142        metrics_logger: metrics::MetricsLogger,
143    ) -> Rc<Self> {
144        let media_buttons_handler = Self {
145            inner: RefCell::new(MediaButtonsHandlerInner {
146                listeners: HashMap::new(),
147                last_event: None,
148                send_event_task_tracker: LocalTaskTracker::new(),
149            }),
150            inspect_status,
151            metrics_logger,
152        };
153        Rc::new(media_buttons_handler)
154    }
155
156    /// Creates a fidl_ui_input::MediaButtonsEvent from a media_buttons::MediaButtonEvent.
157    ///
158    /// # Parameters
159    /// -  `event`: The MediaButtonEvent to create a MediaButtonsEvent from.
160    fn create_media_buttons_event(
161        event: &mut consumer_controls_binding::ConsumerControlsEvent,
162        device_id: u32,
163    ) -> fidl_ui_input::MediaButtonsEvent {
164        let mut new_event = fidl_ui_input::MediaButtonsEvent {
165            volume: Some(0),
166            mic_mute: Some(false),
167            pause: Some(false),
168            camera_disable: Some(false),
169            power: Some(false),
170            function: Some(false),
171            device_id: Some(device_id),
172            wake_lease: event.wake_lease.take(),
173            ..Default::default()
174        };
175        for button in &event.pressed_buttons {
176            match button {
177                fidl_input_report::ConsumerControlButton::VolumeUp => {
178                    new_event.volume = Some(new_event.volume.unwrap().saturating_add(1));
179                }
180                fidl_input_report::ConsumerControlButton::VolumeDown => {
181                    new_event.volume = Some(new_event.volume.unwrap().saturating_sub(1));
182                }
183                fidl_input_report::ConsumerControlButton::MicMute => {
184                    new_event.mic_mute = Some(true);
185                }
186                fidl_input_report::ConsumerControlButton::Pause => {
187                    new_event.pause = Some(true);
188                }
189                fidl_input_report::ConsumerControlButton::CameraDisable => {
190                    new_event.camera_disable = Some(true);
191                }
192                fidl_input_report::ConsumerControlButton::Function => {
193                    new_event.function = Some(true);
194                }
195                fidl_input_report::ConsumerControlButton::Power => {
196                    new_event.power = Some(true);
197                }
198                _ => {}
199            }
200        }
201
202        new_event
203    }
204
205    /// Sends media button events to media button listeners.
206    ///
207    /// # Parameters
208    /// - `event`: The event to send to the listeners.
209    async fn send_event_to_listeners(self: &Rc<Self>, event: &fidl_ui_input::MediaButtonsEvent) {
210        let tracker = &self.inner.borrow().send_event_task_tracker;
211
212        for (handle, listener) in &self.inner.borrow().listeners {
213            let weak_handler = Rc::downgrade(&self);
214            let listener_clone = listener.clone();
215            let handle_clone = handle.clone();
216            let event_to_send = Self::clone_event(event);
217            let fut = async move {
218                match listener_clone.on_event(event_to_send).await {
219                    Ok(_) => {}
220                    Err(e) => {
221                        if let Some(handler) = weak_handler.upgrade() {
222                            handler.inner.borrow_mut().listeners.remove(&handle_clone);
223                            log::info!(
224                                "Unregistering listener; unable to send MediaButtonsEvent: {:?}",
225                                e
226                            )
227                        }
228                    }
229                }
230            };
231
232            let metrics_logger_clone = self.metrics_logger.clone();
233            tracker.track(metrics_logger_clone, fasync::Task::local(fut));
234        }
235    }
236
237    // Add the listener to the registry.
238    ///
239    /// # Parameters
240    /// - `proxy`: A new listener proxy to send events to.
241    pub async fn register_listener_proxy(
242        self: &Rc<Self>,
243        proxy: fidl_ui_policy::MediaButtonsListenerProxy,
244    ) {
245        self.inner
246            .borrow_mut()
247            .listeners
248            .insert(proxy.as_channel().as_handle_ref().as_handle_ref().raw_handle(), proxy.clone());
249
250        // Send the listener the last media button event.
251        if let Some(event) = &self.inner.borrow().last_event {
252            let event_to_send = Self::clone_event(event);
253            let fut = async move {
254                match proxy.on_event(event_to_send).await {
255                    Ok(_) => {}
256                    Err(e) => {
257                        log::info!("Failed to send media buttons event to listener {:?}", e)
258                    }
259                }
260            };
261            let metrics_logger_clone = self.metrics_logger.clone();
262            self.inner
263                .borrow()
264                .send_event_task_tracker
265                .track(metrics_logger_clone, fasync::Task::local(fut));
266        }
267    }
268}
269
270/// Maintains a collection of pending local [`Task`]s, allowing them to be dropped (and cancelled)
271/// en masse.
272#[derive(Debug)]
273pub struct LocalTaskTracker {
274    sender: mpsc::UnboundedSender<fasync::Task<()>>,
275    _receiver_task: fasync::Task<()>,
276}
277
278impl LocalTaskTracker {
279    pub fn new() -> Self {
280        let (sender, receiver) = mpsc::unbounded();
281        let receiver_task = fasync::Task::local(async move {
282            // Drop the tasks as they are completed.
283            receiver.for_each_concurrent(None, |task: fasync::Task<()>| task).await
284        });
285
286        Self { sender, _receiver_task: receiver_task }
287    }
288
289    /// Submits a new task to track.
290    pub fn track(&self, metrics_logger: metrics::MetricsLogger, task: fasync::Task<()>) {
291        match self.sender.unbounded_send(task) {
292            Ok(_) => {}
293            // `Full` should never happen because this is unbounded.
294            // `Disconnected` might happen if the `Service` was dropped. However, it's not clear how
295            // to create such a race condition.
296            Err(e) => {
297                metrics_logger.log_error(
298                    InputPipelineErrorMetricDimensionEvent::MediaButtonErrorWhilePushingTask,
299                    std::format!("Unexpected {e:?} while pushing task"),
300                );
301            }
302        };
303    }
304}
305
306#[cfg(test)]
307mod tests {
308    use super::*;
309    use crate::input_handler::InputHandler;
310    use crate::testing_utilities;
311    use anyhow::Error;
312    use assert_matches::assert_matches;
313    use fidl::endpoints::create_proxy_and_stream;
314    use futures::TryStreamExt;
315    use futures::channel::oneshot;
316    use pretty_assertions::assert_eq;
317    use std::task::Poll;
318    use {fidl_fuchsia_input_report as fidl_input_report, fuchsia_async as fasync};
319
320    fn spawn_device_listener_registry_server(
321        handler: Rc<MediaButtonsHandler>,
322    ) -> fidl_ui_policy::DeviceListenerRegistryProxy {
323        let (device_listener_proxy, mut device_listener_stream) =
324            create_proxy_and_stream::<fidl_ui_policy::DeviceListenerRegistryMarker>();
325
326        fasync::Task::local(async move {
327            loop {
328                match device_listener_stream.try_next().await {
329                    Ok(Some(fidl_ui_policy::DeviceListenerRegistryRequest::RegisterListener {
330                        listener,
331                        responder,
332                    })) => {
333                        handler.register_listener_proxy(listener.into_proxy()).await;
334                        let _ = responder.send();
335                    }
336                    Ok(Some(_)) => {
337                        panic!("Unexpected registration");
338                    }
339                    Ok(None) => {
340                        break;
341                    }
342                    Err(e) => {
343                        panic!("Error handling device listener registry request stream: {}", e);
344                    }
345                }
346            }
347        })
348        .detach();
349
350        device_listener_proxy
351    }
352
353    fn create_ui_input_media_buttons_event(
354        volume: Option<i8>,
355        mic_mute: Option<bool>,
356        pause: Option<bool>,
357        camera_disable: Option<bool>,
358        power: Option<bool>,
359        function: Option<bool>,
360    ) -> fidl_ui_input::MediaButtonsEvent {
361        fidl_ui_input::MediaButtonsEvent {
362            volume,
363            mic_mute,
364            pause,
365            camera_disable,
366            power,
367            function,
368            device_id: Some(0),
369            ..Default::default()
370        }
371    }
372
373    /// Makes a `Task` that waits for a `oneshot`'s value to be set, and then forwards that value to
374    /// a reference-counted container that can be observed outside the task.
375    fn make_signalable_task<T: Default + 'static>()
376    -> (oneshot::Sender<T>, fasync::Task<()>, Rc<RefCell<T>>) {
377        let (sender, receiver) = oneshot::channel();
378        let task_completed = Rc::new(RefCell::new(<T as Default>::default()));
379        let task_completed_ = task_completed.clone();
380        let task = fasync::Task::local(async move {
381            if let Ok(value) = receiver.await {
382                *task_completed_.borrow_mut() = value;
383            }
384        });
385        (sender, task, task_completed)
386    }
387
388    /// Tests that a media button listener can be registered and is sent the latest event upon
389    /// registration.
390    #[fasync::run_singlethreaded(test)]
391    async fn register_media_buttons_listener() {
392        let inspector = fuchsia_inspect::Inspector::default();
393        let test_node = inspector.root().create_child("test_node");
394        let inspect_status = InputHandlerStatus::new(
395            &test_node,
396            "media_buttons_handler",
397            /* generates_events */ false,
398        );
399
400        let media_buttons_handler = Rc::new(MediaButtonsHandler {
401            inner: RefCell::new(MediaButtonsHandlerInner {
402                listeners: HashMap::new(),
403                last_event: Some(create_ui_input_media_buttons_event(
404                    Some(1),
405                    None,
406                    None,
407                    None,
408                    None,
409                    None,
410                )),
411                send_event_task_tracker: LocalTaskTracker::new(),
412            }),
413            inspect_status,
414            metrics_logger: metrics::MetricsLogger::default(),
415        });
416        let device_listener_proxy =
417            spawn_device_listener_registry_server(media_buttons_handler.clone());
418
419        // Register a listener.
420        let (listener, mut listener_stream) =
421            fidl::endpoints::create_request_stream::<fidl_ui_policy::MediaButtonsListenerMarker>();
422        let register_listener_fut = async {
423            let res = device_listener_proxy.register_listener(listener).await;
424            assert!(res.is_ok());
425        };
426
427        // Assert listener was registered and received last event.
428        let expected_event =
429            create_ui_input_media_buttons_event(Some(1), None, None, None, None, None);
430        let assert_fut = async {
431            match listener_stream.next().await {
432                Some(Ok(fidl_ui_policy::MediaButtonsListenerRequest::OnEvent {
433                    event,
434                    responder,
435                })) => {
436                    assert_eq!(event, expected_event);
437                    responder.send().expect("responder failed.");
438                }
439                _ => assert!(false),
440            }
441        };
442        futures::join!(register_listener_fut, assert_fut);
443        assert_eq!(media_buttons_handler.inner.borrow().listeners.len(), 1);
444    }
445
446    /// Tests that all supported buttons are sent.
447    #[fasync::run_singlethreaded(test)]
448    async fn listener_receives_all_buttons() {
449        let event_time = zx::MonotonicInstant::get();
450        let inspector = fuchsia_inspect::Inspector::default();
451        let test_node = inspector.root().create_child("test_node");
452        let inspect_status = InputHandlerStatus::new(
453            &test_node,
454            "media_buttons_handler",
455            /* generates_events */ false,
456        );
457        let media_buttons_handler =
458            MediaButtonsHandler::new_internal(inspect_status, metrics::MetricsLogger::default());
459        let device_listener_proxy =
460            spawn_device_listener_registry_server(media_buttons_handler.clone());
461
462        // Register a listener.
463        let (listener, listener_stream) =
464            fidl::endpoints::create_request_stream::<fidl_ui_policy::MediaButtonsListenerMarker>();
465        let _ = device_listener_proxy.register_listener(listener).await;
466
467        // Setup events and expectations.
468        let descriptor = testing_utilities::consumer_controls_device_descriptor();
469        let input_events = vec![testing_utilities::create_consumer_controls_event(
470            vec![
471                fidl_input_report::ConsumerControlButton::VolumeUp,
472                fidl_input_report::ConsumerControlButton::VolumeDown,
473                fidl_input_report::ConsumerControlButton::Pause,
474                fidl_input_report::ConsumerControlButton::MicMute,
475                fidl_input_report::ConsumerControlButton::CameraDisable,
476                fidl_input_report::ConsumerControlButton::Function,
477                fidl_input_report::ConsumerControlButton::Power,
478            ],
479            event_time,
480            &descriptor,
481        )];
482        let expected_events = vec![create_ui_input_media_buttons_event(
483            Some(0),
484            Some(true),
485            Some(true),
486            Some(true),
487            Some(true),
488            Some(true),
489        )];
490
491        // Assert registered listener receives event.
492        use crate::input_handler::InputHandler as _; // Adapt UnhandledInputHandler to InputHandler
493        assert_input_event_sequence_generates_media_buttons_events!(
494            input_handler: media_buttons_handler,
495            input_events: input_events,
496            expected_events: expected_events,
497            media_buttons_listener_request_stream: vec![listener_stream],
498        );
499    }
500
501    /// Tests that multiple listeners are supported.
502    #[fasync::run_singlethreaded(test)]
503    async fn multiple_listeners_receive_event() {
504        let event_time = zx::MonotonicInstant::get();
505        let inspector = fuchsia_inspect::Inspector::default();
506        let test_node = inspector.root().create_child("test_node");
507        let inspect_status = InputHandlerStatus::new(
508            &test_node,
509            "media_buttons_handler",
510            /* generates_events */ false,
511        );
512        let media_buttons_handler =
513            MediaButtonsHandler::new_internal(inspect_status, metrics::MetricsLogger::default());
514        let device_listener_proxy =
515            spawn_device_listener_registry_server(media_buttons_handler.clone());
516
517        // Register two listeners.
518        let (first_listener, first_listener_stream) =
519            fidl::endpoints::create_request_stream::<fidl_ui_policy::MediaButtonsListenerMarker>();
520        let (second_listener, second_listener_stream) =
521            fidl::endpoints::create_request_stream::<fidl_ui_policy::MediaButtonsListenerMarker>();
522        let _ = device_listener_proxy.register_listener(first_listener).await;
523        let _ = device_listener_proxy.register_listener(second_listener).await;
524
525        // Setup events and expectations.
526        let descriptor = testing_utilities::consumer_controls_device_descriptor();
527        let input_events = vec![testing_utilities::create_consumer_controls_event(
528            vec![fidl_input_report::ConsumerControlButton::VolumeUp],
529            event_time,
530            &descriptor,
531        )];
532        let expected_events = vec![create_ui_input_media_buttons_event(
533            Some(1),
534            Some(false),
535            Some(false),
536            Some(false),
537            Some(false),
538            Some(false),
539        )];
540
541        // Assert registered listeners receives event.
542        use crate::input_handler::InputHandler as _; // Adapt UnhandledInputHandler to InputHandler
543        assert_input_event_sequence_generates_media_buttons_events!(
544            input_handler: media_buttons_handler,
545            input_events: input_events,
546            expected_events: expected_events,
547            media_buttons_listener_request_stream:
548                vec![first_listener_stream, second_listener_stream],
549        );
550    }
551
552    /// Tests that listener is unregistered if channel is closed and we try to send input event to listener
553    #[fuchsia::test]
554    fn unregister_listener_if_channel_closed() {
555        let mut exec = fasync::TestExecutor::new();
556
557        let event_time = zx::MonotonicInstant::get();
558        let inspector = fuchsia_inspect::Inspector::default();
559        let test_node = inspector.root().create_child("test_node");
560        let inspect_status = InputHandlerStatus::new(
561            &test_node,
562            "media_buttons_handler",
563            /* generates_events */ false,
564        );
565        let media_buttons_handler =
566            MediaButtonsHandler::new_internal(inspect_status, metrics::MetricsLogger::default());
567        let media_buttons_handler_clone = media_buttons_handler.clone();
568
569        let mut task = fasync::Task::local(async move {
570            let device_listener_proxy =
571                spawn_device_listener_registry_server(media_buttons_handler.clone());
572
573            // Register three listeners.
574            let (first_listener, mut first_listener_stream) =
575                fidl::endpoints::create_request_stream::<fidl_ui_policy::MediaButtonsListenerMarker>(
576                );
577            let (second_listener, mut second_listener_stream) =
578                fidl::endpoints::create_request_stream::<fidl_ui_policy::MediaButtonsListenerMarker>(
579                );
580            let (third_listener, third_listener_stream) = fidl::endpoints::create_request_stream::<
581                fidl_ui_policy::MediaButtonsListenerMarker,
582            >();
583            let _ = device_listener_proxy.register_listener(first_listener).await;
584            let _ = device_listener_proxy.register_listener(second_listener).await;
585            let _ = device_listener_proxy.register_listener(third_listener).await;
586            assert_eq!(media_buttons_handler.inner.borrow().listeners.len(), 3);
587
588            // Generate input event to be handled by MediaButtonsHandler.
589            let descriptor = testing_utilities::consumer_controls_device_descriptor();
590            let input_event = testing_utilities::create_consumer_controls_event(
591                vec![fidl_input_report::ConsumerControlButton::VolumeUp],
592                event_time,
593                &descriptor,
594            );
595
596            let expected_media_buttons_event = create_ui_input_media_buttons_event(
597                Some(1),
598                Some(false),
599                Some(false),
600                Some(false),
601                Some(false),
602                Some(false),
603            );
604
605            // Drop third registered listener.
606            std::mem::drop(third_listener_stream);
607
608            let _ = media_buttons_handler.clone().handle_input_event(input_event).await;
609            // First listener stalls, responder doesn't send response - subsequent listeners should still be able receive event.
610            if let Some(request) = first_listener_stream.next().await {
611                match request {
612                    Ok(fidl_ui_policy::MediaButtonsListenerRequest::OnEvent {
613                        event,
614                        responder: _,
615                    }) => {
616                        pretty_assertions::assert_eq!(event, expected_media_buttons_event);
617
618                        // No need to send response because we want to simulate reader getting stuck.
619                    }
620                    _ => assert!(false),
621                }
622            } else {
623                assert!(false);
624            }
625
626            // Send response from responder on second listener stream
627            if let Some(request) = second_listener_stream.next().await {
628                match request {
629                    Ok(fidl_ui_policy::MediaButtonsListenerRequest::OnEvent {
630                        event,
631                        responder,
632                    }) => {
633                        pretty_assertions::assert_eq!(event, expected_media_buttons_event);
634                        let _ = responder.send();
635                    }
636                    _ => assert!(false),
637                }
638            } else {
639                assert!(false);
640            }
641        });
642
643        // Must manually run tasks with executor to ensure all tasks in LocalTaskTracker complete/stall before we call final assertion.
644        let _ = exec.run_until_stalled(&mut task);
645
646        // Should only be two listeners still registered in 'inner' after we unregister the listener with closed channel.
647        let _ = exec.run_singlethreaded(async {
648            assert_eq!(media_buttons_handler_clone.inner.borrow().listeners.len(), 2);
649        });
650    }
651
652    /// Tests that handle_input_event returns even if reader gets stuck while sending event to listener
653    #[fasync::run_singlethreaded(test)]
654    async fn stuck_reader_wont_block_input_pipeline() {
655        let event_time = zx::MonotonicInstant::get();
656        let inspector = fuchsia_inspect::Inspector::default();
657        let test_node = inspector.root().create_child("test_node");
658        let inspect_status = InputHandlerStatus::new(
659            &test_node,
660            "media_buttons_handler",
661            /* generates_events */ false,
662        );
663        let media_buttons_handler =
664            MediaButtonsHandler::new_internal(inspect_status, metrics::MetricsLogger::default());
665        let device_listener_proxy =
666            spawn_device_listener_registry_server(media_buttons_handler.clone());
667
668        let (first_listener, mut first_listener_stream) =
669            fidl::endpoints::create_request_stream::<fidl_ui_policy::MediaButtonsListenerMarker>();
670        let (second_listener, mut second_listener_stream) =
671            fidl::endpoints::create_request_stream::<fidl_ui_policy::MediaButtonsListenerMarker>();
672        let _ = device_listener_proxy.register_listener(first_listener).await;
673        let _ = device_listener_proxy.register_listener(second_listener).await;
674
675        // Setup events and expectations.
676        let descriptor = testing_utilities::consumer_controls_device_descriptor();
677        let first_unhandled_input_event = input_device::UnhandledInputEvent {
678            device_event: input_device::InputDeviceEvent::ConsumerControls(
679                consumer_controls_binding::ConsumerControlsEvent::new(
680                    vec![fidl_input_report::ConsumerControlButton::VolumeUp],
681                    None,
682                ),
683            ),
684            device_descriptor: descriptor.clone(),
685            event_time,
686            trace_id: None,
687        };
688        let first_expected_media_buttons_event = create_ui_input_media_buttons_event(
689            Some(1),
690            Some(false),
691            Some(false),
692            Some(false),
693            Some(false),
694            Some(false),
695        );
696
697        assert_matches!(
698            media_buttons_handler
699                .clone()
700                .handle_unhandled_input_event(first_unhandled_input_event)
701                .await
702                .as_slice(),
703            [input_device::InputEvent { handled: input_device::Handled::Yes, .. }]
704        );
705
706        let mut save_responder = None;
707
708        // Ensure handle_input_event attempts to send event to first listener.
709        if let Some(request) = first_listener_stream.next().await {
710            match request {
711                Ok(fidl_ui_policy::MediaButtonsListenerRequest::OnEvent { event, responder }) => {
712                    pretty_assertions::assert_eq!(event, first_expected_media_buttons_event);
713
714                    // No need to send response because we want to simulate reader getting stuck.
715
716                    // Save responder to send response later
717                    save_responder = Some(responder);
718                }
719                _ => assert!(false),
720            }
721        } else {
722            assert!(false)
723        }
724
725        // Ensure handle_input_event still sends event to second listener when reader for first listener is stuck.
726        if let Some(request) = second_listener_stream.next().await {
727            match request {
728                Ok(fidl_ui_policy::MediaButtonsListenerRequest::OnEvent { event, responder }) => {
729                    pretty_assertions::assert_eq!(event, first_expected_media_buttons_event);
730                    let _ = responder.send();
731                }
732                _ => assert!(false),
733            }
734        } else {
735            assert!(false)
736        }
737
738        // Setup second event to handle
739        let second_unhandled_input_event = input_device::UnhandledInputEvent {
740            device_event: input_device::InputDeviceEvent::ConsumerControls(
741                consumer_controls_binding::ConsumerControlsEvent::new(
742                    vec![fidl_input_report::ConsumerControlButton::MicMute],
743                    None,
744                ),
745            ),
746            device_descriptor: descriptor.clone(),
747            event_time,
748            trace_id: None,
749        };
750        let second_expected_media_buttons_event = create_ui_input_media_buttons_event(
751            Some(0),
752            Some(true),
753            Some(false),
754            Some(false),
755            Some(false),
756            Some(false),
757        );
758
759        // Ensure we can handle a subsequent event if listener stalls on first event.
760        assert_matches!(
761            media_buttons_handler
762                .clone()
763                .handle_unhandled_input_event(second_unhandled_input_event)
764                .await
765                .as_slice(),
766            [input_device::InputEvent { handled: input_device::Handled::Yes, .. }]
767        );
768
769        // Ensure events are still sent to listeners if a listener stalls on a previous event.
770        if let Some(request) = second_listener_stream.next().await {
771            match request {
772                Ok(fidl_ui_policy::MediaButtonsListenerRequest::OnEvent { event, responder }) => {
773                    pretty_assertions::assert_eq!(event, second_expected_media_buttons_event);
774                    let _ = responder.send();
775                }
776                _ => assert!(false),
777            }
778        } else {
779            assert!(false)
780        }
781
782        match save_responder {
783            Some(save_responder) => {
784                // Simulate delayed response to first listener for first event
785                let _ = save_responder.send();
786                // First listener should now receive second event after delayed response for first event
787                if let Some(request) = first_listener_stream.next().await {
788                    match request {
789                        Ok(fidl_ui_policy::MediaButtonsListenerRequest::OnEvent {
790                            event,
791                            responder: _,
792                        }) => {
793                            pretty_assertions::assert_eq!(
794                                event,
795                                second_expected_media_buttons_event
796                            );
797
798                            // No need to send response
799                        }
800                        _ => assert!(false),
801                    }
802                } else {
803                    assert!(false)
804                }
805            }
806            None => {
807                assert!(false)
808            }
809        }
810    }
811
812    // Test for LocalTaskTracker
813    #[fuchsia::test]
814    fn local_task_tracker_test() -> Result<(), Error> {
815        let mut exec = fasync::TestExecutor::new();
816
817        let (mut sender_1, task_1, completed_1) = make_signalable_task::<bool>();
818        let (sender_2, task_2, completed_2) = make_signalable_task::<bool>();
819
820        let mut tracker = LocalTaskTracker::new();
821
822        tracker.track(metrics::MetricsLogger::default(), task_1);
823        tracker.track(metrics::MetricsLogger::default(), task_2);
824
825        assert_matches!(exec.run_until_stalled(&mut tracker._receiver_task), Poll::Pending);
826        assert_eq!(Rc::strong_count(&completed_1), 2);
827        assert_eq!(Rc::strong_count(&completed_2), 2);
828        assert!(!sender_1.is_canceled());
829        assert!(!sender_2.is_canceled());
830
831        assert!(sender_2.send(true).is_ok());
832        assert_matches!(exec.run_until_stalled(&mut tracker._receiver_task), Poll::Pending);
833
834        assert_eq!(Rc::strong_count(&completed_1), 2);
835        assert_eq!(Rc::strong_count(&completed_2), 1);
836        assert_eq!(*completed_1.borrow(), false);
837        assert_eq!(*completed_2.borrow(), true);
838        assert!(!sender_1.is_canceled());
839
840        drop(tracker);
841        let mut sender_1_cancellation = sender_1.cancellation();
842        assert_matches!(exec.run_until_stalled(&mut sender_1_cancellation), Poll::Ready(()));
843        assert_eq!(Rc::strong_count(&completed_1), 1);
844        assert!(sender_1.is_canceled());
845
846        Ok(())
847    }
848
849    #[fasync::run_singlethreaded(test)]
850    async fn media_buttons_handler_initialized_with_inspect_node() {
851        let inspector = fuchsia_inspect::Inspector::default();
852        let fake_handlers_node = inspector.root().create_child("input_handlers_node");
853        let _handler =
854            MediaButtonsHandler::new(&fake_handlers_node, metrics::MetricsLogger::default());
855        diagnostics_assertions::assert_data_tree!(inspector, root: {
856            input_handlers_node: {
857                media_buttons_handler: {
858                    events_received_count: 0u64,
859                    events_handled_count: 0u64,
860                    last_received_timestamp_ns: 0u64,
861                    "fuchsia.inspect.Health": {
862                        status: "STARTING_UP",
863                        // Timestamp value is unpredictable and not relevant in this context,
864                        // so we only assert that the property is present.
865                        start_timestamp_nanos: diagnostics_assertions::AnyProperty
866                    },
867                }
868            }
869        });
870    }
871
872    #[fasync::run_singlethreaded(test)]
873    async fn media_buttons_handler_inspect_counts_events() {
874        let inspector = fuchsia_inspect::Inspector::default();
875        let fake_handlers_node = inspector.root().create_child("input_handlers_node");
876        let media_buttons_handler =
877            MediaButtonsHandler::new(&fake_handlers_node, metrics::MetricsLogger::default());
878
879        // Unhandled input event should be counted by inspect.
880        let descriptor = testing_utilities::consumer_controls_device_descriptor();
881        let events = vec![
882            input_device::InputEvent {
883                device_event: input_device::InputDeviceEvent::ConsumerControls(
884                    consumer_controls_binding::ConsumerControlsEvent::new(
885                        vec![fidl_input_report::ConsumerControlButton::VolumeUp],
886                        None,
887                    ),
888                ),
889                device_descriptor: descriptor.clone(),
890                event_time: zx::MonotonicInstant::get(),
891                handled: input_device::Handled::No,
892                trace_id: None,
893            },
894            // Handled input event should be ignored.
895            input_device::InputEvent {
896                device_event: input_device::InputDeviceEvent::ConsumerControls(
897                    consumer_controls_binding::ConsumerControlsEvent::new(
898                        vec![fidl_input_report::ConsumerControlButton::VolumeUp],
899                        None,
900                    ),
901                ),
902                device_descriptor: descriptor.clone(),
903                event_time: zx::MonotonicInstant::get(),
904                handled: input_device::Handled::Yes,
905                trace_id: None,
906            },
907            input_device::InputEvent {
908                device_event: input_device::InputDeviceEvent::ConsumerControls(
909                    consumer_controls_binding::ConsumerControlsEvent::new(
910                        vec![fidl_input_report::ConsumerControlButton::VolumeDown],
911                        None,
912                    ),
913                ),
914                device_descriptor: descriptor.clone(),
915                event_time: zx::MonotonicInstant::get(),
916                handled: input_device::Handled::No,
917                trace_id: None,
918            },
919        ];
920
921        let last_event_timestamp: u64 =
922            events[2].clone().event_time.into_nanos().try_into().unwrap();
923
924        for event in events {
925            media_buttons_handler.clone().handle_input_event(event).await;
926        }
927
928        diagnostics_assertions::assert_data_tree!(inspector, root: {
929            input_handlers_node: {
930                media_buttons_handler: {
931                    events_received_count: 2u64,
932                    events_handled_count: 2u64,
933                    last_received_timestamp_ns: last_event_timestamp,
934                    "fuchsia.inspect.Health": {
935                        status: "STARTING_UP",
936                        // Timestamp value is unpredictable and not relevant in this context,
937                        // so we only assert that the property is present.
938                        start_timestamp_nanos: diagnostics_assertions::AnyProperty
939                    },
940                }
941            }
942        });
943    }
944
945    #[fasync::run_singlethreaded(test)]
946    async fn clone_event_with_lease_duplicates_lease() {
947        let (event_pair, _) = fidl::EventPair::create();
948        let event_with_lease = fidl_ui_input::MediaButtonsEvent {
949            volume: Some(1),
950            mic_mute: Some(true),
951            pause: Some(true),
952            camera_disable: Some(true),
953            power: Some(true),
954            function: Some(true),
955            device_id: Some(1),
956            wake_lease: Some(event_pair),
957            ..Default::default()
958        };
959
960        // Test cloning an event that has a wake lease.
961        // With wake lease argument should duplicate the handle.
962        let cloned_event = MediaButtonsHandler::clone_event(&event_with_lease);
963        assert_eq!(event_with_lease.volume, cloned_event.volume);
964        assert_eq!(event_with_lease.mic_mute, cloned_event.mic_mute);
965        assert_eq!(event_with_lease.pause, cloned_event.pause);
966        assert_eq!(event_with_lease.camera_disable, cloned_event.camera_disable);
967        assert_eq!(event_with_lease.power, cloned_event.power);
968        assert_eq!(event_with_lease.function, cloned_event.function);
969        assert_eq!(event_with_lease.device_id, cloned_event.device_id);
970        assert!(event_with_lease.wake_lease.is_some());
971        assert!(cloned_event.wake_lease.is_some());
972        assert_ne!(
973            event_with_lease.wake_lease.as_ref().unwrap().as_handle_ref().raw_handle(),
974            cloned_event.wake_lease.as_ref().unwrap().as_handle_ref().raw_handle()
975        );
976        assert_eq!(
977            event_with_lease.wake_lease.as_ref().unwrap().koid(),
978            cloned_event.wake_lease.as_ref().unwrap().koid()
979        );
980    }
981
982    #[fasync::run_singlethreaded(test)]
983    async fn clone_event_without_lease_has_no_lease() {
984        // Test cloning an event that does not have a wake lease.
985        let event_without_lease = fidl_ui_input::MediaButtonsEvent {
986            volume: Some(1),
987            mic_mute: Some(true),
988            pause: Some(true),
989            camera_disable: Some(true),
990            power: Some(true),
991            function: Some(true),
992            device_id: Some(1),
993            ..Default::default()
994        };
995
996        // With wake lease argument should result in no wake lease.
997        let cloned_event = MediaButtonsHandler::clone_event(&event_without_lease);
998        assert_eq!(event_without_lease.volume, cloned_event.volume);
999        assert_eq!(event_without_lease.mic_mute, cloned_event.mic_mute);
1000        assert_eq!(event_without_lease.pause, cloned_event.pause);
1001        assert_eq!(event_without_lease.camera_disable, cloned_event.camera_disable);
1002        assert_eq!(event_without_lease.power, cloned_event.power);
1003        assert_eq!(event_without_lease.function, cloned_event.function);
1004        assert_eq!(event_without_lease.device_id, cloned_event.device_id);
1005        assert!(cloned_event.wake_lease.is_none());
1006    }
1007}