1use futures::stream::StreamExt;
28use scopeguard::defer;
29use std::collections::HashMap;
30use {fidl_fuchsia_time_alarms as fta, fuchsia_async as fasync, fuchsia_runtime as fxr};
31
32#[derive(Debug, Copy, Clone)]
34pub enum Response {
35 Immediate,
37 Delayed,
39 Error,
41}
42
43pub const MAGIC_EXPIRE_DEADLINE: i64 = 424242;
45
46#[derive(Debug)]
48pub struct ResponderCleanup {
49 alarm_id: String,
50 responder: Option<fta::WakeAlarmsSetAndWaitResponder>,
51 responder_utc: Option<fta::WakeAlarmsSetAndWaitUtcResponder>,
52 notifier: Option<fidl::endpoints::ClientEnd<fta::NotifierMarker>>,
53}
54
55impl Drop for ResponderCleanup {
56 fn drop(&mut self) {
57 if let Some(responder) = self.responder.take() {
58 log::debug!("dropping responder: {responder:?}");
59 responder
60 .send(Err(fta::WakeAlarmsError::Dropped))
61 .expect("should be able to respond to a FIDL message")
62 }
63 if let Some(responder) = self.responder_utc.take() {
64 log::debug!("dropping responder: {responder:?}");
65 responder
66 .send(Err(fta::WakeAlarmsError::Dropped))
67 .expect("should be able to respond to a FIDL message")
68 }
69 if let Some(notifier) = self.notifier.take() {
70 log::debug!("dropping notifier: {notifier:?}");
71 notifier
72 .into_proxy()
73 .notify_error(&self.alarm_id, fta::WakeAlarmsError::Dropped)
74 .expect("should be able to respond to a FIDL message")
75 }
76 }
77}
78
79fn signal_event(
80 event: &zx::Event,
81 clear_mask: zx::Signals,
82 set_mask: zx::Signals,
83) -> Result<(), zx::Status> {
84 event
85 .signal(clear_mask, set_mask)
86 .inspect_err(|err| log::error!(err:?, clear_mask:?, set_mask:?; "while signaling event"))
87}
88
89#[derive(Debug, Clone, Copy)]
91enum Deadline {
92 Boot(fasync::BootInstant),
93 Utc(fxr::UtcInstant),
94}
95
96impl Deadline {
97 fn into_boot(self) -> fasync::BootInstant {
99 match self {
100 Deadline::Boot(deadline) => deadline,
101 Deadline::Utc(deadline) => fasync::BootInstant::from_nanos(deadline.into_nanos()),
103 }
104 }
105}
106
107enum HandlerVariant {
110 SetAndWait {
111 responder: fta::WakeAlarmsSetAndWaitResponder,
112 },
113 SetAndWaitUtc {
114 responder: fta::WakeAlarmsSetAndWaitUtcResponder,
115 },
116 Set {
117 responder: fta::WakeAlarmsSetResponder,
118 notifier: fidl::endpoints::ClientEnd<fta::NotifierMarker>,
119 },
120}
121
122async fn handle_set_like_method(
123 method_name: &str,
124 message_counter: &zx::Counter,
125 responders: &mut HashMap<String, ResponderCleanup>,
126 deadline: Deadline,
127 mode: fta::SetMode,
128 alarm_id: String,
129 response_type: &Response,
130 handler_variant: HandlerVariant,
131) {
132 log::debug!(
133 "serve_fake_wake_alarms: {}: alarm_id: {:?}: deadline: {:?}",
134 method_name,
135 alarm_id,
136 deadline
137 );
138 defer! {
139 if let fta::SetMode::NotifySetupDone(setup_done) = mode {
140 signal_event(&setup_done, zx::Signals::NONE, zx::Signals::EVENT_SIGNALED).unwrap();
142 }
143 };
144 match response_type {
145 Response::Delayed => {
148 if deadline.into_boot().into_nanos() == MAGIC_EXPIRE_DEADLINE {
149 log::debug!(
150 "serve_fake_wake_alarms: {method_name}: responding immediately to magic deadline"
151 );
152 let r_count_before = responders.len();
155 responders.retain(|k, _| *k != alarm_id);
156 let r_count_after = responders.len();
157
158 message_counter
159 .add(
160 (r_count_before - r_count_after).try_into().expect("should be convertible"),
161 )
162 .expect("add to message_counter");
163 let (_, peer) = zx::EventPair::create();
164 message_counter.add(1).expect("add 1 to message counter");
165 match handler_variant {
166 HandlerVariant::SetAndWait { responder } => {
167 responder.send(Ok(peer)).expect("send FIDL response");
168 }
169 HandlerVariant::SetAndWaitUtc { responder } => {
170 responder.send(Ok(peer)).expect("send FIDL response");
171 }
172 HandlerVariant::Set { responder, notifier } => {
173 responder.send(Ok(())).unwrap();
174 notifier
175 .into_proxy()
176 .notify(&alarm_id, peer)
177 .expect("send Notify FIDL request");
178 }
179 }
180 } else {
181 log::debug!("serve_fake_wake_alarms: {method_name}: will not respond");
182 let removed = match handler_variant {
183 HandlerVariant::SetAndWait { responder } => responders.insert(
184 alarm_id.clone(),
185 ResponderCleanup {
186 alarm_id,
187 responder: Some(responder),
188 responder_utc: None,
189 notifier: None,
190 },
191 ),
192 HandlerVariant::SetAndWaitUtc { responder } => responders.insert(
193 alarm_id.clone(),
194 ResponderCleanup {
195 alarm_id,
196 notifier: None,
197 responder: None,
198 responder_utc: Some(responder),
199 },
200 ),
201 HandlerVariant::Set { responder, notifier } => {
202 responder.send(Ok(())).unwrap();
203 responders.insert(
204 alarm_id.clone(),
205 ResponderCleanup {
206 alarm_id,
207 notifier: Some(notifier),
208 responder_utc: None,
209 responder: None,
210 },
211 )
212 }
213 };
214 if let Some(_) = removed {
217 message_counter.add(1).unwrap();
218 }
219 }
220 }
221 Response::Immediate => {
222 let (_ignored, fake_lease) = zx::EventPair::create();
225 message_counter.add(1).unwrap();
226
227 match handler_variant {
228 HandlerVariant::SetAndWait { responder } => {
229 responder.send(Ok(fake_lease)).expect("infallible");
230 }
231 HandlerVariant::SetAndWaitUtc { responder } => {
232 responder.send(Ok(fake_lease)).expect("infallible");
233 }
234 HandlerVariant::Set { responder, notifier } => {
235 responder.send(Ok(())).expect("send FIDL response");
236 notifier
237 .into_proxy()
238 .notify(&alarm_id, fake_lease)
239 .expect("send Notify FIDL request");
240 }
241 }
242 log::debug!("serve_fake_wake_alarms: {method_name}: test fake responded immediately");
243 }
244 Response::Error => {
245 message_counter.add(1).unwrap();
246 match handler_variant {
247 HandlerVariant::SetAndWait { responder } => {
248 responder.send(Err(fta::WakeAlarmsError::Unspecified)).expect("infallible");
249 }
250 HandlerVariant::SetAndWaitUtc { responder } => {
251 responder.send(Err(fta::WakeAlarmsError::Unspecified)).expect("infallible");
252 }
253 HandlerVariant::Set { responder, notifier } => {
254 responder.send(Ok(())).expect("send FIDL response");
257 notifier
258 .into_proxy()
259 .notify_error(&alarm_id, fta::WakeAlarmsError::Unspecified)
260 .expect("infallible");
261 }
262 }
263 log::debug!("serve_fake_wake_alarms: {method_name}: Responded with error");
264 }
265 }
266}
267
268pub async fn serve_fake_wake_alarms(
279 message_counter: zx::Counter,
280 response_type: Response,
281 mut stream: fta::WakeAlarmsRequestStream,
282 once: bool,
283) {
284 log::warn!("serve_fake_wake_alarms: serving loop entry. response_type={:?}", response_type);
285 let mut responders: HashMap<String, ResponderCleanup> = HashMap::new();
286 if once {
287 return;
288 }
289
290 while let Some(maybe_request) = stream.next().await {
291 match maybe_request {
292 Ok(request) => {
293 log::debug!(
294 "serve_fake_wake_alarms: request: {:?}; response_type: {:?}",
295 request,
296 response_type
297 );
298
299 match request {
300 fta::WakeAlarmsRequest::SetAndWaitUtc {
301 mode,
302 responder,
303 alarm_id,
304 deadline,
305 } => {
306 handle_set_like_method(
307 "set_and_wait",
308 &message_counter,
309 &mut responders,
310 Deadline::Utc(fxr::UtcInstant::from_nanos(deadline.timestamp_utc)),
311 mode,
312 alarm_id,
313 &response_type,
314 HandlerVariant::SetAndWaitUtc { responder },
315 )
316 .await;
317 }
318 fta::WakeAlarmsRequest::SetAndWait { mode, responder, alarm_id, deadline } => {
319 handle_set_like_method(
320 "set_and_wait",
321 &message_counter,
322 &mut responders,
323 Deadline::Boot(deadline.into()),
324 mode,
325 alarm_id,
326 &response_type,
327 HandlerVariant::SetAndWait { responder },
328 )
329 .await;
330 }
331 fta::WakeAlarmsRequest::Set {
332 notifier,
333 deadline,
334 mode,
335 alarm_id,
336 responder,
337 } => {
338 handle_set_like_method(
339 "set",
340 &message_counter,
341 &mut responders,
342 Deadline::Boot(deadline.into()),
343 mode,
344 alarm_id.clone(),
345 &response_type,
346 HandlerVariant::Set { responder, notifier },
347 )
348 .await;
349 }
350 fta::WakeAlarmsRequest::Cancel { alarm_id, .. } => {
351 let r_count_before = responders.len();
352 responders.retain(|k, _| *k != alarm_id);
353 let r_count_after = responders.len();
354 message_counter
355 .add((r_count_before - r_count_after).try_into().unwrap())
356 .unwrap();
357
358 log::debug!("serve_fake_wake_alarms: Cancel: {}", alarm_id);
359 }
360 fta::WakeAlarmsRequest::_UnknownMethod { .. } => unreachable!(),
361 }
362 }
363 Err(e) => {
364 log::warn!("alarms::serve: error in request: {:?}", e);
367 }
368 }
369 }
370 log::warn!("serve_fake_wake_alarms: exiting");
371}