1use std::collections::{HashMap, HashSet};
6use std::rc::Rc;
7use std::sync::atomic::AtomicU64;
8
9#[cfg(test)]
10use anyhow::format_err;
11use anyhow::{Context, Error};
12use audio::types::AudioInfo;
13use audio::AudioInfoLoader;
14use display::display_controller::DisplayInfoLoader;
15use fidl_fuchsia_io::DirectoryProxy;
16use fidl_fuchsia_stash::StoreProxy;
17use fuchsia_component::client::connect_to_protocol;
18#[cfg(test)]
19use fuchsia_component::server::ProtocolConnector;
20use fuchsia_component::server::{ServiceFs, ServiceFsDir, ServiceObjLocal};
21use fuchsia_inspect::component;
22use futures::lock::Mutex;
23use futures::{StreamExt, TryStreamExt};
24#[cfg(test)]
25use log as _;
26use settings_storage::device_storage::DeviceStorage;
27use settings_storage::fidl_storage::FidlStorage;
28use settings_storage::storage_factory::{FidlStorageFactory, StorageFactory};
29use zx::MonotonicDuration;
30use {fidl_fuchsia_update_verify as fupdate, fuchsia_async as fasync};
31
32pub use display::display_configuration::DisplayConfiguration;
33pub use handler::setting_proxy_inspect_info::SettingProxyInspectInfo;
34pub use input::input_device_configuration::InputConfiguration;
35pub use light::light_hardware_configuration::LightHardwareConfiguration;
36use serde::Deserialize;
37pub use service::{Address, Payload};
38
39use crate::accessibility::accessibility_controller::AccessibilityController;
40use crate::agent::authority::Authority;
41use crate::agent::{AgentCreator, Lifespan};
42use crate::audio::audio_controller::AudioController;
43use crate::base::{Dependency, Entity, SettingType};
44use crate::config::base::{AgentType, ControllerFlag};
45use crate::config::default_settings::DefaultSetting;
46use crate::display::display_controller::{DisplayController, ExternalBrightnessControl};
47use crate::do_not_disturb::do_not_disturb_controller::DoNotDisturbController;
48use crate::factory_reset::factory_reset_controller::FactoryResetController;
49use crate::handler::base::GenerateHandler;
50use crate::handler::setting_handler::persist::Handler as DataHandler;
51use crate::handler::setting_handler_factory_impl::SettingHandlerFactoryImpl;
52use crate::handler::setting_proxy::SettingProxy;
53use crate::ingress::fidl;
54use crate::ingress::registration::Registrant;
55use crate::input::input_controller::InputController;
56use crate::inspect::listener_logger::ListenerInspectLogger;
57use crate::intl::intl_controller::IntlController;
58use crate::job::manager::Manager;
59use crate::job::source::Seeder;
60use crate::keyboard::keyboard_controller::KeyboardController;
61use crate::light::light_controller::LightController;
62use crate::night_mode::night_mode_controller::NightModeController;
63use crate::privacy::privacy_controller::PrivacyController;
64use crate::service::message::Delegate;
65use crate::service_context::{GenerateService, ServiceContext};
66use crate::setup::setup_controller::SetupController;
67
68mod accessibility;
69pub mod audio;
70mod clock;
71pub mod display;
72mod do_not_disturb;
73mod event;
74mod factory_reset;
75pub mod input;
76mod intl;
77mod job;
78mod keyboard;
79pub mod light;
80mod night_mode;
81mod privacy;
82mod service;
83mod setup;
84mod storage_migrations;
85
86pub mod agent;
87pub mod base;
88pub mod config;
89pub mod handler;
90pub mod ingress;
91pub mod inspect;
92pub mod message;
93pub(crate) mod migration;
94pub mod service_context;
95pub mod storage;
96pub mod trace;
97
98pub(crate) const DEFAULT_TEARDOWN_TIMEOUT: MonotonicDuration = MonotonicDuration::from_seconds(5);
104const DEFAULT_SETTING_PROXY_MAX_ATTEMPTS: u64 = 3;
105const DEFAULT_SETTING_PROXY_RESPONSE_TIMEOUT_MS: i64 = 10_000;
106
107pub type ExitSender = futures::channel::mpsc::UnboundedSender<()>;
109
110#[derive(PartialEq)]
115enum Runtime {
116 Service,
117 #[cfg(test)]
118 Nested(&'static str),
119}
120
121#[derive(Debug, Default, Clone, Deserialize)]
122pub struct AgentConfiguration {
123 pub agent_types: HashSet<AgentType>,
124}
125
126#[derive(PartialEq, Debug, Clone, Deserialize)]
127pub struct EnabledInterfacesConfiguration {
128 pub interfaces: HashSet<fidl::InterfaceSpec>,
129}
130
131impl EnabledInterfacesConfiguration {
132 pub fn with_interfaces(interfaces: HashSet<fidl::InterfaceSpec>) -> Self {
133 Self { interfaces }
134 }
135}
136
137#[derive(Default, Debug, Clone, Deserialize)]
138pub struct ServiceFlags {
139 pub controller_flags: HashSet<ControllerFlag>,
140}
141
142#[derive(PartialEq, Debug, Default, Clone)]
143pub struct ServiceConfiguration {
144 agent_types: HashSet<AgentType>,
145 fidl_interfaces: HashSet<fidl::Interface>,
146 controller_flags: HashSet<ControllerFlag>,
147}
148
149impl ServiceConfiguration {
150 pub fn from(
151 agent_types: AgentConfiguration,
152 interfaces: EnabledInterfacesConfiguration,
153 flags: ServiceFlags,
154 ) -> Self {
155 let fidl_interfaces: HashSet<fidl::Interface> =
156 interfaces.interfaces.into_iter().map(|x| x.into()).collect();
157
158 Self {
159 agent_types: agent_types.agent_types,
160 fidl_interfaces,
161 controller_flags: flags.controller_flags,
162 }
163 }
164
165 fn set_fidl_interfaces(&mut self, interfaces: HashSet<fidl::Interface>) {
166 self.fidl_interfaces = interfaces;
167 }
168
169 fn set_controller_flags(&mut self, controller_flags: HashSet<ControllerFlag>) {
170 self.controller_flags = controller_flags;
171 }
172}
173
174#[cfg(test)]
179pub struct Environment {
180 pub connector: Option<ProtocolConnector>,
181 pub delegate: Delegate,
182 pub entities: HashSet<Entity>,
183 pub job_seeder: Seeder,
184}
185
186#[cfg(test)]
187impl Environment {
188 pub fn new(
189 connector: Option<ProtocolConnector>,
190 delegate: Delegate,
191 job_seeder: Seeder,
192 entities: HashSet<Entity>,
193 ) -> Environment {
194 Environment { connector, delegate, job_seeder, entities }
195 }
196}
197
198#[cfg(test)]
199fn init_storage_dir() -> DirectoryProxy {
200 let tempdir = tempfile::tempdir().expect("failed to create tempdir");
201 fuchsia_fs::directory::open_in_namespace(
202 tempdir.path().to_str().expect("tempdir path is not valid UTF-8"),
203 fuchsia_fs::PERM_READABLE | fuchsia_fs::PERM_WRITABLE,
204 )
205 .expect("failed to open connection to tempdir")
206}
207
208#[cfg(not(test))]
209fn init_storage_dir() -> DirectoryProxy {
210 panic!("migration dir must be specified");
211}
212
213pub struct EnvironmentBuilder<'a, T: StorageFactory<Storage = DeviceStorage>> {
216 configuration: Option<ServiceConfiguration>,
217 agent_blueprints: Vec<AgentCreator>,
218 event_subscriber_blueprints: Vec<event::subscriber::BlueprintHandle>,
219 storage_factory: Rc<T>,
220 generate_service: Option<GenerateService>,
221 registrants: Vec<Registrant>,
222 settings: Vec<SettingType>,
223 handlers: HashMap<SettingType, GenerateHandler>,
224 setting_proxy_inspect_info: Option<&'a fuchsia_inspect::Node>,
225 active_listener_inspect_logger: Option<Rc<Mutex<ListenerInspectLogger>>>,
226 storage_dir: Option<DirectoryProxy>,
227 store_proxy: Option<StoreProxy>,
228 fidl_storage_factory: Option<Rc<FidlStorageFactory>>,
229 display_configuration: Option<DefaultSetting<DisplayConfiguration, &'static str>>,
230 audio_configuration: Option<DefaultSetting<AudioInfo, &'static str>>,
231 input_configuration: Option<DefaultSetting<InputConfiguration, &'static str>>,
232 light_configuration: Option<DefaultSetting<LightHardwareConfiguration, &'static str>>,
233}
234
235impl<'a, T: StorageFactory<Storage = DeviceStorage> + 'static> EnvironmentBuilder<'a, T> {
236 pub fn new(storage_factory: Rc<T>) -> Self {
239 EnvironmentBuilder {
240 configuration: None,
241 agent_blueprints: vec![],
242 event_subscriber_blueprints: vec![],
243 storage_factory,
244 generate_service: None,
245 handlers: HashMap::new(),
246 registrants: vec![],
247 settings: vec![],
248 setting_proxy_inspect_info: None,
249 active_listener_inspect_logger: None,
250 storage_dir: None,
251 store_proxy: None,
252 fidl_storage_factory: None,
253 display_configuration: None,
254 audio_configuration: None,
255 input_configuration: None,
256 light_configuration: None,
257 }
258 }
259
260 pub fn handler(mut self, setting_type: SettingType, generate_handler: GenerateHandler) -> Self {
262 let _ = self.handlers.insert(setting_type, generate_handler);
264 self
265 }
266
267 pub fn service(mut self, generate_service: GenerateService) -> Self {
269 self.generate_service = Some(generate_service);
270 self
271 }
272
273 pub fn configuration(mut self, configuration: ServiceConfiguration) -> Self {
277 self.configuration = Some(configuration);
278 self
279 }
280
281 pub fn display_configuration(
282 mut self,
283 display_configuration: DefaultSetting<DisplayConfiguration, &'static str>,
284 ) -> Self {
285 self.display_configuration = Some(display_configuration);
286 self
287 }
288
289 pub fn audio_configuration(
290 mut self,
291 audio_configuration: DefaultSetting<AudioInfo, &'static str>,
292 ) -> Self {
293 self.audio_configuration = Some(audio_configuration);
294 self
295 }
296
297 pub fn input_configuration(
298 mut self,
299 input_configuration: DefaultSetting<InputConfiguration, &'static str>,
300 ) -> Self {
301 self.input_configuration = Some(input_configuration);
302 self
303 }
304
305 pub fn light_configuration(
306 mut self,
307 light_configuration: DefaultSetting<LightHardwareConfiguration, &'static str>,
308 ) -> Self {
309 self.light_configuration = Some(light_configuration);
310 self
311 }
312
313 pub fn fidl_interfaces(mut self, interfaces: &[fidl::Interface]) -> Self {
315 if self.configuration.is_none() {
316 self.configuration = Some(ServiceConfiguration::default());
317 }
318
319 if let Some(c) = self.configuration.as_mut() {
320 c.set_fidl_interfaces(interfaces.iter().copied().collect());
321 }
322
323 self
324 }
325
326 pub fn registrants(mut self, mut registrants: Vec<Registrant>) -> Self {
328 self.registrants.append(&mut registrants);
329
330 self
331 }
332
333 pub fn settings(mut self, settings: &[SettingType]) -> Self {
335 self.settings.extend(settings);
336
337 self
338 }
339
340 pub fn flags(mut self, controller_flags: &[ControllerFlag]) -> Self {
342 if self.configuration.is_none() {
343 self.configuration = Some(ServiceConfiguration::default());
344 }
345
346 if let Some(c) = self.configuration.as_mut() {
347 c.set_controller_flags(controller_flags.iter().copied().collect());
348 }
349
350 self
351 }
352
353 pub fn agents(mut self, mut registrars: Vec<AgentCreator>) -> Self {
355 self.agent_blueprints.append(&mut registrars);
356 self
357 }
358
359 pub fn event_subscribers(mut self, subscribers: &[event::subscriber::BlueprintHandle]) -> Self {
361 self.event_subscriber_blueprints.append(&mut subscribers.to_vec());
362 self
363 }
364
365 pub fn setting_proxy_inspect_info(
368 mut self,
369 setting_proxy_inspect_info: &'a fuchsia_inspect::Node,
370 active_listener_inspect_logger: Rc<Mutex<ListenerInspectLogger>>,
371 ) -> Self {
372 self.setting_proxy_inspect_info = Some(setting_proxy_inspect_info);
373 self.active_listener_inspect_logger = Some(active_listener_inspect_logger);
374 self
375 }
376
377 pub fn storage_dir(mut self, storage_dir: DirectoryProxy) -> Self {
378 self.storage_dir = Some(storage_dir);
379 self
380 }
381
382 pub fn store_proxy(mut self, store_proxy: StoreProxy) -> Self {
383 self.store_proxy = Some(store_proxy);
384 self
385 }
386
387 pub fn fidl_storage_factory(mut self, fidl_storage_factory: Rc<FidlStorageFactory>) -> Self {
388 self.fidl_storage_factory = Some(fidl_storage_factory);
389 self
390 }
391
392 async fn prepare_env(
395 mut self,
396 mut fs: ServiceFs<ServiceObjLocal<'_, ()>>,
397 runtime: Runtime,
398 ) -> Result<(ServiceFs<ServiceObjLocal<'_, ()>>, Delegate, Seeder, HashSet<Entity>), Error>
399 {
400 let mut service_dir = match runtime {
401 Runtime::Service => fs.dir("svc"),
402 #[cfg(test)]
403 Runtime::Nested(_) => fs.root_dir(),
404 };
405
406 let _ = service_dir.add_fidl_service(
407 move |mut stream: fupdate::ComponentOtaHealthCheckRequestStream| {
408 fasync::Task::local(async move {
409 while let Some(fupdate::ComponentOtaHealthCheckRequest::GetHealthStatus {
410 responder,
411 }) = stream.try_next().await.expect("error running health check service")
412 {
413 responder
417 .send(fupdate::HealthStatus::Healthy)
418 .expect("failed to send health status");
419 }
420 })
421 .detach();
422 },
423 );
424
425 let delegate = service::MessageHub::create_hub();
427
428 let (agent_types, fidl_interfaces, flags) = match self.configuration {
429 Some(configuration) => (
430 configuration.agent_types,
431 configuration.fidl_interfaces,
432 configuration.controller_flags,
433 ),
434 _ => (HashSet::new(), HashSet::new(), HashSet::new()),
435 };
436
437 self.registrants.extend(fidl_interfaces.into_iter().map(|x| x.registrant()));
438
439 let mut settings = HashSet::new();
440 settings.extend(self.settings);
441
442 for registrant in &self.registrants {
443 for dependency in registrant.get_dependencies() {
444 match dependency {
445 Dependency::Entity(Entity::Handler(setting_type)) => {
446 let _ = settings.insert(*setting_type);
447 }
448 }
449 }
450 }
451
452 let fidl_storage_factory = if let Some(factory) = self.fidl_storage_factory {
453 factory
454 } else {
455 let (migration_id, storage_dir) = if let Some(storage_dir) = self.storage_dir {
456 let store_proxy = self.store_proxy.unwrap_or_else(|| {
457 let store_proxy = connect_to_protocol::<fidl_fuchsia_stash::StoreMarker>()
458 .expect("failed to connect to stash");
459 store_proxy
460 .identify("setting_service")
461 .expect("should be able to identify to stash");
462 store_proxy
463 });
464
465 let migration_manager = storage_migrations::register_migrations(
466 &settings,
467 Clone::clone(&storage_dir),
468 store_proxy,
469 )
470 .context("failed to register migrations")?;
471 let migration_id = match migration_manager.run_migrations().await {
472 Ok(id) => {
473 log::info!("migrated storage to {id:?}");
474 id
475 }
476 Err((id, e)) => {
477 log::error!("Settings migration failed: {e:?}");
478 id
479 }
480 };
481 let migration_id = migration_id.map(|migration| migration.migration_id);
482 (migration_id, storage_dir)
483 } else {
484 (None, init_storage_dir())
485 };
486
487 Rc::new(FidlStorageFactory::new(migration_id.unwrap_or(0), storage_dir))
488 };
489
490 let service_context =
491 Rc::new(ServiceContext::new(self.generate_service, Some(delegate.clone())));
492
493 let context_id_counter = Rc::new(AtomicU64::new(1));
494
495 let mut handler_factory = SettingHandlerFactoryImpl::new(
496 settings.clone(),
497 Rc::clone(&service_context),
498 context_id_counter.clone(),
499 );
500
501 EnvironmentBuilder::register_setting_handlers(
502 &settings,
503 Rc::clone(&self.storage_factory),
504 Rc::clone(&fidl_storage_factory),
505 &flags,
506 self.display_configuration.map(DisplayInfoLoader::new),
507 self.audio_configuration.map(AudioInfoLoader::new),
508 self.input_configuration,
509 self.light_configuration,
510 &mut handler_factory,
511 )
512 .await;
513
514 for (setting_type, handler) in self.handlers {
517 handler_factory.register(setting_type, handler);
518 }
519
520 let agent_blueprints = if agent_types.is_empty() {
521 self.agent_blueprints
522 } else {
523 agent_types.into_iter().map(AgentCreator::from).collect()
524 };
525
526 let job_manager_signature = Manager::spawn(&delegate).await;
527 let job_seeder = Seeder::new(&delegate, job_manager_signature).await;
528
529 let entities = create_environment(
530 service_dir,
531 delegate.clone(),
532 job_seeder.clone(),
533 settings,
534 self.registrants,
535 agent_blueprints,
536 self.event_subscriber_blueprints,
537 service_context,
538 Rc::new(Mutex::new(handler_factory)),
539 self.storage_factory,
540 fidl_storage_factory,
541 self.setting_proxy_inspect_info.unwrap_or_else(|| component::inspector().root()),
542 self.active_listener_inspect_logger
543 .unwrap_or_else(|| Rc::new(Mutex::new(ListenerInspectLogger::new()))),
544 )
545 .await
546 .context("Could not create environment")?;
547
548 Ok((fs, delegate, job_seeder, entities))
549 }
550
551 pub fn spawn(
554 self,
555 mut executor: fasync::LocalExecutor,
556 fs: ServiceFs<ServiceObjLocal<'_, ()>>,
557 ) -> Result<(), Error> {
558 let (mut fs, ..) = executor
559 .run_singlethreaded(self.prepare_env(fs, Runtime::Service))
560 .context("Failed to prepare env")?;
561
562 let _ = fs.take_and_serve_directory_handle().expect("could not service directory handle");
563 executor.run_singlethreaded(fs.collect::<()>());
564 Ok(())
565 }
566
567 #[cfg(test)]
569 pub async fn spawn_nested(self, env_name: &'static str) -> Result<Environment, Error> {
570 let (mut fs, delegate, job_seeder, entities) = self
571 .prepare_env(ServiceFs::new_local(), Runtime::Nested(env_name))
572 .await
573 .context("Failed to prepare env")?;
574 let connector = Some(fs.create_protocol_connector()?);
575 fasync::Task::local(fs.collect()).detach();
576
577 Ok(Environment::new(connector, delegate, job_seeder, entities))
578 }
579
580 #[cfg(test)]
585 pub async fn spawn_and_get_protocol_connector(
586 self,
587 env_name: &'static str,
588 ) -> Result<ProtocolConnector, Error> {
589 let environment = self.spawn_nested(env_name).await?;
590
591 environment.connector.ok_or_else(|| format_err!("connector not created"))
592 }
593
594 async fn register_setting_handlers<F>(
597 components: &HashSet<SettingType>,
598 device_storage_factory: Rc<T>,
599 fidl_storage_factory: Rc<F>,
600 controller_flags: &HashSet<ControllerFlag>,
601 display_loader: Option<DisplayInfoLoader>,
602 audio_loader: Option<AudioInfoLoader>,
603 input_configuration: Option<DefaultSetting<InputConfiguration, &'static str>>,
604 light_configuration: Option<DefaultSetting<LightHardwareConfiguration, &'static str>>,
605 factory_handle: &mut SettingHandlerFactoryImpl,
606 ) where
607 F: StorageFactory<Storage = FidlStorage>,
608 {
609 if components.contains(&SettingType::Accessibility) {
611 device_storage_factory
612 .initialize::<AccessibilityController>()
613 .await
614 .expect("storage should still be initializing");
615 factory_handle.register(
616 SettingType::Accessibility,
617 Box::new(DataHandler::<AccessibilityController>::spawn),
618 );
619 }
620
621 if components.contains(&SettingType::Audio) {
623 let audio_loader = audio_loader.expect("Audio storage requires audio loader");
624 device_storage_factory
625 .initialize_with_loader::<AudioController, _>(audio_loader.clone())
626 .await
627 .expect("storage should still be initializing");
628 factory_handle.register(
629 SettingType::Audio,
630 Box::new(move |context| {
631 DataHandler::<AudioController>::spawn_with(context, audio_loader.clone())
632 }),
633 );
634 }
635
636 if components.contains(&SettingType::Display) {
638 device_storage_factory
639 .initialize_with_loader::<DisplayController, _>(
640 display_loader.expect("Display storage requires display loader"),
641 )
642 .await
643 .expect("storage should still be initializing");
644 factory_handle.register(
645 SettingType::Display,
646 Box::new(
647 if controller_flags.contains(&ControllerFlag::ExternalBrightnessControl) {
648 DataHandler::<DisplayController<ExternalBrightnessControl>>::spawn
649 } else {
650 DataHandler::<DisplayController>::spawn
651 },
652 ),
653 );
654 }
655
656 if components.contains(&SettingType::Light) {
658 let light_configuration = Rc::new(Mutex::new(
659 light_configuration.expect("Light controller requires a light configuration"),
660 ));
661 fidl_storage_factory
662 .initialize::<LightController>()
663 .await
664 .expect("storage should still be initializing");
665 factory_handle.register(
666 SettingType::Light,
667 Box::new(move |context| {
668 DataHandler::<LightController>::spawn_with_async(
669 context,
670 Rc::clone(&light_configuration),
671 )
672 }),
673 );
674 }
675
676 if components.contains(&SettingType::Input) {
678 let input_configuration = Rc::new(std::sync::Mutex::new(
679 input_configuration.expect("Input controller requires an input configuration"),
680 ));
681 device_storage_factory
682 .initialize::<InputController>()
683 .await
684 .expect("storage should still be initializing");
685 factory_handle.register(
686 SettingType::Input,
687 Box::new(move |context| {
688 DataHandler::<InputController>::spawn_with(
689 context,
690 Rc::clone(&input_configuration),
691 )
692 }),
693 );
694 }
695
696 if components.contains(&SettingType::Intl) {
698 device_storage_factory
699 .initialize::<IntlController>()
700 .await
701 .expect("storage should still be initializing");
702 factory_handle
703 .register(SettingType::Intl, Box::new(DataHandler::<IntlController>::spawn));
704 }
705
706 if components.contains(&SettingType::Keyboard) {
708 device_storage_factory
709 .initialize::<KeyboardController>()
710 .await
711 .expect("storage should still be initializing");
712 factory_handle.register(
713 SettingType::Keyboard,
714 Box::new(DataHandler::<KeyboardController>::spawn),
715 );
716 }
717
718 if components.contains(&SettingType::DoNotDisturb) {
720 device_storage_factory
721 .initialize::<DoNotDisturbController>()
722 .await
723 .expect("storage should still be initializing");
724 factory_handle.register(
725 SettingType::DoNotDisturb,
726 Box::new(DataHandler::<DoNotDisturbController>::spawn),
727 );
728 }
729
730 if components.contains(&SettingType::FactoryReset) {
732 device_storage_factory
733 .initialize::<FactoryResetController>()
734 .await
735 .expect("storage should still be initializing");
736 factory_handle.register(
737 SettingType::FactoryReset,
738 Box::new(DataHandler::<FactoryResetController>::spawn),
739 );
740 }
741
742 if components.contains(&SettingType::NightMode) {
744 device_storage_factory
745 .initialize::<NightModeController>()
746 .await
747 .expect("storage should still be initializing");
748 factory_handle.register(
749 SettingType::NightMode,
750 Box::new(DataHandler::<NightModeController>::spawn),
751 );
752 }
753
754 if components.contains(&SettingType::Privacy) {
756 device_storage_factory
757 .initialize::<PrivacyController>()
758 .await
759 .expect("storage should still be initializing");
760 factory_handle
761 .register(SettingType::Privacy, Box::new(DataHandler::<PrivacyController>::spawn));
762 }
763
764 if components.contains(&SettingType::Setup) {
766 device_storage_factory
767 .initialize::<SetupController>()
768 .await
769 .expect("storage should still be initializing");
770 factory_handle
771 .register(SettingType::Setup, Box::new(DataHandler::<SetupController>::spawn));
772 }
773 }
774}
775
776#[allow(clippy::too_many_arguments)]
782async fn create_environment<'a, T, F>(
783 mut service_dir: ServiceFsDir<'_, ServiceObjLocal<'a, ()>>,
784 delegate: service::message::Delegate,
785 job_seeder: Seeder,
786 components: HashSet<SettingType>,
787 registrants: Vec<Registrant>,
788 agent_blueprints: Vec<AgentCreator>,
789 event_subscriber_blueprints: Vec<event::subscriber::BlueprintHandle>,
790 service_context: Rc<ServiceContext>,
791 handler_factory: Rc<Mutex<SettingHandlerFactoryImpl>>,
792 device_storage_factory: Rc<T>,
793 fidl_storage_factory: Rc<F>,
794 setting_proxies_node: &fuchsia_inspect::Node,
795 listener_logger: Rc<Mutex<ListenerInspectLogger>>,
796) -> Result<HashSet<Entity>, Error>
797where
798 T: StorageFactory<Storage = DeviceStorage> + 'static,
799 F: StorageFactory<Storage = FidlStorage> + 'static,
800{
801 for blueprint in event_subscriber_blueprints {
802 blueprint.create(delegate.clone()).await;
803 }
804
805 let mut entities = HashSet::new();
806
807 for setting_type in &components {
808 let _ = SettingProxy::create(
809 *setting_type,
810 handler_factory.clone(),
811 delegate.clone(),
812 DEFAULT_SETTING_PROXY_MAX_ATTEMPTS,
813 DEFAULT_TEARDOWN_TIMEOUT,
814 Some(MonotonicDuration::from_millis(DEFAULT_SETTING_PROXY_RESPONSE_TIMEOUT_MS)),
815 true,
816 setting_proxies_node.create_child(format!("{setting_type:?}")),
817 Rc::clone(&listener_logger),
818 )
819 .await?;
820
821 let _ = entities.insert(Entity::Handler(*setting_type));
822 }
823
824 let mut agent_authority = Authority::create(delegate.clone(), components.clone()).await?;
825
826 for registrant in registrants {
827 if registrant.get_dependencies().iter().all(|dependency| {
828 let dep_met = dependency.is_fulfilled(&entities);
829 if !dep_met {
830 log::error!(
831 "Skipping {} registration due to missing dependency {:?}",
832 registrant.get_interface(),
833 dependency
834 );
835 }
836 dep_met
837 }) {
838 registrant.register(&job_seeder, &mut service_dir);
839 }
840 }
841
842 agent_authority
844 .register(crate::agent::storage_agent::create_registrar(
845 device_storage_factory,
846 fidl_storage_factory,
847 ))
848 .await;
849
850 for blueprint in agent_blueprints {
851 agent_authority.register(blueprint).await;
852 }
853
854 agent_authority
856 .execute_lifespan(Lifespan::Initialization, Rc::clone(&service_context), true)
857 .await
858 .context("Agent initialization failed")?;
859
860 agent_authority
862 .execute_lifespan(Lifespan::Service, Rc::clone(&service_context), false)
863 .await
864 .context("Agent service start failed")?;
865
866 Ok(entities)
867}
868
869#[cfg(test)]
870mod tests;