wake_lease/
wake_lease.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use anyhow::Result;
6use fidl_fuchsia_power_system as fsystem;
7
8pub struct WakeLease {
9    _token: fsystem::LeaseToken,
10}
11
12impl WakeLease {
13    pub async fn take(
14        activity_governor: fsystem::ActivityGovernorProxy,
15        name: String,
16    ) -> Result<Self> {
17        let _token = activity_governor.take_wake_lease(&name).await?;
18        Ok(Self { _token })
19    }
20}
21
22#[cfg(test)]
23mod tests {
24    use super::*;
25    use anyhow::Context;
26    use fidl::endpoints::create_proxy_and_stream;
27    use fuchsia_async as fasync;
28    use futures::channel::mpsc;
29    use futures::prelude::*;
30
31    struct FakeActivityGovernor {
32        // Sends updates in server wake lease state (active, inactive).
33        wake_lease_active: mpsc::UnboundedSender<bool>,
34    }
35
36    impl FakeActivityGovernor {
37        async fn run(&self, stream: fsystem::ActivityGovernorRequestStream) -> Result<()> {
38            stream
39                .map(|request| request.context("failed request"))
40                .try_for_each(|request| async {
41                    match request {
42                        fsystem::ActivityGovernorRequest::TakeWakeLease {
43                            name: _name,
44                            responder,
45                        } => {
46                            let (server_token, client_token) = fsystem::LeaseToken::create();
47                            let wake_lease_active = self.wake_lease_active.clone();
48                            assert!(wake_lease_active.unbounded_send(true).is_ok());
49
50                            // Listen for the client dropping its wake lease token.
51                            fasync::Task::local(async move {
52                                let _ = fasync::OnSignals::new(
53                                    server_token,
54                                    zx::Signals::EVENTPAIR_PEER_CLOSED,
55                                )
56                                .await;
57                                wake_lease_active
58                                    .unbounded_send(false)
59                                    .expect("server dropping wake lease status");
60                            })
61                            .detach();
62
63                            responder.send(client_token).context("send failed")
64                        }
65                        _ => unreachable!(),
66                    }
67                })
68                .await
69        }
70    }
71
72    #[fasync::run_until_stalled(test)]
73    async fn test_acquire_then_release() -> Result<()> {
74        let (client, stream) = create_proxy_and_stream::<fsystem::ActivityGovernorMarker>();
75        let (wake_lease_active_tx, mut wake_lease_active_rx) = mpsc::unbounded::<bool>();
76
77        // Create a FakeActivityGovernor server and run it in the background.
78        fasync::Task::local(async move {
79            let server = FakeActivityGovernor { wake_lease_active: wake_lease_active_tx };
80            server.run(stream).await.expect("FakeActivityGovernor server completion");
81        })
82        .detach();
83
84        // Create and acquire a wake lease.
85        let wake_lease = WakeLease::take(client, "example_wake_lease".to_string()).await?;
86
87        // Check that the server was notified about the acquired wake lease.
88        assert!(wake_lease_active_rx.next().await.expect("server wake lease call"));
89
90        // Release the wake lease and check that the server was notified.
91        drop(wake_lease);
92        assert!(!wake_lease_active_rx.next().await.expect("server wake lease call"));
93
94        Ok(())
95    }
96}