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