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::{HashMap, HashSet};
6use std::rc::Rc;
7use std::sync::atomic::AtomicU64;
8
9#[cfg(test)]
10use anyhow::format_err;
11use anyhow::{Context, Error};
12use audio::AudioInfoLoader;
13use audio::types::AudioInfo;
14use display::display_controller::DisplayInfoLoader;
15use fidl_fuchsia_io::DirectoryProxy;
16use fidl_fuchsia_settings::{
17    IntlRequestStream, KeyboardRequestStream, LightRequestStream, NightModeRequestStream,
18    PrivacyRequestStream, 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 fuchsia_inspect::component;
26use futures::channel::mpsc::{self, UnboundedReceiver, UnboundedSender};
27use futures::lock::Mutex;
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::{
38    ExternalServiceEvent, GenerateService, ServiceContext as CommonServiceContext,
39};
40use settings_light::light_controller::LightController;
41use settings_storage::device_storage::DeviceStorage;
42use settings_storage::fidl_storage::FidlStorage;
43use settings_storage::storage_factory::{FidlStorageFactory, StorageFactory};
44use zx::MonotonicDuration;
45use {fidl_fuchsia_update_verify as fupdate, fuchsia_async as fasync};
46
47pub use display::display_configuration::DisplayConfiguration;
48pub use handler::setting_proxy_inspect_info::SettingProxyInspectInfo;
49pub use input::input_device_configuration::InputConfiguration;
50use serde::Deserialize;
51pub use service::{Address, Payload};
52pub use settings_light::light_hardware_configuration::LightHardwareConfiguration;
53
54use crate::accessibility::accessibility_controller::AccessibilityController;
55use crate::agent::authority::Authority;
56use crate::agent::{AgentCreator, Lifespan};
57use crate::audio::audio_controller::AudioController;
58use crate::base::{Dependency, Entity, SettingType};
59use crate::display::display_controller::{DisplayController, ExternalBrightnessControl};
60use crate::do_not_disturb::do_not_disturb_controller::DoNotDisturbController;
61use crate::factory_reset::factory_reset_controller::FactoryResetController;
62use crate::handler::base::GenerateHandler;
63use crate::handler::setting_handler::persist::Handler as DataHandler;
64use crate::handler::setting_handler_factory_impl::SettingHandlerFactoryImpl;
65use crate::handler::setting_proxy::SettingProxy;
66use crate::ingress::fidl;
67use crate::ingress::registration::Registrant;
68use crate::input::input_controller::InputController;
69use crate::intl::intl_controller::IntlController;
70use crate::job::manager::Manager;
71use crate::job::source::Seeder;
72use crate::keyboard::keyboard_controller::KeyboardController;
73use crate::night_mode::night_mode_controller::NightModeController;
74use crate::privacy::privacy_controller::PrivacyController;
75use crate::service::message::Delegate;
76use crate::service_context::ServiceContext;
77use crate::setup::setup_controller::SetupController;
78
79mod accessibility;
80pub mod audio;
81mod clock;
82pub mod display;
83mod do_not_disturb;
84mod event;
85mod factory_reset;
86pub mod input;
87mod intl;
88mod job;
89mod keyboard;
90mod night_mode;
91mod privacy;
92mod service;
93mod setup;
94mod storage_migrations;
95
96pub mod agent;
97pub mod base;
98pub mod config;
99pub mod handler;
100pub mod ingress;
101pub mod inspect;
102pub mod message;
103pub(crate) mod migration;
104pub mod service_context;
105pub mod storage;
106pub mod trace;
107
108/// This value represents the duration the proxy will wait after the last request
109/// before initiating the teardown of the controller. If a request is received
110/// before the timeout triggers, then the timeout will be canceled.
111// The value of 5 seconds was chosen arbitrarily to allow some time between manual
112// button presses that occurs for some settings.
113pub(crate) const DEFAULT_TEARDOWN_TIMEOUT: MonotonicDuration = MonotonicDuration::from_seconds(5);
114const DEFAULT_SETTING_PROXY_MAX_ATTEMPTS: u64 = 3;
115const DEFAULT_SETTING_PROXY_RESPONSE_TIMEOUT_MS: i64 = 10_000;
116
117/// A common trigger for exiting.
118pub type ExitSender = futures::channel::mpsc::UnboundedSender<()>;
119
120/// Runtime defines where the environment will exist. Service is meant for
121/// production environments and will hydrate components to be discoverable as
122/// an environment service. Nested creates a service only usable in the scope
123/// of a test.
124#[derive(PartialEq)]
125enum Runtime {
126    Service,
127    #[cfg(test)]
128    Nested(&'static str),
129}
130
131#[derive(Debug, Default, Clone, Deserialize)]
132pub struct AgentConfiguration {
133    pub agent_types: HashSet<AgentType>,
134}
135
136#[derive(PartialEq, Debug, Clone, Deserialize)]
137pub struct EnabledInterfacesConfiguration {
138    pub interfaces: HashSet<fidl::InterfaceSpec>,
139}
140
141impl EnabledInterfacesConfiguration {
142    pub fn with_interfaces(interfaces: HashSet<fidl::InterfaceSpec>) -> Self {
143        Self { interfaces }
144    }
145}
146
147#[derive(Default, Debug, Clone, Deserialize)]
148pub struct ServiceFlags {
149    pub controller_flags: HashSet<ControllerFlag>,
150}
151
152#[derive(PartialEq, Debug, Default, Clone)]
153pub struct ServiceConfiguration {
154    agent_types: HashSet<AgentType>,
155    fidl_interfaces: HashSet<fidl::Interface>,
156    controller_flags: HashSet<ControllerFlag>,
157}
158
159impl ServiceConfiguration {
160    pub fn from(
161        agent_types: AgentConfiguration,
162        interfaces: EnabledInterfacesConfiguration,
163        flags: ServiceFlags,
164    ) -> Self {
165        let fidl_interfaces: HashSet<fidl::Interface> =
166            interfaces.interfaces.into_iter().map(|x| x.into()).collect();
167
168        Self {
169            agent_types: agent_types.agent_types,
170            fidl_interfaces,
171            controller_flags: flags.controller_flags,
172        }
173    }
174
175    fn set_fidl_interfaces(&mut self, interfaces: HashSet<fidl::Interface>) {
176        self.fidl_interfaces = interfaces;
177    }
178
179    fn set_controller_flags(&mut self, controller_flags: HashSet<ControllerFlag>) {
180        self.controller_flags = controller_flags;
181    }
182}
183
184/// Environment is handed back when an environment is spawned from the
185/// EnvironmentBuilder. A nested environment (if available) is returned,
186/// along with a receiver to be notified when initialization/setup is
187/// complete.
188#[cfg(test)]
189pub struct Environment {
190    pub connector: Option<ProtocolConnector>,
191    pub delegate: Delegate,
192    pub entities: HashSet<Entity>,
193    pub job_seeder: Seeder,
194}
195
196#[cfg(test)]
197impl Environment {
198    pub fn new(
199        connector: Option<ProtocolConnector>,
200        delegate: Delegate,
201        job_seeder: Seeder,
202        entities: HashSet<Entity>,
203    ) -> Environment {
204        Environment { connector, delegate, job_seeder, entities }
205    }
206}
207
208#[cfg(test)]
209fn init_storage_dir() -> DirectoryProxy {
210    let tempdir = tempfile::tempdir().expect("failed to create tempdir");
211    fuchsia_fs::directory::open_in_namespace(
212        tempdir.path().to_str().expect("tempdir path is not valid UTF-8"),
213        fuchsia_fs::PERM_READABLE | fuchsia_fs::PERM_WRITABLE,
214    )
215    .expect("failed to open connection to tempdir")
216}
217
218#[cfg(not(test))]
219fn init_storage_dir() -> DirectoryProxy {
220    panic!("migration dir must be specified");
221}
222
223/// The [EnvironmentBuilder] aggregates the parameters surrounding an [environment](Environment) and
224/// ultimately spawns an environment based on them.
225pub struct EnvironmentBuilder<'a, T: StorageFactory<Storage = DeviceStorage>> {
226    configuration: Option<ServiceConfiguration>,
227    agent_blueprints: Vec<AgentCreator>,
228    event_subscriber_blueprints: Vec<event::subscriber::BlueprintHandle>,
229    storage_factory: Rc<T>,
230    generate_service: Option<GenerateService>,
231    registrants: Vec<Registrant>,
232    settings: Vec<SettingType>,
233    handlers: HashMap<SettingType, GenerateHandler>,
234    setting_proxy_inspect_info: Option<&'a fuchsia_inspect::Node>,
235    active_listener_inspect_logger: Option<Rc<ListenerInspectLogger>>,
236    storage_dir: Option<DirectoryProxy>,
237    store_proxy: Option<StoreProxy>,
238    fidl_storage_factory: Option<Rc<FidlStorageFactory>>,
239    display_configuration: Option<DefaultSetting<DisplayConfiguration, &'static str>>,
240    audio_configuration: Option<DefaultSetting<AudioInfo, &'static str>>,
241    input_configuration: Option<DefaultSetting<InputConfiguration, &'static str>>,
242    light_configuration: Option<DefaultSetting<LightHardwareConfiguration, &'static str>>,
243    media_buttons_event_txs: Vec<UnboundedSender<settings_media_buttons::Event>>,
244}
245
246impl<'a, T: StorageFactory<Storage = DeviceStorage> + 'static> EnvironmentBuilder<'a, T> {
247    /// Construct a new [EnvironmentBuilder] using `storage_factory` to construct the storage for
248    /// the future [Environment].
249    pub fn new(storage_factory: Rc<T>) -> Self {
250        EnvironmentBuilder {
251            configuration: None,
252            agent_blueprints: vec![],
253            event_subscriber_blueprints: vec![],
254            storage_factory,
255            generate_service: None,
256            handlers: HashMap::new(),
257            registrants: vec![],
258            settings: vec![],
259            setting_proxy_inspect_info: None,
260            active_listener_inspect_logger: None,
261            storage_dir: None,
262            store_proxy: None,
263            fidl_storage_factory: None,
264            display_configuration: None,
265            audio_configuration: None,
266            input_configuration: None,
267            light_configuration: None,
268            media_buttons_event_txs: vec![],
269        }
270    }
271
272    /// Overrides the default [GenerateHandler] for a specific [SettingType].
273    pub fn handler(mut self, setting_type: SettingType, generate_handler: GenerateHandler) -> Self {
274        // Ignore the old handler result.
275        let _ = self.handlers.insert(setting_type, generate_handler);
276        self
277    }
278
279    /// A service generator to be used as an overlay on the ServiceContext.
280    pub fn service(mut self, generate_service: GenerateService) -> Self {
281        self.generate_service = Some(generate_service);
282        self
283    }
284
285    /// A preset configuration to load preset parameters as a base. Note that this will override
286    /// any configuration modifications made by [EnvironmentBuilder::fidl_interface],
287    /// [EnvironmentBuilder::policies], and [EnvironmentBuilder::flags].
288    pub fn configuration(mut self, configuration: ServiceConfiguration) -> Self {
289        self.configuration = Some(configuration);
290        self
291    }
292
293    pub fn display_configuration(
294        mut self,
295        display_configuration: DefaultSetting<DisplayConfiguration, &'static str>,
296    ) -> Self {
297        self.display_configuration = Some(display_configuration);
298        self
299    }
300
301    pub fn audio_configuration(
302        mut self,
303        audio_configuration: DefaultSetting<AudioInfo, &'static str>,
304    ) -> Self {
305        self.audio_configuration = Some(audio_configuration);
306        self
307    }
308
309    pub fn input_configuration(
310        mut self,
311        input_configuration: DefaultSetting<InputConfiguration, &'static str>,
312    ) -> Self {
313        self.input_configuration = Some(input_configuration);
314        self
315    }
316
317    pub fn light_configuration(
318        mut self,
319        light_configuration: DefaultSetting<LightHardwareConfiguration, &'static str>,
320    ) -> Self {
321        self.light_configuration = Some(light_configuration);
322        self
323    }
324
325    /// Will override all fidl interfaces in the [ServiceConfiguration].
326    pub fn fidl_interfaces(mut self, interfaces: &[fidl::Interface]) -> Self {
327        if self.configuration.is_none() {
328            self.configuration = Some(ServiceConfiguration::default());
329        }
330
331        if let Some(c) = self.configuration.as_mut() {
332            c.set_fidl_interfaces(interfaces.iter().copied().collect());
333        }
334
335        self
336    }
337
338    /// Appends the [Registrant]s to the list of registrants already configured.
339    pub fn registrants(mut self, mut registrants: Vec<Registrant>) -> Self {
340        self.registrants.append(&mut registrants);
341
342        self
343    }
344
345    /// Setting types to participate.
346    pub fn settings(mut self, settings: &[SettingType]) -> Self {
347        self.settings.extend(settings);
348
349        self
350    }
351
352    /// Setting types to participate with customized controllers.
353    pub fn flags(mut self, controller_flags: &[ControllerFlag]) -> Self {
354        if self.configuration.is_none() {
355            self.configuration = Some(ServiceConfiguration::default());
356        }
357
358        if let Some(c) = self.configuration.as_mut() {
359            c.set_controller_flags(controller_flags.iter().copied().collect());
360        }
361
362        self
363    }
364
365    /// Appends the supplied [AgentRegistrar]s to the list of agent registrars.
366    pub fn agents(mut self, mut registrars: Vec<AgentCreator>) -> Self {
367        self.agent_blueprints.append(&mut registrars);
368        self
369    }
370
371    /// Event subscribers to participate
372    pub fn event_subscribers(mut self, subscribers: &[event::subscriber::BlueprintHandle]) -> Self {
373        self.event_subscriber_blueprints.append(&mut subscribers.to_vec());
374        self
375    }
376
377    /// Sets the inspect node for setting proxy inspect information and any required
378    /// inspect loggers.
379    pub fn setting_proxy_inspect_info(
380        mut self,
381        setting_proxy_inspect_info: &'a fuchsia_inspect::Node,
382        active_listener_inspect_logger: Rc<ListenerInspectLogger>,
383    ) -> Self {
384        self.setting_proxy_inspect_info = Some(setting_proxy_inspect_info);
385        self.active_listener_inspect_logger = Some(active_listener_inspect_logger);
386        self
387    }
388
389    pub fn storage_dir(mut self, storage_dir: DirectoryProxy) -> Self {
390        self.storage_dir = Some(storage_dir);
391        self
392    }
393
394    pub fn store_proxy(mut self, store_proxy: StoreProxy) -> Self {
395        self.store_proxy = Some(store_proxy);
396        self
397    }
398
399    pub fn fidl_storage_factory(mut self, fidl_storage_factory: Rc<FidlStorageFactory>) -> Self {
400        self.fidl_storage_factory = Some(fidl_storage_factory);
401        self
402    }
403
404    pub fn media_buttons_event_txs(
405        mut self,
406        media_buttons_event_txs: Vec<UnboundedSender<settings_media_buttons::Event>>,
407    ) -> Self {
408        self.media_buttons_event_txs.extend(media_buttons_event_txs);
409        self
410    }
411
412    /// Prepares an environment so that it may be spawned. This ensures that all necessary
413    /// components are spawned and ready to handle events and FIDL requests.
414    async fn prepare_env(
415        mut self,
416        mut fs: ServiceFs<ServiceObjLocal<'_, ()>>,
417        runtime: Runtime,
418    ) -> Result<(ServiceFs<ServiceObjLocal<'_, ()>>, Delegate, Seeder, HashSet<Entity>), Error>
419    {
420        let mut service_dir = match runtime {
421            Runtime::Service => fs.dir("svc"),
422            #[cfg(test)]
423            Runtime::Nested(_) => fs.root_dir(),
424        };
425
426        let _ = service_dir.add_fidl_service(
427            move |mut stream: fupdate::ComponentOtaHealthCheckRequestStream| {
428                fasync::Task::local(async move {
429                    while let Some(fupdate::ComponentOtaHealthCheckRequest::GetHealthStatus {
430                        responder,
431                    }) = stream.try_next().await.expect("error running health check service")
432                    {
433                        // We always respond healthy because the health check can only be served
434                        // if the environment is able to spawn which in turn guarantees that no agents
435                        // have returned an error.
436                        responder
437                            .send(fupdate::HealthStatus::Healthy)
438                            .expect("failed to send health status");
439                    }
440                })
441                .detach();
442            },
443        );
444
445        // Define top level MessageHub for service communication.
446        let delegate = service::MessageHub::create_hub();
447
448        let (agent_types, fidl_interfaces, flags) = match self.configuration {
449            Some(configuration) => (
450                configuration.agent_types,
451                configuration.fidl_interfaces,
452                configuration.controller_flags,
453            ),
454            _ => (HashSet::new(), HashSet::new(), HashSet::new()),
455        };
456
457        self.registrants.extend(fidl_interfaces.into_iter().map(|x| x.registrant()));
458
459        let mut settings = HashSet::new();
460        settings.extend(self.settings);
461
462        for registrant in &self.registrants {
463            for dependency in registrant.get_dependencies() {
464                match dependency {
465                    Dependency::Entity(Entity::Handler(setting_type)) => {
466                        let _ = settings.insert(*setting_type);
467                    }
468                }
469            }
470        }
471
472        let fidl_storage_factory = if let Some(factory) = self.fidl_storage_factory {
473            factory
474        } else {
475            let (migration_id, storage_dir) = if let Some(storage_dir) = self.storage_dir {
476                let store_proxy = self.store_proxy.unwrap_or_else(|| {
477                    let store_proxy = connect_to_protocol::<fidl_fuchsia_stash::StoreMarker>()
478                        .expect("failed to connect to stash");
479                    store_proxy
480                        .identify("setting_service")
481                        .expect("should be able to identify to stash");
482                    store_proxy
483                });
484
485                let migration_manager = storage_migrations::register_migrations(
486                    &settings,
487                    Clone::clone(&storage_dir),
488                    store_proxy,
489                )
490                .context("failed to register migrations")?;
491                let migration_id = match migration_manager.run_migrations().await {
492                    Ok(id) => {
493                        log::info!("migrated storage to {id:?}");
494                        id
495                    }
496                    Err((id, e)) => {
497                        log::error!("Settings migration failed: {e:?}");
498                        id
499                    }
500                };
501                let migration_id = migration_id.map(|migration| migration.migration_id);
502                (migration_id, storage_dir)
503            } else {
504                (None, init_storage_dir())
505            };
506
507            Rc::new(FidlStorageFactory::new(migration_id.unwrap_or(0), storage_dir))
508        };
509
510        let common_service_context = Rc::new(CommonServiceContext::new(self.generate_service));
511        let service_context = Rc::new(ServiceContext::new_from_common(
512            Rc::clone(&common_service_context),
513            Some(delegate.clone()),
514        ));
515
516        let context_id_counter = Rc::new(AtomicU64::new(1));
517
518        let mut handler_factory = SettingHandlerFactoryImpl::new(
519            settings.clone(),
520            Rc::clone(&service_context),
521            context_id_counter.clone(),
522        );
523
524        Self::initialize_storage(&settings, &*fidl_storage_factory, &*self.storage_factory).await;
525
526        let (external_event_tx, external_event_rx) = mpsc::unbounded();
527        let external_publisher = ExternalEventPublisher::new(external_event_tx);
528
529        EnvironmentBuilder::register_setting_handlers(
530            &settings,
531            Rc::clone(&self.storage_factory),
532            &flags,
533            self.display_configuration.map(DisplayInfoLoader::new),
534            self.audio_configuration.map(AudioInfoLoader::new),
535            self.input_configuration,
536            &mut handler_factory,
537            external_publisher.clone(),
538        )
539        .await;
540
541        let listener_logger = self
542            .active_listener_inspect_logger
543            .unwrap_or_else(|| Rc::new(ListenerInspectLogger::new()));
544
545        let RegistrationResult {
546            camera_watcher_event_txs,
547            media_buttons_event_txs,
548            setting_value_rx,
549            usage_event_rx,
550            tasks,
551        } = Self::register_controllers(
552            &settings,
553            Rc::clone(&common_service_context),
554            fidl_storage_factory,
555            self.storage_factory,
556            self.light_configuration,
557            &mut service_dir,
558            Rc::clone(&listener_logger),
559            external_publisher.clone(),
560        )
561        .await;
562        for task in tasks {
563            task.detach();
564        }
565
566        self.media_buttons_event_txs.extend(media_buttons_event_txs);
567
568        // Override the configuration handlers with any custom handlers specified
569        // in the environment.
570        for (setting_type, handler) in self.handlers {
571            handler_factory.register(setting_type, handler);
572        }
573
574        let agent_blueprints = create_agent_blueprints(
575            agent_types,
576            self.agent_blueprints,
577            camera_watcher_event_txs,
578            self.media_buttons_event_txs,
579            setting_value_rx,
580            external_event_rx,
581            external_publisher,
582            usage_event_rx,
583        );
584
585        let job_manager_signature = Manager::spawn(&delegate).await;
586        let job_seeder = Seeder::new(&delegate, job_manager_signature).await;
587
588        let entities = create_environment(
589            service_dir,
590            delegate.clone(),
591            job_seeder.clone(),
592            settings,
593            self.registrants,
594            agent_blueprints,
595            self.event_subscriber_blueprints,
596            service_context,
597            Rc::new(Mutex::new(handler_factory)),
598            self.setting_proxy_inspect_info.unwrap_or_else(|| component::inspector().root()),
599            listener_logger,
600        )
601        .await
602        .context("Could not create environment")?;
603
604        Ok((fs, delegate, job_seeder, entities))
605    }
606
607    /// Spawn an [Environment] on the supplied [fasync::LocalExecutor] so that it may process
608    /// incoming FIDL requests.
609    pub fn spawn(
610        self,
611        mut executor: fasync::LocalExecutor,
612        fs: ServiceFs<ServiceObjLocal<'_, ()>>,
613    ) -> Result<(), Error> {
614        let (mut fs, ..) = executor
615            .run_singlethreaded(self.prepare_env(fs, Runtime::Service))
616            .context("Failed to prepare env")?;
617
618        let _ = fs.take_and_serve_directory_handle().expect("could not service directory handle");
619        executor.run_singlethreaded(fs.collect::<()>());
620        Ok(())
621    }
622
623    /// Spawn a nested [Environment] so that it can be used for tests.
624    #[cfg(test)]
625    pub async fn spawn_nested(self, env_name: &'static str) -> Result<Environment, Error> {
626        let (mut fs, delegate, job_seeder, entities) = self
627            .prepare_env(ServiceFs::new_local(), Runtime::Nested(env_name))
628            .await
629            .context("Failed to prepare env")?;
630        let connector = Some(fs.create_protocol_connector()?);
631        fasync::Task::local(fs.collect()).detach();
632
633        Ok(Environment::new(connector, delegate, job_seeder, entities))
634    }
635
636    /// Spawns a nested environment and returns the associated
637    /// ProtocolConnector. Note that this is a helper function that provides a
638    /// shortcut for calling EnvironmentBuilder::name() and
639    /// EnvironmentBuilder::spawn().
640    #[cfg(test)]
641    pub async fn spawn_and_get_protocol_connector(
642        self,
643        env_name: &'static str,
644    ) -> Result<ProtocolConnector, Error> {
645        let environment = self.spawn_nested(env_name).await?;
646
647        environment.connector.ok_or_else(|| format_err!("connector not created"))
648    }
649}
650
651struct RegistrationResult {
652    camera_watcher_event_txs: Vec<UnboundedSender<bool>>,
653    media_buttons_event_txs: Vec<UnboundedSender<settings_media_buttons::Event>>,
654    setting_value_rx: UnboundedReceiver<(&'static str, String)>,
655    usage_event_rx: UnboundedReceiver<UsageEvent>,
656    tasks: Vec<fasync::Task<()>>,
657}
658
659impl<'a, T: StorageFactory<Storage = DeviceStorage> + 'static> EnvironmentBuilder<'a, T> {
660    async fn initialize_storage<F, D>(
661        components: &HashSet<SettingType>,
662        fidl_storage_factory: &F,
663        device_storage_factory: &D,
664    ) where
665        F: StorageFactory<Storage = FidlStorage>,
666        D: StorageFactory<Storage = DeviceStorage>,
667    {
668        if components.contains(&SettingType::Intl) {
669            device_storage_factory
670                .initialize::<IntlController>()
671                .await
672                .expect("storage should still be initializing");
673        }
674
675        if components.contains(&SettingType::Keyboard) {
676            device_storage_factory
677                .initialize::<KeyboardController>()
678                .await
679                .expect("storage should still be initializing");
680        }
681
682        if components.contains(&SettingType::Light) {
683            fidl_storage_factory
684                .initialize::<LightController>()
685                .await
686                .expect("storage should still be initializing");
687        }
688
689        if components.contains(&SettingType::NightMode) {
690            device_storage_factory
691                .initialize::<NightModeController>()
692                .await
693                .expect("storage should still be initializing");
694        }
695
696        if components.contains(&SettingType::Privacy) {
697            device_storage_factory
698                .initialize::<PrivacyController>()
699                .await
700                .expect("storage should still be initializing");
701        }
702
703        if components.contains(&SettingType::Setup) {
704            device_storage_factory
705                .initialize::<SetupController>()
706                .await
707                .expect("storage should still be initializing");
708        }
709    }
710
711    async fn register_controllers<F, D>(
712        components: &HashSet<SettingType>,
713        service_context: Rc<CommonServiceContext>,
714        fidl_storage_factory: Rc<F>,
715        device_storage_factory: Rc<D>,
716        light_configuration: Option<DefaultSetting<LightHardwareConfiguration, &'static str>>,
717        service_dir: &mut ServiceFsDir<'_, ServiceObjLocal<'_, ()>>,
718        listener_logger: Rc<ListenerInspectLogger>,
719        external_publisher: ExternalEventPublisher,
720    ) -> RegistrationResult
721    where
722        F: StorageFactory<Storage = FidlStorage>,
723        D: StorageFactory<Storage = DeviceStorage>,
724    {
725        let (setting_value_tx, setting_value_rx) = mpsc::unbounded();
726        let (usage_event_tx, usage_event_rx) = mpsc::unbounded();
727        let camera_watcher_event_txs = vec![];
728        let mut media_buttons_event_txs = vec![];
729        let mut tasks = vec![];
730
731        // Start handlers for all components.
732        if components.contains(&SettingType::Light) {
733            let mut light_configuration =
734                light_configuration.expect("Light controller requires a light configuration");
735            match settings_light::setup_light_api(
736                Rc::clone(&service_context),
737                &mut light_configuration,
738                fidl_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(settings_light::SetupResult {
746                    mut light_fidl_handler,
747                    media_buttons_event_tx,
748                    task,
749                }) => {
750                    media_buttons_event_txs.push(media_buttons_event_tx);
751                    tasks.push(task);
752                    let _ = service_dir.add_fidl_service(move |stream: LightRequestStream| {
753                        light_fidl_handler.handle_stream(stream)
754                    });
755                }
756                Err(e) => {
757                    log::error!("Failed to setup light api: {e:?}");
758                }
759            }
760        }
761
762        if components.contains(&SettingType::Intl) {
763            let intl::SetupResult { mut intl_fidl_handler, task } = intl::setup_intl_api(
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            )
768            .await;
769            tasks.push(task);
770            let _ = service_dir.add_fidl_service(move |stream: IntlRequestStream| {
771                intl_fidl_handler.handle_stream(stream)
772            });
773        }
774
775        if components.contains(&SettingType::Keyboard) {
776            let keyboard::SetupResult { mut keyboard_fidl_handler, task } =
777                keyboard::setup_keyboard_api(
778                    Rc::clone(&device_storage_factory),
779                    SettingValuePublisher::new(setting_value_tx.clone()),
780                    UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
781                )
782                .await;
783            tasks.push(task);
784            let _ = service_dir.add_fidl_service(move |stream: KeyboardRequestStream| {
785                keyboard_fidl_handler.handle_stream(stream)
786            });
787        }
788
789        if components.contains(&SettingType::NightMode) {
790            let night_mode::SetupResult { mut night_mode_fidl_handler, task } =
791                night_mode::setup_night_mode_api(
792                    Rc::clone(&device_storage_factory),
793                    SettingValuePublisher::new(setting_value_tx.clone()),
794                    UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
795                )
796                .await;
797            tasks.push(task);
798            let _ = service_dir.add_fidl_service(move |stream: NightModeRequestStream| {
799                night_mode_fidl_handler.handle_stream(stream)
800            });
801        }
802
803        if components.contains(&SettingType::Privacy) {
804            let privacy::SetupResult { mut privacy_fidl_handler, task } =
805                privacy::setup_privacy_api(
806                    Rc::clone(&device_storage_factory),
807                    SettingValuePublisher::new(setting_value_tx.clone()),
808                    UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
809                )
810                .await;
811            tasks.push(task);
812            let _ = service_dir.add_fidl_service(move |stream: PrivacyRequestStream| {
813                privacy_fidl_handler.handle_stream(stream)
814            });
815        }
816
817        if components.contains(&SettingType::Setup) {
818            let setup::SetupResult { mut setup_fidl_handler, task } = setup::setup_setup_api(
819                service_context,
820                device_storage_factory,
821                SettingValuePublisher::new(setting_value_tx),
822                UsagePublisher::new(usage_event_tx, listener_logger),
823                external_publisher,
824            )
825            .await;
826            tasks.push(task);
827            let _ = service_dir.add_fidl_service(move |stream: SetupRequestStream| {
828                setup_fidl_handler.handle_stream(stream)
829            });
830        }
831
832        RegistrationResult {
833            camera_watcher_event_txs,
834            media_buttons_event_txs,
835            setting_value_rx,
836            usage_event_rx,
837            tasks,
838        }
839    }
840
841    /// Initializes storage and registers handler generation functions for the configured setting
842    /// types.
843    async fn register_setting_handlers(
844        components: &HashSet<SettingType>,
845        device_storage_factory: Rc<T>,
846        controller_flags: &HashSet<ControllerFlag>,
847        display_loader: Option<DisplayInfoLoader>,
848        audio_loader: Option<AudioInfoLoader>,
849        input_configuration: Option<DefaultSetting<InputConfiguration, &'static str>>,
850        factory_handle: &mut SettingHandlerFactoryImpl,
851        external_publisher: ExternalEventPublisher,
852    ) {
853        // Accessibility
854        if components.contains(&SettingType::Accessibility) {
855            device_storage_factory
856                .initialize::<AccessibilityController<T>>()
857                .await
858                .expect("storage should still be initializing");
859            let device_storage_factory = Rc::clone(&device_storage_factory);
860            factory_handle.register(
861                SettingType::Accessibility,
862                Box::new(move |context| {
863                    DataHandler::<AccessibilityController<T>>::spawn_with_async(
864                        context,
865                        Rc::clone(&device_storage_factory),
866                    )
867                }),
868            );
869        }
870
871        // Audio
872        if components.contains(&SettingType::Audio) {
873            let audio_loader = audio_loader.expect("Audio storage requires audio loader");
874            device_storage_factory
875                .initialize_with_loader::<AudioController<T>, _>(audio_loader.clone())
876                .await
877                .expect("storage should still be initializing");
878            let device_storage_factory = Rc::clone(&device_storage_factory);
879            factory_handle.register(
880                SettingType::Audio,
881                Box::new(move |context| {
882                    DataHandler::<AudioController<T>>::spawn_with_async(
883                        context,
884                        (Rc::clone(&device_storage_factory), audio_loader.clone()),
885                    )
886                }),
887            );
888        }
889
890        // Display
891        if components.contains(&SettingType::Display) {
892            device_storage_factory
893                .initialize_with_loader::<DisplayController<T>, _>(
894                    display_loader.expect("Display storage requires display loader"),
895                )
896                .await
897                .expect("storage should still be initializing");
898            let device_storage_factory = Rc::clone(&device_storage_factory);
899            let external_brightness_control =
900                controller_flags.contains(&ControllerFlag::ExternalBrightnessControl);
901            factory_handle.register(
902                SettingType::Display,
903                Box::new(
904                    move |context| {
905                        if external_brightness_control {
906                            DataHandler::<DisplayController<T, ExternalBrightnessControl>>::spawn_with_async(
907                                context,
908                                Rc::clone(&device_storage_factory))
909                        } else {
910                            DataHandler::<DisplayController<T>>::spawn_with_async(
911                                context,
912                                Rc::clone(&device_storage_factory))
913                        }
914                    }
915                ),
916            );
917        }
918
919        // Input
920        if components.contains(&SettingType::Input) {
921            let input_configuration = Rc::new(std::sync::Mutex::new(
922                input_configuration.expect("Input controller requires an input configuration"),
923            ));
924            device_storage_factory
925                .initialize::<InputController<T>>()
926                .await
927                .expect("storage should still be initializing");
928            let device_storage_factory = Rc::clone(&device_storage_factory);
929            factory_handle.register(
930                SettingType::Input,
931                Box::new(move |context| {
932                    DataHandler::<InputController<T>>::spawn_with_async(
933                        context,
934                        (
935                            Rc::clone(&device_storage_factory),
936                            Rc::clone(&input_configuration),
937                            external_publisher.clone(),
938                        ),
939                    )
940                }),
941            );
942        }
943
944        // Do not disturb
945        if components.contains(&SettingType::DoNotDisturb) {
946            device_storage_factory
947                .initialize::<DoNotDisturbController<T>>()
948                .await
949                .expect("storage should still be initializing");
950            let device_storage_factory = Rc::clone(&device_storage_factory);
951            factory_handle.register(
952                SettingType::DoNotDisturb,
953                Box::new(move |context| {
954                    DataHandler::<DoNotDisturbController<T>>::spawn_with_async(
955                        context,
956                        Rc::clone(&device_storage_factory),
957                    )
958                }),
959            );
960        }
961
962        // Factory Reset
963        if components.contains(&SettingType::FactoryReset) {
964            device_storage_factory
965                .initialize::<FactoryResetController<T>>()
966                .await
967                .expect("storage should still be initializing");
968            let device_storage_factory = Rc::clone(&device_storage_factory);
969            factory_handle.register(
970                SettingType::FactoryReset,
971                Box::new(move |context| {
972                    DataHandler::<FactoryResetController<T>>::spawn_with_async(
973                        context,
974                        Rc::clone(&device_storage_factory),
975                    )
976                }),
977            );
978        }
979    }
980}
981
982fn create_agent_blueprints(
983    agent_types: HashSet<AgentType>,
984    agent_blueprints: Vec<AgentCreator>,
985    camera_watcher_event_txs: Vec<UnboundedSender<bool>>,
986    media_buttons_event_txs: Vec<UnboundedSender<settings_media_buttons::Event>>,
987    setting_value_rx: UnboundedReceiver<(&'static str, String)>,
988    external_event_rx: UnboundedReceiver<ExternalServiceEvent>,
989    external_publisher: ExternalEventPublisher,
990    mut usage_router_rx: UnboundedReceiver<UsageEvent>,
991) -> Vec<AgentCreator> {
992    let (proxy_event_tx, proxy_event_rx) = mpsc::unbounded();
993    let (usage_event_tx, usage_event_rx) = mpsc::unbounded();
994
995    // Route general inspect requests to specific inspect agents.
996    fasync::Task::local(async move {
997        while let Some(usage_event) = usage_router_rx.next().await {
998            let _ = proxy_event_tx.unbounded_send(usage_event.clone());
999            let _ = usage_event_tx.unbounded_send(usage_event);
1000        }
1001    })
1002    .detach();
1003    let camera_registrar = agent_types.contains(&AgentType::CameraWatcher).then(|| {
1004        agent::camera_watcher::create_registrar(
1005            camera_watcher_event_txs,
1006            external_publisher.clone(),
1007        )
1008    });
1009    let media_buttons_registrar = agent_types.contains(&AgentType::MediaButtons).then(|| {
1010        agent::media_buttons::create_registrar(media_buttons_event_txs, external_publisher)
1011    });
1012    let inspect_settings_values_registrar = agent_types
1013        .contains(&AgentType::InspectSettingValues)
1014        .then(|| agent::inspect::setting_values::create_registrar(setting_value_rx));
1015    let inspect_external_apis_registrar = agent_types
1016        .contains(&AgentType::InspectExternalApis)
1017        .then(|| agent::inspect::external_apis::create_registrar(external_event_rx));
1018    let inspect_setting_proxy_registrar = agent_types
1019        .contains(&AgentType::InspectSettingProxy)
1020        .then(|| agent::inspect::setting_proxy::create_registrar(proxy_event_rx));
1021    let inspect_usages_registrar = agent_types
1022        .contains(&AgentType::InspectSettingTypeUsage)
1023        .then(|| agent::inspect::usage_counts::create_registrar(usage_event_rx));
1024
1025    let agent_registrars = [
1026        camera_registrar,
1027        media_buttons_registrar,
1028        inspect_settings_values_registrar,
1029        inspect_external_apis_registrar,
1030        inspect_setting_proxy_registrar,
1031        inspect_usages_registrar,
1032    ];
1033
1034    let mut agent_blueprints = if agent_types.iter().all(|t| {
1035        matches!(
1036            t,
1037            AgentType::CameraWatcher
1038                | AgentType::MediaButtons
1039                | AgentType::InspectSettingValues
1040                | AgentType::InspectExternalApis
1041                | AgentType::InspectSettingProxy
1042                | AgentType::InspectSettingTypeUsage
1043        )
1044    }) {
1045        agent_blueprints
1046    } else {
1047        agent_types.into_iter().filter_map(AgentCreator::from_type).collect()
1048    };
1049
1050    agent_blueprints.extend(agent_registrars.into_iter().filter_map(|r| r));
1051    agent_blueprints
1052}
1053
1054/// Brings up the settings service environment.
1055///
1056/// This method generates the necessary infrastructure to support the settings
1057/// service (handlers, agents, etc.) and brings up the components necessary to
1058/// support the components specified in the components HashSet.
1059#[allow(clippy::too_many_arguments)]
1060async fn create_environment<'a>(
1061    mut service_dir: ServiceFsDir<'_, ServiceObjLocal<'a, ()>>,
1062    delegate: service::message::Delegate,
1063    job_seeder: Seeder,
1064    components: HashSet<SettingType>,
1065    registrants: Vec<Registrant>,
1066    agent_blueprints: Vec<AgentCreator>,
1067    event_subscriber_blueprints: Vec<event::subscriber::BlueprintHandle>,
1068    service_context: Rc<ServiceContext>,
1069    handler_factory: Rc<Mutex<SettingHandlerFactoryImpl>>,
1070    setting_proxies_node: &fuchsia_inspect::Node,
1071    listener_logger: Rc<ListenerInspectLogger>,
1072) -> Result<HashSet<Entity>, Error> {
1073    for blueprint in event_subscriber_blueprints {
1074        blueprint.create(delegate.clone()).await;
1075    }
1076
1077    let mut entities = HashSet::new();
1078
1079    for setting_type in &components {
1080        let _ = SettingProxy::create(
1081            *setting_type,
1082            handler_factory.clone(),
1083            delegate.clone(),
1084            DEFAULT_SETTING_PROXY_MAX_ATTEMPTS,
1085            DEFAULT_TEARDOWN_TIMEOUT,
1086            Some(MonotonicDuration::from_millis(DEFAULT_SETTING_PROXY_RESPONSE_TIMEOUT_MS)),
1087            true,
1088            setting_proxies_node.create_child(format!("{setting_type:?}")),
1089            Rc::clone(&listener_logger),
1090        )
1091        .await?;
1092
1093        let _ = entities.insert(Entity::Handler(*setting_type));
1094    }
1095
1096    let mut agent_authority = Authority::create(delegate.clone(), components.clone()).await?;
1097
1098    for registrant in registrants {
1099        if registrant.get_dependencies().iter().all(|dependency| {
1100            let dep_met = dependency.is_fulfilled(&entities);
1101            if !dep_met {
1102                log::error!(
1103                    "Skipping {} registration due to missing dependency {:?}",
1104                    registrant.get_interface(),
1105                    dependency
1106                );
1107            }
1108            dep_met
1109        }) {
1110            registrant.register(&job_seeder, &mut service_dir);
1111        }
1112    }
1113
1114    for blueprint in agent_blueprints {
1115        agent_authority.register(blueprint).await;
1116    }
1117
1118    // Execute initialization agents sequentially
1119    agent_authority
1120        .execute_lifespan(Lifespan::Initialization, Rc::clone(&service_context), true)
1121        .await
1122        .context("Agent initialization failed")?;
1123
1124    // Execute service agents concurrently
1125    agent_authority
1126        .execute_lifespan(Lifespan::Service, Rc::clone(&service_context), false)
1127        .await
1128        .context("Agent service start failed")?;
1129
1130    Ok(entities)
1131}
1132
1133#[cfg(test)]
1134mod tests;