• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Suspend/Resume API.
2 
3 use crate::{Message, RPCProxy};
4 use log::warn;
5 use std::collections::HashMap;
6 use tokio::sync::mpsc::Sender;
7 
8 /// Defines the Suspend/Resume API.
9 ///
10 /// This API is exposed by `btadapterd` and independent of the suspend/resume detection mechanism
11 /// which depends on the actual operating system the daemon runs on. Possible clients of this API
12 /// include `btmanagerd` with Chrome OS `powerd` integration, `btmanagerd` with systemd Inhibitor
13 /// interface, or any script hooked to suspend/resume events.
14 pub trait ISuspend {
15     /// Adds an observer to suspend events.
16     ///
17     /// Returns true if the callback can be registered.
register_callback(&mut self, callback: Box<dyn ISuspendCallback + Send>) -> bool18     fn register_callback(&mut self, callback: Box<dyn ISuspendCallback + Send>) -> bool;
19 
20     /// Removes an observer to suspend events.
21     ///
22     /// Returns true if the callback can be removed, false if `callback_id` is not recognized.
unregister_callback(&mut self, callback_id: u32) -> bool23     fn unregister_callback(&mut self, callback_id: u32) -> bool;
24 
25     /// Prepares the stack for suspend, identified by `suspend_id`.
26     ///
27     /// Returns a positive number identifying the suspend if it can be started. If there is already
28     /// a suspend, that active suspend id is returned.
suspend(&self, suspend_type: SuspendType) -> u3229     fn suspend(&self, suspend_type: SuspendType) -> u32;
30 
31     /// Undoes previous suspend preparation identified by `suspend_id`.
32     ///
33     /// Returns true if suspend can be resumed, and false if there is no suspend to resume.
resume(&self) -> bool34     fn resume(&self) -> bool;
35 }
36 
37 /// Suspend events.
38 pub trait ISuspendCallback: RPCProxy {
39     /// Triggered when a callback is registered and given an identifier `callback_id`.
on_callback_registered(&self, callback_id: u32)40     fn on_callback_registered(&self, callback_id: u32);
41 
42     /// Triggered when the stack is ready for suspend and tell the observer the id of the suspend.
on_suspend_ready(&self, suspend_id: u32)43     fn on_suspend_ready(&self, suspend_id: u32);
44 
45     /// Triggered when the stack has resumed the previous suspend.
on_resumed(&self, suspend_id: u32)46     fn on_resumed(&self, suspend_id: u32);
47 }
48 
49 #[derive(FromPrimitive, ToPrimitive)]
50 #[repr(u32)]
51 pub enum SuspendType {
52     NoWakesAllowed,
53     AllowWakeFromHid,
54     Other,
55 }
56 
57 /// Implementation of the suspend API.
58 pub struct Suspend {
59     tx: Sender<Message>,
60     callbacks: HashMap<u32, Box<dyn ISuspendCallback + Send>>,
61 }
62 
63 impl Suspend {
new(tx: Sender<Message>) -> Suspend64     pub fn new(tx: Sender<Message>) -> Suspend {
65         Self { tx, callbacks: HashMap::new() }
66     }
67 
callback_registered(&mut self, id: u32)68     pub(crate) fn callback_registered(&mut self, id: u32) {
69         match self.callbacks.get(&id) {
70             Some(callback) => callback.on_callback_registered(id),
71             None => warn!("Suspend callback {} does not exist", id),
72         }
73     }
74 
remove_callback(&mut self, id: u32) -> bool75     pub(crate) fn remove_callback(&mut self, id: u32) -> bool {
76         match self.callbacks.get_mut(&id) {
77             Some(callback) => {
78                 callback.unregister(id);
79                 self.callbacks.remove(&id);
80                 true
81             }
82             None => false,
83         }
84     }
85 }
86 
87 impl ISuspend for Suspend {
register_callback(&mut self, mut callback: Box<dyn ISuspendCallback + Send>) -> bool88     fn register_callback(&mut self, mut callback: Box<dyn ISuspendCallback + Send>) -> bool {
89         let tx = self.tx.clone();
90 
91         let id = callback.register_disconnect(Box::new(move |cb_id| {
92             let tx = tx.clone();
93             tokio::spawn(async move {
94                 let _result = tx.send(Message::SuspendCallbackDisconnected(cb_id)).await;
95             });
96         }));
97 
98         let tx = self.tx.clone();
99         tokio::spawn(async move {
100             let _result = tx.send(Message::SuspendCallbackRegistered(id)).await;
101         });
102 
103         self.callbacks.insert(id, callback);
104         true
105     }
106 
unregister_callback(&mut self, callback_id: u32) -> bool107     fn unregister_callback(&mut self, callback_id: u32) -> bool {
108         self.remove_callback(callback_id)
109     }
110 
suspend(&self, _suspend_type: SuspendType) -> u32111     fn suspend(&self, _suspend_type: SuspendType) -> u32 {
112         todo!()
113     }
114 
resume(&self) -> bool115     fn resume(&self) -> bool {
116         todo!()
117     }
118 }
119