session_manager_lib/
power.rs1use anyhow::{Context, anyhow};
6use fidl::endpoints::{ClientEnd, Proxy, create_endpoints};
7use power_broker_client::PowerElementContext;
8use rand::Rng;
9use rand::distr::Alphanumeric;
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::rng().sample_iter(&Alphanumeric).take(8).map(char::from).collect();
70 let (element_runner_client, element_runner) =
71 create_endpoints::<fbroker::ElementRunnerMarker>();
72 let power_element_context = Arc::new(
73 PowerElementContext::builder(
74 &topology,
75 format!("session-manager-element-{random_string}").as_str(),
76 &power_levels,
77 element_runner_client,
78 )
79 .initial_current_level(POWER_ON_LEVEL)
80 .dependencies(vec![fbroker::LevelDependency {
81 dependent_level: POWER_ON_LEVEL,
82 requires_token: application_activity_token,
83 requires_level_by_preference: vec![
84 fsystem::ApplicationActivityLevel::Active.into_primitive(),
85 ],
86 }])
87 .build()
88 .await
89 .map_err(|e| anyhow!("PowerBroker::AddElementError({e:?}"))?,
90 );
91 let pe_context = power_element_context.clone();
92 fasync::Task::local(async move {
93 pe_context.run(element_runner, None , None ).await;
94 })
95 .detach();
96
97 let lease = power_element_context
99 .lessor
100 .lease(POWER_ON_LEVEL)
101 .await?
102 .map_err(|e| anyhow!("PowerBroker::LeaseError({e:?})"))?;
103
104 let lease = lease.into_proxy();
106 let mut status = fbroker::LeaseStatus::Unknown;
107 loop {
108 match lease.watch_status(status).await? {
109 fbroker::LeaseStatus::Satisfied => break,
110 new_status => status = new_status,
111 }
112 }
113 let lease = lease
114 .into_client_end()
115 .expect("Proxy should be in a valid state to convert into client end");
116
117 let boot_control =
118 fuchsia_component::client::connect_to_protocol::<fsystem::BootControlMarker>()?;
119 let () = boot_control.set_boot_complete().await?;
120
121 Ok(Self { power_element_context, lease: Some(lease) })
122 }
123
124 pub fn take_lease(&mut self) -> Option<ClientEnd<fbroker::LeaseControlMarker>> {
125 self.lease.take()
126 }
127
128 pub fn has_lease(&self) -> bool {
129 self.lease.is_some()
130 }
131}