From d2a2927ea5057c3b9d3c07a40ab453d488c54dcf Mon Sep 17 00:00:00 2001
From: Martin Brabham <optedoblivion@google.com>
Date: Wed, 12 Oct 2022 19:46:33 +0000
Subject: [PATCH] Fix suspend/resume synchronization

Bug: 189495534
Test: system/gd/cert/run --clean --topshim SuspendTest
Tag: #floss
Change-Id: I159a721786863fb5bebe8d7165808efeb287136b
---
 system/bta/dm/bta_dm_api.cc                   |  42 +++++++
 system/bta/include/bta_api.h                  |  33 ++++++
 system/btif/src/btif_dm.cc                    |  10 +-
 system/gd/rust/linux/client/src/callbacks.rs  |   2 +-
 system/gd/rust/linux/client/src/dbus_iface.rs |   6 +-
 system/gd/rust/linux/mgmt/src/dbus_iface.rs   |   6 +-
 .../linux/mgmt/src/powerd_suspend_manager.rs  |  17 +--
 .../rust/linux/service/src/iface_bluetooth.rs |   6 +-
 system/gd/rust/linux/stack/src/lib.rs         |   7 +-
 system/gd/rust/linux/stack/src/suspend.rs     | 109 ++++++++++++------
 system/main/shim/acl.cc                       |  44 +++++++
 system/main/shim/acl.h                        |   6 +
 system/main/shim/btm_api.cc                   |   5 +-
 system/stack/include/hci_error_code.h         |   1 +
 14 files changed, 236 insertions(+), 58 deletions(-)

diff --git a/system/bta/dm/bta_dm_api.cc b/system/bta/dm/bta_dm_api.cc
index 01b497c367d..6be4aba7f9c 100644
--- a/system/bta/dm/bta_dm_api.cc
+++ b/system/bta/dm/bta_dm_api.cc
@@ -676,6 +676,34 @@ void BTA_DmClearEventFilter(void) {
   do_in_main_thread(FROM_HERE, base::Bind(bta_dm_clear_event_filter));
 }
 
+/*******************************************************************************
+ *
+ * Function         BTA_DmClearEventMask
+ *
+ * Description      This function clears the event mask
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmClearEventMask(void) {
+  APPL_TRACE_API("BTA_DmClearEventMask");
+  do_in_main_thread(FROM_HERE, base::Bind(bta_dm_clear_event_mask));
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmClearEventMask
+ *
+ * Description      This function clears the filter accept list
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmClearFilterAcceptList(void) {
+  APPL_TRACE_API("BTA_DmClearFilterAcceptList");
+  do_in_main_thread(FROM_HERE, base::Bind(bta_dm_clear_filter_accept_list));
+}
+
 /*******************************************************************************
  *
  * Function         BTA_DmLeRand
@@ -690,6 +718,20 @@ void BTA_DmLeRand(LeRandCallback cb) {
   do_in_main_thread(FROM_HERE, base::Bind(bta_dm_le_rand, cb));
 }
 
+/*******************************************************************************
+ *
+ * Function         BTA_DmDisconnectAllAcls
+ *
+ * Description      This function will disconnect all LE and Classic ACLs.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmDisconnectAllAcls() {
+  APPL_TRACE_API("BTA_DmLeRand");
+  do_in_main_thread(FROM_HERE, base::Bind(bta_dm_disconnect_all_acls));
+}
+
 void BTA_DmSetEventFilterConnectionSetupAllDevices() {
   APPL_TRACE_API("BTA_DmSetEventFilterConnectionSetupAllDevices");
   do_in_main_thread(
diff --git a/system/bta/include/bta_api.h b/system/bta/include/bta_api.h
index f7cad22c537..58c4c28551a 100644
--- a/system/bta/include/bta_api.h
+++ b/system/bta/include/bta_api.h
@@ -1222,6 +1222,39 @@ extern void BTA_VendorInit(void);
  ******************************************************************************/
 extern void BTA_DmClearEventFilter(void);
 
