Skip to main content

settings_input/
input_controller.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::input_device_configuration::InputConfiguration;
6use crate::input_fidl_handler::Publisher;
7use crate::types::{
8    DeviceState, DeviceStateSource, InputDevice, InputDeviceType, InputInfo, InputInfoSources,
9    InputState, Microphone,
10};
11use anyhow::{Context, Error};
12use fuchsia_async as fasync;
13use futures::StreamExt;
14use futures::channel::mpsc::UnboundedReceiver;
15use futures::channel::oneshot::Sender;
16use serde::{Deserialize, Serialize};
17use settings_camera::connect_to_camera;
18use settings_common::config::default_settings::DefaultSetting;
19use settings_common::inspect::event::{
20    ExternalEventPublisher, ResponseType, SettingValuePublisher,
21};
22use settings_common::service_context::ServiceContext;
23use settings_media_buttons::{Event, MediaButtons};
24use settings_storage::UpdateState;
25use settings_storage::device_storage::{DeviceStorage, DeviceStorageCompatible};
26use settings_storage::storage_factory::{NoneT, StorageAccess, StorageFactory};
27use std::borrow::Cow;
28use std::rc::Rc;
29
30pub(crate) const DEFAULT_CAMERA_NAME: &str = "camera";
31pub(crate) const DEFAULT_MIC_NAME: &str = "microphone";
32
33// The MAX_INPUT_DEVICES, in conjunction with the FIDL API's constraint of 128-byte names, ensures
34// that we don't exceed the 64 KiB default transport limit for the API (with some padding). It also
35// lessens the chance that we OOM while loading the device list from disk to memory.
36pub(crate) const MAX_INPUT_DEVICES: usize = fidl_fuchsia_settings::MAX_INPUT_DEVICES as usize;
37
38type UpdateInputResult = Result<Option<InputInfo>, InputError>;
39fn check_publish(
40    result: UpdateInputResult,
41    publish: impl Fn(InputInfo),
42) -> Result<Option<()>, InputError> {
43    result.map(|info| info.map(publish))
44}
45
46#[derive(thiserror::Error, Debug)]
47pub(crate) enum InputError {
48    #[error("Failed to initialize controller: {0:?}")]
49    InitFailure(Error),
50    #[error("Unsupported device type: {0:?}")]
51    Unsupported(InputDeviceType),
52    #[error("External failure for Input dependency: {0:?} request:{1:?} error:{2}")]
53    ExternalFailure(Cow<'static, str>, Cow<'static, str>, Cow<'static, str>),
54    #[error("Write failed for Input: {0:?}")]
55    WriteFailure(Error),
56    #[error("The maximum number of input devices has been reached.")]
57    MaximumInputDeviceLimitReached(Cow<'static, str>),
58    #[error("Unexpected error: {0}")]
59    UnexpectedError(Cow<'static, str>),
60}
61
62impl From<&InputError> for ResponseType {
63    fn from(error: &InputError) -> Self {
64        match error {
65            InputError::InitFailure(..) => ResponseType::InitFailure,
66            InputError::Unsupported(..) => ResponseType::UnsupportedError,
67            InputError::ExternalFailure(..) => ResponseType::ExternalFailure,
68            InputError::WriteFailure(..) => ResponseType::StorageFailure,
69            InputError::MaximumInputDeviceLimitReached(..) => {
70                ResponseType::MaximumInputDevicesReached
71            }
72            InputError::UnexpectedError(..) => ResponseType::UnexpectedError,
73        }
74    }
75}
76
77impl DeviceStorageCompatible for InputInfoSources {
78    type Loader = NoneT;
79    const KEY: &'static str = "input_info";
80
81    fn try_deserialize_from(value: &str) -> Result<Self, Error> {
82        Self::extract(value).or_else(|e| {
83            log::info!("Failed to deserialize InputInfoSources. Falling back to V2: {e:?}");
84            InputInfoSourcesV2::try_deserialize_from(value).map(Self::from)
85        })
86    }
87}
88
89impl From<InputInfoSourcesV2> for InputInfoSources {
90    fn from(v2: InputInfoSourcesV2) -> Self {
91        let mut input_state = v2.input_device_state;
92
93        // Convert the old states into an input device.
94        input_state.set_source_state(
95            InputDeviceType::MICROPHONE,
96            DEFAULT_MIC_NAME.to_string(),
97            DeviceStateSource::HARDWARE,
98            if v2.hw_microphone.muted { DeviceState::MUTED } else { DeviceState::AVAILABLE },
99        );
100        input_state.set_source_state(
101            InputDeviceType::MICROPHONE,
102            DEFAULT_MIC_NAME.to_string(),
103            DeviceStateSource::SOFTWARE,
104            if v2.sw_microphone.muted { DeviceState::MUTED } else { DeviceState::AVAILABLE },
105        );
106
107        InputInfoSources { input_device_state: input_state }
108    }
109}
110
111impl From<InputInfoSources> for InputInfo {
112    fn from(info: InputInfoSources) -> InputInfo {
113        InputInfo { input_device_state: info.input_device_state }
114    }
115}
116
117#[derive(PartialEq, Default, Debug, Clone, Serialize, Deserialize)]
118pub struct InputInfoSourcesV2 {
119    hw_microphone: Microphone,
120    sw_microphone: Microphone,
121    input_device_state: InputState,
122}
123
124impl DeviceStorageCompatible for InputInfoSourcesV2 {
125    type Loader = NoneT;
126    const KEY: &'static str = "input_info_sources_v2";
127
128    fn try_deserialize_from(value: &str) -> Result<Self, Error> {
129        Self::extract(value).or_else(|e| {
130            log::info!("Failed to deserialize InputInfoSourcesV2. Falling back to V1: {e:?}");
131            InputInfoSourcesV1::try_deserialize_from(value).map(Self::from)
132        })
133    }
134}
135
136impl From<InputInfoSourcesV1> for InputInfoSourcesV2 {
137    fn from(v1: InputInfoSourcesV1) -> Self {
138        InputInfoSourcesV2 {
139            hw_microphone: v1.hw_microphone,
140            sw_microphone: v1.sw_microphone,
141            input_device_state: InputState::new(),
142        }
143    }
144}
145
146#[derive(PartialEq, Default, Debug, Clone, Copy, Serialize, Deserialize)]
147pub struct InputInfoSourcesV1 {
148    pub hw_microphone: Microphone,
149    pub sw_microphone: Microphone,
150}
151
152impl DeviceStorageCompatible for InputInfoSourcesV1 {
153    type Loader = NoneT;
154    const KEY: &'static str = "input_info_sources_v1";
155}
156
157pub(crate) enum Request {
158    Set(Vec<InputDevice>, Sender<Result<(), InputError>>),
159}
160
161pub struct InputController {
162    service_context: Rc<ServiceContext>,
163    /// Persistent storage.
164    store: Rc<DeviceStorage>,
165
166    /// Local tracking of the input device states.
167    input_device_state: InputState,
168
169    /// Configuration for this device.
170    input_device_config: InputConfiguration,
171    publisher: Option<Publisher>,
172    setting_value_publisher: SettingValuePublisher<InputInfo>,
173    external_publisher: ExternalEventPublisher,
174}
175
176impl StorageAccess for InputController {
177    type Storage = DeviceStorage;
178    type Data = InputInfoSources;
179    const STORAGE_KEY: &'static str = InputInfoSources::KEY;
180}
181
182impl InputController {
183    pub(super) async fn new<F>(
184        service_context: Rc<ServiceContext>,
185        default_setting: &mut DefaultSetting<InputConfiguration, &'static str>,
186        storage_factory: Rc<F>,
187        setting_value_publisher: SettingValuePublisher<InputInfo>,
188        external_publisher: ExternalEventPublisher,
189    ) -> Result<Self, InputError>
190    where
191        F: StorageFactory<Storage = DeviceStorage>,
192    {
193        let input_device_config = default_setting
194            .load_default_value()
195            .context("Unable to load input device config")
196            .map_err(InputError::InitFailure)?
197            .expect("Input requires a configuration");
198        Ok(InputController::create_with_config(
199            service_context,
200            input_device_config,
201            &*storage_factory,
202            setting_value_publisher,
203            external_publisher,
204        )
205        .await)
206    }
207
208    /// Alternate constructor that allows specifying a configuration.
209    pub(crate) async fn create_with_config<F>(
210        service_context: Rc<ServiceContext>,
211        input_device_config: InputConfiguration,
212        storage_factory: &F,
213        setting_value_publisher: SettingValuePublisher<InputInfo>,
214        external_publisher: ExternalEventPublisher,
215    ) -> Self
216    where
217        F: StorageFactory<Storage = DeviceStorage>,
218    {
219        Self {
220            service_context,
221            store: storage_factory.get_store().await,
222            input_device_state: InputState::new(),
223            input_device_config,
224            publisher: None,
225            setting_value_publisher,
226            external_publisher,
227        }
228    }
229
230    // Whether the configuration for this device contains a specific |device_type|.
231    async fn has_input_device(&self, device_type: InputDeviceType) -> bool {
232        let input_device_config_state: InputState = self.input_device_config.clone().into();
233        input_device_config_state.device_types().contains(&device_type)
234    }
235
236    pub(super) fn register_publisher(&mut self, publisher: Publisher) {
237        self.publisher = Some(publisher);
238    }
239
240    fn publish(&self, info: InputInfo) {
241        let _ = self.setting_value_publisher.publish(&info);
242        if let Some(publisher) = self.publisher.as_ref() {
243            publisher.set(info);
244        }
245    }
246
247    pub(super) async fn handle(
248        mut self,
249        mut camera_event_rx: UnboundedReceiver<(bool, super::ResultSender)>,
250        mut media_buttons_event_rx: UnboundedReceiver<(Event, super::ResultSender)>,
251        mut request_rx: UnboundedReceiver<Request>,
252    ) -> fasync::Task<()> {
253        fasync::Task::local(async move {
254            let mut next_camera_event = camera_event_rx.next();
255            let mut next_media_buttons_event = media_buttons_event_rx.next();
256            let mut next_request = request_rx.next();
257            loop {
258                futures::select! {
259                    event = next_camera_event => {
260                        let Some((is_muted, response_tx)) = event else {
261                            continue;
262                        };
263                        next_camera_event = camera_event_rx.next();
264                        let res = self.handle_camera_event(is_muted).await;
265                        let _ = response_tx.send(res);
266                    }
267                    event = next_media_buttons_event => {
268                        let Some((Event::OnButton(buttons), response_tx)) = event else {
269                            continue;
270                        };
271                        next_media_buttons_event = media_buttons_event_rx.next();
272                        let res = self.handle_media_buttons_event(buttons).await;
273                        let _ = response_tx.send(res);
274                    }
275                    request = next_request => {
276                        let Some(request) = request else {
277                            continue;
278                        };
279                        next_request = request_rx.next();
280                        let Request::Set(input_devices, tx) = request;
281                        let res = check_publish(
282                            self.set_input_states(input_devices, DeviceStateSource::SOFTWARE).await,
283                            |info| self.publish(info)).map(|_|{});
284                        let _ = tx.send(res);
285                    }
286                }
287            }
288        })
289    }
290
291    async fn handle_camera_event(&mut self, is_muted: bool) -> Result<Option<()>, InputError> {
292        let stored_info = self.get_stored_info().await;
293        let old_state = Self::get_cam_sw_state_from(&stored_info.input_device_state)?;
294        if old_state.has_state(DeviceState::MUTED) != is_muted {
295            check_publish(
296                self.set_sw_camera_mute(is_muted, DEFAULT_CAMERA_NAME.to_string()).await,
297                |info| self.publish(info),
298            )
299        } else {
300            Ok(None)
301        }
302    }
303
304    async fn handle_media_buttons_event(
305        &mut self,
306        mut buttons: MediaButtons,
307    ) -> Result<Option<()>, InputError> {
308        if buttons.mic_mute.is_some() && !self.has_input_device(InputDeviceType::MICROPHONE).await {
309            buttons.set_mic_mute(None);
310        }
311        if buttons.camera_disable.is_some() && !self.has_input_device(InputDeviceType::CAMERA).await
312        {
313            buttons.set_camera_disable(None);
314        }
315        check_publish(self.set_hw_media_buttons_state(buttons).await, |info| self.publish(info))
316    }
317
318    // Wrapper around client.read() that fills in the config
319    // as the default value if the read value is empty. It may be empty
320    // after a migration from a previous InputInfoSources version
321    // or on pave.
322    async fn get_stored_info(&self) -> InputInfo {
323        let mut input_info = InputInfo::from(self.store.get::<InputInfo>().await);
324        if input_info.input_device_state.is_empty() {
325            input_info.input_device_state = self.input_device_config.clone().into();
326        }
327        input_info
328    }
329
330    /// Restores the input state.
331    pub(super) async fn restore(&mut self) -> Result<InputInfo, InputError> {
332        let input_info = self.get_stored_info().await;
333        self.input_device_state = input_info.input_device_state.clone();
334
335        if self.input_device_config.devices.iter().any(|d| d.device_type == InputDeviceType::CAMERA)
336        {
337            match self.get_cam_sw_state() {
338                Ok(state) => {
339                    // Camera setup failure should not prevent start of service. This also allows
340                    // clients to see that the camera may not be usable.
341                    if let Err(e) = self.push_cam_sw_state(state).await {
342                        log::error!("Unable to restore camera state: {e:?}");
343                        self.set_cam_err_state(state);
344                    }
345                }
346                Err(e) => {
347                    log::error!("Unable to load cam sw state: {e:?}");
348                    self.set_cam_err_state(DeviceState::ERROR);
349                }
350            }
351        }
352        Ok(input_info)
353    }
354
355    async fn set_sw_camera_mute(&mut self, disabled: bool, name: String) -> UpdateInputResult {
356        let mut input_info = self.get_stored_info().await;
357        input_info.input_device_state.set_source_state(
358            InputDeviceType::CAMERA,
359            name.clone(),
360            DeviceStateSource::SOFTWARE,
361            if disabled { DeviceState::MUTED } else { DeviceState::AVAILABLE },
362        );
363
364        self.input_device_state.set_source_state(
365            InputDeviceType::CAMERA,
366            name.clone(),
367            DeviceStateSource::SOFTWARE,
368            if disabled { DeviceState::MUTED } else { DeviceState::AVAILABLE },
369        );
370        self.store
371            .write(&input_info)
372            .await
373            .map(|state| (UpdateState::Updated == state).then_some(input_info))
374            .context("writing sw camera info")
375            .map_err(InputError::WriteFailure)
376    }
377
378    /// Sets the hardware mic/cam state from the muted states in `media_buttons`.
379    async fn set_hw_media_buttons_state(
380        &mut self,
381        media_buttons: MediaButtons,
382    ) -> UpdateInputResult {
383        let mut states_to_process = Vec::new();
384        if let Some(mic_mute) = media_buttons.mic_mute {
385            states_to_process.push((InputDeviceType::MICROPHONE, mic_mute));
386        }
387        if let Some(camera_disable) = media_buttons.camera_disable {
388            states_to_process.push((InputDeviceType::CAMERA, camera_disable));
389        }
390
391        let mut input_info = self.get_stored_info().await;
392
393        for (device_type, muted) in states_to_process.into_iter() {
394            // Fetch current state.
395            let hw_state_res = input_info.input_device_state.get_source_state(
396                device_type,
397                device_type.to_string(),
398                DeviceStateSource::HARDWARE,
399            );
400
401            let mut hw_state = hw_state_res.map_err(|err| {
402                InputError::UnexpectedError(
403                    format!("Could not fetch current hw mute state: {err:?}").into(),
404                )
405            })?;
406
407            if muted {
408                // Unset available and set muted.
409                hw_state &= !DeviceState::AVAILABLE;
410                hw_state |= DeviceState::MUTED;
411            } else {
412                // Set available and unset muted.
413                hw_state |= DeviceState::AVAILABLE;
414                hw_state &= !DeviceState::MUTED;
415            }
416
417            // Set the updated state.
418            input_info.input_device_state.set_source_state(
419                device_type,
420                device_type.to_string(),
421                DeviceStateSource::HARDWARE,
422                hw_state,
423            );
424            self.input_device_state.set_source_state(
425                device_type,
426                device_type.to_string(),
427                DeviceStateSource::HARDWARE,
428                hw_state,
429            );
430        }
431
432        self.store
433            .write(&input_info)
434            .await
435            .map(|state| (UpdateState::Updated == state).then_some(input_info))
436            .context("writing hw media buttons")
437            .map_err(InputError::WriteFailure)
438    }
439
440    /// Sets state for the given input devices.
441    async fn set_input_states(
442        &mut self,
443        input_devices: Vec<InputDevice>,
444        source: DeviceStateSource,
445    ) -> UpdateInputResult {
446        let mut input_info = self.get_stored_info().await;
447        let device_types = input_info.input_device_state.device_types();
448        let cam_state = self.get_cam_sw_state().ok();
449
450        // Firstly, do a validation pass to make sure the input_devices contain only valid devices,
451        // and any newly added devices are not going to exceed our maximum device limit.
452        let mut new_devices = Vec::new();
453        for input_device in input_devices.iter() {
454            if !device_types.contains(&input_device.device_type) {
455                return Err(InputError::Unsupported(input_device.device_type));
456            }
457
458            let already_exists = input_info
459                .input_device_state
460                .contains_device(input_device.device_type, &input_device.name);
461
462            let already_counted = new_devices
463                .iter()
464                .any(|(dt, name)| *dt == input_device.device_type && *name == &input_device.name);
465
466            if !already_exists && !already_counted {
467                new_devices.push((input_device.device_type, &input_device.name));
468            }
469        }
470
471        // Abort if applying these new devices would exceed the limit.
472        if input_info.input_device_state.total_devices() + new_devices.len() > MAX_INPUT_DEVICES {
473            log::error!(
474                "Maximum number of supported input devices ({MAX_INPUT_DEVICES}) has been reached."
475            );
476            return Err(InputError::MaximumInputDeviceLimitReached(
477                format!("Maximum limit of {MAX_INPUT_DEVICES} input devices has been reached.")
478                    .into(),
479            ));
480        }
481
482        // Update the function-scoped storage cache with the requested changes. This will allow us
483        // to determine if any camera state has changed, necessary for the logic which follows.
484        for input_device in &input_devices {
485            input_info.input_device_state.insert_device(input_device.clone(), source);
486        }
487
488        // If the device has a camera, it should successfully get the sw state, and
489        // push the state if it has changed. If the device does not have a camera,
490        // it should be None both here and above, and thus not detect a change.
491        let modified_cam_state = Self::get_cam_sw_state_from(&input_info.input_device_state).ok();
492        if cam_state != modified_cam_state
493            && let Some(state) = modified_cam_state
494        {
495            self.push_cam_sw_state(state).await?;
496        }
497
498        // All prerequisites are done, and camera changes are committed to the hardware. We can now
499        // finalize the update by updating our cache, and queue the write to storage.
500        for input_device in input_devices {
501            self.input_device_state.insert_device(input_device, source);
502        }
503
504        self.store
505            .write(&input_info)
506            .await
507            .map(|state| (UpdateState::Updated == state).then_some(input_info))
508            .context("writing input states")
509            .map_err(InputError::WriteFailure)
510    }
511
512    /// Pulls the software state of the camera from the given `input_state`.
513    fn get_cam_sw_state_from(input_state: &InputState) -> Result<DeviceState, InputError> {
514        input_state
515            .get_source_state(
516                InputDeviceType::CAMERA,
517                DEFAULT_CAMERA_NAME.to_string(),
518                DeviceStateSource::SOFTWARE,
519            )
520            .map_err(|e| {
521                InputError::UnexpectedError(
522                    format!("Could not find camera software state: {e:?}").into(),
523                )
524            })
525    }
526
527    /// Pulls the current software state of the camera from the device state.
528    fn get_cam_sw_state(&self) -> Result<DeviceState, InputError> {
529        Self::get_cam_sw_state_from(&self.input_device_state)
530    }
531
532    /// Set the camera state into an error condition.
533    fn set_cam_err_state(&mut self, mut state: DeviceState) {
534        state.set(DeviceState::ERROR, true);
535        self.input_device_state.set_source_state(
536            InputDeviceType::CAMERA,
537            DEFAULT_CAMERA_NAME.to_string(),
538            DeviceStateSource::SOFTWARE,
539            state,
540        )
541    }
542
543    /// Forwards the given software state to the camera3 api. Will first establish
544    /// a connection to the camera3.DeviceWatcher api. This function should only be called
545    /// when there is a camera included in the config. The config is used to populate the
546    /// stored input_info, so the input_info's input_device_state can be checked whether its
547    /// device_types contains Camera prior to calling this function.
548    async fn push_cam_sw_state(&mut self, cam_state: DeviceState) -> Result<(), InputError> {
549        let is_muted = cam_state.has_state(DeviceState::MUTED);
550
551        // Start up a connection to the camera device watcher and connect to the
552        // camera proxy using the id that is returned. The connection will drop out
553        // of scope after the mute state is sent.
554        let camera_proxy =
555            connect_to_camera(&self.service_context, self.external_publisher.clone())
556                .await
557                .map_err(|e| {
558                    InputError::UnexpectedError(
559                        format!("Could not connect to camera device: {e:?}").into(),
560                    )
561                })?;
562
563        camera_proxy.set_software_mute_state(is_muted).await.map_err(|e| {
564            InputError::ExternalFailure(
565                "fuchsia.camera3.Device".into(),
566                "SetSoftwareMuteState".into(),
567                format!("{e:?}").into(),
568            )
569        })
570    }
571}
572
573#[cfg(test)]
574mod tests {
575    use super::*;
576    use crate::input_device_configuration::{InputDeviceConfiguration, SourceState};
577    use fuchsia_async as fasync;
578    use fuchsia_inspect::component;
579    use futures::channel::mpsc;
580    use settings_common::inspect::config_logger::InspectConfigLogger;
581    use settings_common::service_context::ServiceContext;
582    use settings_test_common::storage::InMemoryStorageFactory;
583
584    #[fuchsia::test]
585    fn test_input_migration_v1_to_current() {
586        const MUTED_MIC: Microphone = Microphone { muted: true };
587        let v1 = InputInfoSourcesV1 { sw_microphone: MUTED_MIC, ..Default::default() };
588
589        let serialized_v1 = v1.serialize_to();
590        let current = InputInfoSources::try_deserialize_from(&serialized_v1)
591            .expect("deserialization should succeed");
592        let mut expected_input_state = InputState::new();
593        expected_input_state.set_source_state(
594            InputDeviceType::MICROPHONE,
595            DEFAULT_MIC_NAME.to_string(),
596            DeviceStateSource::SOFTWARE,
597            DeviceState::MUTED,
598        );
599        expected_input_state.set_source_state(
600            InputDeviceType::MICROPHONE,
601            DEFAULT_MIC_NAME.to_string(),
602            DeviceStateSource::HARDWARE,
603            DeviceState::AVAILABLE,
604        );
605        assert_eq!(current.input_device_state, expected_input_state);
606    }
607
608    #[fuchsia::test]
609    fn test_input_migration_v1_to_v2() {
610        const MUTED_MIC: Microphone = Microphone { muted: true };
611        let v1 = InputInfoSourcesV1 { sw_microphone: MUTED_MIC, ..Default::default() };
612
613        let serialized_v1 = v1.serialize_to();
614        let v2 = InputInfoSourcesV2::try_deserialize_from(&serialized_v1)
615            .expect("deserialization should succeed");
616
617        assert_eq!(v2.hw_microphone, Microphone { muted: false });
618        assert_eq!(v2.sw_microphone, MUTED_MIC);
619        assert_eq!(v2.input_device_state, InputState::new());
620    }
621
622    #[fuchsia::test]
623    fn test_input_migration_v2_to_current() {
624        const DEFAULT_CAMERA_NAME: &str = "camera";
625        const MUTED_MIC: Microphone = Microphone { muted: true };
626        let mut v2 = InputInfoSourcesV2::default();
627        v2.input_device_state.set_source_state(
628            InputDeviceType::CAMERA,
629            DEFAULT_CAMERA_NAME.to_string(),
630            DeviceStateSource::SOFTWARE,
631            DeviceState::AVAILABLE,
632        );
633        v2.input_device_state.set_source_state(
634            InputDeviceType::CAMERA,
635            DEFAULT_CAMERA_NAME.to_string(),
636            DeviceStateSource::HARDWARE,
637            DeviceState::MUTED,
638        );
639        v2.sw_microphone = MUTED_MIC;
640
641        let serialized_v2 = v2.serialize_to();
642        let current = InputInfoSources::try_deserialize_from(&serialized_v2)
643            .expect("deserialization should succeed");
644        let mut expected_input_state = InputState::new();
645
646        expected_input_state.set_source_state(
647            InputDeviceType::MICROPHONE,
648            DEFAULT_MIC_NAME.to_string(),
649            DeviceStateSource::SOFTWARE,
650            DeviceState::MUTED,
651        );
652        expected_input_state.set_source_state(
653            InputDeviceType::MICROPHONE,
654            DEFAULT_MIC_NAME.to_string(),
655            DeviceStateSource::HARDWARE,
656            DeviceState::AVAILABLE,
657        );
658        expected_input_state.set_source_state(
659            InputDeviceType::CAMERA,
660            DEFAULT_CAMERA_NAME.to_string(),
661            DeviceStateSource::SOFTWARE,
662            DeviceState::AVAILABLE,
663        );
664        expected_input_state.set_source_state(
665            InputDeviceType::CAMERA,
666            DEFAULT_CAMERA_NAME.to_string(),
667            DeviceStateSource::HARDWARE,
668            DeviceState::MUTED,
669        );
670
671        assert_eq!(current.input_device_state, expected_input_state);
672    }
673
674    #[fuchsia::test]
675    async fn test_camera_error_on_restore() {
676        let (event_tx, _event_rx) = mpsc::unbounded();
677        let external_publisher = ExternalEventPublisher::new(event_tx);
678        let storage_factory = InMemoryStorageFactory::new();
679        storage_factory
680            .initialize::<InputController>()
681            .await
682            .expect("controller should have impls");
683        let (value_tx, _value_rx) = mpsc::unbounded();
684        let setting_value_publisher = SettingValuePublisher::new(value_tx);
685        let mut controller: InputController =
686            InputController::create_with_config::<InMemoryStorageFactory>(
687                Rc::new(ServiceContext::new(None)),
688                InputConfiguration {
689                    devices: vec![InputDeviceConfiguration {
690                        device_name: DEFAULT_CAMERA_NAME.to_string(),
691                        device_type: InputDeviceType::CAMERA,
692                        source_states: vec![SourceState {
693                            source: DeviceStateSource::SOFTWARE,
694                            state: 0,
695                        }],
696                        mutable_toggle_state: 0,
697                    }],
698                },
699                &storage_factory,
700                setting_value_publisher,
701                external_publisher,
702            )
703            .await;
704
705        // Restore should pass.
706        let result = controller.restore().await;
707        assert!(result.is_ok());
708
709        // But the camera state should show an error.
710        let camera_state = controller
711            .input_device_state
712            .get_state(InputDeviceType::CAMERA, DEFAULT_CAMERA_NAME.to_string())
713            .unwrap();
714        assert!(camera_state.has_state(DeviceState::ERROR));
715    }
716
717    #[fasync::run_until_stalled(test)]
718    async fn test_controller_creation_with_default_config() {
719        let config_logger = InspectConfigLogger::new(component::inspector().root());
720        let mut default_setting = DefaultSetting::new(
721            Some(InputConfiguration::default()),
722            "/config/data/input_device_config.json",
723            Rc::new(std::sync::Mutex::new(config_logger)),
724        );
725
726        let (event_tx, _) = mpsc::unbounded();
727        let external_publisher = ExternalEventPublisher::new(event_tx);
728
729        let storage_factory = InMemoryStorageFactory::new();
730        storage_factory
731            .initialize::<InputController>()
732            .await
733            .expect("controller should have impls");
734        let (value_tx, _value_rx) = mpsc::unbounded();
735        let setting_value_publisher = SettingValuePublisher::new(value_tx);
736        let _controller = InputController::new(
737            Rc::new(ServiceContext::new(None)),
738            &mut default_setting,
739            Rc::new(storage_factory),
740            setting_value_publisher,
741            external_publisher,
742        )
743        .await
744        .expect("Should have controller");
745    }
746
747    #[fuchsia::test]
748    async fn test_set_input_states_limit() {
749        let (event_tx, _event_rx) = mpsc::unbounded();
750        let external_publisher = ExternalEventPublisher::new(event_tx);
751        let storage_factory = InMemoryStorageFactory::new();
752        storage_factory
753            .initialize::<InputController>()
754            .await
755            .expect("controller should have impls");
756        let (value_tx, _value_rx) = mpsc::unbounded();
757        let setting_value_publisher = SettingValuePublisher::new(value_tx);
758
759        let mut device_configs = Vec::new();
760        for i in 0..MAX_INPUT_DEVICES {
761            device_configs.push(InputDeviceConfiguration {
762                device_name: format!("mic{i}"),
763                device_type: InputDeviceType::MICROPHONE,
764                source_states: vec![SourceState { source: DeviceStateSource::SOFTWARE, state: 0 }],
765                mutable_toggle_state: 0,
766            });
767        }
768
769        let mut controller: InputController =
770            InputController::create_with_config::<InMemoryStorageFactory>(
771                Rc::new(ServiceContext::new(None)),
772                InputConfiguration { devices: device_configs },
773                &storage_factory,
774                setting_value_publisher,
775                external_publisher,
776            )
777            .await;
778
779        let _ = controller.restore().await;
780
781        let overflow_dev = InputDevice {
782            name: "mic_max_exceeded".to_string(),
783            device_type: InputDeviceType::MICROPHONE,
784            source_states: [(DeviceStateSource::SOFTWARE, DeviceState::AVAILABLE)].into(),
785            state: DeviceState::AVAILABLE,
786        };
787        let res =
788            controller.set_input_states(vec![overflow_dev], DeviceStateSource::SOFTWARE).await;
789        match res {
790            Err(InputError::MaximumInputDeviceLimitReached(msg)) => {
791                assert_eq!(
792                    msg,
793                    format!("Maximum limit of {MAX_INPUT_DEVICES} input devices has been reached.")
794                );
795            }
796            _ => panic!("Expected MaximumInputDeviceLimitReached, got {res:?}"),
797        }
798    }
799
800    async fn handle_camera3_device(
801        mut stream: fidl_fuchsia_camera3::DeviceRequestStream,
802        camera_muted: std::sync::Arc<std::sync::atomic::AtomicBool>,
803    ) {
804        use futures::StreamExt;
805        use std::sync::atomic::Ordering;
806        while let Some(Ok(req)) = stream.next().await {
807            if let fidl_fuchsia_camera3::DeviceRequest::SetSoftwareMuteState { muted, responder } =
808                req
809            {
810                camera_muted.store(muted, Ordering::Relaxed);
811                let _ = responder.send();
812            }
813        }
814    }
815
816    async fn handle_camera3_device_watcher(
817        mut stream: fidl_fuchsia_camera3::DeviceWatcherRequestStream,
818        camera_muted: std::sync::Arc<std::sync::atomic::AtomicBool>,
819    ) {
820        use futures::StreamExt;
821        while let Some(Ok(req)) = stream.next().await {
822            #[allow(unreachable_patterns)]
823            match req {
824                fidl_fuchsia_camera3::DeviceWatcherRequest::WatchDevices { responder } => {
825                    let _ = responder.send(&[fidl_fuchsia_camera3::WatchDevicesEvent::Added(1)]);
826                }
827                fidl_fuchsia_camera3::DeviceWatcherRequest::ConnectToDevice {
828                    id: _,
829                    request,
830                    control_handle: _,
831                } => {
832                    let camera_muted = camera_muted.clone();
833                    fasync::Task::local(handle_camera3_device(request.into_stream(), camera_muted))
834                        .detach();
835                }
836                _ => {}
837            }
838        }
839    }
840
841    #[fuchsia::test]
842    // This tests the bug documented in https://fxbug.dev/521503847. This test validates that
843    // the in-memory cached state of the Settings service doesn't commit changes prior to
844    // updating the hardware state. If that were to happen, the camera hardware could get "stuck"
845    // in its current state, while further updates are rejected due to the internal cache believing
846    // that the update is already applied.
847    async fn test_set_input_states_retry_on_failure() {
848        use fidl::endpoints::DiscoverableProtocolMarker;
849        use std::sync::Arc;
850        use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
851
852        let call_count = Arc::new(AtomicUsize::new(0));
853        let call_count_clone = call_count.clone();
854
855        let camera_muted = Arc::new(AtomicBool::new(false));
856        let camera_muted_clone = camera_muted.clone();
857
858        // Mock the camera service, rejecting the first call (count == 1) to simulate a failure.
859        let service_context = Rc::new(ServiceContext::new(Some(Box::new(
860            move |service_name: &str, channel: zx::Channel| {
861                let count = call_count_clone.fetch_add(1, Ordering::Relaxed);
862                let camera_muted_clone = camera_muted_clone.clone();
863                let service_name = service_name.to_string();
864                Box::pin(async move {
865                    if count == 1 {
866                        return Err(anyhow::Error::msg("injected failure"));
867                    }
868                    if service_name != fidl_fuchsia_camera3::DeviceWatcherMarker::PROTOCOL_NAME {
869                        return Err(anyhow::Error::msg("unsupported service"));
870                    }
871                    let stream = fidl::endpoints::ServerEnd::<
872                        fidl_fuchsia_camera3::DeviceWatcherMarker,
873                    >::new(channel)
874                    .into_stream();
875                    fasync::Task::local(handle_camera3_device_watcher(stream, camera_muted_clone))
876                        .detach();
877                    Ok(())
878                })
879            },
880        ))));
881
882        // Initialize the mocked "persistent" storage.
883        let storage_factory = InMemoryStorageFactory::new();
884        storage_factory
885            .initialize::<InputController>()
886            .await
887            .expect("controller should have impls");
888        let (value_tx, _value_rx) = mpsc::unbounded();
889        let setting_value_publisher = SettingValuePublisher::new(value_tx);
890        let (event_tx, _event_rx) = mpsc::unbounded();
891        let external_publisher = ExternalEventPublisher::new(event_tx);
892
893        let mut controller = InputController::create_with_config::<InMemoryStorageFactory>(
894            service_context,
895            InputConfiguration {
896                devices: vec![InputDeviceConfiguration {
897                    device_name: DEFAULT_CAMERA_NAME.to_string(),
898                    device_type: InputDeviceType::CAMERA,
899                    source_states: vec![SourceState {
900                        source: DeviceStateSource::SOFTWARE,
901                        state: 0, // AVAILABLE
902                    }],
903                    mutable_toggle_state: 0,
904                }],
905            },
906            &storage_factory,
907            setting_value_publisher,
908            external_publisher,
909        )
910        .await;
911
912        let _ = controller.restore().await;
913
914        // Verify initial state is AVAILABLE (not muted).
915        let camera_state = controller
916            .input_device_state
917            .get_state(InputDeviceType::CAMERA, DEFAULT_CAMERA_NAME.to_string())
918            .unwrap();
919        assert!(!camera_state.has_state(DeviceState::MUTED));
920
921        // Create a request to MUTE the camera. The hardware API call will fail on this request,
922        // due to the previously configured mock camera service.
923        let mute_device = InputDevice {
924            name: DEFAULT_CAMERA_NAME.to_string(),
925            device_type: InputDeviceType::CAMERA,
926            source_states: [(DeviceStateSource::SOFTWARE, DeviceState::MUTED)].into(),
927            state: DeviceState::MUTED,
928        };
929
930        let res = controller
931            .set_input_states(vec![mute_device.clone()], DeviceStateSource::SOFTWARE)
932            .await;
933        assert!(res.is_err());
934        assert_eq!(call_count.load(Ordering::Relaxed), 2);
935        assert!(!camera_muted.load(Ordering::Relaxed));
936
937        // Attempt to mute again. If the bug this test tracks is present, this will skip
938        // push_cam_sw_state and return Ok, because the service thinks the state is already MUTED
939        // due to the in-memory state being updated despite the hardware update failing.
940        let res2 =
941            controller.set_input_states(vec![mute_device], DeviceStateSource::SOFTWARE).await;
942
943        // If the bug is fixed, we expect that the camera service will have been called again, the
944        // result was okay and the mute state was properly updated.
945        assert_eq!(call_count.load(Ordering::Relaxed), 3);
946        assert!(res2.is_ok());
947        assert!(camera_muted.load(Ordering::Relaxed));
948    }
949}