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