1use core::future::Future;
6use fdf_component::{Driver, DriverContext};
7use futures::TryStreamExt;
8use log::{error, warn};
9use std::sync::{Arc, Weak};
10use zx::Status;
11use {fidl_fuchsia_power_system as fpower, fuchsia_async as fasync};
12
13pub trait SuspendableDriver: Driver {
16 fn suspend(&self) -> impl Future<Output = ()> + Send;
19
20 fn resume(&self) -> impl Future<Output = ()> + Send;
23
24 fn suspend_enabled(&self) -> bool;
27}
28
29pub struct Suspendable<T: Driver> {
31 #[allow(unused)]
32 scope: fasync::Scope,
33 driver: Arc<T>,
34}
35
36async fn run_suspend_blocker<T: SuspendableDriver>(
37 driver: Weak<T>,
38 mut service: fpower::SuspendBlockerRequestStream,
39) {
40 use fpower::SuspendBlockerRequest::*;
41 while let Some(req) = service.try_next().await.unwrap() {
42 match req {
43 BeforeSuspend { responder, .. } => {
44 if let Some(driver) = driver.upgrade() {
45 driver.suspend().await;
46 } else {
47 return;
48 }
49 responder.send()
50 }
51 AfterResume { responder, .. } => {
52 if let Some(driver) = driver.upgrade() {
53 driver.resume().await;
54 } else {
55 return;
56 }
57 responder.send()
58 }
59 _ => {
61 warn!("Received unknown sag listener request");
62 Ok(())
63 }
64 }
65 .unwrap()
66 }
67}
68
69impl<T: SuspendableDriver + Send + Sync> Driver for Suspendable<T> {
70 const NAME: &str = T::NAME;
71
72 async fn start(context: DriverContext) -> Result<Self, Status> {
73 let sag: fpower::ActivityGovernorProxy =
74 context.incoming.connect_protocol().map_err(|err| {
75 error!("Error connecting to sag: {err}");
76 Status::INTERNAL
77 })?;
78
79 let driver = Arc::new(T::start(context).await?);
80
81 let scope = fasync::Scope::new_with_name("suspend");
82 if driver.suspend_enabled() {
83 let (client, server) = fidl::endpoints::create_endpoints();
84
85 let _ = sag
86 .register_suspend_blocker(fpower::ActivityGovernorRegisterSuspendBlockerRequest {
87 suspend_blocker: Some(client),
88 name: Some(Self::NAME.into()),
89 ..Default::default()
90 })
91 .await
92 .map_err(|err| {
93 error!("Error connecting to sag: {err}");
94 Status::INTERNAL
95 })?
96 .map_err(|err| {
97 error!("Error connecting to sag: {err:?}");
98 Status::INTERNAL
99 })?;
100
101 let weak_driver = Arc::downgrade(&driver);
102 scope
103 .spawn(async move { run_suspend_blocker(weak_driver, server.into_stream()).await });
104 }
105
106 Ok(Self { driver, scope })
107 }
108
109 async fn stop(&self) {
110 self.driver.stop().await;
111 }
112}