1use crate::power::{SuspendState, SuspendStats};
6use crate::task::CurrentTask;
7
8use std::collections::{HashMap, HashSet};
9use std::future::Future;
10use std::sync::{Arc, Weak};
11
12use anyhow::{Context, anyhow};
13use fidl::endpoints::Proxy;
14use fidl_fuchsia_power_observability as fobs;
15use fidl_fuchsia_session_power as fpower;
16use fidl_fuchsia_starnix_runner as frunner;
17use fuchsia_component::client::connect_to_protocol_sync;
18use fuchsia_inspect as inspect;
19use fuchsia_inspect::ArrayProperty;
20use futures::stream::{FusedStream, Next};
21use futures::{FutureExt, StreamExt};
22use starnix_logging::{log_info, log_warn};
23use starnix_sync::{
24 EbpfSuspendLock, LockDepGuard, LockDepMutex, LockDepReadGuard, LockDepRwLock,
25 PowerMessageCountersLock, SuspendResumeManagerInnerLock,
26};
27use starnix_uapi::arc_key::WeakKey;
28use starnix_uapi::errors::Errno;
29use starnix_uapi::{errno, error};
30use std::collections::VecDeque;
31use std::fmt;
32use zx::Peered;
33
34#[derive(Debug, Default)]
36pub struct WakeupSource {
37 pub last_actor: Option<starnix_task_command::TaskCommand>,
39
40 active_count: u64,
42
43 event_count: u64,
46
47 wakeup_count: u64,
53
54 expire_count: u64,
56
57 active_since: zx::MonotonicInstant,
60
61 total_time: zx::MonotonicDuration,
63
64 max_time: zx::MonotonicDuration,
66
67 last_change: zx::MonotonicInstant,
69}
70
71impl WakeupSource {
72 pub fn display_name(&self, origin: &WakeupSourceOrigin) -> String {
74 match &self.last_actor {
75 Some(actor) => format!("{} [{}]", origin.to_string(), actor),
76 None => origin.to_string(),
77 }
78 }
79
80 pub fn active_duration(&self) -> zx::MonotonicDuration {
84 if self.active_since == zx::MonotonicInstant::ZERO {
85 zx::MonotonicDuration::default()
86 } else {
87 let now = zx::MonotonicInstant::get();
88 now - self.active_since
89 }
90 }
91}
92
93#[derive(Debug, Clone, Eq, PartialEq, Hash)]
94pub enum WakeupSourceOrigin {
95 WakeLock(String),
96 Epoll(crate::vfs::EpollKey),
97 HAL(String),
98}
99
100impl std::string::ToString for WakeupSourceOrigin {
101 fn to_string(&self) -> String {
102 match self {
103 WakeupSourceOrigin::WakeLock(lock) => lock.clone(),
104 WakeupSourceOrigin::Epoll(key) => format!("[epoll] {}", key),
105 WakeupSourceOrigin::HAL(lock) => format!("[HAL] {}", lock),
106 }
107 }
108}
109
110pub struct SuspendResumeManager {
112 inner: Arc<LockDepMutex<SuspendResumeManagerInner, SuspendResumeManagerInnerLock>>,
114
115 message_counters:
118 Arc<LockDepMutex<HashSet<WeakKey<OwnedMessageCounter>>, PowerMessageCountersLock>>,
119
120 ebpf_suspend_lock: LockDepRwLock<(), EbpfSuspendLock>,
122}
123
124pub struct SuspendResumeManagerInner {
127 suspend_stats: SuspendStats,
129 sync_on_suspend_enabled: bool,
130
131 suspend_events: VecDeque<SuspendEvent>,
132
133 wakeup_sources: HashMap<WakeupSourceOrigin, WakeupSource>,
135
136 active_lock_reader: zx::EventPair,
139
140 active_lock_writer: zx::EventPair,
144
145 active_wakeup_source_count: u64,
147
148 total_wakeup_source_event_count: u64,
151
152 external_wake_sources: HashMap<zx::Koid, ExternalWakeSource>,
154}
155
156#[derive(Debug)]
157struct ExternalWakeSource {
158 handle: zx::NullableHandle,
160 signals: zx::Signals,
162 name: String,
164}
165
166impl SuspendResumeManager {
167 pub fn add_external_wake_source(
168 &self,
169 handle: zx::NullableHandle,
170 signals: zx::Signals,
171 name: String,
172 ) -> Result<(), Errno> {
173 let manager = connect_to_protocol_sync::<frunner::ManagerMarker>()
174 .map_err(|e| errno!(EINVAL, format!("Failed to connect to manager: {e:?}")))?;
175 manager
176 .add_wake_source(frunner::ManagerAddWakeSourceRequest {
177 container_job: Some(
178 fuchsia_runtime::job_default()
179 .duplicate_handle(zx::Rights::SAME_RIGHTS)
180 .expect("Failed to dup handle"),
181 ),
182 name: Some(name.clone()),
183 handle: Some(
184 handle.duplicate_handle(zx::Rights::SAME_RIGHTS).map_err(|e| errno!(EIO, e))?,
185 ),
186 signals: Some(signals.bits()),
187 ..Default::default()
188 })
189 .map_err(|e| errno!(EIO, e))?;
190
191 let koid = handle.koid().map_err(|e| errno!(EINVAL, e))?;
192 self.lock().external_wake_sources.insert(
193 koid,
194 ExternalWakeSource {
195 handle: handle
196 .duplicate_handle(zx::Rights::SAME_RIGHTS)
197 .map_err(|e| errno!(EIO, e))?,
198 signals,
199 name,
200 },
201 );
202 Ok(())
203 }
204
205 pub fn remove_external_wake_source(&self, handle: zx::NullableHandle) -> Result<(), Errno> {
206 let manager = connect_to_protocol_sync::<frunner::ManagerMarker>()
207 .map_err(|e| errno!(EINVAL, format!("Failed to connect to manager: {e:?}")))?;
208
209 let koid = handle.koid().map_err(|e| errno!(EINVAL, e))?;
210 self.lock().external_wake_sources.remove(&koid);
211
212 manager
213 .remove_wake_source(frunner::ManagerRemoveWakeSourceRequest {
214 container_job: Some(
215 fuchsia_runtime::job_default()
216 .duplicate_handle(zx::Rights::SAME_RIGHTS)
217 .expect("Failed to dup handle"),
218 ),
219 handle: Some(handle),
220 ..Default::default()
221 })
222 .map_err(|e| errno!(EIO, e))?;
223
224 Ok(())
225 }
226}
227
228pub type EbpfSuspendGuard<'a> = LockDepReadGuard<'a, ()>;
229
230#[derive(Clone, Debug)]
231pub enum SuspendEvent {
232 Attempt { time: zx::BootInstant, state: String },
233 Resume { time: zx::BootInstant, reason: String },
234 Fail { time: zx::BootInstant, wakeup_sources: Option<Vec<String>> },
235}
236
237const INSPECT_RING_BUFFER_CAPACITY: usize = 128;
239
240impl Default for SuspendResumeManagerInner {
241 fn default() -> Self {
242 let (active_lock_reader, active_lock_writer) = zx::EventPair::create();
243 active_lock_writer
244 .signal_peer(zx::Signals::empty(), zx::Signals::USER_0)
245 .expect("Failed to signal peer");
246 Self {
247 suspend_stats: Default::default(),
248 sync_on_suspend_enabled: false,
249 suspend_events: VecDeque::with_capacity(INSPECT_RING_BUFFER_CAPACITY),
250 wakeup_sources: Default::default(),
251 active_lock_reader,
252 active_lock_writer,
253 active_wakeup_source_count: 0,
254 total_wakeup_source_event_count: 0,
255 external_wake_sources: Default::default(),
256 }
257 }
258}
259
260impl SuspendResumeManagerInner {
261 pub fn can_suspend(&self) -> bool {
263 self.active_wakeup_source_count == 0
264 }
265
266 pub fn active_wake_locks(&self) -> Vec<WakeupSourceOrigin> {
267 self.wakeup_sources
268 .iter()
269 .filter_map(|(name, source)| match name {
270 WakeupSourceOrigin::WakeLock(_) => {
271 if source.active_since > zx::MonotonicInstant::ZERO {
272 Some(name.clone())
273 } else {
274 None
275 }
276 }
277 _ => None,
278 })
279 .collect()
280 }
281
282 pub fn inactive_wake_locks(&self) -> Vec<WakeupSourceOrigin> {
283 self.wakeup_sources
284 .iter()
285 .filter_map(|(name, source)| match name {
286 WakeupSourceOrigin::WakeLock(_) => {
287 if source.active_since == zx::MonotonicInstant::ZERO {
288 Some(name.clone())
289 } else {
290 None
291 }
292 }
293 _ => None,
294 })
295 .collect()
296 }
297
298 fn signal_wake_events(&mut self) {
300 let (clear_mask, set_mask) = if self.active_wakeup_source_count == 0 {
301 (zx::Signals::EVENT_SIGNALED, zx::Signals::USER_0)
302 } else {
303 (zx::Signals::USER_0, zx::Signals::EVENT_SIGNALED)
304 };
305 self.active_lock_writer.signal_peer(clear_mask, set_mask).expect("Failed to signal peer");
306 }
307
308 fn update_suspend_stats<UpdateFn>(&mut self, update: UpdateFn)
309 where
310 UpdateFn: FnOnce(&mut SuspendStats),
311 {
312 update(&mut self.suspend_stats);
313 }
314
315 fn add_suspend_event(&mut self, event: SuspendEvent) {
316 if self.suspend_events.len() >= INSPECT_RING_BUFFER_CAPACITY {
317 self.suspend_events.pop_front();
318 }
319 self.suspend_events.push_back(event);
320 }
321
322 fn record_suspend_events(&self, node: &inspect::Node) {
323 let events_node = node.create_child("suspend_events");
324 for (i, event) in self.suspend_events.iter().enumerate() {
325 let child = events_node.create_child(i.to_string());
326 match event {
327 SuspendEvent::Attempt { time, state } => {
328 child.record_int(fobs::SUSPEND_ATTEMPTED_AT, time.into_nanos());
329 child.record_string(fobs::SUSPEND_REQUESTED_STATE, state);
330 }
331 SuspendEvent::Resume { time, reason } => {
332 child.record_int(fobs::SUSPEND_RESUMED_AT, time.into_nanos());
333 child.record_string(fobs::SUSPEND_RESUME_REASON, reason);
334 }
335 SuspendEvent::Fail { time, wakeup_sources } => {
336 child.record_int(fobs::SUSPEND_FAILED_AT, time.into_nanos());
337 if let Some(names) = wakeup_sources {
338 let names_array =
339 child.create_string_array(fobs::WAKEUP_SOURCES_NAME, names.len());
340 for (i, name) in names.iter().enumerate() {
341 names_array.set(i, name);
342 }
343 child.record(names_array);
344 }
345 }
346 }
347 events_node.record(child);
348 }
349 node.record(events_node);
350 }
351
352 fn record_wakeup_sources(&self, node: &inspect::Node) {
353 let wakeup_node = node.create_child("wakeup_sources");
354 for (origin, source) in self.wakeup_sources.iter() {
355 let child = wakeup_node.create_child(&source.display_name(origin));
356 child.record_uint("active_count", source.active_count);
357 child.record_uint("event_count", source.event_count);
358 child.record_uint("wakeup_count", source.wakeup_count);
359 child.record_uint("expire_count", source.expire_count);
360 child.record_int("active_since (ns)", source.active_since.into_nanos());
361 child.record_int("active_duration_mono (ns)", source.active_duration().into_nanos());
364 child.record_int("total_time (ms)", source.total_time.into_millis());
365 child.record_int("max_time (ms)", source.max_time.into_millis());
366 child.record_int("last_change (ns)", source.last_change.into_nanos());
367 wakeup_node.record(child);
368 }
369 node.record(wakeup_node);
370 }
371}
372
373pub type SuspendResumeManagerHandle = Arc<SuspendResumeManager>;
374
375impl Default for SuspendResumeManager {
376 fn default() -> Self {
377 let message_counters: Arc<
378 LockDepMutex<HashSet<WeakKey<OwnedMessageCounter>>, PowerMessageCountersLock>,
379 > = Default::default();
380 let message_counters_clone = message_counters.clone();
381 let root = inspect::component::inspector().root();
382 root.record_lazy_values("message_counters", move || {
383 let message_counters_clone = message_counters_clone.clone();
384 async move {
385 let inspector = fuchsia_inspect::Inspector::default();
386 let root = inspector.root();
387 let message_counters = message_counters_clone.lock();
388 let active_counter_names: Vec<String> = message_counters
389 .iter()
390 .filter_map(|c| c.0.upgrade())
391 .map(|c| c.to_string())
392 .collect();
393 let message_counters_inspect =
394 root.create_string_array("message_counters", active_counter_names.len());
395 for (i, name) in active_counter_names.iter().enumerate() {
396 message_counters_inspect.set(i, name);
397 }
398 root.record(message_counters_inspect);
399 Ok(inspector)
400 }
401 .boxed()
402 });
403 let inner = Arc::new(LockDepMutex::new(SuspendResumeManagerInner::default()));
404 let inner_clone = inner.clone();
405 root.record_lazy_child("wakeup_sources", move || {
406 let inner = inner_clone.clone();
407 async move {
408 let inspector = fuchsia_inspect::Inspector::default();
409 let root = inspector.root();
410 let state = inner.lock();
411
412 state.record_suspend_events(root);
413 state.record_wakeup_sources(root);
414
415 Ok(inspector)
416 }
417 .boxed()
418 });
419 Self { message_counters, inner, ebpf_suspend_lock: Default::default() }
420 }
421}
422
423impl SuspendResumeManager {
424 pub fn lock(&self) -> LockDepGuard<'_, SuspendResumeManagerInner> {
426 self.inner.lock()
427 }
428
429 pub fn init(
431 self: &SuspendResumeManagerHandle,
432 system_task: &CurrentTask,
433 ) -> Result<(), anyhow::Error> {
434 let handoff = system_task
435 .kernel()
436 .connect_to_protocol_at_container_svc::<fpower::HandoffMarker>()?
437 .into_sync_proxy();
438 match handoff.take(zx::MonotonicInstant::INFINITE) {
439 Ok(parent_lease) => {
440 let parent_lease = parent_lease
441 .map_err(|e| anyhow!("Failed to take lessor and lease from parent: {e:?}"))?;
442 drop(parent_lease)
443 }
444 Err(e) => {
445 if e.is_closed() {
446 log_warn!(
447 "Failed to send the fuchsia.session.power/Handoff.Take request. Assuming no Handoff protocol exists and moving on..."
448 );
449 } else {
450 return Err(e).context("Handoff::Take");
451 }
452 }
453 }
454 Ok(())
455 }
456
457 pub fn activate_wakeup_source(&self, origin: WakeupSourceOrigin) -> bool {
458 self.activate_wakeup_source_with_actor(origin, None)
459 }
460
461 pub fn activate_wakeup_source_with_actor(
462 &self,
463 origin: WakeupSourceOrigin,
464 actor: Option<starnix_task_command::TaskCommand>,
465 ) -> bool {
466 let mut state = self.lock();
467 let did_activate = {
468 let entry = state.wakeup_sources.entry(origin).or_default();
469 entry.last_actor = actor;
470 let now = zx::MonotonicInstant::get();
471 entry.active_count += 1;
472 entry.event_count += 1;
473 entry.last_change = now;
474 if entry.active_since == zx::MonotonicInstant::ZERO {
475 entry.active_since = now;
476 true
477 } else {
478 false
479 }
480 };
481 if did_activate {
482 state.active_wakeup_source_count += 1;
483 state.signal_wake_events();
484 }
485 did_activate
486 }
487
488 pub fn deactivate_wakeup_source(&self, origin: &WakeupSourceOrigin) -> bool {
489 self.remove_wakeup_source(origin, false)
490 }
491
492 pub fn timeout_wakeup_source(&self, origin: &WakeupSourceOrigin) -> bool {
493 self.remove_wakeup_source(origin, true)
494 }
495
496 fn remove_wakeup_source(&self, origin: &WakeupSourceOrigin, timed_out: bool) -> bool {
497 let mut state = self.lock();
498 let removed = match state.wakeup_sources.get_mut(origin) {
499 Some(entry) if entry.active_since != zx::MonotonicInstant::ZERO => {
500 if timed_out {
501 entry.expire_count += 1;
502 }
503
504 let now = zx::MonotonicInstant::get();
505 let duration = now - entry.active_since;
506 entry.total_time += duration;
507 entry.max_time = std::cmp::max(duration, entry.max_time);
508 entry.last_change = now;
509 entry.active_since = zx::MonotonicInstant::ZERO;
510
511 true
512 }
513 _ => false,
514 };
515 if removed {
516 state.active_wakeup_source_count -= 1;
517 state.total_wakeup_source_event_count += 1;
518 state.signal_wake_events();
519 }
520 removed
521 }
522
523 pub fn add_message_counter(
524 &self,
525 name: &str,
526 counter: Option<zx::Counter>,
527 ) -> OwnedMessageCounterHandle {
528 let container_counter = OwnedMessageCounter::new(name, counter);
529 let mut message_counters = self.message_counters.lock();
530 message_counters.insert(WeakKey::from(&container_counter));
531 message_counters.retain(|c| c.0.upgrade().is_some());
532 container_counter
533 }
534
535 pub fn has_nonzero_message_counter(&self) -> bool {
536 self.message_counters.lock().iter().any(|c| {
537 let Some(c) = c.0.upgrade() else {
538 return false;
539 };
540 c.counter.as_ref().and_then(|counter| counter.read().ok()).map_or(false, |v| v != 0)
541 })
542 }
543
544 pub fn duplicate_lock_event(&self) -> zx::EventPair {
547 let state = self.lock();
548 state
549 .active_lock_reader
550 .duplicate_handle(zx::Rights::SAME_RIGHTS)
551 .expect("Failed to duplicate handle")
552 }
553
554 pub fn suspend_stats(&self) -> SuspendStats {
556 self.lock().suspend_stats.clone()
557 }
558
559 pub fn total_wakeup_events(&self) -> u64 {
560 let state = self.lock();
561 state.total_wakeup_source_event_count + state.suspend_stats.success_count
562 }
563
564 pub fn sync_on_suspend_enabled(&self) -> bool {
568 self.lock().sync_on_suspend_enabled.clone()
569 }
570
571 pub fn set_sync_on_suspend(&self, enable: bool) {
574 self.lock().sync_on_suspend_enabled = enable;
575 }
576
577 pub fn suspend_states(&self) -> HashSet<SuspendState> {
579 HashSet::from([SuspendState::Idle])
581 }
582
583 pub fn suspend(&self, suspend_state: SuspendState) -> Result<(), Errno> {
584 let suspend_start_time = zx::BootInstant::get();
585 let mut state = self.lock();
586 state.add_suspend_event(SuspendEvent::Attempt {
587 time: suspend_start_time,
588 state: suspend_state.to_string(),
589 });
590
591 if !state.can_suspend() {
593 self.report_failed_suspension(state, "kernel wake lock");
594 return error!(EINVAL);
595 }
596
597 let external_wake_source_abort = state.external_wake_sources.values().find_map(|source| {
599 if source.handle.wait_one(source.signals, zx::MonotonicInstant::INFINITE_PAST).is_ok() {
600 Some(source.name.clone())
601 } else {
602 None
603 }
604 });
605
606 if let Some(name) = external_wake_source_abort {
607 self.report_failed_suspension(state, &format!("external wake source: {}", name));
608 return error!(EINVAL);
609 }
610
611 std::mem::drop(state);
615
616 let _ebpf_lock = self.ebpf_suspend_lock.write();
619
620 let manager = connect_to_protocol_sync::<frunner::ManagerMarker>()
621 .expect("Failed to connect to manager");
622 fuchsia_trace::duration!("power", "suspend_container:fidl");
623
624 let container_job = Some(
625 fuchsia_runtime::job_default()
626 .duplicate_handle(zx::Rights::SAME_RIGHTS)
627 .expect("Failed to dup handle"),
628 );
629 let wake_lock_event = Some(self.duplicate_lock_event());
630
631 log_info!("Requesting container suspension.");
632 match manager.suspend_container(
633 frunner::ManagerSuspendContainerRequest {
634 container_job,
635 wake_locks: wake_lock_event,
636 ..Default::default()
637 },
638 zx::Instant::INFINITE,
639 ) {
640 Ok(Ok(res)) => {
641 self.report_container_resumed(suspend_start_time, res);
642 }
643 e => {
644 let state = self.lock();
645 self.report_failed_suspension(state, &format!("runner error {:?}", e));
646 return error!(EINVAL);
647 }
648 }
649 Ok(())
650 }
651
652 fn report_container_resumed(
653 &self,
654 suspend_start_time: zx::BootInstant,
655 res: frunner::ManagerSuspendContainerResponse,
656 ) {
657 let wake_time = zx::BootInstant::get();
658 let resume_reason = res.resume_reason.clone().map(|s| format!("0 {}", s));
661 log_info!("Resuming from container suspension: {:?}", resume_reason);
662 let mut state = self.lock();
663 state.update_suspend_stats(|suspend_stats| {
664 suspend_stats.success_count += 1;
665 suspend_stats.last_time_in_suspend_operations = (wake_time - suspend_start_time).into();
666 suspend_stats.last_time_in_sleep =
667 zx::BootDuration::from_nanos(res.suspend_time.unwrap_or(0));
668 suspend_stats.last_resume_reason = resume_reason.clone();
669 });
670 state.add_suspend_event(SuspendEvent::Resume {
671 time: wake_time,
672 reason: resume_reason.unwrap_or_default(),
673 });
674 fuchsia_trace::instant!("power", "suspend_container:done", fuchsia_trace::Scope::Process);
675 }
676
677 fn report_failed_suspension(
678 &self,
679 mut state: LockDepGuard<'_, SuspendResumeManagerInner>,
680 failure_reason: &str,
681 ) {
682 let wake_time = zx::BootInstant::get();
683 state.update_suspend_stats(|suspend_stats| {
684 suspend_stats.fail_count += 1;
685 suspend_stats.last_failed_errno = Some(errno!(EINVAL));
686 suspend_stats.last_resume_reason = None;
687 });
688
689 let mut wakeup_sources: Vec<String> = state
690 .wakeup_sources
691 .iter_mut()
692 .filter_map(|(origin, source)| {
693 if source.active_since > zx::MonotonicInstant::ZERO {
694 source.wakeup_count += 1;
695 Some(source.display_name(origin))
696 } else {
697 None
698 }
699 })
700 .collect();
701
702 for source in state.external_wake_sources.values() {
703 if source.handle.wait_one(source.signals, zx::MonotonicInstant::INFINITE_PAST).is_ok() {
704 wakeup_sources.push(source.name.clone());
705 }
706 }
707
708 let last_resume_reason = format!("Abort: {}", wakeup_sources.join(" "));
709 state.update_suspend_stats(|suspend_stats| {
710 suspend_stats.last_resume_reason = Some(last_resume_reason);
712 });
713
714 log_warn!(
716 "Suspend failed due to {:?}. Here are the active wakeup sources: {:?}",
717 failure_reason,
718 wakeup_sources,
719 );
720 state.add_suspend_event(SuspendEvent::Fail {
722 time: wake_time,
723 wakeup_sources: Some(wakeup_sources),
724 });
725 fuchsia_trace::instant!("power", "suspend_container:error", fuchsia_trace::Scope::Process);
726 }
727
728 pub fn acquire_ebpf_suspend_lock<'a>(&'a self) -> EbpfSuspendGuard<'a> {
729 self.ebpf_suspend_lock.read()
730 }
731}
732
733pub trait OnWakeOps: Send + Sync {
735 fn on_wake(&self, current_task: &CurrentTask, baton_lease: &zx::NullableHandle);
744}
745
746pub fn create_proxy_for_wake_events_counter_zero(
764 remote_channel: zx::Channel,
765 name: String,
766) -> (zx::Channel, zx::Counter) {
767 let (local_proxy, kernel_channel) = zx::Channel::create();
768 let counter = zx::Counter::create();
769
770 let local_counter =
771 counter.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("Failed to duplicate counter");
772
773 let manager = fuchsia_component::client::connect_to_protocol_sync::<frunner::ManagerMarker>()
774 .expect("failed");
775 manager
776 .proxy_wake_channel(frunner::ManagerProxyWakeChannelRequest {
777 container_job: Some(
778 fuchsia_runtime::job_default()
779 .duplicate_handle(zx::Rights::SAME_RIGHTS)
780 .expect("Failed to dup handle"),
781 ),
782 container_channel: Some(kernel_channel),
783 remote_channel: Some(remote_channel),
784 counter: Some(counter),
785 name: Some(name),
786 ..Default::default()
787 })
788 .expect("Failed to create proxy");
789
790 (local_proxy, local_counter)
791}
792
793pub fn create_proxy_for_wake_events_counter(
812 remote_channel: zx::Channel,
813 name: String,
814) -> (zx::Channel, zx::Counter) {
815 let (proxy, counter) = create_proxy_for_wake_events_counter_zero(remote_channel, name);
816
817 counter.add(1).expect("Failed to add to counter");
820
821 (proxy, counter)
822}
823
824pub fn mark_proxy_message_handled(counter: &zx::Counter) {
829 counter.add(-1).expect("Failed to decrement counter");
830}
831
832pub fn mark_all_proxy_messages_handled(counter: &zx::Counter) {
834 counter.write(0).expect("Failed to decrement counter");
835}
836
837pub fn create_watcher_for_wake_events(watcher: zx::EventPair) {
841 let manager = fuchsia_component::client::connect_to_protocol_sync::<frunner::ManagerMarker>()
842 .expect("failed");
843 manager
844 .register_wake_watcher(
845 frunner::ManagerRegisterWakeWatcherRequest {
846 watcher: Some(watcher),
847 ..Default::default()
848 },
849 zx::Instant::INFINITE,
850 )
851 .expect("Failed to register wake watcher");
852}
853
854#[derive(Debug)]
863pub struct SharedMessageCounter(Weak<OwnedMessageCounter>);
864
865impl Drop for SharedMessageCounter {
866 fn drop(&mut self) {
867 if let Some(message_counter) = self.0.upgrade() {
868 message_counter.mark_handled();
869 }
870 }
871}
872
873pub struct OwnedMessageCounter {
878 name: String,
879 counter: Option<zx::Counter>,
880}
881pub type OwnedMessageCounterHandle = Arc<OwnedMessageCounter>;
882
883impl Drop for OwnedMessageCounter {
884 fn drop(&mut self) {
889 self.counter.as_ref().map(mark_all_proxy_messages_handled);
890 }
891}
892
893impl OwnedMessageCounter {
894 pub fn new(name: &str, counter: Option<zx::Counter>) -> OwnedMessageCounterHandle {
895 Arc::new(Self { name: name.to_string(), counter })
896 }
897
898 pub fn mark_handled(&self) {
903 self.counter.as_ref().map(mark_proxy_message_handled);
904 }
905
906 pub fn mark_pending(&self) {
910 self.counter.as_ref().map(|c| c.add(1).expect("Failed to increment counter"));
911 }
912
913 pub fn share(
917 self: &OwnedMessageCounterHandle,
918 new_pending_message: bool,
919 ) -> SharedMessageCounter {
920 if new_pending_message {
921 self.mark_pending();
922 }
923 SharedMessageCounter(Arc::downgrade(self))
924 }
925}
926
927impl fmt::Display for OwnedMessageCounter {
928 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
929 write!(f, "Counter({}): {:?}", self.name, self.counter.as_ref().map(|c| c.read()))
930 }
931}
932
933pub struct ContainerWakingProxy<P: Proxy> {
938 counter: OwnedMessageCounterHandle,
939 proxy: P,
940}
941
942impl<P: Proxy> ContainerWakingProxy<P> {
943 pub fn new(counter: OwnedMessageCounterHandle, proxy: P) -> Self {
944 Self { counter, proxy }
945 }
946
947 pub fn call<T, F, R>(&self, future: F) -> R
951 where
952 F: FnOnce(&P) -> R,
953 R: Future<Output = T>,
954 {
955 let f = future(&self.proxy);
963 self.counter.mark_handled();
964 f
965 }
966}
967
968pub struct ContainerWakingStream<S: FusedStream + Unpin> {
973 counter: OwnedMessageCounterHandle,
974 stream: S,
975}
976
977impl<S: FusedStream + Unpin> ContainerWakingStream<S> {
978 pub fn new(counter: OwnedMessageCounterHandle, stream: S) -> Self {
979 Self { counter, stream }
980 }
981
982 pub fn next(&mut self) -> Next<'_, S> {
986 let is_terminated = self.stream.is_terminated();
988 let next = self.stream.next();
989 if !is_terminated {
990 self.counter.mark_handled();
991 }
992 next
993 }
994}
995
996#[cfg(test)]
997mod test {
998 use super::*;
999 use diagnostics_assertions::assert_data_tree;
1000 use fidl::endpoints::create_proxy_and_stream;
1001 use fidl_test_placeholders::{EchoMarker, EchoRequest};
1002 use fuchsia_async as fasync;
1003 use fuchsia_inspect as inspect;
1004 use futures::StreamExt;
1005
1006 #[::fuchsia::test]
1007 fn test_counter_zero_initialization() {
1008 let (_endpoint, endpoint) = zx::Channel::create();
1009 let (_channel, counter) =
1010 super::create_proxy_for_wake_events_counter_zero(endpoint, "test".into());
1011 assert_eq!(counter.read(), Ok(0));
1012 }
1013
1014 #[::fuchsia::test]
1015 fn test_counter_initialization() {
1016 let (_endpoint, endpoint) = zx::Channel::create();
1017 let (_channel, counter) =
1018 super::create_proxy_for_wake_events_counter(endpoint, "test".into());
1019 assert_eq!(counter.read(), Ok(1));
1020 }
1021
1022 #[::fuchsia::test]
1023 async fn test_container_waking_proxy() {
1024 let (proxy, mut stream) = create_proxy_and_stream::<EchoMarker>();
1025 let server_task = fasync::Task::spawn(async move {
1026 let request = stream.next().await.unwrap().unwrap();
1027 match request {
1028 EchoRequest::EchoString { value, responder } => {
1029 responder.send(value.as_deref()).unwrap();
1030 }
1031 }
1032 });
1033
1034 let counter = zx::Counter::create();
1035 counter.add(5).unwrap();
1036 assert_eq!(counter.read(), Ok(5));
1037
1038 let waking_proxy = ContainerWakingProxy {
1039 counter: OwnedMessageCounter::new(
1040 "test_proxy",
1041 Some(counter.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap()),
1042 ),
1043 proxy,
1044 };
1045
1046 let response_future = waking_proxy.call(|p| p.echo_string(Some("hello")));
1047
1048 assert_eq!(counter.read(), Ok(4));
1050
1051 let response = response_future.await.unwrap();
1052 assert_eq!(response.as_deref(), Some("hello"));
1053
1054 server_task.await;
1055
1056 assert_eq!(counter.read(), Ok(4));
1057 drop(waking_proxy);
1058 assert_eq!(counter.read(), Ok(0));
1059 }
1060
1061 #[::fuchsia::test]
1062 async fn test_container_waking_stream() {
1063 let (proxy, stream) = create_proxy_and_stream::<EchoMarker>();
1064 let client_task = fasync::Task::spawn(async move {
1065 let response = proxy.echo_string(Some("hello")).await.unwrap();
1066 assert_eq!(response.as_deref(), Some("hello"));
1067 });
1068
1069 let counter = zx::Counter::create();
1070 counter.add(5).unwrap();
1071 assert_eq!(counter.read(), Ok(5));
1072
1073 let mut waking_stream = ContainerWakingStream {
1074 counter: OwnedMessageCounter::new(
1075 "test_stream",
1076 Some(counter.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap()),
1077 ),
1078 stream,
1079 };
1080
1081 let request_future = waking_stream.next();
1082
1083 assert_eq!(counter.read(), Ok(4));
1085
1086 let request = request_future.await.unwrap().unwrap();
1087 match request {
1088 EchoRequest::EchoString { value, responder } => {
1089 assert_eq!(value.as_deref(), Some("hello"));
1090 responder.send(value.as_deref()).unwrap();
1091 }
1092 }
1093
1094 client_task.await;
1095
1096 assert_eq!(counter.read(), Ok(4));
1097 drop(waking_stream);
1098 assert_eq!(counter.read(), Ok(0));
1099 }
1100
1101 #[::fuchsia::test]
1102 async fn test_message_counters_inspect() {
1103 let power_manager = SuspendResumeManager::default();
1104 let inspector = inspect::component::inspector();
1105
1106 let zx_counter = zx::Counter::create();
1107 let counter_handle = power_manager.add_message_counter(
1108 "test_counter",
1109 Some(zx_counter.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap()),
1110 );
1111
1112 zx_counter.add(1).unwrap();
1113
1114 assert_data_tree!(inspector, root: contains {
1115 message_counters: vec!["Counter(test_counter): Some(Ok(1))"],
1116 });
1117
1118 zx_counter.add(1).unwrap();
1119 assert_data_tree!(inspector, root: contains {
1120 message_counters: vec!["Counter(test_counter): Some(Ok(2))"],
1121 });
1122
1123 drop(counter_handle);
1124 assert_data_tree!(inspector, root: contains {
1125 message_counters: Vec::<String>::new(),
1126 });
1127 }
1128
1129 #[::fuchsia::test]
1130 fn test_shared_message_counter() {
1131 let zx_counter = zx::Counter::create();
1133 let owned_counter = OwnedMessageCounter::new(
1134 "test_shared_counter",
1135 Some(zx_counter.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap()),
1136 );
1137 zx_counter.add(5).unwrap();
1138 assert_eq!(zx_counter.read(), Ok(5));
1139
1140 let shared_counter = owned_counter.share(false);
1142 assert_eq!(zx_counter.read(), Ok(5));
1143
1144 drop(shared_counter);
1146 assert_eq!(zx_counter.read(), Ok(4));
1147
1148 let shared_counter_2 = owned_counter.share(true);
1150 assert_eq!(zx_counter.read(), Ok(5));
1151
1152 drop(shared_counter_2);
1154 assert_eq!(zx_counter.read(), Ok(4));
1155
1156 let shared_counter_3 = owned_counter.share(false);
1158 assert_eq!(zx_counter.read(), Ok(4));
1159
1160 drop(owned_counter);
1162 assert_eq!(zx_counter.read(), Ok(0));
1163
1164 drop(shared_counter_3);
1166 assert_eq!(zx_counter.read(), Ok(0));
1167 }
1168
1169 #[::fuchsia::test]
1170 async fn test_container_waking_event_termination() {
1171 let stream = futures::stream::iter(vec![0]).fuse();
1172 let counter = zx::Counter::create();
1173 counter.add(2).unwrap();
1174 assert_eq!(counter.read(), Ok(2));
1175 let mut waking_stream = ContainerWakingStream {
1176 counter: OwnedMessageCounter::new(
1177 "test_stream",
1178 Some(counter.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap()),
1179 ),
1180 stream,
1181 };
1182
1183 assert_eq!(waking_stream.next().await, Some(0));
1184 assert_eq!(counter.read(), Ok(1));
1185
1186 assert_eq!(waking_stream.next().await, None);
1187 assert_eq!(waking_stream.next().await, None);
1188 assert_eq!(counter.read(), Ok(0));
1190 }
1191
1192 #[::fuchsia::test]
1193 fn test_external_wake_source_aborts_suspend() {
1194 let manager = SuspendResumeManager::default();
1195 let event = zx::Event::create();
1196 let signals = zx::Signals::USER_0;
1197
1198 let res = manager.add_external_wake_source(
1203 event.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap().into_handle(),
1204 signals,
1205 "test_external".to_string(),
1206 );
1207
1208 if res.is_err() {
1209 println!(
1210 "Skipping test_external_wake_source_aborts_suspend because runner connection failed: {:?}",
1211 res
1212 );
1213 return;
1214 }
1215
1216 event.signal(zx::Signals::empty(), signals).unwrap();
1218
1219 let state = manager.lock();
1220 assert!(state.external_wake_sources.contains_key(&event.koid().unwrap()));
1221 }
1222}