session_manager_lib/
power.rs1use anyhow::{Context, anyhow};
6use fidl::endpoints::{ClientEnd, Proxy, create_endpoints};
7use fidl_fuchsia_power_broker as fbroker;
8use fidl_fuchsia_power_system as fsystem;
9use fuchsia_async as fasync;
10use power_broker_client::PowerElementContext;
11use rand::Rng;
12use rand::distr::Alphanumeric;
13use std::sync::Arc;
14
15pub struct PowerElement {
28 #[allow(dead_code)]
30 power_element_context: Arc<PowerElementContext>,
31
32 lease: Option<ClientEnd<fbroker::LeaseControlMarker>>,
34}
35
36static POWER_ON_LEVEL: fbroker::PowerLevel = 1;
44
45impl PowerElement {
46 pub async fn new() -> Result<Self, anyhow::Error> {
49 let topology = fuchsia_component::client::connect_to_protocol::<fbroker::TopologyMarker>()?;
50 let activity_governor =
51 fuchsia_component::client::connect_to_protocol::<fsystem::ActivityGovernorMarker>()?;
52
53 let power_elements = activity_governor
55 .get_power_elements()
56 .await
57 .context("cannot get power elements from SAG")?;
58 let Some(Some(application_activity_token)) = power_elements
59 .application_activity
60 .map(|application_activity| application_activity.assertive_dependency_token)
61 else {
62 return Err(anyhow!("Did not find application activity assertive dependency token"));
63 };
64
65 let power_levels: Vec<u8> = (0..=POWER_ON_LEVEL).collect();
67 let random_string: String =
68 rand::rng().sample_iter(&Alphanumeric).take(8).map(char::from).collect();
69 let (element_runner_client, element_runner) =
70 create_endpoints::<fbroker::ElementRunnerMarker>();
71 let power_element_context = Arc::new(
72 PowerElementContext::builder(
73 &topology,
74 format!("session-manager-element-{random_string}").as_str(),
75 &power_levels,
76 element_runner_client,
77 )
78 .initial_current_level(POWER_ON_LEVEL)
79 .dependencies(vec![fbroker::LevelDependency {
80 dependent_level: Some(POWER_ON_LEVEL),
81 requires_token: Some(application_activity_token),
82 requires_level_by_preference: Some(vec![
83 fsystem::ApplicationActivityLevel::Active.into_primitive(),
84 ]),
85 ..Default::default()
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}