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        EnvironmentBuilder::register_setting_handlers(
527            &settings,
528            Rc::clone(&self.storage_factory),
529            &flags,
530            self.display_configuration.map(DisplayInfoLoader::new),
531            self.audio_configuration.map(AudioInfoLoader::new),
532            self.input_configuration,
533            &mut handler_factory,
534        )
535        .await;
536
537        let listener_logger = self
538            .active_listener_inspect_logger
539            .unwrap_or_else(|| Rc::new(ListenerInspectLogger::new()));
540
541        let RegistrationResult {
542            media_buttons_event_txs,
543            setting_value_rx,
544            external_event_rx,
545            usage_event_rx,
546            tasks,
547        } = Self::register_controllers(
548            &settings,
549            Rc::clone(&common_service_context),
550            fidl_storage_factory,
551            self.storage_factory,
552            self.light_configuration,
553            &mut service_dir,
554            Rc::clone(&listener_logger),
555        )
556        .await;
557        for task in tasks {
558            task.detach();
559        }
560
561        self.media_buttons_event_txs.extend(media_buttons_event_txs);
562
563        // Override the configuration handlers with any custom handlers specified
564        // in the environment.
565        for (setting_type, handler) in self.handlers {
566            handler_factory.register(setting_type, handler);
567        }
568
569        let agent_blueprints = create_agent_blueprints(
570            agent_types,
571            self.agent_blueprints,
572            self.media_buttons_event_txs,
573            setting_value_rx,
574            external_event_rx,
575            usage_event_rx,
576        );
577
578        let job_manager_signature = Manager::spawn(&delegate).await;
579        let job_seeder = Seeder::new(&delegate, job_manager_signature).await;
580
581        let entities = create_environment(
582            service_dir,
583            delegate.clone(),
584            job_seeder.clone(),
585            settings,
586            self.registrants,
587            agent_blueprints,
588            self.event_subscriber_blueprints,
589            service_context,
590            Rc::new(Mutex::new(handler_factory)),
591            self.setting_proxy_inspect_info.unwrap_or_else(|| component::inspector().root()),
592            listener_logger,
593        )
594        .await
595        .context("Could not create environment")?;
596
597        Ok((fs, delegate, job_seeder, entities))
598    }
599
600    /// Spawn an [Environment] on the supplied [fasync::LocalExecutor] so that it may process
601    /// incoming FIDL requests.
602    pub fn spawn(
603        self,
604        mut executor: fasync::LocalExecutor,
605        fs: ServiceFs<ServiceObjLocal<'_, ()>>,
606    ) -> Result<(), Error> {
607        let (mut fs, ..) = executor
608            .run_singlethreaded(self.prepare_env(fs, Runtime::Service))
609            .context("Failed to prepare env")?;
610
611        let _ = fs.take_and_serve_directory_handle().expect("could not service directory handle");
612        executor.run_singlethreaded(fs.collect::<()>());
613        Ok(())
614    }
615
616    /// Spawn a nested [Environment] so that it can be used for tests.
617    #[cfg(test)]
618    pub async fn spawn_nested(self, env_name: &'static str) -> Result<Environment, Error> {
619        let (mut fs, delegate, job_seeder, entities) = self
620            .prepare_env(ServiceFs::new_local(), Runtime::Nested(env_name))
621            .await
622            .context("Failed to prepare env")?;
623        let connector = Some(fs.create_protocol_connector()?);
624        fasync::Task::local(fs.collect()).detach();
625
626        Ok(Environment::new(connector, delegate, job_seeder, entities))
627    }
628
629    /// Spawns a nested environment and returns the associated
630    /// ProtocolConnector. Note that this is a helper function that provides a
631    /// shortcut for calling EnvironmentBuilder::name() and
632    /// EnvironmentBuilder::spawn().
633    #[cfg(test)]
634    pub async fn spawn_and_get_protocol_connector(
635        self,
636        env_name: &'static str,
637    ) -> Result<ProtocolConnector, Error> {
638        let environment = self.spawn_nested(env_name).await?;
639
640        environment.connector.ok_or_else(|| format_err!("connector not created"))
641    }
642}
643
644struct RegistrationResult {
645    media_buttons_event_txs: Vec<UnboundedSender<settings_media_buttons::Event>>,
646    setting_value_rx: UnboundedReceiver<(&'static str, String)>,
647    external_event_rx: UnboundedReceiver<ExternalServiceEvent>,
648    usage_event_rx: UnboundedReceiver<UsageEvent>,
649    tasks: Vec<fasync::Task<()>>,
650}
651
652impl<'a, T: StorageFactory<Storage = DeviceStorage> + 'static> EnvironmentBuilder<'a, T> {
653    async fn initialize_storage<F, D>(
654        components: &HashSet<SettingType>,
655        fidl_storage_factory: &F,
656        device_storage_factory: &D,
657    ) where
658        F: StorageFactory<Storage = FidlStorage>,
659        D: StorageFactory<Storage = DeviceStorage>,
660    {
661        if components.contains(&SettingType::Intl) {
662            device_storage_factory
663                .initialize::<IntlController>()
664                .await
665                .expect("storage should still be initializing");
666        }
667
668        if components.contains(&SettingType::Keyboard) {
669            device_storage_factory
670                .initialize::<KeyboardController>()
671                .await
672                .expect("storage should still be initializing");
673        }
674
675        if components.contains(&SettingType::Light) {
676            fidl_storage_factory
677                .initialize::<LightController>()
678                .await
679                .expect("storage should still be initializing");
680        }
681
682        if components.contains(&SettingType::NightMode) {
683            device_storage_factory
684                .initialize::<NightModeController>()
685                .await
686                .expect("storage should still be initializing");
687        }
688
689        if components.contains(&SettingType::Privacy) {
690            device_storage_factory
691                .initialize::<PrivacyController>()
692                .await
693                .expect("storage should still be initializing");
694        }
695
696        if components.contains(&SettingType::Setup) {
697            device_storage_factory
698                .initialize::<SetupController>()
699                .await
700                .expect("storage should still be initializing");
701        }
702    }
703
704    async fn register_controllers<F, D>(
705        components: &HashSet<SettingType>,
706        service_context: Rc<CommonServiceContext>,
707        fidl_storage_factory: Rc<F>,
708        device_storage_factory: Rc<D>,
709        light_configuration: Option<DefaultSetting<LightHardwareConfiguration, &'static str>>,
710        service_dir: &mut ServiceFsDir<'_, ServiceObjLocal<'_, ()>>,
711        listener_logger: Rc<ListenerInspectLogger>,
712    ) -> RegistrationResult
713    where
714        F: StorageFactory<Storage = FidlStorage>,
715        D: StorageFactory<Storage = DeviceStorage>,
716    {
717        let (setting_value_tx, setting_value_rx) = mpsc::unbounded();
718        let (external_event_tx, external_event_rx) = mpsc::unbounded();
719        let (usage_event_tx, usage_event_rx) = mpsc::unbounded();
720        let external_publisher = ExternalEventPublisher::new(external_event_tx);
721        let mut media_buttons_event_txs = vec![];
722        let mut tasks = vec![];
723
724        // Start handlers for all components.
725        if components.contains(&SettingType::Light) {
726            let mut light_configuration =
727                light_configuration.expect("Light controller requires a light configuration");
728            match settings_light::setup_light_api(
729                Rc::clone(&service_context),
730                &mut light_configuration,
731                fidl_storage_factory,
732                SettingValuePublisher::new(setting_value_tx.clone()),
733                UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
734                external_publisher.clone(),
735            )
736            .await
737            {
738                Ok(settings_light::SetupResult {
739                    mut light_fidl_handler,
740                    media_buttons_event_tx,
741                    task,
742                }) => {
743                    media_buttons_event_txs.push(media_buttons_event_tx);
744                    tasks.push(task);
745                    let _ = service_dir.add_fidl_service(move |stream: LightRequestStream| {
746                        light_fidl_handler.handle_stream(stream)
747                    });
748                }
749                Err(e) => {
750                    log::error!("Failed to setup light api: {e:?}");
751                }
752            }
753        }
754
755        if components.contains(&SettingType::Intl) {
756            let intl::SetupResult { mut intl_fidl_handler, task } = intl::setup_intl_api(
757                Rc::clone(&device_storage_factory),
758                SettingValuePublisher::new(setting_value_tx.clone()),
759                UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
760            )
761            .await;
762            tasks.push(task);
763            let _ = service_dir.add_fidl_service(move |stream: IntlRequestStream| {
764                intl_fidl_handler.handle_stream(stream)
765            });
766        }
767
768        if components.contains(&SettingType::Keyboard) {
769            let keyboard::SetupResult { mut keyboard_fidl_handler, task } =
770                keyboard::setup_keyboard_api(
771                    Rc::clone(&device_storage_factory),
772                    SettingValuePublisher::new(setting_value_tx.clone()),
773                    UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
774                )
775                .await;
776            tasks.push(task);
777            let _ = service_dir.add_fidl_service(move |stream: KeyboardRequestStream| {
778                keyboard_fidl_handler.handle_stream(stream)
779            });
780        }
781
782        if components.contains(&SettingType::NightMode) {
783            let night_mode::SetupResult { mut night_mode_fidl_handler, task } =
784                night_mode::setup_night_mode_api(
785                    Rc::clone(&device_storage_factory),
786                    SettingValuePublisher::new(setting_value_tx.clone()),
787                    UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
788                )
789                .await;
790            tasks.push(task);
791            let _ = service_dir.add_fidl_service(move |stream: NightModeRequestStream| {
792                night_mode_fidl_handler.handle_stream(stream)
793            });
794        }
795
796        if components.contains(&SettingType::Privacy) {
797            let privacy::SetupResult { mut privacy_fidl_handler, task } =
798                privacy::setup_privacy_api(
799                    Rc::clone(&device_storage_factory),
800                    SettingValuePublisher::new(setting_value_tx.clone()),
801                    UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
802                )
803                .await;
804            tasks.push(task);
805            let _ = service_dir.add_fidl_service(move |stream: PrivacyRequestStream| {
806                privacy_fidl_handler.handle_stream(stream)
807            });
808        }
809
810        if components.contains(&SettingType::Setup) {
811            let setup::SetupResult { mut setup_fidl_handler, task } = setup::setup_setup_api(
812                service_context,
813                device_storage_factory,
814                SettingValuePublisher::new(setting_value_tx),
815                UsagePublisher::new(usage_event_tx, listener_logger),
816                external_publisher,
817            )
818            .await;
819            tasks.push(task);
820            let _ = service_dir.add_fidl_service(move |stream: SetupRequestStream| {
821                setup_fidl_handler.handle_stream(stream)
822            });
823        }
824
825        RegistrationResult {
826            media_buttons_event_txs,
827            setting_value_rx,
828            external_event_rx,
829            usage_event_rx,
830            tasks,
831        }
832    }
833
834    /// Initializes storage and registers handler generation functions for the configured setting
835    /// types.
836    async fn register_setting_handlers(
837        components: &HashSet<SettingType>,
838        device_storage_factory: Rc<T>,
839        controller_flags: &HashSet<ControllerFlag>,
840        display_loader: Option<DisplayInfoLoader>,
841        audio_loader: Option<AudioInfoLoader>,
842        input_configuration: Option<DefaultSetting<InputConfiguration, &'static str>>,
843        factory_handle: &mut SettingHandlerFactoryImpl,
844    ) {
845        // Accessibility
846        if components.contains(&SettingType::Accessibility) {
847            device_storage_factory
848                .initialize::<AccessibilityController<T>>()
849                .await
850                .expect("storage should still be initializing");
851            let device_storage_factory = Rc::clone(&device_storage_factory);
852            factory_handle.register(
853                SettingType::Accessibility,
854                Box::new(move |context| {
855                    DataHandler::<AccessibilityController<T>>::spawn_with_async(
856                        context,
857                        Rc::clone(&device_storage_factory),
858                    )
859                }),
860            );
861        }
862
863        // Audio
864        if components.contains(&SettingType::Audio) {
865            let audio_loader = audio_loader.expect("Audio storage requires audio loader");
866            device_storage_factory
867                .initialize_with_loader::<AudioController<T>, _>(audio_loader.clone())
868                .await
869                .expect("storage should still be initializing");
870            let device_storage_factory = Rc::clone(&device_storage_factory);
871            factory_handle.register(
872                SettingType::Audio,
873                Box::new(move |context| {
874                    DataHandler::<AudioController<T>>::spawn_with_async(
875                        context,
876                        (Rc::clone(&device_storage_factory), audio_loader.clone()),
877                    )
878                }),
879            );
880        }
881
882        // Display
883        if components.contains(&SettingType::Display) {
884            device_storage_factory
885                .initialize_with_loader::<DisplayController<T>, _>(
886                    display_loader.expect("Display storage requires display loader"),
887                )
888                .await
889                .expect("storage should still be initializing");
890            let device_storage_factory = Rc::clone(&device_storage_factory);
891            let external_brightness_control =
892                controller_flags.contains(&ControllerFlag::ExternalBrightnessControl);
893            factory_handle.register(
894                SettingType::Display,
895                Box::new(
896                    move |context| {
897                        if external_brightness_control {
898                            DataHandler::<DisplayController<T, ExternalBrightnessControl>>::spawn_with_async(
899                                context,
900                                Rc::clone(&device_storage_factory))
901                        } else {
902                            DataHandler::<DisplayController<T>>::spawn_with_async(
903                                context,
904                                Rc::clone(&device_storage_factory))
905                        }
906                    }
907                ),
908            );
909        }
910
911        // Input
912        if components.contains(&SettingType::Input) {
913            let input_configuration = Rc::new(std::sync::Mutex::new(
914                input_configuration.expect("Input controller requires an input configuration"),
915            ));
916            device_storage_factory
917                .initialize::<InputController<T>>()
918                .await
919                .expect("storage should still be initializing");
920            let device_storage_factory = Rc::clone(&device_storage_factory);
921            factory_handle.register(
922                SettingType::Input,
923                Box::new(move |context| {
924                    DataHandler::<InputController<T>>::spawn_with_async(
925                        context,
926                        (Rc::clone(&device_storage_factory), Rc::clone(&input_configuration)),
927                    )
928                }),
929            );
930        }
931
932        // Do not disturb
933        if components.contains(&SettingType::DoNotDisturb) {
934            device_storage_factory
935                .initialize::<DoNotDisturbController<T>>()
936                .await
937                .expect("storage should still be initializing");
938            let device_storage_factory = Rc::clone(&device_storage_factory);
939            factory_handle.register(
940                SettingType::DoNotDisturb,
941                Box::new(move |context| {
942                    DataHandler::<DoNotDisturbController<T>>::spawn_with_async(
943                        context,
944                        Rc::clone(&device_storage_factory),
945                    )
946                }),
947            );
948        }
949
950        // Factory Reset
951        if components.contains(&SettingType::FactoryReset) {
952            device_storage_factory
953                .initialize::<FactoryResetController<T>>()
954                .await
955                .expect("storage should still be initializing");
956            let device_storage_factory = Rc::clone(&device_storage_factory);
957            factory_handle.register(
958                SettingType::FactoryReset,
959                Box::new(move |context| {
960                    DataHandler::<FactoryResetController<T>>::spawn_with_async(
961                        context,
962                        Rc::clone(&device_storage_factory),
963                    )
964                }),
965            );
966        }
967    }
968}
969
970fn create_agent_blueprints(
971    agent_types: HashSet<AgentType>,
972    agent_blueprints: Vec<AgentCreator>,
973    media_buttons_event_txs: Vec<UnboundedSender<settings_media_buttons::Event>>,
974    setting_value_rx: UnboundedReceiver<(&'static str, String)>,
975    external_event_rx: UnboundedReceiver<ExternalServiceEvent>,
976    mut usage_router_rx: UnboundedReceiver<UsageEvent>,
977) -> Vec<AgentCreator> {
978    let (proxy_event_tx, proxy_event_rx) = mpsc::unbounded();
979    let (usage_event_tx, usage_event_rx) = mpsc::unbounded();
980
981    // Route general inspect requests to specific inspect agents.
982    fasync::Task::local(async move {
983        while let Some(usage_event) = usage_router_rx.next().await {
984            let _ = proxy_event_tx.unbounded_send(usage_event.clone());
985            let _ = usage_event_tx.unbounded_send(usage_event);
986        }
987    })
988    .detach();
989    let media_buttons_registrar = agent_types
990        .contains(&AgentType::MediaButtons)
991        .then(|| agent::media_buttons::create_registrar(media_buttons_event_txs));
992    let inspect_settings_values_registrar = agent_types
993        .contains(&AgentType::InspectSettingValues)
994        .then(|| agent::inspect::setting_values::create_registrar(setting_value_rx));
995    let inspect_external_apis_registrar = agent_types
996        .contains(&AgentType::InspectExternalApis)
997        .then(|| agent::inspect::external_apis::create_registrar(external_event_rx));
998    let inspect_setting_proxy_registrar = agent_types
999        .contains(&AgentType::InspectSettingProxy)
1000        .then(|| agent::inspect::setting_proxy::create_registrar(proxy_event_rx));
1001    let inspect_usages_registrar = agent_types
1002        .contains(&AgentType::InspectSettingTypeUsage)
1003        .then(|| agent::inspect::usage_counts::create_registrar(usage_event_rx));
1004
1005    let agent_registrars = [
1006        media_buttons_registrar,
1007        inspect_settings_values_registrar,
1008        inspect_external_apis_registrar,
1009        inspect_setting_proxy_registrar,
1010        inspect_usages_registrar,
1011    ];
1012
1013    let mut agent_blueprints = if agent_types.iter().all(|t| {
1014        matches!(
1015            t,
1016            AgentType::MediaButtons
1017                | AgentType::InspectSettingValues
1018                | AgentType::InspectExternalApis
1019                | AgentType::InspectSettingProxy
1020                | AgentType::InspectSettingTypeUsage
1021        )
1022    }) {
1023        agent_blueprints
1024    } else {
1025        agent_types.into_iter().filter_map(AgentCreator::from_type).collect()
1026    };
1027
1028    agent_blueprints.extend(agent_registrars.into_iter().filter_map(|r| r));
1029    agent_blueprints
1030}
1031
1032/// Brings up the settings service environment.
1033///
1034/// This method generates the necessary infrastructure to support the settings
1035/// service (handlers, agents, etc.) and brings up the components necessary to
1036/// support the components specified in the components HashSet.
1037#[allow(clippy::too_many_arguments)]
1038async fn create_environment<'a>(
1039    mut service_dir: ServiceFsDir<'_, ServiceObjLocal<'a, ()>>,
1040    delegate: service::message::Delegate,
1041    job_seeder: Seeder,
1042    components: HashSet<SettingType>,
1043    registrants: Vec<Registrant>,
1044    agent_blueprints: Vec<AgentCreator>,
1045    event_subscriber_blueprints: Vec<event::subscriber::BlueprintHandle>,
1046    service_context: Rc<ServiceContext>,
1047    handler_factory: Rc<Mutex<SettingHandlerFactoryImpl>>,
1048    setting_proxies_node: &fuchsia_inspect::Node,
1049    listener_logger: Rc<ListenerInspectLogger>,
1050) -> Result<HashSet<Entity>, Error> {
1051    for blueprint in event_subscriber_blueprints {
1052        blueprint.create(delegate.clone()).await;
1053    }
1054
1055    let mut entities = HashSet::new();
1056
1057    for setting_type in &components {
1058        let _ = SettingProxy::create(
1059            *setting_type,
1060            handler_factory.clone(),
1061            delegate.clone(),
1062            DEFAULT_SETTING_PROXY_MAX_ATTEMPTS,
1063            DEFAULT_TEARDOWN_TIMEOUT,
1064            Some(MonotonicDuration::from_millis(DEFAULT_SETTING_PROXY_RESPONSE_TIMEOUT_MS)),
1065            true,
1066            setting_proxies_node.create_child(format!("{setting_type:?}")),
1067            Rc::clone(&listener_logger),
1068        )
1069        .await?;
1070
1071        let _ = entities.insert(Entity::Handler(*setting_type));
1072    }
1073
1074    let mut agent_authority = Authority::create(delegate.clone(), components.clone()).await?;
1075
1076    for registrant in registrants {
1077        if registrant.get_dependencies().iter().all(|dependency| {
1078            let dep_met = dependency.is_fulfilled(&entities);
1079            if !dep_met {
1080                log::error!(
1081                    "Skipping {} registration due to missing dependency {:?}",
1082                    registrant.get_interface(),
1083                    dependency
1084                );
1085            }
1086            dep_met
1087        }) {
1088            registrant.register(&job_seeder, &mut service_dir);
1089        }
1090    }
1091
1092    for blueprint in agent_blueprints {
1093        agent_authority.register(blueprint).await;
1094    }
1095
1096    // Execute initialization agents sequentially
1097    agent_authority
1098        .execute_lifespan(Lifespan::Initialization, Rc::clone(&service_context), true)
1099        .await
1100        .context("Agent initialization failed")?;
1101
1102    // Execute service agents concurrently
1103    agent_authority
1104        .execute_lifespan(Lifespan::Service, Rc::clone(&service_context), false)
1105        .await
1106        .context("Agent service start failed")?;
1107
1108    Ok(entities)
1109}
1110
1111#[cfg(test)]
1112mod tests;