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