+/*******************************************************************************
+ *
+ * Function         BTA_DmClearEventMask
+ *
+ * Description      This function clears the event mask
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmClearEventMask(void);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmDisconnectAllAcls
+ *
+ * Description      This function will disconnect all LE and Classic ACLs.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmDisconnectAllAcls(void);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmClearFilterAcceptList
+ *
+ * Description      This function clears the filter accept list
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmClearFilterAcceptList(void);
+
 using LeRandCallback = base::Callback<void(uint64_t)>;
 /*******************************************************************************
  *
diff --git a/system/btif/src/btif_dm.cc b/system/btif/src/btif_dm.cc
index 6362729c58c..9b6e1d04e8c 100644
--- a/system/btif/src/btif_dm.cc
+++ b/system/btif/src/btif_dm.cc
@@ -3521,27 +3521,27 @@ bool btif_get_address_type(const RawAddress& bda, tBLE_ADDR_TYPE* p_addr_type) {
 
 void btif_dm_clear_event_filter() {
   LOG_VERBOSE("%s: called", __func__);
-  bta_dm_clear_event_filter();
+  BTA_DmClearEventFilter();
 }
 
 void btif_dm_clear_event_mask() {
   LOG_VERBOSE("%s: called", __func__);
-  bta_dm_clear_event_mask();
+  BTA_DmClearEventMask();
 }
 
 void btif_dm_clear_filter_accept_list() {
   LOG_VERBOSE("%s: called", __func__);
-  bta_dm_clear_filter_accept_list();
+  BTA_DmClearFilterAcceptList();
 }
 
 void btif_dm_disconnect_all_acls() {
   LOG_VERBOSE("%s: called", __func__);
-  bta_dm_disconnect_all_acls();
+  BTA_DmDisconnectAllAcls();
 }
 
 void btif_dm_le_rand(LeRandCallback callback) {
   LOG_VERBOSE("%s: called", __func__);
-  bta_dm_le_rand(callback);
+  BTA_DmLeRand(callback);
 }
 
 void btif_dm_set_event_filter_connection_setup_all_devices() {
diff --git a/system/gd/rust/linux/client/src/callbacks.rs b/system/gd/rust/linux/client/src/callbacks.rs
index cc5d9840faa..003b68dfa8b 100644
--- a/system/gd/rust/linux/client/src/callbacks.rs
+++ b/system/gd/rust/linux/client/src/callbacks.rs
@@ -797,7 +797,7 @@ impl SuspendCallback {
 impl ISuspendCallback for SuspendCallback {
     // TODO(b/224606285): Implement suspend utils in btclient.
     fn on_callback_registered(&self, _callback_id: u32) {}
-    fn on_suspend_ready(&self, _suspend_id: u32) {}
+    fn on_suspend_ready(&self, _suspend_id: i32) {}
     fn on_resumed(&self, _suspend_id: i32) {}
 }
 
diff --git a/system/gd/rust/linux/client/src/dbus_iface.rs b/system/gd/rust/linux/client/src/dbus_iface.rs
index ef4d62a6262..03cac4de477 100644
--- a/system/gd/rust/linux/client/src/dbus_iface.rs
+++ b/system/gd/rust/linux/client/src/dbus_iface.rs
@@ -1453,12 +1453,12 @@ impl ISuspend for SuspendDBus {
     }
 
     #[dbus_method("Suspend")]
-    fn suspend(&mut self, _suspend_type: SuspendType) {
+    fn suspend(&mut self, _suspend_type: SuspendType, suspend_id: i32) {
         dbus_generated!()
     }
 
     #[dbus_method("Resume")]
-    fn resume(&self) -> bool {
+    fn resume(&mut self) -> bool {
         dbus_generated!()
     }
 }
@@ -1475,7 +1475,7 @@ impl ISuspendCallback for ISuspendCallbackDBus {
     #[dbus_method("OnCallbackRegistered")]
     fn on_callback_registered(&self, callback_id: u32) {}
     #[dbus_method("OnSuspendReady")]
-    fn on_suspend_ready(&self, suspend_id: u32) {}
+    fn on_suspend_ready(&self, suspend_id: i32) {}
     #[dbus_method("OnResumed")]
     fn on_resumed(&self, suspend_id: i32) {}
 }
diff --git a/system/gd/rust/linux/mgmt/src/dbus_iface.rs b/system/gd/rust/linux/mgmt/src/dbus_iface.rs
index 95ce28e0387..1dbe461c0d5 100644
--- a/system/gd/rust/linux/mgmt/src/dbus_iface.rs
+++ b/system/gd/rust/linux/mgmt/src/dbus_iface.rs
@@ -55,12 +55,12 @@ impl ISuspend for SuspendDBus {
     }
 
     #[dbus_method("Suspend")]
-    fn suspend(&mut self, _suspend_type: SuspendType) {
+    fn suspend(&mut self, _suspend_type: SuspendType, suspend_id: i32) {
         dbus_generated!()
     }
 
     #[dbus_method("Resume")]
-    fn resume(&self) -> bool {
+    fn resume(&mut self) -> bool {
         dbus_generated!()
     }
 }
@@ -78,7 +78,7 @@ impl ISuspendCallback for ISuspendCallbackDBus {
     #[dbus_method("OnCallbackRegistered")]
     fn on_callback_registered(&self, callback_id: u32) {}
     #[dbus_method("OnSuspendReady")]
-    fn on_suspend_ready(&self, suspend_id: u32) {}
+    fn on_suspend_ready(&self, suspend_id: i32) {}
     #[dbus_method("OnResumed")]
     fn on_resumed(&self, suspend_id: i32) {}
 }
diff --git a/system/gd/rust/linux/mgmt/src/powerd_suspend_manager.rs b/system/gd/rust/linux/mgmt/src/powerd_suspend_manager.rs
index cbddb9c38c2..4f8acb06e45 100644
--- a/system/gd/rust/linux/mgmt/src/powerd_suspend_manager.rs
+++ b/system/gd/rust/linux/mgmt/src/powerd_suspend_manager.rs
@@ -115,7 +115,7 @@ impl ISuspendCallback for SuspendCallback {
         log::debug!("Suspend callback registered, callback_id = {}", callback_id);
     }
 
-    fn on_suspend_ready(&self, suspend_id: u32) {
+    fn on_suspend_ready(&self, suspend_id: i32) {
         // Received when adapter is ready to suspend. Tell powerd that suspend is ready.
         log::debug!("Suspend ready, adapter suspend_id = {}", suspend_id);
 
@@ -446,11 +446,14 @@ impl PowerdSuspendManager {
                 let mut suspend_dbus_rpc = adapter_suspend_dbus.rpc.clone();
                 tokio::spawn(async move {
                     let result = suspend_dbus_rpc
-                        .suspend(match suspend_imminent.get_reason() {
-                            SuspendImminent_Reason::IDLE => SuspendType::AllowWakeFromHid,
-                            SuspendImminent_Reason::LID_CLOSED => SuspendType::NoWakesAllowed,
-                            SuspendImminent_Reason::OTHER => SuspendType::Other,
-                        })
+                        .suspend(
+                            match suspend_imminent.get_reason() {
+                                SuspendImminent_Reason::IDLE => SuspendType::AllowWakeFromHid,
+                                SuspendImminent_Reason::LID_CLOSED => SuspendType::NoWakesAllowed,
+                                SuspendImminent_Reason::OTHER => SuspendType::Other,
+                            },
+                            suspend_imminent.get_suspend_id(),
+                        )
                         .await;
 
                     log::debug!("Adapter suspend call, success = {}", result.is_ok());
@@ -485,7 +488,7 @@ impl PowerdSuspendManager {
         self.context.lock().unwrap().pending_suspend_imminent = None;
 
         if let Some(adapter_suspend_dbus) = &self.context.lock().unwrap().adapter_suspend_dbus {
-            let suspend_dbus_rpc = adapter_suspend_dbus.rpc.clone();
+            let mut suspend_dbus_rpc = adapter_suspend_dbus.rpc.clone();
             tokio::spawn(async move {
                 let result = suspend_dbus_rpc.resume().await;
                 log::debug!("Adapter resume call, success = {}", result.unwrap_or(false));
diff --git a/system/gd/rust/linux/service/src/iface_bluetooth.rs b/system/gd/rust/linux/service/src/iface_bluetooth.rs
index 4cd8237e71c..58104315840 100644
--- a/system/gd/rust/linux/service/src/iface_bluetooth.rs
+++ b/system/gd/rust/linux/service/src/iface_bluetooth.rs
@@ -564,12 +564,12 @@ impl ISuspend for ISuspendDBus {
     }
 
     #[dbus_method("Suspend")]
-    fn suspend(&mut self, suspend_type: SuspendType) {
+    fn suspend(&mut self, suspend_type: SuspendType, suspend_id: i32) {
         dbus_generated!()
     }
 
     #[dbus_method("Resume")]
-    fn resume(&self) -> bool {
+    fn resume(&mut self) -> bool {
         dbus_generated!()
     }
 }
@@ -584,7 +584,7 @@ impl ISuspendCallback for SuspendCallbackDBus {
         dbus_generated!()
     }
     #[dbus_method("OnSuspendReady")]
-    fn on_suspend_ready(&self, suspend_id: u32) {
+    fn on_suspend_ready(&self, suspend_id: i32) {
         dbus_generated!()
     }
     #[dbus_method("OnResumed")]
diff --git a/system/gd/rust/linux/stack/src/lib.rs b/system/gd/rust/linux/stack/src/lib.rs
index 92074482780..50b34be6197 100644
--- a/system/gd/rust/linux/stack/src/lib.rs
+++ b/system/gd/rust/linux/stack/src/lib.rs
@@ -79,7 +79,8 @@ pub enum Message {
     // Suspend related
     SuspendCallbackRegistered(u32),
     SuspendCallbackDisconnected(u32),
-    SuspendReady(u32),
+    SuspendReady(i32),
+    ResumeReady(i32),
 
     // Scanner related
     ScannerCallbackDisconnected(u32),
@@ -228,6 +229,10 @@ impl Stack {
                     suspend.lock().unwrap().suspend_ready(suspend_id);
                 }
 
+                Message::ResumeReady(suspend_id) => {
+                    suspend.lock().unwrap().resume_ready(suspend_id);
+                }
+
                 Message::ScannerCallbackDisconnected(id) => {
                     bluetooth_gatt.lock().unwrap().remove_scanner_callback(id);
                 }
diff --git a/system/gd/rust/linux/stack/src/suspend.rs b/system/gd/rust/linux/stack/src/suspend.rs
index a12c399674e..a85c18f308a 100644
--- a/system/gd/rust/linux/stack/src/suspend.rs
+++ b/system/gd/rust/linux/stack/src/suspend.rs
@@ -29,12 +29,12 @@ pub trait ISuspend {
     ///
     /// Returns a positive number identifying the suspend if it can be started. If there is already
     /// a suspend, that active suspend id is returned.
-    fn suspend(&mut self, suspend_type: SuspendType);
+    fn suspend(&mut self, suspend_type: SuspendType, suspend_id: i32);
 
     /// Undoes previous suspend preparation identified by `suspend_id`.
     ///
     /// Returns true if suspend can be resumed, and false if there is no suspend to resume.
-    fn resume(&self) -> bool;
+    fn resume(&mut self) -> bool;
 }
 
 /// Suspend events.
@@ -43,7 +43,7 @@ pub trait ISuspendCallback: RPCProxy {
     fn on_callback_registered(&self, callback_id: u32);
 
     /// Triggered when the stack is ready for suspend and tell the observer the id of the suspend.
-    fn on_suspend_ready(&self, suspend_id: u32);
+    fn on_suspend_ready(&self, suspend_id: i32);
 
     /// Triggered when the stack has resumed the previous suspend.
     fn on_resumed(&self, suspend_id: i32);
@@ -59,6 +59,20 @@ pub enum SuspendType {
 
 struct SuspendState {
     le_rand_expected: bool,
+    suspend_expected: bool,
+    resume_expected: bool,
+    suspend_id: Option<i32>,
+}
+
+impl SuspendState {
+    pub fn new() -> SuspendState {
+        Self {
+            le_rand_expected: false,
+            suspend_expected: false,
+            resume_expected: false,
+            suspend_id: None,
+        }
+    }
 }
 
 /// Implementation of the suspend API.
@@ -90,7 +104,7 @@ impl Suspend {
             is_connected_suspend: false,
             was_a2dp_connected: false,
             suspend_timeout_joinhandle: None,
-            suspend_state: Arc::new(Mutex::new(SuspendState { le_rand_expected: false })),
+            suspend_state: Arc::new(Mutex::new(SuspendState::new())),
         }
     }
 
@@ -105,11 +119,17 @@ impl Suspend {
         self.callbacks.remove_callback(id)
     }
 
-    pub(crate) fn suspend_ready(&self, suspend_id: u32) {
+    pub(crate) fn suspend_ready(&self, suspend_id: i32) {
         self.callbacks.for_all_callbacks(|callback| {
             callback.on_suspend_ready(suspend_id);
         });
     }
+
+    pub(crate) fn resume_ready(&self, suspend_id: i32) {
+        self.callbacks.for_all_callbacks(|callback| {
+            callback.on_resumed(suspend_id);
+        });
+    }
 }
 
 impl ISuspend for Suspend {
@@ -128,37 +148,30 @@ impl ISuspend for Suspend {
         self.remove_callback(callback_id)
     }
 
-    fn suspend(&mut self, suspend_type: SuspendType) {
-        // self.was_a2dp_connected = TODO(230604670): check if A2DP is connected
-        // self.current_advertiser_ids = TODO(224603198): save all advertiser ids
+    fn suspend(&mut self, suspend_type: SuspendType, suspend_id: i32) {
         self.intf.lock().unwrap().clear_event_mask();
         self.intf.lock().unwrap().clear_event_filter();
         self.intf.lock().unwrap().clear_filter_accept_list();
-        // self.gatt.lock().unwrap().advertising_disable(); TODO(224602924): suspend all adv.
+        // TODO(224602924): How do we get the advertising ids?
+        self.gatt.lock().unwrap().stop_advertising_set(0);
+        // TODO(224602924): How do we get the scanning ids?
         self.gatt.lock().unwrap().stop_scan(0);
         self.intf.lock().unwrap().disconnect_all_acls();
 
         // Handle wakeful cases (Connected/Other)
         // Treat Other the same as Connected
         match suspend_type {
-            SuspendType::AllowWakeFromHid => {
-                // TODO(231345733): API For allowing classic HID only
-                // TODO(230604670): check if A2DP is connected
-                // TODO(224603198): save all advertiser information
-            }
-            SuspendType::NoWakesAllowed => {
-                self.intf.lock().unwrap().clear_event_filter();
-                self.intf.lock().unwrap().clear_event_mask();
-            }
-            _ => {
+            SuspendType::AllowWakeFromHid | SuspendType::Other => {
                 self.intf.lock().unwrap().allow_wake_by_hid();
+                // self.was_a2dp_connected = TODO(230604670): check if A2DP is connected
+                // TODO(230604670): check if A2DP is connected
             }
+            _ => {}
         }
-        self.intf.lock().unwrap().clear_filter_accept_list();
-        self.intf.lock().unwrap().disconnect_all_acls();
-
-        self.bt.lock().unwrap().le_rand();
         self.suspend_state.lock().unwrap().le_rand_expected = true;
+        self.suspend_state.lock().unwrap().suspend_expected = true;
+        self.suspend_state.lock().unwrap().suspend_id = Some(suspend_id);
+        self.bt.lock().unwrap().le_rand();
 
         if let Some(join_handle) = &self.suspend_timeout_joinhandle {
             join_handle.abort();
@@ -172,27 +185,42 @@ impl ISuspend for Suspend {
             log::error!("Suspend did not complete in 2 seconds, continuing anyway.");
 
             suspend_state.lock().unwrap().le_rand_expected = false;
+            suspend_state.lock().unwrap().suspend_expected = false;
+            suspend_state.lock().unwrap().suspend_id = None;
             tokio::spawn(async move {
-                let _result = tx.send(Message::SuspendReady(1)).await;
+                let _result = tx.send(Message::SuspendReady(suspend_id)).await;
             });
         }));
     }
 
-    fn resume(&self) -> bool {
+    fn resume(&mut self) -> bool {
         self.intf.lock().unwrap().set_default_event_mask();
         self.intf.lock().unwrap().set_event_filter_inquiry_result_all_devices();
         self.intf.lock().unwrap().set_event_filter_connection_setup_all_devices();
         if self.is_connected_suspend {
             if self.was_a2dp_connected {
-                // TODO(230604670): self.intf.lock().unwrap().restore_filter_accept_list();
                 // TODO(230604670): reconnect to a2dp device
             }
             // TODO(224603198): start all advertising again
         }
 
-        self.callbacks.for_all_callbacks(|callback| {
-            callback.on_resumed(1);
-        });
+        self.suspend_state.lock().unwrap().le_rand_expected = true;
+        self.suspend_state.lock().unwrap().resume_expected = true;
+        self.bt.lock().unwrap().le_rand();
+
+        let tx = self.tx.clone();
+        let suspend_state = self.suspend_state.clone();
+        let suspend_id = self.suspend_state.lock().unwrap().suspend_id.unwrap();
+        self.suspend_timeout_joinhandle = Some(tokio::spawn(async move {
+            tokio::time::sleep(tokio::time::Duration::from_millis(2000)).await;
+            log::error!("Resume did not complete in 2 seconds, continuing anyway.");
+
+            suspend_state.lock().unwrap().le_rand_expected = false;
+            suspend_state.lock().unwrap().resume_expected = false;
+            tokio::spawn(async move {
+                let _result = tx.send(Message::ResumeReady(suspend_id)).await;
+            });
+        }));
 
         true
     }
@@ -206,15 +234,30 @@ impl BtifBluetoothCallbacks for Suspend {
             log::warn!("Unexpected LE Rand callback, ignoring.");
             return;
         }
+        self.suspend_state.lock().unwrap().le_rand_expected = false;
 
         if let Some(join_handle) = &self.suspend_timeout_joinhandle {
             join_handle.abort();
             self.suspend_timeout_joinhandle = None;
         }
 
-        let tx = self.tx.clone();
-        tokio::spawn(async move {
-            let _result = tx.send(Message::SuspendReady(1)).await;
-        });
+        let suspend_id = self.suspend_state.lock().unwrap().suspend_id.unwrap();
+
+        if self.suspend_state.lock().unwrap().suspend_expected {
+            self.suspend_state.lock().unwrap().suspend_expected = false;
+            let tx = self.tx.clone();
+            tokio::spawn(async move {
+                let _result = tx.send(Message::SuspendReady(suspend_id)).await;
+            });
+        }
+
+        self.suspend_state.lock().unwrap().suspend_id = Some(suspend_id);
+        if self.suspend_state.lock().unwrap().resume_expected {
+            self.suspend_state.lock().unwrap().resume_expected = false;
+            let tx = self.tx.clone();
+            tokio::spawn(async move {
+                let _result = tx.send(Message::ResumeReady(suspend_id)).await;
+            });
+        }
     }
 }
diff --git a/system/main/shim/acl.cc b/system/main/shim/acl.cc
index b23fde01468..58f9b3200f0 100644
--- a/system/main/shim/acl.cc
+++ b/system/main/shim/acl.cc
@@ -840,6 +840,15 @@ struct shim::legacy::Acl::impl {
     handle_to_le_connection_map_[handle]->EnqueuePacket(std::move(packet));
   }
 
+  void DisconnectClassicConnections(std::promise<void> promise) {
+    LOG_INFO("Disconnect gd acl shim classic connections");
+    for (auto& connection : handle_to_classic_connection_map_) {
+      disconnect_classic(connection.first, HCI_ERR_REMOTE_POWER_OFF,
+                         "Suspend disconnect");
+    }
+    promise.set_value();
+  }
+
   void ShutdownClassicConnections(std::promise<void> promise) {
     LOG_INFO("Shutdown gd acl shim classic connections");
     for (auto& connection : handle_to_classic_connection_map_) {
@@ -849,6 +858,15 @@ struct shim::legacy::Acl::impl {
     promise.set_value();
   }
 
+  void DisconnectLeConnections(std::promise<void> promise) {
+    LOG_INFO("Disconnect gd acl shim le connections");
+    for (auto& connection : handle_to_le_connection_map_) {
+      disconnect_le(connection.first, HCI_ERR_REMOTE_POWER_OFF,
+                    "Suspend disconnect");
+    }
+    promise.set_value();
+  }
+
   void ShutdownLeConnections(std::promise<void> promise) {
     LOG_INFO("Shutdown gd acl shim le connections");
     for (auto& connection : handle_to_le_connection_map_) {
@@ -995,6 +1013,10 @@ struct shim::legacy::Acl::impl {
     LOG_DEBUG("Cleared entire Le address acceptlist count:%zu", count);
   }
 
+  void le_rand(LeRandCallback cb ) {
+    controller_get_interface()->le_rand(cb);
+  }
+
   void AddToAddressResolution(const hci::AddressWithType& address_with_type,
                               const std::array<uint8_t, 16>& peer_irk,
                               const std::array<uint8_t, 16>& local_irk) {
@@ -1650,6 +1672,24 @@ void shim::legacy::Acl::DumpConnectionHistory(int fd) const {
   pimpl_->DumpConnectionHistory(fd);
 }
 
+void shim::legacy::Acl::DisconnectAllForSuspend() {
+  if (CheckForOrphanedAclConnections()) {
+    std::promise<void> disconnect_promise;
+    auto disconnect_future = disconnect_promise.get_future();
+    handler_->CallOn(pimpl_.get(), &Acl::impl::DisconnectClassicConnections,
+                     std::move(disconnect_promise));
+    disconnect_future.wait();
+
+    disconnect_promise = std::promise<void>();
+
+    disconnect_future = disconnect_promise.get_future();
+    handler_->CallOn(pimpl_.get(), &Acl::impl::DisconnectLeConnections,
+                     std::move(disconnect_promise));
+    disconnect_future.wait();
+    LOG_WARN("Disconnected open ACL connections");
+  }
+}
+
 void shim::legacy::Acl::Shutdown() {
   if (CheckForOrphanedAclConnections()) {
     std::promise<void> shutdown_promise;
@@ -1694,6 +1734,10 @@ void shim::legacy::Acl::ClearFilterAcceptList() {
   handler_->CallOn(pimpl_.get(), &Acl::impl::clear_acceptlist);
 }
 
+void shim::legacy::Acl::LeRand(LeRandCallback cb) {
+  handler_->CallOn(pimpl_.get(), &Acl::impl::le_rand, cb);
+}
+
 void shim::legacy::Acl::AddToAddressResolution(
     const hci::AddressWithType& address_with_type,
     const std::array<uint8_t, 16>& peer_irk,
diff --git a/system/main/shim/acl.h b/system/main/shim/acl.h
index 53ae43eac66..a4ede403548 100644
--- a/system/main/shim/acl.h
+++ b/system/main/shim/acl.h
@@ -32,6 +32,8 @@
 #include "stack/include/bt_types.h"
 #include "types/raw_address.h"
 
+using LeRandCallback = base::Callback<void(uint64_t)>;
+
 namespace bluetooth {
 namespace shim {
 namespace legacy {
@@ -106,14 +108,18 @@ class Acl : public hci::acl_manager::ConnectionCallbacks,
   void Dump(int fd) const;
   void DumpConnectionHistory(int fd) const;
 
+  void DisconnectAllForSuspend();
   void Shutdown();
   void FinalShutdown();
+  void LeRand(LeRandCallback cb);
 
   void ClearFilterAcceptList();
 
   void AddDeviceToFilterAcceptList(
       const hci::AddressWithType& address_with_type);
 
+  void ClearEventFilter();
+
  protected:
   void on_incoming_acl_credits(uint16_t handle, uint16_t credits);
   void write_data_sync(uint16_t hci_handle,
diff --git a/system/main/shim/btm_api.cc b/system/main/shim/btm_api.cc
index 720e9d5e81d..ef1f2378028 100644
--- a/system/main/shim/btm_api.cc
+++ b/system/main/shim/btm_api.cc
@@ -1349,12 +1349,13 @@ tBTM_STATUS bluetooth::shim::BTM_ClearFilterAcceptList() {
 }
 
 tBTM_STATUS bluetooth::shim::BTM_DisconnectAllAcls() {
-  Stack::GetInstance()->GetAcl()->Shutdown();
+  Stack::GetInstance()->GetAcl()->DisconnectAllForSuspend();
+//  Stack::GetInstance()->GetAcl()->Shutdown();
   return BTM_SUCCESS;
 }
 
 tBTM_STATUS bluetooth::shim::BTM_LeRand(LeRandCallback cb) {
-  controller_get_interface()->le_rand(cb);
+  Stack::GetInstance()->GetAcl()->LeRand(cb);
   return BTM_SUCCESS;
 }
 
diff --git a/system/stack/include/hci_error_code.h b/system/stack/include/hci_error_code.h
index bbff6a61c25..c2abb8d340d 100644
--- a/system/stack/include/hci_error_code.h
+++ b/system/stack/include/hci_error_code.h
@@ -44,6 +44,7 @@ typedef enum : uint8_t {
   HCI_ERR_HOST_TIMEOUT = 0x10,  // stack/btm/btm_ble_gap,
   HCI_ERR_ILLEGAL_PARAMETER_FMT = 0x12,
   HCI_ERR_PEER_USER = 0x13,
+  HCI_ERR_REMOTE_POWER_OFF = 0x15,
   HCI_ERR_CONN_CAUSE_LOCAL_HOST = 0x16,
   HCI_ERR_REPEATED_ATTEMPTS = 0x17,
   HCI_ERR_PAIRING_NOT_ALLOWED = 0x18,
-- 
GitLab