1use std::collections::HashSet;
6use std::rc::Rc;
7
8#[cfg(test)]
9use anyhow::format_err;
10use anyhow::{Context, Error};
11use audio::AudioInfoLoader;
12use audio::types::AudioInfo;
13use display::display_controller::DisplayInfoLoader;
14use fidl_fuchsia_io::DirectoryProxy;
15use fidl_fuchsia_settings::{
16 AccessibilityRequestStream, AudioRequestStream, DisplayRequestStream,
17 DoNotDisturbRequestStream, FactoryResetRequestStream, InputRequestStream, IntlRequestStream,
18 KeyboardRequestStream, LightRequestStream, NightModeRequestStream, PrivacyRequestStream,
19 SetupRequestStream,
20};
21use fidl_fuchsia_stash::StoreProxy;
22use fuchsia_component::client::connect_to_protocol;
23#[cfg(test)]
24use fuchsia_component::server::ProtocolConnector;
25use fuchsia_component::server::{ServiceFs, ServiceFsDir, ServiceObjLocal};
26use futures::channel::mpsc::{self, UnboundedReceiver, UnboundedSender};
27use futures::{StreamExt, TryStreamExt};
28#[cfg(test)]
29use log as _;
30use serde::Deserialize;
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::{ExternalServiceEvent, GenerateService, ServiceContext};
38use settings_do_not_disturb::do_not_disturb_controller::DoNotDisturbController;
39use settings_factory_reset::factory_reset_controller::FactoryResetController;
40use settings_input::input_controller::InputController;
41use settings_intl::intl_controller::IntlController;
42use settings_keyboard::keyboard_controller::KeyboardController;
43use settings_light::light_controller::LightController;
44use settings_night_mode::night_mode_controller::NightModeController;
45use settings_privacy::privacy_controller::PrivacyController;
46use settings_setup::setup_controller::SetupController;
47use settings_storage::device_storage::DeviceStorage;
48use settings_storage::fidl_storage::FidlStorage;
49use settings_storage::storage_factory::{FidlStorageFactory, StorageFactory};
50use {fidl_fuchsia_update_verify as fupdate, fuchsia_async as fasync};
51
52pub use display::display_configuration::DisplayConfiguration;
53pub use settings_input::input_device_configuration::InputConfiguration;
54pub use settings_light::light_hardware_configuration::LightHardwareConfiguration;
55
56use crate::accessibility::accessibility_controller::AccessibilityController;
57use crate::audio::Request as AudioRequest;
58use crate::audio::audio_controller::AudioController;
59use crate::base::SettingType;
60use crate::display::display_controller::{DisplayController, ExternalBrightnessControl};
61use crate::ingress::fidl;
62
63mod accessibility;
64pub mod audio;
65mod clock;
66pub mod display;
67mod storage_migrations;
68
69pub mod agent;
70pub mod base;
71pub mod ingress;
72pub(crate) mod migration;
73
74pub type ExitSender = futures::channel::mpsc::UnboundedSender<()>;
76
77#[derive(PartialEq)]
82enum Runtime {
83 Service,
84 #[cfg(test)]
85 Nested(&'static str),
86}
87
88#[derive(Debug, Default, Clone, Deserialize)]
89pub struct AgentConfiguration {
90 pub agent_types: HashSet<AgentType>,
91}
92
93#[derive(PartialEq, Debug, Clone, Deserialize)]
94pub struct EnabledInterfacesConfiguration {
95 pub interfaces: HashSet<fidl::InterfaceSpec>,
96}
97
98impl EnabledInterfacesConfiguration {
99 pub fn with_interfaces(interfaces: HashSet<fidl::InterfaceSpec>) -> Self {
100 Self { interfaces }
101 }
102}
103
104#[derive(Default, Debug, Clone, Deserialize)]
105pub struct ServiceFlags {
106 pub controller_flags: HashSet<ControllerFlag>,
107}
108
109#[derive(PartialEq, Debug, Default, Clone)]
110pub struct ServiceConfiguration {
111 agent_types: HashSet<AgentType>,
112 fidl_interfaces: HashSet<fidl::Interface>,
113 controller_flags: HashSet<ControllerFlag>,
114}
115
116impl ServiceConfiguration {
117 pub fn from(
118 agent_types: AgentConfiguration,
119 interfaces: EnabledInterfacesConfiguration,
120 flags: ServiceFlags,
121 ) -> Self {
122 let fidl_interfaces: HashSet<fidl::Interface> =
123 interfaces.interfaces.into_iter().map(|x| x.into()).collect();
124
125 Self {
126 agent_types: agent_types.agent_types,
127 fidl_interfaces,
128 controller_flags: flags.controller_flags,
129 }
130 }
131
132 fn set_fidl_interfaces(&mut self, interfaces: HashSet<fidl::Interface>) {
133 self.fidl_interfaces = interfaces;
134 }
135
136 fn set_controller_flags(&mut self, controller_flags: HashSet<ControllerFlag>) {
137 self.controller_flags = controller_flags;
138 }
139}
140
141#[cfg(test)]
146pub struct Environment {
147 pub connector: Option<ProtocolConnector>,
148 pub settings: HashSet<SettingType>,
149}
150
151#[cfg(test)]
152impl Environment {
153 pub fn new(
154 connector: Option<ProtocolConnector>,
155 settings: HashSet<SettingType>,
156 ) -> Environment {
157 Environment { connector, settings }
158 }
159}
160
161#[cfg(test)]
162fn init_storage_dir() -> DirectoryProxy {
163 let tempdir = tempfile::tempdir().expect("failed to create tempdir");
164 fuchsia_fs::directory::open_in_namespace(
165 tempdir.path().to_str().expect("tempdir path is not valid UTF-8"),
166 fuchsia_fs::PERM_READABLE | fuchsia_fs::PERM_WRITABLE,
167 )
168 .expect("failed to open connection to tempdir")
169}
170
171#[cfg(not(test))]
172fn init_storage_dir() -> DirectoryProxy {
173 panic!("migration dir must be specified");
174}
175
176pub struct EnvironmentBuilder<T: StorageFactory<Storage = DeviceStorage>> {
179 configuration: Option<ServiceConfiguration>,
180 storage_factory: Rc<T>,
181 generate_service: Option<GenerateService>,
182 settings: Vec<SettingType>,
183 active_listener_inspect_logger: Option<Rc<ListenerInspectLogger>>,
184 storage_dir: Option<DirectoryProxy>,
185 store_proxy: Option<StoreProxy>,
186 fidl_storage_factory: Option<Rc<FidlStorageFactory>>,
187 display_configuration: Option<DefaultSetting<DisplayConfiguration, &'static str>>,
188 audio_configuration: Option<DefaultSetting<AudioInfo, &'static str>>,
189 input_configuration: Option<DefaultSetting<InputConfiguration, &'static str>>,
190 light_configuration: Option<DefaultSetting<LightHardwareConfiguration, &'static str>>,
191 media_buttons_event_txs: Vec<UnboundedSender<settings_media_buttons::Event>>,
192}
193
194impl<T: StorageFactory<Storage = DeviceStorage> + 'static> EnvironmentBuilder<T> {
195 pub fn new(storage_factory: Rc<T>) -> Self {
198 EnvironmentBuilder {
199 configuration: None,
200 storage_factory,
201 generate_service: None,
202 settings: vec![],
203 active_listener_inspect_logger: None,
204 storage_dir: None,
205 store_proxy: None,
206 fidl_storage_factory: None,
207 display_configuration: None,
208 audio_configuration: None,
209 input_configuration: None,
210 light_configuration: None,
211 media_buttons_event_txs: vec![],
212 }
213 }
214
215 pub fn service(mut self, generate_service: GenerateService) -> Self {
217 self.generate_service = Some(generate_service);
218 self
219 }
220
221 pub fn configuration(mut self, configuration: ServiceConfiguration) -> Self {
225 self.configuration = Some(configuration);
226 self
227 }
228
229 pub fn display_configuration(
230 mut self,
231 display_configuration: DefaultSetting<DisplayConfiguration, &'static str>,
232 ) -> Self {
233 self.display_configuration = Some(display_configuration);
234 self
235 }
236
237 pub fn audio_configuration(
238 mut self,
239 audio_configuration: DefaultSetting<AudioInfo, &'static str>,
240 ) -> Self {
241 self.audio_configuration = Some(audio_configuration);
242 self
243 }
244
245 pub fn input_configuration(
246 mut self,
247 input_configuration: DefaultSetting<InputConfiguration, &'static str>,
248 ) -> Self {
249 self.input_configuration = Some(input_configuration);
250 self
251 }
252
253 pub fn light_configuration(
254 mut self,
255 light_configuration: DefaultSetting<LightHardwareConfiguration, &'static str>,
256 ) -> Self {
257 self.light_configuration = Some(light_configuration);
258 self
259 }
260
261 pub fn fidl_interfaces(mut self, interfaces: &[fidl::Interface]) -> Self {
263 if self.configuration.is_none() {
264 self.configuration = Some(ServiceConfiguration::default());
265 }
266
267 if let Some(c) = self.configuration.as_mut() {
268 c.set_fidl_interfaces(interfaces.iter().copied().collect());
269 }
270
271 self
272 }
273
274 pub fn settings(mut self, settings: &[SettingType]) -> Self {
276 self.settings.extend(settings);
277
278 self
279 }
280
281 pub fn flags(mut self, controller_flags: &[ControllerFlag]) -> Self {
283 if self.configuration.is_none() {
284 self.configuration = Some(ServiceConfiguration::default());
285 }
286
287 if let Some(c) = self.configuration.as_mut() {
288 c.set_controller_flags(controller_flags.iter().copied().collect());
289 }
290
291 self
292 }
293
294 pub fn listener_inspect_logger(
297 mut self,
298 active_listener_inspect_logger: Rc<ListenerInspectLogger>,
299 ) -> Self {
300 self.active_listener_inspect_logger = Some(active_listener_inspect_logger);
301 self
302 }
303
304 pub fn storage_dir(mut self, storage_dir: DirectoryProxy) -> Self {
305 self.storage_dir = Some(storage_dir);
306 self
307 }
308
309 pub fn store_proxy(mut self, store_proxy: StoreProxy) -> Self {
310 self.store_proxy = Some(store_proxy);
311 self
312 }
313
314 pub fn fidl_storage_factory(mut self, fidl_storage_factory: Rc<FidlStorageFactory>) -> Self {
315 self.fidl_storage_factory = Some(fidl_storage_factory);
316 self
317 }
318
319 pub fn media_buttons_event_txs(
320 mut self,
321 media_buttons_event_txs: Vec<UnboundedSender<settings_media_buttons::Event>>,
322 ) -> Self {
323 self.media_buttons_event_txs.extend(media_buttons_event_txs);
324 self
325 }
326
327 async fn prepare_env(
330 mut self,
331 mut fs: ServiceFs<ServiceObjLocal<'_, ()>>,
332 runtime: Runtime,
333 ) -> Result<(ServiceFs<ServiceObjLocal<'_, ()>>, HashSet<SettingType>), Error> {
334 let mut service_dir = match runtime {
335 Runtime::Service => fs.dir("svc"),
336 #[cfg(test)]
337 Runtime::Nested(_) => fs.root_dir(),
338 };
339
340 let _ = service_dir.add_fidl_service(
341 move |mut stream: fupdate::ComponentOtaHealthCheckRequestStream| {
342 fasync::Task::local(async move {
343 while let Some(fupdate::ComponentOtaHealthCheckRequest::GetHealthStatus {
344 responder,
345 }) = stream.try_next().await.expect("error running health check service")
346 {
347 responder
351 .send(fupdate::HealthStatus::Healthy)
352 .expect("failed to send health status");
353 }
354 })
355 .detach();
356 },
357 );
358
359 let (agent_types, fidl_interfaces, flags) = match self.configuration {
360 Some(configuration) => (
361 configuration.agent_types,
362 configuration.fidl_interfaces,
363 configuration.controller_flags,
364 ),
365 _ => (HashSet::new(), HashSet::new(), HashSet::new()),
366 };
367
368 let mut settings: HashSet<_> = fidl_interfaces.into_iter().map(SettingType::from).collect();
369 settings.extend(self.settings);
370
371 let fidl_storage_factory = if let Some(factory) = self.fidl_storage_factory {
372 factory
373 } else {
374 let (migration_id, storage_dir) = if let Some(storage_dir) = self.storage_dir {
375 let store_proxy = self.store_proxy.unwrap_or_else(|| {
376 let store_proxy = connect_to_protocol::<fidl_fuchsia_stash::StoreMarker>()
377 .expect("failed to connect to stash");
378 store_proxy
379 .identify("setting_service")
380 .expect("should be able to identify to stash");
381 store_proxy
382 });
383
384 let migration_manager = storage_migrations::register_migrations(
385 &settings,
386 Clone::clone(&storage_dir),
387 store_proxy,
388 )
389 .context("failed to register migrations")?;
390 let migration_id = match migration_manager.run_migrations().await {
391 Ok(id) => {
392 log::info!("migrated storage to {id:?}");
393 id
394 }
395 Err((id, e)) => {
396 log::error!("Settings migration failed: {e:?}");
397 id
398 }
399 };
400 let migration_id = migration_id.map(|migration| migration.migration_id);
401 (migration_id, storage_dir)
402 } else {
403 (None, init_storage_dir())
404 };
405
406 Rc::new(FidlStorageFactory::new(migration_id.unwrap_or(0), storage_dir))
407 };
408
409 let service_context = Rc::new(ServiceContext::new(self.generate_service));
410
411 let audio_info_loader = self.audio_configuration.map(AudioInfoLoader::new);
412 Self::initialize_storage(
413 &settings,
414 &*fidl_storage_factory,
415 &*self.storage_factory,
416 audio_info_loader.clone(),
417 self.display_configuration.map(DisplayInfoLoader::new),
418 )
419 .await;
420
421 let (external_event_tx, external_event_rx) = mpsc::unbounded();
422 let external_publisher = ExternalEventPublisher::new(external_event_tx);
423
424 let listener_logger = self
425 .active_listener_inspect_logger
426 .unwrap_or_else(|| Rc::new(ListenerInspectLogger::new()));
427
428 let RegistrationResult {
429 camera_watcher_event_txs,
430 media_buttons_event_txs,
431 setting_value_rx,
432 usage_event_rx,
433 audio_request_tx,
434 tasks,
435 } = Self::register_controllers(
436 &settings,
437 Rc::clone(&service_context),
438 fidl_storage_factory,
439 self.storage_factory,
440 &flags,
441 audio_info_loader,
442 self.input_configuration,
443 self.light_configuration,
444 &mut service_dir,
445 Rc::clone(&listener_logger),
446 external_publisher.clone(),
447 )
448 .await;
449 for task in tasks {
450 task.detach();
451 }
452
453 self.media_buttons_event_txs.extend(media_buttons_event_txs);
454
455 let agent_result = create_agents(
456 &settings,
457 agent_types,
458 camera_watcher_event_txs,
459 self.media_buttons_event_txs,
460 setting_value_rx,
461 external_event_rx,
462 external_publisher,
463 usage_event_rx,
464 audio_request_tx,
465 );
466
467 run_agents(agent_result, service_context).await;
468
469 Ok((fs, settings))
470 }
471
472 pub fn spawn(
475 self,
476 mut executor: fasync::LocalExecutor,
477 fs: ServiceFs<ServiceObjLocal<'_, ()>>,
478 ) -> Result<(), Error> {
479 let (mut fs, ..) = executor
480 .run_singlethreaded(self.prepare_env(fs, Runtime::Service))
481 .context("Failed to prepare env")?;
482
483 let _ = fs.take_and_serve_directory_handle().expect("could not service directory handle");
484 executor.run_singlethreaded(fs.collect::<()>());
485 Ok(())
486 }
487
488 #[cfg(test)]
490 pub async fn spawn_nested(self, env_name: &'static str) -> Result<Environment, Error> {
491 let (mut fs, entities) = self
492 .prepare_env(ServiceFs::new_local(), Runtime::Nested(env_name))
493 .await
494 .context("Failed to prepare env")?;
495 let connector = Some(fs.create_protocol_connector()?);
496 fasync::Task::local(fs.collect()).detach();
497
498 Ok(Environment::new(connector, entities))
499 }
500
501 #[cfg(test)]
506 pub async fn spawn_and_get_protocol_connector(
507 self,
508 env_name: &'static str,
509 ) -> Result<ProtocolConnector, Error> {
510 let environment = self.spawn_nested(env_name).await?;
511
512 environment.connector.ok_or_else(|| format_err!("connector not created"))
513 }
514}
515
516struct RegistrationResult {
517 camera_watcher_event_txs: Vec<UnboundedSender<bool>>,
518 media_buttons_event_txs: Vec<UnboundedSender<settings_media_buttons::Event>>,
519 setting_value_rx: UnboundedReceiver<(&'static str, String)>,
520 usage_event_rx: UnboundedReceiver<UsageEvent>,
521 audio_request_tx: Option<UnboundedSender<AudioRequest>>,
522 tasks: Vec<fasync::Task<()>>,
523}
524
525impl<T: StorageFactory<Storage = DeviceStorage> + 'static> EnvironmentBuilder<T> {
526 async fn initialize_storage<F, D>(
527 components: &HashSet<SettingType>,
528 fidl_storage_factory: &F,
529 device_storage_factory: &D,
530 audio_info_loader: Option<AudioInfoLoader>,
531 display_loader: Option<DisplayInfoLoader>,
532 ) where
533 F: StorageFactory<Storage = FidlStorage>,
534 D: StorageFactory<Storage = DeviceStorage>,
535 {
536 if components.contains(&SettingType::Accessibility) {
537 device_storage_factory
538 .initialize::<AccessibilityController>()
539 .await
540 .expect("storage should still be initializing");
541 }
542
543 if components.contains(&SettingType::Audio) {
544 device_storage_factory
545 .initialize_with_loader::<AudioController, _>(
546 audio_info_loader.expect("Audio storage requires audio configuration"),
547 )
548 .await
549 .expect("storage should still be initializing");
550 }
551
552 if components.contains(&SettingType::Display) {
553 device_storage_factory
554 .initialize_with_loader::<DisplayController, _>(
555 display_loader.expect("Display storage requires display configuration"),
556 )
557 .await
558 .expect("storage should still be initializing");
559 }
560
561 if components.contains(&SettingType::DoNotDisturb) {
562 device_storage_factory
563 .initialize::<DoNotDisturbController>()
564 .await
565 .expect("storage should still be initializing");
566 }
567
568 if components.contains(&SettingType::FactoryReset) {
569 device_storage_factory
570 .initialize::<FactoryResetController>()
571 .await
572 .expect("storage should still be initializing");
573 }
574
575 if components.contains(&SettingType::Input) {
576 device_storage_factory
577 .initialize::<InputController>()
578 .await
579 .expect("storage should still be initializing");
580 }
581
582 if components.contains(&SettingType::Intl) {
583 device_storage_factory
584 .initialize::<IntlController>()
585 .await
586 .expect("storage should still be initializing");
587 }
588
589 if components.contains(&SettingType::Keyboard) {
590 device_storage_factory
591 .initialize::<KeyboardController>()
592 .await
593 .expect("storage should still be initializing");
594 }
595
596 if components.contains(&SettingType::Light) {
597 fidl_storage_factory
598 .initialize::<LightController>()
599 .await
600 .expect("storage should still be initializing");
601 }
602
603 if components.contains(&SettingType::NightMode) {
604 device_storage_factory
605 .initialize::<NightModeController>()
606 .await
607 .expect("storage should still be initializing");
608 }
609
610 if components.contains(&SettingType::Privacy) {
611 device_storage_factory
612 .initialize::<PrivacyController>()
613 .await
614 .expect("storage should still be initializing");
615 }
616
617 if components.contains(&SettingType::Setup) {
618 device_storage_factory
619 .initialize::<SetupController>()
620 .await
621 .expect("storage should still be initializing");
622 }
623 }
624
625 async fn register_controllers<F, D>(
626 components: &HashSet<SettingType>,
627 service_context: Rc<ServiceContext>,
628 fidl_storage_factory: Rc<F>,
629 device_storage_factory: Rc<D>,
630 controller_flags: &HashSet<ControllerFlag>,
631 audio_info_loader: Option<AudioInfoLoader>,
632 input_configuration: Option<DefaultSetting<InputConfiguration, &'static str>>,
633 light_configuration: Option<DefaultSetting<LightHardwareConfiguration, &'static str>>,
634 service_dir: &mut ServiceFsDir<'_, ServiceObjLocal<'_, ()>>,
635 listener_logger: Rc<ListenerInspectLogger>,
636 external_publisher: ExternalEventPublisher,
637 ) -> RegistrationResult
638 where
639 F: StorageFactory<Storage = FidlStorage>,
640 D: StorageFactory<Storage = DeviceStorage>,
641 {
642 let (setting_value_tx, setting_value_rx) = mpsc::unbounded();
643 let (usage_event_tx, usage_event_rx) = mpsc::unbounded();
644 let mut camera_watcher_event_txs = vec![];
645 let mut media_buttons_event_txs = vec![];
646 let mut tasks = vec![];
647
648 if components.contains(&SettingType::Accessibility) {
650 let accessibility::SetupResult { mut accessibility_fidl_handler, task } =
651 accessibility::setup_accessibility_api(
652 Rc::clone(&device_storage_factory),
653 SettingValuePublisher::new(setting_value_tx.clone()),
654 UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
655 )
656 .await;
657 tasks.push(task);
658 let _ = service_dir.add_fidl_service(move |stream: AccessibilityRequestStream| {
659 accessibility_fidl_handler.handle_stream(stream)
660 });
661 }
662
663 let audio_request_tx = if components.contains(&SettingType::Audio) {
664 let audio::SetupResult { mut audio_fidl_handler, request_tx: audio_request_tx, task } =
665 audio::setup_audio_api(
666 Rc::clone(&service_context),
667 audio_info_loader.expect("Audio controller requires audio configuration"),
668 Rc::clone(&device_storage_factory),
669 SettingValuePublisher::new(setting_value_tx.clone()),
670 UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
671 external_publisher.clone(),
672 )
673 .await;
674 tasks.push(task);
675 let _ = service_dir.add_fidl_service(move |stream: AudioRequestStream| {
676 audio_fidl_handler.handle_stream(stream)
677 });
678 Some(audio_request_tx)
679 } else {
680 None
681 };
682
683 if components.contains(&SettingType::Display) {
684 let result = if controller_flags.contains(&ControllerFlag::ExternalBrightnessControl) {
685 display::setup_display_api::<D, ExternalBrightnessControl>(
686 &*service_context,
687 Rc::clone(&device_storage_factory),
688 SettingValuePublisher::new(setting_value_tx.clone()),
689 UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
690 external_publisher.clone(),
691 )
692 .await
693 } else {
694 display::setup_display_api::<D, ()>(
695 &*service_context,
696 Rc::clone(&device_storage_factory),
697 SettingValuePublisher::new(setting_value_tx.clone()),
698 UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
699 external_publisher.clone(),
700 )
701 .await
702 };
703 match result {
704 Ok(display::SetupResult { mut display_fidl_handler, task }) => {
705 tasks.push(task);
706 let _ = service_dir.add_fidl_service(move |stream: DisplayRequestStream| {
707 display_fidl_handler.handle_stream(stream)
708 });
709 }
710 Err(e) => {
711 log::error!("Failed to setup display api: {e:?}");
712 }
713 }
714 }
715
716 if components.contains(&SettingType::DoNotDisturb) {
717 let settings_do_not_disturb::SetupResult { mut do_not_disturb_fidl_handler, task } =
718 settings_do_not_disturb::setup_do_not_disturb_api(
719 Rc::clone(&device_storage_factory),
720 SettingValuePublisher::new(setting_value_tx.clone()),
721 UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
722 )
723 .await;
724 tasks.push(task);
725 let _ = service_dir.add_fidl_service(move |stream: DoNotDisturbRequestStream| {
726 do_not_disturb_fidl_handler.handle_stream(stream)
727 });
728 }
729
730 if components.contains(&SettingType::FactoryReset) {
731 match settings_factory_reset::setup_factory_reset_api(
732 &*service_context,
733 Rc::clone(&device_storage_factory),
734 SettingValuePublisher::new(setting_value_tx.clone()),
735 UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
736 external_publisher.clone(),
737 )
738 .await
739 {
740 Ok(settings_factory_reset::SetupResult {
741 mut factory_reset_fidl_handler,
742 task,
743 }) => {
744 tasks.push(task);
745 let _ =
746 service_dir.add_fidl_service(move |stream: FactoryResetRequestStream| {
747 factory_reset_fidl_handler.handle_stream(stream)
748 });
749 }
750 Err(e) => {
751 log::error!("Failed to setup factory reset api: {e:?}");
752 }
753 }
754 }
755
756 if components.contains(&SettingType::Input) {
757 let mut input_configuration =
758 input_configuration.expect("Input controller requires an input configuration");
759 match settings_input::setup_input_api(
760 Rc::clone(&service_context),
761 &mut input_configuration,
762 Rc::clone(&device_storage_factory),
763 SettingValuePublisher::new(setting_value_tx.clone()),
764 UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
765 external_publisher.clone(),
766 )
767 .await
768 {
769 Ok(settings_input::SetupResult {
770 mut input_fidl_handler,
771 camera_watcher_event_tx,
772 media_buttons_event_tx,
773 task,
774 }) => {
775 camera_watcher_event_txs.push(camera_watcher_event_tx);
776 media_buttons_event_txs.push(media_buttons_event_tx);
777 tasks.push(task);
778 let _ = service_dir.add_fidl_service(move |stream: InputRequestStream| {
779 input_fidl_handler.handle_stream(stream)
780 });
781 }
782 Err(e) => {
783 log::error!("Failed to setup input api: {e:?}");
784 }
785 }
786 }
787
788 if components.contains(&SettingType::Light) {
789 let mut light_configuration =
790 light_configuration.expect("Light controller requires a light configuration");
791 match settings_light::setup_light_api(
792 Rc::clone(&service_context),
793 &mut light_configuration,
794 fidl_storage_factory,
795 SettingValuePublisher::new(setting_value_tx.clone()),
796 UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
797 external_publisher.clone(),
798 )
799 .await
800 {
801 Ok(settings_light::SetupResult {
802 mut light_fidl_handler,
803 media_buttons_event_tx,
804 task,
805 }) => {
806 media_buttons_event_txs.push(media_buttons_event_tx);
807 tasks.push(task);
808 let _ = service_dir.add_fidl_service(move |stream: LightRequestStream| {
809 light_fidl_handler.handle_stream(stream)
810 });
811 }
812 Err(e) => {
813 log::error!("Failed to setup light api: {e:?}");
814 }
815 }
816 }
817
818 if components.contains(&SettingType::Intl) {
819 let settings_intl::SetupResult { mut intl_fidl_handler, task } =
820 settings_intl::setup_intl_api(
821 Rc::clone(&device_storage_factory),
822 SettingValuePublisher::new(setting_value_tx.clone()),
823 UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
824 )
825 .await;
826 tasks.push(task);
827 let _ = service_dir.add_fidl_service(move |stream: IntlRequestStream| {
828 intl_fidl_handler.handle_stream(stream)
829 });
830 }
831
832 if components.contains(&SettingType::Keyboard) {
833 let settings_keyboard::SetupResult { mut keyboard_fidl_handler, task } =
834 settings_keyboard::setup_keyboard_api(
835 Rc::clone(&device_storage_factory),
836 SettingValuePublisher::new(setting_value_tx.clone()),
837 UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
838 )
839 .await;
840 tasks.push(task);
841 let _ = service_dir.add_fidl_service(move |stream: KeyboardRequestStream| {
842 keyboard_fidl_handler.handle_stream(stream)
843 });
844 }
845
846 if components.contains(&SettingType::NightMode) {
847 let settings_night_mode::SetupResult { mut night_mode_fidl_handler, task } =
848 settings_night_mode::setup_night_mode_api(
849 Rc::clone(&device_storage_factory),
850 SettingValuePublisher::new(setting_value_tx.clone()),
851 UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
852 )
853 .await;
854 tasks.push(task);
855 let _ = service_dir.add_fidl_service(move |stream: NightModeRequestStream| {
856 night_mode_fidl_handler.handle_stream(stream)
857 });
858 }
859
860 if components.contains(&SettingType::Privacy) {
861 let settings_privacy::SetupResult { mut privacy_fidl_handler, task } =
862 settings_privacy::setup_privacy_api(
863 Rc::clone(&device_storage_factory),
864 SettingValuePublisher::new(setting_value_tx.clone()),
865 UsagePublisher::new(usage_event_tx.clone(), Rc::clone(&listener_logger)),
866 )
867 .await;
868 tasks.push(task);
869 let _ = service_dir.add_fidl_service(move |stream: PrivacyRequestStream| {
870 privacy_fidl_handler.handle_stream(stream)
871 });
872 }
873
874 if components.contains(&SettingType::Setup) {
875 let settings_setup::SetupResult { mut setup_fidl_handler, task } =
876 settings_setup::setup_setup_api(
877 service_context,
878 device_storage_factory,
879 SettingValuePublisher::new(setting_value_tx),
880 UsagePublisher::new(usage_event_tx, listener_logger),
881 external_publisher,
882 )
883 .await;
884 tasks.push(task);
885 let _ = service_dir.add_fidl_service(move |stream: SetupRequestStream| {
886 setup_fidl_handler.handle_stream(stream)
887 });
888 }
889
890 RegistrationResult {
891 camera_watcher_event_txs,
892 media_buttons_event_txs,
893 setting_value_rx,
894 usage_event_rx,
895 audio_request_tx,
896 tasks,
897 }
898 }
899}
900
901struct AgentResult {
902 earcons_agent: Option<agent::earcons::agent::Agent>,
903 camera_watcher_agent: Option<settings_camera_watcher_agent::CameraWatcherAgent>,
904 media_buttons_agent: Option<settings_media_buttons_agent::MediaButtonsAgent>,
905 inspect_settings_values_agent: Option<agent::inspect::setting_values::AgentSetup>,
906 inspect_external_apis_agent: Option<agent::inspect::external_apis::ExternalApiInspectAgent>,
907 inspect_setting_proxy_agent: Option<agent::inspect::setting_proxy::SettingProxyInspectAgent>,
908 inspect_usages_agent: Option<agent::inspect::usage_counts::SettingTypeUsageInspectAgent>,
909}
910
911fn create_agents(
912 settings: &HashSet<SettingType>,
913 agent_types: HashSet<AgentType>,
914 camera_watcher_event_txs: Vec<UnboundedSender<bool>>,
915 media_buttons_event_txs: Vec<UnboundedSender<settings_media_buttons::Event>>,
916 setting_value_rx: UnboundedReceiver<(&'static str, String)>,
917 external_event_rx: UnboundedReceiver<ExternalServiceEvent>,
918 external_publisher: ExternalEventPublisher,
919 mut usage_router_rx: UnboundedReceiver<UsageEvent>,
920 audio_request_tx: Option<UnboundedSender<AudioRequest>>,
921) -> AgentResult {
922 let (proxy_event_tx, proxy_event_rx) = mpsc::unbounded();
923 let (usage_event_tx, usage_event_rx) = mpsc::unbounded();
924
925 fasync::Task::local(async move {
927 while let Some(usage_event) = usage_router_rx.next().await {
928 let _ = proxy_event_tx.unbounded_send(usage_event.clone());
929 let _ = usage_event_tx.unbounded_send(usage_event);
930 }
931 })
932 .detach();
933 let earcons_agent = agent_types
934 .contains(&AgentType::Earcons)
935 .then(|| agent::earcons::agent::Agent::new(audio_request_tx, external_publisher.clone()));
936 let camera_watcher_agent = agent_types.contains(&AgentType::CameraWatcher).then(|| {
937 settings_camera_watcher_agent::CameraWatcherAgent::new(
938 camera_watcher_event_txs,
939 external_publisher.clone(),
940 )
941 });
942 let media_buttons_agent = agent_types.contains(&AgentType::MediaButtons).then(|| {
943 settings_media_buttons_agent::MediaButtonsAgent::new(
944 media_buttons_event_txs,
945 external_publisher,
946 )
947 });
948 let inspect_settings_values_agent = agent_types
949 .contains(&AgentType::InspectSettingValues)
950 .then(|| {
951 agent::inspect::setting_values::SettingValuesInspectAgent::new(
952 settings.iter().map(|setting| format!("{setting:?}")).collect(),
953 setting_value_rx,
954 )
955 })
956 .and_then(|opt| opt);
957 let inspect_external_apis_agent = agent_types
958 .contains(&AgentType::InspectExternalApis)
959 .then(|| agent::inspect::external_apis::ExternalApiInspectAgent::new(external_event_rx));
960 let inspect_setting_proxy_agent = agent_types
961 .contains(&AgentType::InspectSettingProxy)
962 .then(|| agent::inspect::setting_proxy::SettingProxyInspectAgent::new(proxy_event_rx));
963 let inspect_usages_agent = agent_types
964 .contains(&AgentType::InspectSettingTypeUsage)
965 .then(|| agent::inspect::usage_counts::SettingTypeUsageInspectAgent::new(usage_event_rx));
966
967 AgentResult {
968 earcons_agent,
969 camera_watcher_agent,
970 media_buttons_agent,
971 inspect_settings_values_agent,
972 inspect_external_apis_agent,
973 inspect_setting_proxy_agent,
974 inspect_usages_agent,
975 }
976}
977
978async fn run_agents(agent_result: AgentResult, service_context: Rc<ServiceContext>) {
979 if let Some(earcons_agent) = agent_result.earcons_agent {
980 earcons_agent.initialize(Rc::clone(&service_context)).await;
981 }
982
983 if let Some(inspect_settings_values_agent) = agent_result.inspect_settings_values_agent {
984 inspect_settings_values_agent.initialize(
985 #[cfg(test)]
986 None,
987 );
988 }
989
990 if let Some(inspect_external_apis_agent) = agent_result.inspect_external_apis_agent {
991 inspect_external_apis_agent.initialize();
992 }
993
994 if let Some(inspect_setting_proxy_agent) = agent_result.inspect_setting_proxy_agent {
995 inspect_setting_proxy_agent.initialize();
996 }
997
998 if let Some(inspect_usages_agent) = agent_result.inspect_usages_agent {
999 inspect_usages_agent.initialize();
1000 }
1001
1002 if let Some(camera_watcher_agent) = agent_result.camera_watcher_agent {
1003 if let Err(e) = camera_watcher_agent.spawn(&*service_context).await {
1004 log::error!("Failed to spawn camera watcher agent: {e:?}");
1005 }
1006 }
1007
1008 if let Some(media_buttons_agent) = agent_result.media_buttons_agent {
1009 if let Err(e) = media_buttons_agent.spawn(&*service_context).await {
1010 log::error!("Failed to spawn camera watcher agent: {e:?}");
1011 }
1012 }
1013}
1014
1015#[cfg(test)]
1016mod tests;