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 dependency_type: fbroker::DependencyType::Assertive,
82 dependent_level: POWER_ON_LEVEL,
83 requires_token: application_activity_token,
84 requires_level_by_preference: vec![
85 fsystem::ApplicationActivityLevel::Active.into_primitive(),
86 ],
87 }])
88 .build()
89 .await
90 .map_err(|e| anyhow!("PowerBroker::AddElementError({e:?}"))?,
91 );
92 let pe_context = power_element_context.clone();
93 fasync::Task::local(async move {
94 pe_context.run(element_runner, None , None ).await;
95 })
96 .detach();
97
98 let lease = power_element_context
100 .lessor
101 .lease(POWER_ON_LEVEL)
102 .await?
103 .map_err(|e| anyhow!("PowerBroker::LeaseError({e:?})"))?;
104
105 let lease = lease.into_proxy();
107 let mut status = fbroker::LeaseStatus::Unknown;
108 loop {
109 match lease.watch_status(status).await? {
110 fbroker::LeaseStatus::Satisfied => break,
111 new_status => status = new_status,
112 }
113 }
114 let lease = lease
115 .into_client_end()
116 .expect("Proxy should be in a valid state to convert into client end");
117
118 let boot_control =
119 fuchsia_component::client::connect_to_protocol::<fsystem::BootControlMarker>()?;
120 let () = boot_control.set_boot_complete().await?;
121
122 Ok(Self { power_element_context, lease: Some(lease) })
123 }
124
125 pub fn take_lease(&mut self) -> Option<ClientEnd<fbroker::LeaseControlMarker>> {
126 self.lease.take()
127 }
128
129 pub fn has_lease(&self) -> bool {
130 self.lease.is_some()
131 }
132}