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