Skip to main content

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