fxfs_platform_testing/fuchsia/
power.rs1use fidl_fuchsia_power_battery::{
6 BatteryInfoWatcherMarker, BatteryInfoWatcherRequest, BatteryManagerMarker, BatteryManagerProxy,
7 ChargeSource,
8};
9use fidl_fuchsia_power_system as _;
10use fuchsia_component_client::connect_to_protocol;
11use futures::stream::{BoxStream, StreamExt};
12use fxfs::filesystem::{PowerManager, WakeLease};
13use fxfs::log::*;
14use std::sync::Arc;
15
16pub struct FuchsiaPowerManager {}
17
18impl FuchsiaPowerManager {
19 pub fn new() -> Arc<Self> {
20 Arc::new(Self {})
21 }
22
23 fn watch_battery_with_proxy(
24 proxy: BatteryManagerProxy,
25 ) -> BoxStream<'static, (bool, Option<WakeLease>)> {
26 let (watcher_client, watcher_stream) =
27 fidl::endpoints::create_request_stream::<BatteryInfoWatcherMarker>();
28
29 if let Err(error) = proxy.watch(watcher_client) {
30 error!(error:?; "Failed to register battery watcher");
31 return futures::stream::empty().boxed();
32 }
33
34 futures::stream::unfold(watcher_stream, |mut stream| async move {
35 match stream.next().await {
36 Some(Ok(BatteryInfoWatcherRequest::OnChangeBatteryInfo {
37 info,
38 wake_lease,
39 responder,
40 })) => {
41 let _ = responder.send();
42 let on_battery = !matches!(
46 info.charge_source,
47 Some(ChargeSource::AcAdapter)
48 | Some(ChargeSource::Usb)
49 | Some(ChargeSource::Wireless)
50 );
51 let lease = wake_lease.map(WakeLease::new);
52 Some(((on_battery, lease), stream))
53 }
54 Some(Err(error)) => {
55 error!(error:?; "Battery watcher stream error");
56 None
57 }
58 None => None,
59 }
60 })
61 .boxed()
62 }
63}
64
65impl PowerManager for FuchsiaPowerManager {
66 fn watch_battery(self: Arc<Self>) -> BoxStream<'static, (bool, Option<WakeLease>)> {
67 match connect_to_protocol::<BatteryManagerMarker>() {
68 Ok(proxy) => Self::watch_battery_with_proxy(proxy),
69 Err(error) => {
70 warn!(error:?; "Failed to connect to BatteryManager");
71 futures::stream::empty().boxed()
72 }
73 }
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80 use fidl_fuchsia_power_battery::{BatteryInfo, BatteryManagerRequest};
81
82 #[fuchsia::test]
83 async fn test_watch_battery_charge_sources_and_lease() {
84 let _manager = FuchsiaPowerManager::new();
85 let (proxy, mut manager_stream) =
86 fidl::endpoints::create_proxy_and_stream::<BatteryManagerMarker>();
87
88 let mut battery_stream = FuchsiaPowerManager::watch_battery_with_proxy(proxy);
89
90 let watcher_proxy = match manager_stream.next().await {
91 Some(Ok(BatteryManagerRequest::Watch { watcher, .. })) => watcher.into_proxy(),
92 other => panic!("Unexpected request: {:?}", other),
93 };
94
95 let server_task = fuchsia_async::Task::spawn(async move {
96 watcher_proxy
98 .on_change_battery_info(
99 &BatteryInfo {
100 charge_source: Some(ChargeSource::AcAdapter),
101 ..Default::default()
102 },
103 None,
104 )
105 .await
106 .unwrap();
107
108 let (ep1, _ep2) = zx::EventPair::create();
110 watcher_proxy
111 .on_change_battery_info(
112 &BatteryInfo { charge_source: Some(ChargeSource::Usb), ..Default::default() },
113 Some(ep1),
114 )
115 .await
116 .unwrap();
117
118 watcher_proxy
120 .on_change_battery_info(
121 &BatteryInfo {
122 charge_source: Some(ChargeSource::Wireless),
123 ..Default::default()
124 },
125 None,
126 )
127 .await
128 .unwrap();
129
130 watcher_proxy
132 .on_change_battery_info(
133 &BatteryInfo { charge_source: Some(ChargeSource::None), ..Default::default() },
134 None,
135 )
136 .await
137 .unwrap();
138
139 watcher_proxy.on_change_battery_info(&BatteryInfo::default(), None).await.unwrap();
141 });
142
143 let (on_battery, lease) = battery_stream.next().await.unwrap();
144 assert!(!on_battery);
145 assert!(lease.is_none());
146
147 let (on_battery, lease) = battery_stream.next().await.unwrap();
148 assert!(!on_battery);
149 assert!(lease.is_some());
150
151 let (on_battery, lease) = battery_stream.next().await.unwrap();
152 assert!(!on_battery);
153 assert!(lease.is_none());
154
155 let (on_battery, lease) = battery_stream.next().await.unwrap();
156 assert!(on_battery);
157 assert!(lease.is_none());
158
159 let (on_battery, lease) = battery_stream.next().await.unwrap();
160 assert!(on_battery);
161 assert!(lease.is_none());
162
163 server_task.await;
164 assert!(battery_stream.next().await.is_none());
165 }
166
167 #[fuchsia::test]
168 async fn test_watch_battery_disconnected_proxy() {
169 let (proxy, manager_stream) =
170 fidl::endpoints::create_proxy_and_stream::<BatteryManagerMarker>();
171 drop(manager_stream);
172
173 let mut battery_stream = FuchsiaPowerManager::watch_battery_with_proxy(proxy);
174 assert!(battery_stream.next().await.is_none());
175 }
176}