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