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::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
108pub(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
117pub type ExitSender = futures::channel::mpsc::UnboundedSender<()>;
119
120#[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#[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
223pub 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 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 pub fn handler(mut self, setting_type: SettingType, generate_handler: GenerateHandler) -> Self {
274 let _ = self.handlers.insert(setting_type, generate_handler);
276 self
277 }
278
279 pub fn service(mut self, generate_service: GenerateService) -> Self {
281 self.generate_service = Some(generate_service);
282 self
283 }
284
285 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 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 pub fn registrants(mut self, mut registrants: Vec<Registrant>) -> Self {
340 self.registrants.append(&mut registrants);
341
342 self
343 }
344
345 pub fn settings(mut self, settings: &[SettingType]) -> Self {
347 self.settings.extend(settings);
348
349 self
350 }
351
352 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 pub fn agents(mut self, mut registrars: Vec<AgentCreator>) -> Self {
367 self.agent_blueprints.append(&mut registrars);
368 self
369 }
370
371 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 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 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 responder
437 .send(fupdate::HealthStatus::Healthy)
438 .expect("failed to send health status");
439 }
440 })
441 .detach();
442 },
443 );
444
445 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 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 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 #[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 #[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 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 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 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 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 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 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 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 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 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#[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 agent_authority
1098 .execute_lifespan(Lifespan::Initialization, Rc::clone(&service_context), true)
1099 .await
1100 .context("Agent initialization failed")?;
1101
1102 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;