use anyhow::{anyhow, Context};
use fidl::endpoints::{ClientEnd, Proxy};
use fidl_fuchsia_power_broker as fbroker;
use fidl_fuchsia_power_system as fsystem;
use rand::{distributions::Alphanumeric, Rng};
pub struct PowerElement {
#[allow(dead_code)]
power_element: ClientEnd<fbroker::ElementControlMarker>,
lease: Option<ClientEnd<fbroker::LeaseControlMarker>>,
}
static POWER_ON_LEVEL: fbroker::PowerLevel = 1;
impl PowerElement {
pub async fn new() -> Result<Self, anyhow::Error> {
let topology = fuchsia_component::client::connect_to_protocol::<fbroker::TopologyMarker>()?;
let activity_governor =
fuchsia_component::client::connect_to_protocol::<fsystem::ActivityGovernorMarker>()?;
let power_elements = activity_governor
.get_power_elements()
.await
.context("cannot get power elements from SAG")?;
let Some(Some(application_activity_token)) = power_elements
.application_activity
.map(|application_activity| application_activity.active_dependency_token)
else {
return Err(anyhow!("Did not find application activity active dependency token"));
};
let power_levels: Vec<u8> = (0..=POWER_ON_LEVEL).collect();
let (lessor, lessor_server_end) = fidl::endpoints::create_proxy::<fbroker::LessorMarker>()?;
let random_string: String =
rand::thread_rng().sample_iter(&Alphanumeric).take(8).map(char::from).collect();
let power_element = topology
.add_element(fbroker::ElementSchema {
element_name: Some(format!("session-manager-element-{}", random_string)),
initial_current_level: Some(POWER_ON_LEVEL),
valid_levels: Some(power_levels),
dependencies: Some(vec![fbroker::LevelDependency {
dependency_type: fbroker::DependencyType::Active,
dependent_level: POWER_ON_LEVEL,
requires_token: application_activity_token,
requires_level: fsystem::ApplicationActivityLevel::Active.into_primitive(),
}]),
lessor_channel: Some(lessor_server_end),
..Default::default()
})
.await?
.map_err(|e| anyhow!("PowerBroker::AddElementError({e:?})"))?;
let lease = lessor
.lease(POWER_ON_LEVEL)
.await?
.map_err(|e| anyhow!("PowerBroker::LeaseError({e:?})"))?;
let lease = lease.into_proxy()?;
let mut status = fbroker::LeaseStatus::Unknown;
loop {
match lease.watch_status(status).await? {
fbroker::LeaseStatus::Satisfied => break,
new_status @ _ => status = new_status,
}
}
let lease = lease.into_client_end().expect("No ongoing calls on lease");
Ok(Self { power_element, lease: Some(lease) })
}
pub fn take_lease(&mut self) -> Option<ClientEnd<fbroker::LeaseControlMarker>> {
self.lease.take()
}
pub fn has_lease(&self) -> bool {
self.lease.is_some()
}
}