1use crate::common_utils::common::macros::{fx_err_and_bail, with_line};
6use crate::power::types;
7use anyhow::Error;
8use fidl_fuchsia_power_metrics::{Metric, Power, RecorderMarker, RecorderProxy, StatisticsArgs};
9use fuchsia_component::client::connect_to_protocol;
10use serde_json::Value;
11
12const CLIENT_ID: &'static str = "sl4f";
13
14#[derive(Debug)]
15pub struct PowerFacade {
16 logger_proxy: Option<RecorderProxy>,
18}
19
20impl PowerFacade {
21 pub fn new() -> PowerFacade {
22 PowerFacade { logger_proxy: None }
23 }
24
25 fn get_logger_proxy(&self) -> Result<RecorderProxy, Error> {
26 if let Some(proxy) = &self.logger_proxy {
27 Ok(proxy.clone())
28 } else {
29 match connect_to_protocol::<RecorderMarker>() {
30 Ok(proxy) => Ok(proxy),
31 Err(e) => fx_err_and_bail!(
32 &with_line!("PowerFacade::get_logger_proxy"),
33 format_err!("Failed to create proxy: {:?}", e)
34 ),
35 }
36 }
37 }
38
39 pub async fn start_logging(&self, args: Value) -> Result<types::RecorderResult, Error> {
48 let req: types::StartLoggingRequest = serde_json::from_value(args)?;
49 let statistics_args = req
50 .statistics_interval_ms
51 .map(|i| Box::new(StatisticsArgs { statistics_interval_ms: i }));
52 let proxy = self.get_logger_proxy()?;
53 proxy
55 .start_logging(
56 CLIENT_ID,
57 &[Metric::Power(Power {
58 sampling_interval_ms: req.sampling_interval_ms,
59 statistics_args,
60 })],
61 req.duration_ms,
62 false,
63 false,
64 )
65 .await?
66 .map_err(|e| format_err!("Received RecorderError: {:?}", e))?;
67 Ok(types::RecorderResult::Success)
68 }
69
70 pub async fn start_logging_forever(&self, args: Value) -> Result<types::RecorderResult, Error> {
78 let req: types::StartLoggingForeverRequest = serde_json::from_value(args)?;
79 let statistics_args = req
80 .statistics_interval_ms
81 .map(|i| Box::new(StatisticsArgs { statistics_interval_ms: i }));
82 let proxy = self.get_logger_proxy()?;
83 proxy
85 .start_logging_forever(
86 CLIENT_ID,
87 &[Metric::Power(Power {
88 sampling_interval_ms: req.sampling_interval_ms,
89 statistics_args,
90 })],
91 false,
92 false,
93 )
94 .await?
95 .map_err(|e| format_err!("Received RecorderError: {:?}", e))?;
96 Ok(types::RecorderResult::Success)
97 }
98
99 pub async fn stop_logging(&self) -> Result<types::RecorderResult, Error> {
101 self.get_logger_proxy()?.stop_logging(CLIENT_ID).await?;
102 Ok(types::RecorderResult::Success)
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109 use assert_matches::assert_matches;
110 use fidl::endpoints::create_proxy_and_stream;
111 use fidl_fuchsia_power_metrics::RecorderRequest;
112 use fuchsia_async as fasync;
113 use futures::prelude::*;
114 use serde_json::json;
115
116 #[fasync::run_singlethreaded(test)]
118 async fn test_start_logging() {
119 let query_sampling_interval_ms = 500;
120 let query_duration_ms = 10_000;
121 let query_statitics_interval_ms = 1_000;
122
123 let (proxy, mut stream) = create_proxy_and_stream::<RecorderMarker>();
124
125 let _stream_task = fasync::Task::local(async move {
126 match stream.try_next().await {
127 Ok(Some(RecorderRequest::StartLogging {
128 client_id,
129 metrics,
130 duration_ms,
131 output_samples_to_syslog,
132 output_stats_to_syslog,
133 responder,
134 })) => {
135 assert_eq!(String::from("sl4f"), client_id);
136 assert_eq!(metrics.len(), 1);
137 assert_eq!(
138 metrics[0],
139 Metric::Power(Power {
140 sampling_interval_ms: query_sampling_interval_ms,
141 statistics_args: Some(Box::new(StatisticsArgs {
142 statistics_interval_ms: query_statitics_interval_ms,
143 })),
144 }),
145 );
146 assert_eq!(output_samples_to_syslog, false);
147 assert_eq!(output_stats_to_syslog, false);
148 assert_eq!(duration_ms, query_duration_ms);
149
150 responder.send(Ok(())).unwrap();
151 }
152 other => panic!("Unexpected stream item: {:?}", other),
153 }
154 });
155
156 let facade = PowerFacade { logger_proxy: Some(proxy) };
157
158 assert_matches!(
159 facade
160 .start_logging(json!({
161 "sampling_interval_ms": query_sampling_interval_ms,
162 "statistics_interval_ms": query_statitics_interval_ms,
163 "duration_ms": query_duration_ms
164 }))
165 .await,
166 Ok(types::RecorderResult::Success)
167 );
168 }
169
170 #[fasync::run_singlethreaded(test)]
172 async fn test_start_logging_forever() {
173 let query_sampling_interval_ms = 500;
174
175 let (proxy, mut stream) = create_proxy_and_stream::<RecorderMarker>();
176
177 let _stream_task = fasync::Task::local(async move {
178 match stream.try_next().await {
179 Ok(Some(RecorderRequest::StartLoggingForever {
180 client_id,
181 metrics,
182 output_samples_to_syslog,
183 output_stats_to_syslog,
184 responder,
185 })) => {
186 assert_eq!(String::from("sl4f"), client_id);
187 assert_eq!(metrics.len(), 1);
188 assert_eq!(
189 metrics[0],
190 Metric::Power(Power {
191 sampling_interval_ms: query_sampling_interval_ms,
192 statistics_args: None,
193 }),
194 );
195 assert_eq!(output_samples_to_syslog, false);
196 assert_eq!(output_stats_to_syslog, false);
197
198 responder.send(Ok(())).unwrap();
199 }
200 other => panic!("Unexpected stream item: {:?}", other),
201 }
202 });
203
204 let facade = PowerFacade { logger_proxy: Some(proxy) };
205
206 assert_matches!(
207 facade
208 .start_logging_forever(json!({
209 "sampling_interval_ms": query_sampling_interval_ms
210 }))
211 .await,
212 Ok(types::RecorderResult::Success)
213 );
214 }
215
216 #[fasync::run_singlethreaded(test)]
218 async fn test_stop_logging() {
219 let (proxy, mut stream) = create_proxy_and_stream::<RecorderMarker>();
220
221 let _stream_task = fasync::Task::local(async move {
222 match stream.try_next().await {
223 Ok(Some(RecorderRequest::StopLogging { client_id, responder })) => {
224 assert_eq!(String::from("sl4f"), client_id);
225 responder.send(true).unwrap()
226 }
227 other => panic!("Unexpected stream item: {:?}", other),
228 }
229 });
230
231 let facade = PowerFacade { logger_proxy: Some(proxy) };
232
233 assert_matches!(facade.stop_logging().await, Ok(types::RecorderResult::Success));
234 }
235}