1use 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::types::AudioInfo;
13use audio::AudioInfoLoader;
14use display::display_controller::DisplayInfoLoader;
15use fidl_fuchsia_io::DirectoryProxy;
16use fidl_fuchsia_settings::LightRequestStream;
17use fidl_fuchsia_stash::StoreProxy;
18use fuchsia_component::client::connect_to_protocol;
19#[cfg(test)]
20use fuchsia_component::server::ProtocolConnector;
21use fuchsia_component::server::{ServiceFs, ServiceFsDir, ServiceObjLocal};
22use fuchsia_inspect::component;
23use futures::channel::mpsc::{self, UnboundedReceiver, UnboundedSender};
24use futures::lock::Mutex;
25use futures::{StreamExt, TryStreamExt};
26#[cfg(test)]
27use log as _;
28use settings_common::config::default_settings::DefaultSetting;
29use settings_common::config::{AgentType, ControllerFlag};
30use settings_common::inspect::event::{
31 ExternalEventPublisher, SettingValuePublisher, UsageEvent, UsagePublisher,
32};
33use settings_common::inspect::listener_logger::ListenerInspectLogger;
34use settings_common::service_context::{
35 ExternalServiceEvent, GenerateService, ServiceContext as CommonServiceContext,
36};
37use settings_light::light_controller::LightController;
38use settings_storage::device_storage::DeviceStorage;
39use settings_storage::fidl_storage::FidlStorage;
40use settings_storage::storage_factory::{FidlStorageFactory, StorageFactory};
41use zx::MonotonicDuration;
42use {fidl_fuchsia_update_verify as fupdate, fuchsia_async as fasync};
43
44pub use display::display_configuration::DisplayConfiguration;
45pub use handler::setting_proxy_inspect_info::SettingProxyInspectInfo;
46pub use input::input_device_configuration::InputConfiguration;
47use serde::Deserialize;
48pub use service::{Address, Payload};
49pub use settings_light::light_hardware_configuration::LightHardwareConfiguration;
50
51use crate::accessibility::accessibility_controller::AccessibilityController;
52use crate::agent::authority::Authority;
53use crate::agent::{AgentCreator, Lifespan};
54use crate::audio::audio_controller::AudioController;
55use crate::base::{Dependency, Entity, SettingType};
56use crate::display::display_controller::{DisplayController, ExternalBrightnessControl};
57use crate::do_not_disturb::do_not_disturb_controller::DoNotDisturbController;
58use crate::factory_reset::factory_reset_controller::FactoryResetController;
59use crate::handler::base::GenerateHandler;
60use crate::handler::setting_handler::persist::Handler as DataHandler;
61use crate::handler::setting_handler_factory_impl::SettingHandlerFactoryImpl;
62use crate::handler::setting_proxy::SettingProxy;
63use crate::ingress::fidl;
64use crate::ingress::registration::Registrant;
65use crate::input::input_controller::InputController;
66use crate::intl::intl_controller::IntlController;
67use crate::job::manager::Manager;
68use crate::job::source::Seeder;
69use crate::keyboard::keyboard_controller::KeyboardController;
70use crate::night_mode::night_mode_controller::NightModeController;
71use crate::privacy::privacy_controller::PrivacyController;
72use crate::service::message::Delegate;
73use crate::service_context::ServiceContext;
74use crate::setup::setup_controller::SetupController;
75
76mod accessibility;
77pub mod audio;
78mod clock;
79pub mod display;
80mod do_not_disturb;
81mod event;
82mod factory_reset;
83pub mod input;
84mod intl;
85mod job;
86mod keyboard;
87mod night_mode;
88mod privacy;
89mod service;
90mod setup;
91mod storage_migrations;
92
93pub mod agent;
94pub mod base;
95pub mod config;
96pub mod handler;
97pub mod ingress;
98pub mod inspect;
99pub mod message;
100pub(crate) mod migration;
101pub mod service_context;
102pub mod storage;
103pub mod trace;
104
105pub(crate) const DEFAULT_TEARDOWN_TIMEOUT: MonotonicDuration = MonotonicDuration::from_seconds(5);
111const DEFAULT_SETTING_PROXY_MAX_ATTEMPTS: u64 = 3;
112const DEFAULT_SETTING_PROXY_RESPONSE_TIMEOUT_MS: i64 = 10_000;
113
114pub type ExitSender = futures::channel::mpsc::UnboundedSender<()>;
116
117#[derive(PartialEq)]
122enum Runtime {
123 Service,
124 #[cfg(test)]
125 Nested(&'static str),
126}
127
128#[derive(Debug, Default, Clone, Deserialize)]
129pub struct AgentConfiguration {
130 pub agent_types: HashSet<AgentType>,
131}
132
133#[derive(PartialEq, Debug, Clone, Deserialize)]
134pub struct EnabledInterfacesConfiguration {
135 pub interfaces: HashSet<fidl::InterfaceSpec>,
136}
137
138impl EnabledInterfacesConfiguration {
139 pub fn with_interfaces(interfaces: HashSet<fidl::InterfaceSpec>) -> Self {
140 Self { interfaces }
141 }
142}
143
144#[derive(Default, Debug, Clone, Deserialize)]
145pub struct ServiceFlags {
146 pub controller_flags: HashSet<ControllerFlag>,
147}
148
149#[derive(PartialEq, Debug, Default, Clone)]
150pub struct ServiceConfiguration {
151 agent_types: HashSet<AgentType>,
152 fidl_interfaces: HashSet<fidl::Interface>,
153 controller_flags: HashSet<ControllerFlag>,
154}
155
156impl ServiceConfiguration {
157 pub fn from(
158 agent_types: AgentConfiguration,
159 interfaces: EnabledInterfacesConfiguration,
160 flags: ServiceFlags,
161 ) -> Self {
162 let fidl_interfaces: HashSet<fidl::Interface> =
163 interfaces.interfaces.into_iter().map(|x| x.into()).collect();
164
165 Self {
166 agent_types: agent_types.agent_types,
167 fidl_interfaces,
168 controller_flags: flags.controller_flags,
169 }
170 }
171
172 fn set_fidl_interfaces(&mut self, interfaces: HashSet<fidl::Interface>) {
173 self.fidl_interfaces = interfaces;
174 }
175
176 fn set_controller_flags(&mut self, controller_flags: HashSet<ControllerFlag>) {
177 self.controller_flags = controller_flags;
178 }
179}
180
181#[cfg(test)]
186pub struct Environment {
187 pub connector: Option<ProtocolConnector>,
188 pub delegate: Delegate,
189 pub entities: HashSet<Entity>,
190 pub job_seeder: Seeder,
191}
192
193#[cfg(test)]
194impl Environment {
195 pub fn new(
196 connector: Option<ProtocolConnector>,
197 delegate: Delegate,
198 job_seeder: Seeder,
199 entities: HashSet<Entity>,
200 ) -> Environment {
201 Environment { connector, delegate, job_seeder, entities }
202 }
203}
204
205#[cfg(test)]
206fn init_storage_dir() -> DirectoryProxy {
207 let tempdir = tempfile::tempdir().expect("failed to create tempdir");
208 fuchsia_fs::directory::open_in_namespace(
209 tempdir.path().to_str().expect("tempdir path is not valid UTF-8"),
210 fuchsia_fs::PERM_READABLE | fuchsia_fs::PERM_WRITABLE,
211 )
212 .expect("failed to open connection to tempdir")
213}
214
215#[cfg(not(test))]
216fn init_storage_dir() -> DirectoryProxy {
217 panic!("migration dir must be specified");
218}
219
220pub struct EnvironmentBuilder<'a, T: StorageFactory<Storage = DeviceStorage>> {
223 configuration: Option<ServiceConfiguration>,
224 agent_blueprints: Vec<AgentCreator>,
225 event_subscriber_blueprints: Vec<event::subscriber::BlueprintHandle>,
226 storage_factory: Rc<T>,
227 generate_service: Option<GenerateService>,
228 registrants: Vec<Registrant>,
229 settings: Vec<SettingType>,
230 handlers: HashMap<SettingType, GenerateHandler>,
231 setting_proxy_inspect_info: Option<&'a fuchsia_inspect::Node>,
232 active_listener_inspect_logger: Option<Rc<ListenerInspectLogger>>,
233 storage_dir: Option<DirectoryProxy>,
234 store_proxy: Option<StoreProxy>,
235 fidl_storage_factory: Option<Rc<FidlStorageFactory>>,
236 display_configuration: Option<DefaultSetting<DisplayConfiguration, &'static str>>,
237 audio_configuration: Option<DefaultSetting<AudioInfo, &'static str>>,
238 input_configuration: Option<DefaultSetting<InputConfiguration, &'static str>>,
239 light_configuration: Option<DefaultSetting<LightHardwareConfiguration, &'static str>>,
240 media_buttons_event_txs: Vec<UnboundedSender<settings_media_buttons::Event>>,
241}
242
243impl<'a, T: StorageFactory<Storage = DeviceStorage> + 'static> EnvironmentBuilder<'a, T> {
244 pub fn new(storage_factory: Rc<T>) -> Self {
247 EnvironmentBuilder {
248 configuration: None,
249 agent_blueprints: vec![],
250 event_subscriber_blueprints: vec![],
251 storage_factory,
252 generate_service: None,
253 handlers: HashMap::new(),
254 registrants: vec![],
255 settings: vec![],
256 setting_proxy_inspect_info: None,
257 active_listener_inspect_logger: None,
258 storage_dir: None,
259 store_proxy: None,
260 fidl_storage_factory: None,
261 display_configuration: None,
262 audio_configuration: None,
263 input_configuration: None,
264 light_configuration: None,
265 media_buttons_event_txs: vec![],
266 }
267 }
268
269 pub fn handler(mut self, setting_type: SettingType, generate_handler: GenerateHandler) -> Self {
271 let _ = self.handlers.insert(setting_type, generate_handler);
273 self
274 }
275
276 pub fn service(mut self, generate_service: GenerateService) -> Self {
278 self.generate_service = Some(generate_service);
279 self
280 }
281
282 pub fn configuration(mut self, configuration: ServiceConfiguration) -> Self {
286 self.configuration = Some(configuration);
287 self
288 }
289
290 pub fn display_configuration(
291 mut self,
292 display_configuration: DefaultSetting<DisplayConfiguration, &'static str>,
293 ) -> Self {
294 self.display_configuration = Some(display_configuration);
295 self
296 }
297
298 pub fn audio_configuration(
299 mut self,
300 audio_configuration: DefaultSetting<AudioInfo, &'static str>,
301 ) -> Self {
302 self.audio_configuration = Some(audio_configuration);
303 self
304 }
305
306 pub fn input_configuration(
307 mut self,
308 input_configuration: DefaultSetting<InputConfiguration, &'static str>,
309 ) -> Self {
310 self.input_configuration = Some(input_configuration);
311 self
312 }
313
314 pub fn light_configuration(
315 mut self,
316 light_configuration: DefaultSetting<LightHardwareConfiguration, &'static str>,
317 ) -> Self {
318 self.light_configuration = Some(light_configuration);
319 self
320 }
321
322 pub fn fidl_interfaces(mut self, interfaces: &[fidl::Interface]) -> Self {
324 if self.configuration.is_none() {
325 self.configuration = Some(ServiceConfiguration::default());
326 }
327
328 if let Some(c) = self.configuration.as_mut() {
329 c.set_fidl_interfaces(interfaces.iter().copied().collect());
330 }
331
332 self
333 }
334
335 pub fn registrants(mut self, mut registrants: Vec<Registrant>) -> Self {
337 self.registrants.append(&mut registrants);
338
339 self
340 }
341
342 pub fn settings(mut self, settings: &[SettingType]) -> Self {
344 self.settings.extend(settings);
345
346 self
347 }
348
349 pub fn flags(mut self, controller_flags: &[ControllerFlag]) -> Self {
351 if self.configuration.is_none() {
352 self.configuration = Some(ServiceConfiguration::default());
353 }
354
355 if let Some(c) = self.configuration.as_mut() {
356 c.set_controller_flags(controller_flags.iter().copied().collect());
357 }
358
359 self
360 }
361
362 pub fn agents(mut self, mut registrars: Vec<AgentCreator>) -> Self {
364 self.agent_blueprints.append(&mut registrars);
365 self
366 }
367
368 pub fn event_subscribers(mut self, subscribers: &[event::subscriber::BlueprintHandle]) -> Self {
370 self.event_subscriber_blueprints.append(&mut subscribers.to_vec());
371 self
372 }
373
374 pub fn setting_proxy_inspect_info(
377 mut self,
378 setting_proxy_inspect_info: &'a fuchsia_inspect::Node,
379 active_listener_inspect_logger: Rc<ListenerInspectLogger>,
380 ) -> Self {
381 self.setting_proxy_inspect_info = Some(setting_proxy_inspect_info);
382 self.active_listener_inspect_logger = Some(active_listener_inspect_logger);
383 self
384 }
385
386 pub fn storage_dir(mut self, storage_dir: DirectoryProxy) -> Self {
387 self.storage_dir = Some(storage_dir);
388 self
389 }
390
391 pub fn store_proxy(mut self, store_proxy: StoreProxy) -> Self {
392 self.store_proxy = Some(store_proxy);
393 self
394 }
395
396 pub fn fidl_storage_factory(mut self, fidl_storage_factory: Rc<FidlStorageFactory>) -> Self {
397 self.fidl_storage_factory = Some(fidl_storage_factory);
398 self
399 }
400
401 pub fn media_buttons_event_txs(
402 mut self,
403 media_buttons_event_txs: Vec<UnboundedSender<settings_media_buttons::Event>>,
404 ) -> Self {
405 self.media_buttons_event_txs.extend(media_buttons_event_txs);
406 self
407 }
408
409 async fn prepare_env(
412 mut self,
413 mut fs: ServiceFs<ServiceObjLocal<'_, ()>>,
414 runtime: Runtime,
415 ) -> Result<(ServiceFs<ServiceObjLocal<'_, ()>>, Delegate, Seeder, HashSet<Entity>), Error>
416 {
417 let mut service_dir = match runtime {
418 Runtime::Service => fs.dir("svc"),
419 #[cfg(test)]
420 Runtime::Nested(_) => fs.root_dir(),
421 };
422
423 let _ = service_dir.add_fidl_service(
424 move |mut stream: fupdate::ComponentOtaHealthCheckRequestStream| {
425 fasync::Task::local(async move {
426 while let Some(fupdate::ComponentOtaHealthCheckRequest::GetHealthStatus {
427 responder,
428 }) = stream.try_next().await.expect("error running health check service")
429 {
430 responder
434 .send(fupdate::HealthStatus::Healthy)
435 .expect("failed to send health status");
436 }
437 })
438 .detach();
439 },
440 );
441
442 let delegate = service::MessageHub::create_hub();
444
445 let (agent_types, fidl_interfaces, flags) = match self.configuration {
446 Some(configuration) => (
447 configuration.agent_types,
448 configuration.fidl_interfaces,
449 configuration.controller_flags,
450 ),
451 _ => (HashSet::new(), HashSet::new(), HashSet::new()),
452 };
453
454 self.registrants.extend(fidl_interfaces.into_iter().map(|x| x.registrant()));
455
456 let mut settings = HashSet::new();
457 settings.extend(self.settings);
458
459 for registrant in &self.registrants {
460 for dependency in registrant.get_dependencies() {
461 match dependency {
462 Dependency::Entity(Entity::Handler(setting_type)) => {
463 let _ = settings.insert(*setting_type);
464 }
465 }
466 }
467 }
468
469 let fidl_storage_factory = if let Some(factory) = self.fidl_storage_factory {
470 factory
471 } else {
472 let (migration_id, storage_dir) = if let Some(storage_dir) = self.storage_dir {
473 let store_proxy = self.store_proxy.unwrap_or_else(|| {
474 let store_proxy = connect_to_protocol::<fidl_fuchsia_stash::StoreMarker>()
475 .expect("failed to connect to stash");
476 store_proxy
477 .identify("setting_service")
478 .expect("should be able to identify to stash");
479 store_proxy
480 });
481
482 let migration_manager = storage_migrations::register_migrations(
483 &settings,
484 Clone::clone(&storage_dir),
485 store_proxy,
486 )
487 .context("failed to register migrations")?;
488 let migration_id = match migration_manager.run_migrations().await {
489 Ok(id) => {
490 log::info!("migrated storage to {id:?}");
491 id
492 }
493 Err((id, e)) => {
494 log::error!("Settings migration failed: {e:?}");
495 id
496 }
497 };
498 let migration_id = migration_id.map(|migration| migration.migration_id);
499 (migration_id, storage_dir)
500 } else {
501 (None, init_storage_dir())
502 };
503
504 Rc::new(FidlStorageFactory::new(migration_id.unwrap_or(0), storage_dir))
505 };
506
507 let common_service_context = Rc::new(CommonServiceContext::new(self.generate_service));
508 let service_context = Rc::new(ServiceContext::new_from_common(
509 Rc::clone(&common_service_context),
510 Some(delegate.clone()),
511 ));
512
513 let context_id_counter = Rc::new(AtomicU64::new(1));
514
515 let mut handler_factory = SettingHandlerFactoryImpl::new(
516 settings.clone(),
517 Rc::clone(&service_context),
518 context_id_counter.clone(),
519 );
520
521 let listener_logger = self
522 .active_listener_inspect_logger
523 .unwrap_or_else(|| Rc::new(ListenerInspectLogger::new()));
524
525 let RegistrationResult {
526 media_buttons_event_txs,
527 setting_value_rx,
528 external_event_rx,
529 usage_event_rx,
530 tasks,
531 } = Self::register_controllers(
532 &settings,
533 Rc::clone(&common_service_context),
534 fidl_storage_factory,
535 self.light_configuration,
536 &mut service_dir,
537 Rc::clone(&listener_logger),
538 )
539 .await;
540 for task in tasks {
541 task.detach();
542 }
543
544 self.media_buttons_event_txs.extend(media_buttons_event_txs);
545
546 EnvironmentBuilder::register_setting_handlers(
547 &settings,
548 Rc::clone(&self.storage_factory),
549 &flags,
550 self.display_configuration.map(DisplayInfoLoader::new),
551 self.audio_configuration.map(AudioInfoLoader::new),
552 self.input_configuration,
553 &mut handler_factory,
554 )
555 .await;
556
557 for (setting_type, handler) in self.handlers {
560 handler_factory.register(setting_type, handler);
561 }
562
563 let agent_blueprints = create_agent_blueprints(
564 agent_types,
565 self.agent_blueprints,
566 self.media_buttons_event_txs,
567 setting_value_rx,
568 external_event_rx,
569 usage_event_rx,
570 );
571
572 let job_manager_signature = Manager::spawn(&delegate).await;
573 let job_seeder = Seeder::new(&delegate, job_manager_signature).await;
574
575 let entities = create_environment(
576 service_dir,
577 delegate.clone(),
578 job_seeder.clone(),
579 settings,
580 self.registrants,
581 agent_blueprints,
582 self.event_subscriber_blueprints,
583 service_context,
584 Rc::new(Mutex::new(handler_factory)),
585 self.storage_factory,
586 self.setting_proxy_inspect_info.unwrap_or_else(|| component::inspector().root()),
587 listener_logger,
588 )
589 .await
590 .context("Could not create environment")?;
591
592 Ok((fs, delegate, job_seeder, entities))
593 }
594
595 pub fn spawn(
598 self,
599 mut executor: fasync::LocalExecutor,
600 fs: ServiceFs<ServiceObjLocal<'_, ()>>,
601 ) -> Result<(), Error> {
602 let (mut fs, ..) = executor
603 .run_singlethreaded(self.prepare_env(fs, Runtime::Service))
604 .context("Failed to prepare env")?;
605
606 let _ = fs.take_and_serve_directory_handle().expect("could not service directory handle");
607 executor.run_singlethreaded(fs.collect::<()>());
608 Ok(())
609 }
610
611 #[cfg(test)]
613 pub async fn spawn_nested(self, env_name: &'static str) -> Result<Environment, Error> {
614 let (mut fs, delegate, job_seeder, entities) = self
615 .prepare_env(ServiceFs::new_local(), Runtime::Nested(env_name))
616 .await
617 .context("Failed to prepare env")?;
618 let connector = Some(fs.create_protocol_connector()?);
619 fasync::Task::local(fs.collect()).detach();
620
621 Ok(Environment::new(connector, delegate, job_seeder, entities))
622 }
623
624 #[cfg(test)]
629 pub async fn spawn_and_get_protocol_connector(
630 self,
631 env_name: &'static str,
632 ) -> Result<ProtocolConnector, Error> {
633 let environment = self.spawn_nested(env_name).await?;
634
635 environment.connector.ok_or_else(|| format_err!("connector not created"))
636 }
637}
638
639struct RegistrationResult {
640 media_buttons_event_txs: Vec<UnboundedSender<settings_media_buttons::Event>>,
641 setting_value_rx: UnboundedReceiver<(&'static str, String)>,
642 external_event_rx: UnboundedReceiver<ExternalServiceEvent>,
643 usage_event_rx: UnboundedReceiver<UsageEvent>,
644 tasks: Vec<fasync::Task<()>>,
645}
646
647impl<'a, T: StorageFactory<Storage = DeviceStorage> + 'static> EnvironmentBuilder<'a, T> {
648 async fn register_controllers<F>(
649 components: &HashSet<SettingType>,
650 service_context: Rc<CommonServiceContext>,
651 fidl_storage_factory: Rc<F>,
652 light_configuration: Option<DefaultSetting<LightHardwareConfiguration, &'static str>>,
653 service_dir: &mut ServiceFsDir<'_, ServiceObjLocal<'_, ()>>,
654 listener_logger: Rc<ListenerInspectLogger>,
655 ) -> RegistrationResult
656 where
657 F: StorageFactory<Storage = FidlStorage>,
658 {
659 let (setting_value_tx, setting_value_rx) = mpsc::unbounded();
660 let (external_event_tx, external_event_rx) = mpsc::unbounded();
661 let (usage_event_tx, usage_event_rx) = mpsc::unbounded();
662 let external_publisher = ExternalEventPublisher::new(external_event_tx);
663 let mut media_buttons_event_txs = vec![];
664 let mut tasks = vec![];
665 if components.contains(&SettingType::Light) {
667 fidl_storage_factory
668 .initialize::<LightController>()
669 .await
670 .expect("storage should still be initializing");
671 }
672
673 if components.contains(&SettingType::Light) {
675 let mut light_configuration =
676 light_configuration.expect("Light controller requires a light configuration");
677 match settings_light::setup_light_api(
678 service_context,
679 &mut light_configuration,
680 fidl_storage_factory,
681 SettingValuePublisher::new(setting_value_tx),
682 UsagePublisher::new(usage_event_tx, listener_logger),
683 external_publisher,
684 )
685 .await
686 {
687 Ok(settings_light::SetupResult {
688 mut light_fidl_handler,
689 media_buttons_event_tx,
690 task,
691 }) => {
692 media_buttons_event_txs.push(media_buttons_event_tx);
693 tasks.push(task);
694 let _ = service_dir.add_fidl_service(move |stream: LightRequestStream| {
695 light_fidl_handler.handle_stream(stream)
696 });
697 }
698 Err(e) => {
699 log::error!("Failed to setup light api: {e:?}");
700 }
701 }
702 }
703
704 RegistrationResult {
705 media_buttons_event_txs,
706 setting_value_rx,
707 external_event_rx,
708 usage_event_rx,
709 tasks,
710 }
711 }
712
713 async fn register_setting_handlers(
716 components: &HashSet<SettingType>,
717 device_storage_factory: Rc<T>,
718 controller_flags: &HashSet<ControllerFlag>,
719 display_loader: Option<DisplayInfoLoader>,
720 audio_loader: Option<AudioInfoLoader>,
721 input_configuration: Option<DefaultSetting<InputConfiguration, &'static str>>,
722 factory_handle: &mut SettingHandlerFactoryImpl,
723 ) {
724 if components.contains(&SettingType::Accessibility) {
726 device_storage_factory
727 .initialize::<AccessibilityController<T>>()
728 .await
729 .expect("storage should still be initializing");
730 let device_storage_factory = Rc::clone(&device_storage_factory);
731 factory_handle.register(
732 SettingType::Accessibility,
733 Box::new(move |context| {
734 DataHandler::<AccessibilityController<T>>::spawn_with_async(
735 context,
736 Rc::clone(&device_storage_factory),
737 )
738 }),
739 );
740 }
741
742 if components.contains(&SettingType::Audio) {
744 let audio_loader = audio_loader.expect("Audio storage requires audio loader");
745 device_storage_factory
746 .initialize_with_loader::<AudioController<T>, _>(audio_loader.clone())
747 .await
748 .expect("storage should still be initializing");
749 let device_storage_factory = Rc::clone(&device_storage_factory);
750 factory_handle.register(
751 SettingType::Audio,
752 Box::new(move |context| {
753 DataHandler::<AudioController<T>>::spawn_with_async(
754 context,
755 (Rc::clone(&device_storage_factory), audio_loader.clone()),
756 )
757 }),
758 );
759 }
760
761 if components.contains(&SettingType::Display) {
763 device_storage_factory
764 .initialize_with_loader::<DisplayController<T>, _>(
765 display_loader.expect("Display storage requires display loader"),
766 )
767 .await
768 .expect("storage should still be initializing");
769 let device_storage_factory = Rc::clone(&device_storage_factory);
770 let external_brightness_control =
771 controller_flags.contains(&ControllerFlag::ExternalBrightnessControl);
772 factory_handle.register(
773 SettingType::Display,
774 Box::new(
775 move |context| {
776 if external_brightness_control {
777 DataHandler::<DisplayController<T, ExternalBrightnessControl>>::spawn_with_async(
778 context,
779 Rc::clone(&device_storage_factory))
780 } else {
781 DataHandler::<DisplayController<T>>::spawn_with_async(
782 context,
783 Rc::clone(&device_storage_factory))
784 }
785 }
786 ),
787 );
788 }
789
790 if components.contains(&SettingType::Input) {
792 let input_configuration = Rc::new(std::sync::Mutex::new(
793 input_configuration.expect("Input controller requires an input configuration"),
794 ));
795 device_storage_factory
796 .initialize::<InputController<T>>()
797 .await
798 .expect("storage should still be initializing");
799 let device_storage_factory = Rc::clone(&device_storage_factory);
800 factory_handle.register(
801 SettingType::Input,
802 Box::new(move |context| {
803 DataHandler::<InputController<T>>::spawn_with_async(
804 context,
805 (Rc::clone(&device_storage_factory), Rc::clone(&input_configuration)),
806 )
807 }),
808 );
809 }
810
811 if components.contains(&SettingType::Intl) {
813 device_storage_factory
814 .initialize::<IntlController<T>>()
815 .await
816 .expect("storage should still be initializing");
817 let device_storage_factory = Rc::clone(&device_storage_factory);
818 factory_handle.register(
819 SettingType::Intl,
820 Box::new(move |context| {
821 DataHandler::<IntlController<T>>::spawn_with_async(
822 context,
823 Rc::clone(&device_storage_factory),
824 )
825 }),
826 );
827 }
828
829 if components.contains(&SettingType::Keyboard) {
831 device_storage_factory
832 .initialize::<KeyboardController>()
833 .await
834 .expect("storage should still be initializing");
835 factory_handle.register(
836 SettingType::Keyboard,
837 Box::new(DataHandler::<KeyboardController>::spawn),
838 );
839 }
840
841 if components.contains(&SettingType::DoNotDisturb) {
843 device_storage_factory
844 .initialize::<DoNotDisturbController<T>>()
845 .await
846 .expect("storage should still be initializing");
847 let device_storage_factory = Rc::clone(&device_storage_factory);
848 factory_handle.register(
849 SettingType::DoNotDisturb,
850 Box::new(move |context| {
851 DataHandler::<DoNotDisturbController<T>>::spawn_with_async(
852 context,
853 Rc::clone(&device_storage_factory),
854 )
855 }),
856 );
857 }
858
859 if components.contains(&SettingType::FactoryReset) {
861 device_storage_factory
862 .initialize::<FactoryResetController<T>>()
863 .await
864 .expect("storage should still be initializing");
865 let device_storage_factory = Rc::clone(&device_storage_factory);
866 factory_handle.register(
867 SettingType::FactoryReset,
868 Box::new(move |context| {
869 DataHandler::<FactoryResetController<T>>::spawn_with_async(
870 context,
871 Rc::clone(&device_storage_factory),
872 )
873 }),
874 );
875 }
876
877 if components.contains(&SettingType::NightMode) {
879 device_storage_factory
880 .initialize::<NightModeController>()
881 .await
882 .expect("storage should still be initializing");
883 factory_handle.register(
884 SettingType::NightMode,
885 Box::new(DataHandler::<NightModeController>::spawn),
886 );
887 }
888
889 if components.contains(&SettingType::Privacy) {
891 device_storage_factory
892 .initialize::<PrivacyController>()
893 .await
894 .expect("storage should still be initializing");
895 factory_handle
896 .register(SettingType::Privacy, Box::new(DataHandler::<PrivacyController>::spawn));
897 }
898
899 if components.contains(&SettingType::Setup) {
901 device_storage_factory
902 .initialize::<SetupController>()
903 .await
904 .expect("storage should still be initializing");
905 factory_handle
906 .register(SettingType::Setup, Box::new(DataHandler::<SetupController>::spawn));
907 }
908 }
909}
910
911fn create_agent_blueprints(
912 agent_types: HashSet<AgentType>,
913 agent_blueprints: Vec<AgentCreator>,
914 media_buttons_event_txs: Vec<UnboundedSender<settings_media_buttons::Event>>,
915 setting_value_rx: UnboundedReceiver<(&'static str, String)>,
916 external_event_rx: UnboundedReceiver<ExternalServiceEvent>,
917 mut usage_router_rx: UnboundedReceiver<UsageEvent>,
918) -> Vec<AgentCreator> {
919 let (proxy_event_tx, proxy_event_rx) = mpsc::unbounded();
920 let (usage_event_tx, usage_event_rx) = mpsc::unbounded();
921
922 fasync::Task::local(async move {
924 while let Some(usage_event) = usage_router_rx.next().await {
925 let _ = proxy_event_tx.unbounded_send(usage_event.clone());
926 let _ = usage_event_tx.unbounded_send(usage_event);
927 }
928 })
929 .detach();
930 let media_buttons_registrar = agent_types
931 .contains(&AgentType::MediaButtons)
932 .then(|| agent::media_buttons::create_registrar(media_buttons_event_txs));
933 let inspect_settings_values_registrar = agent_types
934 .contains(&AgentType::InspectSettingValues)
935 .then(|| agent::inspect::setting_values::create_registrar(setting_value_rx));
936 let inspect_external_apis_registrar = agent_types
937 .contains(&AgentType::InspectExternalApis)
938 .then(|| agent::inspect::external_apis::create_registrar(external_event_rx));
939 let inspect_setting_proxy_registrar = agent_types
940 .contains(&AgentType::InspectSettingProxy)
941 .then(|| agent::inspect::setting_proxy::create_registrar(proxy_event_rx));
942 let inspect_usages_registrar = agent_types
943 .contains(&AgentType::InspectSettingTypeUsage)
944 .then(|| agent::inspect::usage_counts::create_registrar(usage_event_rx));
945
946 let agent_registrars = [
947 media_buttons_registrar,
948 inspect_settings_values_registrar,
949 inspect_external_apis_registrar,
950 inspect_setting_proxy_registrar,
951 inspect_usages_registrar,
952 ];
953
954 let mut agent_blueprints = if agent_types.iter().all(|t| {
955 matches!(
956 t,
957 AgentType::MediaButtons
958 | AgentType::InspectSettingValues
959 | AgentType::InspectExternalApis
960 | AgentType::InspectSettingProxy
961 | AgentType::InspectSettingTypeUsage
962 )
963 }) {
964 agent_blueprints
965 } else {
966 agent_types.into_iter().filter_map(AgentCreator::from_type).collect()
967 };
968
969 agent_blueprints.extend(agent_registrars.into_iter().filter_map(|r| r));
970 agent_blueprints
971}
972
973#[allow(clippy::too_many_arguments)]
979async fn create_environment<'a, T>(
980 mut service_dir: ServiceFsDir<'_, ServiceObjLocal<'a, ()>>,
981 delegate: service::message::Delegate,
982 job_seeder: Seeder,
983 components: HashSet<SettingType>,
984 registrants: Vec<Registrant>,
985 agent_blueprints: Vec<AgentCreator>,
986 event_subscriber_blueprints: Vec<event::subscriber::BlueprintHandle>,
987 service_context: Rc<ServiceContext>,
988 handler_factory: Rc<Mutex<SettingHandlerFactoryImpl>>,
989 device_storage_factory: Rc<T>,
990 setting_proxies_node: &fuchsia_inspect::Node,
991 listener_logger: Rc<ListenerInspectLogger>,
992) -> Result<HashSet<Entity>, Error>
993where
994 T: StorageFactory<Storage = DeviceStorage> + 'static,
995{
996 for blueprint in event_subscriber_blueprints {
997 blueprint.create(delegate.clone()).await;
998 }
999
1000 let mut entities = HashSet::new();
1001
1002 for setting_type in &components {
1003 let _ = SettingProxy::create(
1004 *setting_type,
1005 handler_factory.clone(),
1006 delegate.clone(),
1007 DEFAULT_SETTING_PROXY_MAX_ATTEMPTS,
1008 DEFAULT_TEARDOWN_TIMEOUT,
1009 Some(MonotonicDuration::from_millis(DEFAULT_SETTING_PROXY_RESPONSE_TIMEOUT_MS)),
1010 true,
1011 setting_proxies_node.create_child(format!("{setting_type:?}")),
1012 Rc::clone(&listener_logger),
1013 )
1014 .await?;
1015
1016 let _ = entities.insert(Entity::Handler(*setting_type));
1017 }
1018
1019 let mut agent_authority = Authority::create(delegate.clone(), components.clone()).await?;
1020
1021 for registrant in registrants {
1022 if registrant.get_dependencies().iter().all(|dependency| {
1023 let dep_met = dependency.is_fulfilled(&entities);
1024 if !dep_met {
1025 log::error!(
1026 "Skipping {} registration due to missing dependency {:?}",
1027 registrant.get_interface(),
1028 dependency
1029 );
1030 }
1031 dep_met
1032 }) {
1033 registrant.register(&job_seeder, &mut service_dir);
1034 }
1035 }
1036
1037 agent_authority
1039 .register(crate::agent::storage_agent::create_registrar(device_storage_factory))
1040 .await;
1041
1042 for blueprint in agent_blueprints {
1043 agent_authority.register(blueprint).await;
1044 }
1045
1046 agent_authority
1048 .execute_lifespan(Lifespan::Initialization, Rc::clone(&service_context), true)
1049 .await
1050 .context("Agent initialization failed")?;
1051
1052 agent_authority
1054 .execute_lifespan(Lifespan::Service, Rc::clone(&service_context), false)
1055 .await
1056 .context("Agent service start failed")?;
1057
1058 Ok(entities)
1059}
1060
1061#[cfg(test)]
1062mod tests;