settings/
lib.rs

1// Copyright 2019 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 std::collections::HashSet;
6use std::rc::Rc;
7
8#[cfg(test)]
9use anyhow::format_err;
10use anyhow::{Context, Error};
11use audio::AudioInfoLoader;
12use audio::types::AudioInfo;
13use display::display_controller::DisplayInfoLoader;
14use fidl_fuchsia_io::DirectoryProxy;
15use fidl_fuchsia_settings::{
16    AccessibilityRequestStream, AudioRequestStream, DisplayRequestStream,
17    DoNotDisturbRequestStream, FactoryResetRequestStream, InputRequestStream, IntlRequestStream,
18    KeyboardRequestStream, LightRequestStream, NightModeRequestStream, PrivacyRequestStream,
19    SetupRequestStream,
20};
21use fidl_fuchsia_stash::StoreProxy;
22use fuchsia_component::client::connect_to_protocol;
23#[cfg(test)]
24use fuchsia_component::server::ProtocolConnector;
25use fuchsia_component::server::{ServiceFs, ServiceFsDir, ServiceObjLocal};
26use futures::channel::mpsc::{self, UnboundedReceiver, UnboundedSender};
27use futures::{StreamExt, TryStreamExt};
28#[cfg(test)]
29use log as _;
30use serde::Deserialize;
31use settings_common::config::default_settings::DefaultSetting;
32use settings_common::config::{AgentType, ControllerFlag};
33use settings_common::inspect::event::{
34    ExternalEventPublisher, SettingValuePublisher, UsageEvent, UsagePublisher,
35};
36use settings_common::inspect::listener_logger::ListenerInspectLogger;
37use settings_common::service_context::{ExternalServiceEvent, GenerateService, ServiceContext};
38use settings_do_not_disturb::do_not_disturb_controller::DoNotDisturbController;
39use settings_factory_reset::factory_reset_controller::FactoryResetController;
40use settings_input::input_controller::InputController;
41use settings_intl::intl_controller::IntlController;
42use settings_keyboard::keyboard_controller::KeyboardController;
43use settings_light::light_controller::LightController;
44use settings_night_mode::night_mode_controller::NightModeController;
45use settings_privacy::privacy_controller::PrivacyController;
46use settings_setup::setup_controller::SetupController;
47use settings_storage::device_storage::DeviceStorage;
48use settings_storage::fidl_storage::FidlStorage;
49use settings_storage::storage_factory::{FidlStorageFactory, StorageFactory};
50use {fidl_fuchsia_update_verify as fupdate, fuchsia_async as fasync};
51
52pub use display::display_configuration::DisplayConfiguration;
53pub use settings_input::input_device_configuration::InputConfiguration;
54pub use settings_light::light_hardware_configuration::LightHardwareConfiguration;
55
56use crate::accessibility::accessibility_controller::AccessibilityController;
57use crate::audio::Request as AudioRequest;
58use crate::audio::audio_controller::AudioController;
59use crate::base::SettingType;
60use crate::display::display_controller::{DisplayController, ExternalBrightnessControl};
61use crate::ingress::fidl;
62
63mod accessibility;
64pub mod audio;
65mod clock;
66pub mod display;
67mod storage_migrations;
68
69pub mod agent;
70pub mod base;
71pub mod ingress;
72pub(crate) mod migration;
73
74/// A common trigger for exiting.
75pub type ExitSender = futures::channel::mpsc::UnboundedSender<()>;
76
77/// Runtime defines where the environment will exist. Service is meant for
78/// production environments and will hydrate components to be discoverable as
79/// an environment service. Nested creates a service only usable in the scope
80/// of a test.
81#[derive(PartialEq)]
82enum Runtime {
83    Service,
84    #[cfg(test)]
85    Nested(&'static str),
86}
87
88#[derive(Debug, Default, Clone, Deserialize)]
89pub struct AgentConfiguration {
90    pub agent_types: HashSet<AgentType>,
91}
92
93#[derive(PartialEq, Debug, Clone, Deserialize)]
94pub struct EnabledInterfacesConfiguration {
95    pub interfaces: HashSet<fidl::InterfaceSpec>,
96}
97
98impl EnabledInterfacesConfiguration {
99    pub fn with_interfaces(interfaces: HashSet<fidl::InterfaceSpec>) -> Self {
100        Self { interfaces }
101    }
102}
103
104#[derive(Default, Debug, Clone, Deserialize)]
105pub struct ServiceFlags {
106    pub controller_flags: HashSet<ControllerFlag>,
107}
108
109#[derive(PartialEq, Debug, Default, Clone)]
110pub struct ServiceConfiguration {
111    agent_types: HashSet<AgentType>,
112    fidl_interfaces: HashSet<fidl::Interface>,
113    controller_flags: HashSet<ControllerFlag>,
114}
115
116impl ServiceConfiguration {
117    pub fn from(
118        agent_types: AgentConfiguration,
119        interfaces: EnabledInterfacesConfiguration,
120        flags: ServiceFlags,
121    ) -> Self {
122        let fidl_interfaces: HashSet<fidl::Interface> =
123            interfaces.interfaces.into_iter().map(|x| x.into()).collect();
124
125        Self {
126            agent_types: agent_types.agent_types,
127            fidl_interfaces,
128            controller_flags: flags.controller_flags,
129        }
130    }
131
132    fn set_fidl_interfaces(&mut self, interfaces: HashSet<fidl::Interface>) {
133        self.fidl_interfaces = interfaces;
134    }
135
136    fn set_controller_flags(&mut self, controller_flags: HashSet<ControllerFlag>) {
137        self.controller_flags = controller_flags;
138    }
139}
140
141/// Environment is handed back when an environment is spawned from the
142/// EnvironmentBuilder. A nested environment (if available) is returned,
143/// along with a receiver to be notified when initialization/setup is
144/// complete.
145#[cfg(test)]
146pub struct Environment {
147    pub connector: Option<ProtocolConnector>,
148    pub settings: HashSet<SettingType>,
149}
150
151#[cfg(test)]
152impl Environment {
153    pub fn new(
154        connector: Option<ProtocolConnector>,
155        settings: HashSet<SettingType>,
156    ) -> Environment {
157        Environment { connector, settings }
158    }
159}
160
161#[cfg(test)]
162fn init_storage_dir() -> DirectoryProxy {
163    let tempdir = tempfile::tempdir().expect("failed to create tempdir");
164    fuchsia_fs::directory::open_in_namespace(
165        tempdir.path().to_str().expect("tempdir path is not valid UTF-8"),
166        fuchsia_fs::PERM_READABLE | fuchsia_fs::PERM_WRITABLE,
167    )
168    .expect("failed to open connection to tempdir")
169}
170
171#[cfg(not(test))]
172fn init_storage_dir() -> DirectoryProxy {
173    panic!("migration dir must be specified");
174}
175
176/// The [EnvironmentBuilder] aggregates the parameters surrounding an [environment](Environment) and
177/// ultimately spawns an environment based on them.
178pub struct EnvironmentBuilder<T: StorageFactory<Storage = DeviceStorage>> {
179    configuration: Option<ServiceConfiguration>,
180    storage_factory: Rc<T>,
181    generate_service: Option<GenerateService>,
182    settings: Vec<SettingType>,
183    active_listener_inspect_logger: Option<Rc<ListenerInspectLogger>>,
184    storage_dir: Option<DirectoryProxy>,
185    store_proxy: Option<StoreProxy>,
186    fidl_storage_factory: Option<Rc<FidlStorageFactory>>,
187    display_configuration: Option<DefaultSetting<DisplayConfiguration, &'static str>>,
188    audio_configuration: Option<DefaultSetting<AudioInfo, &'static str>>,
189    input_configuration: Option<DefaultSetting<InputConfiguration, &'static str>>,
190    light_configuration: Option<DefaultSetting<LightHardwareConfiguration, &'static str>>,
191    media_buttons_event_txs: Vec<UnboundedSender<settings_media_buttons::Event>>,
192}
193
194impl<T: StorageFactory<Storage = DeviceStorage> + 'static> EnvironmentBuilder<T> {
195    /// Construct a new [EnvironmentBuilder] using `storage_factory` to construct the storage for
196    /// the future [Environment].
197    pub fn new(storage_factory: Rc<T>) -> Self {
198        EnvironmentBuilder {
199            configuration: None,
200            storage_factory,
201            generate_service: None,
202            settings: vec![],
203            active_listener_inspect_logger: None,
204            storage_dir: None,
205            store_proxy: None,
206            fidl_storage_factory: None,
207            display_configuration: None,
208            audio_configuration: None,
209            input_configuration: None,
210            light_configuration: None,
211            media_buttons_event_txs: vec![],
212        }
213    }
214
215    /// A service generator to be used as an overlay on the ServiceContext.
216    pub fn service(mut self, generate_service: GenerateService) -> Self {
217        self.generate_service = Some(generate_service);
218        self
219    }
220
221    /// A preset configuration to load preset parameters as a base. Note that this will override
222    /// any configuration modifications made by [EnvironmentBuilder::fidl_interface],
223    /// [EnvironmentBuilder::policies], and [EnvironmentBuilder::flags].
224    pub fn configuration(mut self, configuration: ServiceConfiguration) -> Self {
225        self.configuration = Some(configuration);
226        self
227    }
228
229    pub fn display_configuration(
230        mut self,
231        display_configuration: DefaultSetting<DisplayConfiguration, &'static str>,
232    ) -> Self {
233        self.display_configuration = Some(display_configuration);
234        self
235    }
236
237    pub fn audio_configuration(
238        mut self,
239        audio_configuration: DefaultSetting<AudioInfo, &'static str>,
240    ) -> Self {
241        self.audio_configuration = Some(audio_configuration);
242        self
243    }
244
245    pub fn input_configuration(
246        mut self,
247        input_configuration: DefaultSetting<InputConfiguration, &'static str>,
248    ) -> Self {
249        self.input_configuration = Some(input_configuration);
250        self
251    }
252
253    pub fn light_configuration(
254        mut self,
255        light_configuration: DefaultSetting<LightHardwareConfiguration, &'static str>,
256    ) -> Self {
257        self.light_configuration = Some(light_configuration);
258        self
259    }
260
261    /// Will override all fidl interfaces in the [ServiceConfiguration].
262    pub fn fidl_interfaces(mut self, interfaces: &[fidl::Interface]) -> Self {
263        if self.configuration.is_none() {
264            self.configuration = Some(ServiceConfiguration::default());
265        }
266
267        if let Some(c) = self.configuration.as_mut() {
268            c.set_fidl_interfaces(interfaces.iter().copied().collect());
269        }
270
271        self
272    }
273
274    /// Setting types to participate.
275    pub fn settings(mut self, settings: &[SettingType]) -> Self {
276        self.settings.extend(settings);
277
278        self
279    }
280
281    /// Setting types to participate with customized controllers.
282    pub fn flags(mut self, controller_flags: &[ControllerFlag]) -> Self {
283        if self.configuration.is_none() {
284            self.configuration = Some(ServiceConfiguration::default());
285        }
286
287        if let Some(c) = self.configuration.as_mut() {
288            c.set_controller_flags(controller_flags.iter().copied().collect());
289        }
290
291        self
292    }
293
294    /// Sets the inspect node for setting proxy inspect information and any required
295    /// inspect loggers.
296    pub fn listener_inspect_logger(
297        mut self,
298        active_listener_inspect_logger: Rc<ListenerInspectLogger>,
299    ) -> Self {
300        self.active_listener_inspect_logger = Some(active_listener_inspect_logger);
301        self
302    }
303
304    pub fn storage_dir(mut self, storage_dir: DirectoryProxy) -> Self {
305        self.storage_dir = Some(storage_dir);
306        self
307    }
308
309    pub fn store_proxy(mut self, store_proxy: StoreProxy) -> Self {
310        self.store_proxy = Some(store_proxy);
311        self
312    }
313
314    pub fn fidl_storage_factory(mut self, fidl_storage_factory: Rc<FidlStorageFactory>) -> Self {
315        self.fidl_storage_factory = Some(fidl_storage_factory);
316        self
317    }
318
319    pub fn media_buttons_event_txs(
320        mut self,
321        media_buttons_event_txs: Vec<UnboundedSender<settings_media_buttons::Event>>,
322    ) -> Self {
323        self.media_buttons_event_txs.extend(media_buttons_event_txs);
324        self
325    }
326
327    /// Prepares an environment so that it may be spawned. This ensures that all necessary
328    /// components are spawned and ready to handle events and FIDL requests.
329    async fn prepare_env(
330        mut self,
331        mut fs: ServiceFs<ServiceObjLocal<'_, ()>>,
332        runtime: Runtime,
333    ) -> Result<(ServiceFs<ServiceObjLocal<'_, ()>>, HashSet<SettingType>), Error> {
334        let mut service_dir = match runtime {
335            Runtime::Service => fs.dir("svc"),
336            #[cfg(test)]
337            Runtime::Nested(_) => fs.root_dir(),
338        };
339
340        let _ = service_dir.add_fidl_service(
341            move |mut stream: fupdate::ComponentOtaHealthCheckRequestStream| {
342                fasync::Task::local(async move {
343                    while let Some(fupdate::ComponentOtaHealthCheckRequest::GetHealthStatus {
344                        responder,
345                    }) = stream.try_next().await.expect("error running health check service")
346                    {
347                        // We always respond healthy because the health check can only be served
348                        // if the environment is able to spawn which in turn guarantees that no agents
349                        // have returned an error.
350                        responder
351                            .send(fupdate::HealthStatus::Healthy)
352                            .expect("failed to send health status");
353                    }
354                })
355                .detach();
356            },
357        );
358
359        let (agent_types, fidl_interfaces, flags) = match self.configuration {
360            Some(configuration) => (
361                configuration.agent_types,
362                configuration.fidl_interfaces,
363                configuration.controller_flags,
364            ),
365            _ => (HashSet::new(), HashSet::new(), HashSet::new()),
366        };
367
368        let mut settings: HashSet<_> = fidl_interfaces.into_iter().map(SettingType::from).collect();
369        settings.extend(self.settings);
370
371        let fidl_storage_factory = if let Some(factory) = self.fidl_storage_factory {
372            factory
373        } else {
374            let (migration_id, storage_dir) = if let Some(storage_dir) = self.storage_dir {
375                let store_proxy = self.store_proxy.unwrap_or_else(|| {
376                    let store_proxy = connect_to_protocol::<fidl_fuchsia_stash::StoreMarker>()
377                        .expect("failed to connect to stash");
378                    store_proxy
379                        .identify("setting_service")
380                        .expect("should be able to identify to stash");
381                    store_proxy
382                });
383
384                let migration_manager = storage_migrations::register_migrations(
385                    &settings,
386                    Clone::clone(&storage_dir),
387                    store_proxy,
388                )
389                .context("failed to register migrations")?;
390                let migration_id = match migration_manager.run_migrations().await {
391                    Ok(id) => {
392                        log::info!("migrated storage to {id:?}");
393                        id
394                    }
395                    Err((id, e)) => {
396                        log::error!("Settings migration failed: {e:?}");
397                        id
398                    }
399                };
400                let migration_id = migration_id.map(|migration| migration.migration_id);
401                (migration_id, storage_dir)
402            } else {
403                (None, init_storage_dir())
404            };
405
406            Rc::new(FidlStorageFactory::new(migration_id.unwrap_or(0), storage_dir))
407        };
408
409        let service_context = Rc::new(ServiceContext::new(self.generate_service));
410
411        let audio_info_loader = self.audio_configuration.map(AudioInfoLoader::new);
412        Self::initialize_storage(
413            &settings,
414            &*fidl_storage_factory,
415            &*self.storage_factory,
416            audio_info_loader.clone(),
417            self.display_configuration.map(DisplayInfoLoader::new),
418        )
419        .await;
420
421        let (external_event_tx, external_event_rx) = mpsc::unbounded();
422        let external_publisher = ExternalEventPublisher::new(external_event_tx);
423
424        let listener_logger = self
425            .active_listener_inspect_logger
426            .unwrap_or_else(|| Rc::new(ListenerInspectLogger::new()));
427
428        let RegistrationResult {
429            camera_watcher_event_txs,
430            media_buttons_event_txs,
431            setting_value_rx,
432            usage_event_rx,
433            audio_request_tx,
434            tasks,
435        } = Self::register_controllers(
436            &settings,
437            Rc::clone(&service_context),
438            fidl_storage_factory,
439            self.storage_factory,
440            &flags,
441            audio_info_loader,
442            self.input_configuration,
443            self.light_configuration,
444            &mut service_dir,
445            Rc::clone(&listener_logger),
446            external_publisher.clone(),
447        )
448        .await;
449        for task in tasks {
450            task.detach();
451        }
452
453        self.media_buttons_event_txs.extend(media_buttons_event_txs);
454
455        let agent_result = create_agents(
456            &settings,
457            agent_types,
458            camera_watcher_event_txs,
459            self.media_buttons_event_txs,
460            setting_value_rx,
461            external_event_rx,
462            external_publisher,
463            usage_event_rx,
464            audio_request_tx,
465        );
466
467        run_agents(agent_result, service_context).await;
468
469        Ok((fs, settings))
470    }
471
472    /// Spawn an [Environment] on the supplied [fasync::LocalExecutor] so that it may process
473    /// incoming FIDL requests.
474    pub fn spawn(
475        self,
476        mut executor: fasync::LocalExecutor,
477        fs: ServiceFs<ServiceObjLocal<'_, ()>>,
478    ) -> Result<(), Error> {
479        let (mut fs, ..) = executor
480            .run_singlethreaded(self.prepare_env(fs, Runtime::Service))
481            .context("Failed to prepare env")?;
482
483        let _ = fs.take_and_serve_directory_handle().expect("could not service directory handle");
484        executor.run_singlethreaded(fs.collect::<()>());
485        Ok(())
486    }
487
488    /// Spawn a nested [Environment] so that it can be used for tests.
489    #[cfg(test)]
490    pub async fn spawn_nested(self, env_name: &'static str) -> Result<Environment, Error> {
491        let (mut fs, entities) = self
492            .prepare_env(ServiceFs::new_local(), Runtime::Nested(env_name))
493            .await
494            .context("Failed to prepare env")?;
495        let connector = Some(fs.create_protocol_connector()?);
496        fasync::Task::local(fs.collect()).detach();
497
498        Ok(Environment::new(connector, entities))
499    }
500
501    /// Spawns a nested environment and returns the associated
502    /// ProtocolConnector. Note that this is a helper function that provides a
503    /// shortcut for calling EnvironmentBuilder::name() and
504    /// EnvironmentBuilder::spawn().
505    #[cfg(test)]
506    pub async fn spawn_and_get_protocol_connector(
507        self,
508        env_name: &'static str,
509    ) -> Result<ProtocolConnector, Error> {
510        let environment = self.spawn_nested(env_name).await?;
511
512        environment.connector.ok_or_else(|| format_err!("connector not created"))
513    }
514}
515
516struct RegistrationResult {
517    camera_watcher_event_txs: Vec<UnboundedSender<bool>>,
518    media_buttons_event_txs: Vec<UnboundedSender<settings_media_buttons::Event>>,
519    setting_value_rx: UnboundedReceiver<(&'static str, String)>,
520    usage_event_rx: UnboundedReceiver<UsageEvent>,
521    audio_request_tx: Option<UnboundedSender<AudioRequest>>,
522    tasks: Vec<fasync::Task<()>>,
523}
524
525impl<T: StorageFactory<Storage = DeviceStorage> + 'static> EnvironmentBuilder<T> {
526    async fn initialize_storage<F, D>(
527        components: &HashSet<SettingType>,
528        fidl_storage_factory: &F,
529        device_storage_factory: &D,
530        audio_info_loader: Option<AudioInfoLoader>,
531        display_loader: Option<DisplayInfoLoader>,
532    ) where
533        F: StorageFactory<Storage = FidlStorage>,
534        D: StorageFactory<Storage = DeviceStorage>,
535    {
536        if components.contains(&SettingType::Accessibility) {
537            device_storage_factory
538                .initialize::<AccessibilityController>()
539                .await
540                .expect("storage should still be initializing");
541        }
542
543        if components.contains(&SettingType::Audio) {
544            device_storage_factory
545                .initialize_with_loader::<AudioController, _>(
546                    audio_info_loader.expect("Audio storage requires audio configuration"),
547                )
548                .await
549                .expect("storage should still be initializing");
550        }
551
552        if components.contains(&SettingType::Display) {
553            device_storage_factory
554                .initialize_with_loader::<DisplayController, _>(
555                    display_loader.expect("Display storage requires display configuration"),
556                )
557                .await
558                .expect("storage should still be initializing");
559        }
560
561        if components.contains(&SettingType::DoNotDisturb) {
562            device_storage_factory
563                .initialize::<DoNotDisturbController>()
564                .await
565                .expect("storage should still be initializing");
566        }
567
568        if components.contains(&SettingType::FactoryReset) {
569            device_storage_factory
570                .initialize::<FactoryResetController>()
571                .await
572                .expect("storage should still be initializing");
573        }
574
575        if components.contains(&SettingType::Input) {
576            device_storage_factory
577                .initialize::<InputController>()
578                .await
579                .expect("storage should still be initializing");
580        }
581
582        if components.contains(&SettingType::Intl) {
583            device_storage_factory
584                .initialize::<IntlController>()
585                .await
586                .expect("storage should still be initializing");
587        }
588
589        if components.contains(&SettingType::Keyboard) {
590            device_storage_factory
591                .initialize::<KeyboardController>()
592                .await
593                .expect("storage should still be initializing");
594        }
595
596        if components.contains(&SettingType::Light) {
597            fidl_storage_factory
598                .initialize::<LightController>()
599                .await
600                .expect("storage should still be initializing");
601        }
602
603        if components.contains(&SettingType::NightMode) {
604            device_storage_factory
605                .initialize::<NightModeController>()
606                .await
607                .expect("storage should still be initializing");
608        }
609
610        if components.contains(&SettingType::Privacy) {
611            device_storage_factory
612                .initialize::<PrivacyController>()
613                .await
614                .expect("storage should still be initializing");
615        }
616
617        if components.contains(&SettingType::Setup) {
618            device_storage_factory
619                .initialize::<SetupController>()
620                .await
621                .expect("storage should still be initializing");
622        }
623    }
624
625    async fn register_controllers<F, D>(
626        components: &HashSet<SettingType>,
627        service_context: Rc<ServiceContext>,
628        fidl_storage_factory: Rc<F>,
629        device_storage_factory: Rc<D>,
630        controller_flags: &HashSet<ControllerFlag>,
631        audio_info_loader: Option<AudioInfoLoader>,
632        input_configuration: Option<DefaultSetting<InputConfiguration, &'static str>>,
633        light_configuration: Option<DefaultSetting<LightHardwareConfiguration, &'static str>>,
634        service_dir: &mut ServiceFsDir<'_, ServiceObjLocal<'_, ()>>,
635        listener_logger: Rc<ListenerInspectLogger>,
636        external_publisher: ExternalEventPublisher,
637    ) -> RegistrationResult
638    where
639        F: StorageFactory<Storage = FidlStorage>,
640        D: StorageFactory<Storage = DeviceStorage>,
641    {
642        let (setting_value_tx, setting_value_rx) = mpsc::unbounded();
643        let (usage_event_tx, usage_event_rx) = mpsc::unbounded();
644        let mut camera_watcher_event_txs = vec![];
645        let mut media_buttons_event_txs = vec![];
646        let mut tasks = vec![];
647
648        // Start handlers for all components.
649        if components.contains(&SettingType::Accessibility) {
650            let accessibility::SetupResult { mut accessibility_fidl_handler, task } =
651                accessibility::setup_accessibility_api(
652                    Rc::clone(&device_storage_factory),
653                    SettingValuePublisher::new(setting_value_tx.clone()),
654                    UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
655                )
656                .await;
657            tasks.push(task);
658            let _ = service_dir.add_fidl_service(move |stream: AccessibilityRequestStream| {
659                accessibility_fidl_handler.handle_stream(stream)
660            });
661        }
662
663        let audio_request_tx = if components.contains(&SettingType::Audio) {
664            let audio::SetupResult { mut audio_fidl_handler, request_tx: audio_request_tx, task } =
665                audio::setup_audio_api(
666                    Rc::clone(&service_context),
667                    audio_info_loader.expect("Audio controller requires audio configuration"),
668                    Rc::clone(&device_storage_factory),
669                    SettingValuePublisher::new(setting_value_tx.clone()),
670                    UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
671                    external_publisher.clone(),
672                )
673                .await;
674            tasks.push(task);
675            let _ = service_dir.add_fidl_service(move |stream: AudioRequestStream| {
676                audio_fidl_handler.handle_stream(stream)
677            });
678            Some(audio_request_tx)
679        } else {
680            None
681        };
682
683        if components.contains(&SettingType::Display) {
684            let result = if controller_flags.contains(&ControllerFlag::ExternalBrightnessControl) {
685                display::setup_display_api::<D, ExternalBrightnessControl>(
686                    &*service_context,
687                    Rc::clone(&device_storage_factory),
688                    SettingValuePublisher::new(setting_value_tx.clone()),
689                    UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
690                    external_publisher.clone(),
691                )
692                .await
693            } else {
694                display::setup_display_api::<D, ()>(
695                    &*service_context,
696                    Rc::clone(&device_storage_factory),
697                    SettingValuePublisher::new(setting_value_tx.clone()),
698                    UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
699                    external_publisher.clone(),
700                )
701                .await
702            };
703            match result {
704                Ok(display::SetupResult { mut display_fidl_handler, task }) => {
705                    tasks.push(task);
706                    let _ = service_dir.add_fidl_service(move |stream: DisplayRequestStream| {
707                        display_fidl_handler.handle_stream(stream)
708                    });
709                }
710                Err(e) => {
711                    log::error!("Failed to setup display api: {e:?}");
712                }
713            }
714        }
715
716        if components.contains(&SettingType::DoNotDisturb) {
717            let settings_do_not_disturb::SetupResult { mut do_not_disturb_fidl_handler, task } =
718                settings_do_not_disturb::setup_do_not_disturb_api(
719                    Rc::clone(&device_storage_factory),
720                    SettingValuePublisher::new(setting_value_tx.clone()),
721                    UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
722                )
723                .await;
724            tasks.push(task);
725            let _ = service_dir.add_fidl_service(move |stream: DoNotDisturbRequestStream| {
726                do_not_disturb_fidl_handler.handle_stream(stream)
727            });
728        }
729
730        if components.contains(&SettingType::FactoryReset) {
731            match settings_factory_reset::setup_factory_reset_api(
732                &*service_context,
733                Rc::clone(&device_storage_factory),
734                SettingValuePublisher::new(setting_value_tx.clone()),
735                UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
736                external_publisher.clone(),
737            )
738            .await
739            {
740                Ok(settings_factory_reset::SetupResult {
741                    mut factory_reset_fidl_handler,
742                    task,
743                }) => {
744                    tasks.push(task);
745                    let _ =
746                        service_dir.add_fidl_service(move |stream: FactoryResetRequestStream| {
747                            factory_reset_fidl_handler.handle_stream(stream)
748                        });
749                }
750                Err(e) => {
751                    log::error!("Failed to setup factory reset api: {e:?}");
752                }
753            }
754        }
755
756        if components.contains(&SettingType::Input) {
757            let mut input_configuration =
758                input_configuration.expect("Input controller requires an input configuration");
759            match settings_input::setup_input_api(
760                Rc::clone(&service_context),
761                &mut input_configuration,
762                Rc::clone(&device_storage_factory),
763                SettingValuePublisher::new(setting_value_tx.clone()),
764                UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
765                external_publisher.clone(),
766            )
767            .await
768            {
769                Ok(settings_input::SetupResult {
770                    mut input_fidl_handler,
771                    camera_watcher_event_tx,
772                    media_buttons_event_tx,
773                    task,
774                }) => {
775                    camera_watcher_event_txs.push(camera_watcher_event_tx);
776                    media_buttons_event_txs.push(media_buttons_event_tx);
777                    tasks.push(task);
778                    let _ = service_dir.add_fidl_service(move |stream: InputRequestStream| {
779                        input_fidl_handler.handle_stream(stream)
780                    });
781                }
782                Err(e) => {
783                    log::error!("Failed to setup input api: {e:?}");
784                }
785            }
786        }
787
788        if components.contains(&SettingType::Light) {
789            let mut light_configuration =
790                light_configuration.expect("Light controller requires a light configuration");
791            match settings_light::setup_light_api(
792                Rc::clone(&service_context),
793                &mut light_configuration,
794                fidl_storage_factory,
795                SettingValuePublisher::new(setting_value_tx.clone()),
796                UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
797                external_publisher.clone(),
798            )
799            .await
800            {
801                Ok(settings_light::SetupResult {
802                    mut light_fidl_handler,
803                    media_buttons_event_tx,
804                    task,
805                }) => {
806                    media_buttons_event_txs.push(media_buttons_event_tx);
807                    tasks.push(task);
808                    let _ = service_dir.add_fidl_service(move |stream: LightRequestStream| {
809                        light_fidl_handler.handle_stream(stream)
810                    });
811                }
812                Err(e) => {
813                    log::error!("Failed to setup light api: {e:?}");
814                }
815            }
816        }
817
818        if components.contains(&SettingType::Intl) {
819            let settings_intl::SetupResult { mut intl_fidl_handler, task } =
820                settings_intl::setup_intl_api(
821                    Rc::clone(&device_storage_factory),
822                    SettingValuePublisher::new(setting_value_tx.clone()),
823                    UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
824                )
825                .await;
826            tasks.push(task);
827            let _ = service_dir.add_fidl_service(move |stream: IntlRequestStream| {
828                intl_fidl_handler.handle_stream(stream)
829            });
830        }
831
832        if components.contains(&SettingType::Keyboard) {
833            let settings_keyboard::SetupResult { mut keyboard_fidl_handler, task } =
834                settings_keyboard::setup_keyboard_api(
835                    Rc::clone(&device_storage_factory),
836                    SettingValuePublisher::new(setting_value_tx.clone()),
837                    UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
838                )
839                .await;
840            tasks.push(task);
841            let _ = service_dir.add_fidl_service(move |stream: KeyboardRequestStream| {
842                keyboard_fidl_handler.handle_stream(stream)
843            });
844        }
845
846        if components.contains(&SettingType::NightMode) {
847            let settings_night_mode::SetupResult { mut night_mode_fidl_handler, task } =
848                settings_night_mode::setup_night_mode_api(
849                    Rc::clone(&device_storage_factory),
850                    SettingValuePublisher::new(setting_value_tx.clone()),
851                    UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
852                )
853                .await;
854            tasks.push(task);
855            let _ = service_dir.add_fidl_service(move |stream: NightModeRequestStream| {
856                night_mode_fidl_handler.handle_stream(stream)
857            });
858        }
859
860        if components.contains(&SettingType::Privacy) {
861            let settings_privacy::SetupResult { mut privacy_fidl_handler, task } =
862                settings_privacy::setup_privacy_api(
863                    Rc::clone(&device_storage_factory),
864                    SettingValuePublisher::new(setting_value_tx.clone()),
865                    UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
866                )
867                .await;
868            tasks.push(task);
869            let _ = service_dir.add_fidl_service(move |stream: PrivacyRequestStream| {
870                privacy_fidl_handler.handle_stream(stream)
871            });
872        }
873
874        if components.contains(&SettingType::Setup) {
875            let settings_setup::SetupResult { mut setup_fidl_handler, task } =
876                settings_setup::setup_setup_api(
877                    service_context,
878                    device_storage_factory,
879                    SettingValuePublisher::new(setting_value_tx),
880                    UsagePublisher::new(usage_event_tx, listener_logger),
881                    external_publisher,
882                )
883                .await;
884            tasks.push(task);
885            let _ = service_dir.add_fidl_service(move |stream: SetupRequestStream| {
886                setup_fidl_handler.handle_stream(stream)
887            });
888        }
889
890        RegistrationResult {
891            camera_watcher_event_txs,
892            media_buttons_event_txs,
893            setting_value_rx,
894            usage_event_rx,
895            audio_request_tx,
896            tasks,
897        }
898    }
899}
900
901struct AgentResult {
902    earcons_agent: Option<agent::earcons::agent::Agent>,
903    camera_watcher_agent: Option<settings_camera_watcher_agent::CameraWatcherAgent>,
904    media_buttons_agent: Option<settings_media_buttons_agent::MediaButtonsAgent>,
905    inspect_settings_values_agent: Option<agent::inspect::setting_values::AgentSetup>,
906    inspect_external_apis_agent: Option<agent::inspect::external_apis::ExternalApiInspectAgent>,
907    inspect_setting_proxy_agent: Option<agent::inspect::setting_proxy::SettingProxyInspectAgent>,
908    inspect_usages_agent: Option<agent::inspect::usage_counts::SettingTypeUsageInspectAgent>,
909}
910
911fn create_agents(
912    settings: &HashSet<SettingType>,
913    agent_types: HashSet<AgentType>,
914    camera_watcher_event_txs: Vec<UnboundedSender<bool>>,
915    media_buttons_event_txs: Vec<UnboundedSender<settings_media_buttons::Event>>,
916    setting_value_rx: UnboundedReceiver<(&'static str, String)>,
917    external_event_rx: UnboundedReceiver<ExternalServiceEvent>,
918    external_publisher: ExternalEventPublisher,
919    mut usage_router_rx: UnboundedReceiver<UsageEvent>,
920    audio_request_tx: Option<UnboundedSender<AudioRequest>>,
921) -> AgentResult {
922    let (proxy_event_tx, proxy_event_rx) = mpsc::unbounded();
923    let (usage_event_tx, usage_event_rx) = mpsc::unbounded();
924
925    // Route general inspect requests to specific inspect agents.
926    fasync::Task::local(async move {
927        while let Some(usage_event) = usage_router_rx.next().await {
928            let _ = proxy_event_tx.unbounded_send(usage_event.clone());
929            let _ = usage_event_tx.unbounded_send(usage_event);
930        }
931    })
932    .detach();
933    let earcons_agent = agent_types
934        .contains(&AgentType::Earcons)
935        .then(|| agent::earcons::agent::Agent::new(audio_request_tx, external_publisher.clone()));
936    let camera_watcher_agent = agent_types.contains(&AgentType::CameraWatcher).then(|| {
937        settings_camera_watcher_agent::CameraWatcherAgent::new(
938            camera_watcher_event_txs,
939            external_publisher.clone(),
940        )
941    });
942    let media_buttons_agent = agent_types.contains(&AgentType::MediaButtons).then(|| {
943        settings_media_buttons_agent::MediaButtonsAgent::new(
944            media_buttons_event_txs,
945            external_publisher,
946        )
947    });
948    let inspect_settings_values_agent = agent_types
949        .contains(&AgentType::InspectSettingValues)
950        .then(|| {
951            agent::inspect::setting_values::SettingValuesInspectAgent::new(
952                settings.iter().map(|setting| format!("{setting:?}")).collect(),
953                setting_value_rx,
954            )
955        })
956        .and_then(|opt| opt);
957    let inspect_external_apis_agent = agent_types
958        .contains(&AgentType::InspectExternalApis)
959        .then(|| agent::inspect::external_apis::ExternalApiInspectAgent::new(external_event_rx));
960    let inspect_setting_proxy_agent = agent_types
961        .contains(&AgentType::InspectSettingProxy)
962        .then(|| agent::inspect::setting_proxy::SettingProxyInspectAgent::new(proxy_event_rx));
963    let inspect_usages_agent = agent_types
964        .contains(&AgentType::InspectSettingTypeUsage)
965        .then(|| agent::inspect::usage_counts::SettingTypeUsageInspectAgent::new(usage_event_rx));
966
967    AgentResult {
968        earcons_agent,
969        camera_watcher_agent,
970        media_buttons_agent,
971        inspect_settings_values_agent,
972        inspect_external_apis_agent,
973        inspect_setting_proxy_agent,
974        inspect_usages_agent,
975    }
976}
977
978async fn run_agents(agent_result: AgentResult, service_context: Rc<ServiceContext>) {
979    if let Some(earcons_agent) = agent_result.earcons_agent {
980        earcons_agent.initialize(Rc::clone(&service_context)).await;
981    }
982
983    if let Some(inspect_settings_values_agent) = agent_result.inspect_settings_values_agent {
984        inspect_settings_values_agent.initialize(
985            #[cfg(test)]
986            None,
987        );
988    }
989
990    if let Some(inspect_external_apis_agent) = agent_result.inspect_external_apis_agent {
991        inspect_external_apis_agent.initialize();
992    }
993
994    if let Some(inspect_setting_proxy_agent) = agent_result.inspect_setting_proxy_agent {
995        inspect_setting_proxy_agent.initialize();
996    }
997
998    if let Some(inspect_usages_agent) = agent_result.inspect_usages_agent {
999        inspect_usages_agent.initialize();
1000    }
1001
1002    if let Some(camera_watcher_agent) = agent_result.camera_watcher_agent {
1003        if let Err(e) = camera_watcher_agent.spawn(&*service_context).await {
1004            log::error!("Failed to spawn camera watcher agent: {e:?}");
1005        }
1006    }
1007
1008    if let Some(media_buttons_agent) = agent_result.media_buttons_agent {
1009        if let Err(e) = media_buttons_agent.spawn(&*service_context).await {
1010            log::error!("Failed to spawn camera watcher agent: {e:?}");
1011        }
1012    }
1013}
1014
1015#[cfg(test)]
1016mod tests;