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