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