session_manager_lib/
power.rsuse anyhow::{anyhow, Context};
use fidl::endpoints::{ClientEnd, Proxy};
use power_broker_client::{basic_update_fn_factory, run_power_element, PowerElementContext};
use rand::distributions::Alphanumeric;
use rand::Rng;
use std::sync::Arc;
use {
fidl_fuchsia_power_broker as fbroker, fidl_fuchsia_power_system as fsystem,
fuchsia_async as fasync,
};
pub struct PowerElement {
#[allow(dead_code)]
power_element_context: Arc<PowerElementContext>,
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.assertive_dependency_token)
else {
return Err(anyhow!("Did not find application activity assertive dependency token"));
};
let power_levels: Vec<u8> = (0..=POWER_ON_LEVEL).collect();
let random_string: String =
rand::thread_rng().sample_iter(&Alphanumeric).take(8).map(char::from).collect();
let power_element_context = Arc::new(
PowerElementContext::builder(
&topology,
format!("session-manager-element-{random_string}").as_str(),
&power_levels,
)
.initial_current_level(POWER_ON_LEVEL)
.dependencies(vec![fbroker::LevelDependency {
dependency_type: fbroker::DependencyType::Assertive,
dependent_level: POWER_ON_LEVEL,
requires_token: application_activity_token,
requires_level_by_preference: vec![
fsystem::ApplicationActivityLevel::Active.into_primitive()
],
}])
.build()
.await
.map_err(|e| anyhow!("PowerBroker::AddElementError({e:?}"))?,
);
let pe_context = power_element_context.clone();
fasync::Task::local(async move {
run_power_element(
pe_context.name(),
&pe_context.required_level,
POWER_ON_LEVEL, None, basic_update_fn_factory(&pe_context),
)
.await;
})
.detach();
let lease = power_element_context
.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("Proxy should be in a valid state to convert into client end");
let boot_control =
fuchsia_component::client::connect_to_protocol::<fsystem::BootControlMarker>()?;
let () = boot_control.set_boot_complete().await?;
Ok(Self { power_element_context, 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()
}
}