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