session_manager_lib/
power.rs1use anyhow::{anyhow, Context};
6use fidl::endpoints::{ClientEnd, Proxy};
7use power_broker_client::{basic_update_fn_factory, run_power_element, PowerElementContext};
8use rand::distributions::Alphanumeric;
9use rand::Rng;
10use std::sync::Arc;
11use {
12 fidl_fuchsia_power_broker as fbroker, fidl_fuchsia_power_system as fsystem,
13 fuchsia_async as fasync,
14};
15
16pub struct PowerElement {
29 #[allow(dead_code)]
31 power_element_context: Arc<PowerElementContext>,
32
33 lease: Option<ClientEnd<fbroker::LeaseControlMarker>>,
35}
36
37static POWER_ON_LEVEL: fbroker::PowerLevel = 1;
45
46impl PowerElement {
47 pub async fn new() -> Result<Self, anyhow::Error> {
50 let topology = fuchsia_component::client::connect_to_protocol::<fbroker::TopologyMarker>()?;
51 let activity_governor =
52 fuchsia_component::client::connect_to_protocol::<fsystem::ActivityGovernorMarker>()?;
53
54 let power_elements = activity_governor
56 .get_power_elements()
57 .await
58 .context("cannot get power elements from SAG")?;
59 let Some(Some(application_activity_token)) = power_elements
60 .application_activity
61 .map(|application_activity| application_activity.assertive_dependency_token)
62 else {
63 return Err(anyhow!("Did not find application activity assertive dependency token"));
64 };
65
66 let power_levels: Vec<u8> = (0..=POWER_ON_LEVEL).collect();
68 let random_string: String =
69 rand::thread_rng().sample_iter(&Alphanumeric).take(8).map(char::from).collect();
70 let power_element_context = Arc::new(
71 PowerElementContext::builder(
72 &topology,
73 format!("session-manager-element-{random_string}").as_str(),
74 &power_levels,
75 )
76 .initial_current_level(POWER_ON_LEVEL)
77 .dependencies(vec![fbroker::LevelDependency {
78 dependency_type: fbroker::DependencyType::Assertive,
79 dependent_level: POWER_ON_LEVEL,
80 requires_token: application_activity_token,
81 requires_level_by_preference: vec![
82 fsystem::ApplicationActivityLevel::Active.into_primitive()
83 ],
84 }])
85 .build()
86 .await
87 .map_err(|e| anyhow!("PowerBroker::AddElementError({e:?}"))?,
88 );
89 let pe_context = power_element_context.clone();
90 fasync::Task::local(async move {
91 run_power_element(
92 pe_context.name(),
93 &pe_context.required_level,
94 POWER_ON_LEVEL, None, basic_update_fn_factory(&pe_context),
97 )
98 .await;
99 })
100 .detach();
101
102 let lease = power_element_context
104 .lessor
105 .lease(POWER_ON_LEVEL)
106 .await?
107 .map_err(|e| anyhow!("PowerBroker::LeaseError({e:?})"))?;
108
109 let lease = lease.into_proxy();
111 let mut status = fbroker::LeaseStatus::Unknown;
112 loop {
113 match lease.watch_status(status).await? {
114 fbroker::LeaseStatus::Satisfied => break,
115 new_status => status = new_status,
116 }
117 }
118 let lease = lease
119 .into_client_end()
120 .expect("Proxy should be in a valid state to convert into client end");
121
122 let boot_control =
123 fuchsia_component::client::connect_to_protocol::<fsystem::BootControlMarker>()?;
124 let () = boot_control.set_boot_complete().await?;
125
126 Ok(Self { power_element_context, lease: Some(lease) })
127 }
128
129 pub fn take_lease(&mut self) -> Option<ClientEnd<fbroker::LeaseControlMarker>> {
130 self.lease.take()
131 }
132
133 pub fn has_lease(&self) -> bool {
134 self.lease.is_some()
135 }
136}