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