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