From f232c69809831acbd9b00107f22d5bd38b022eb1 Mon Sep 17 00:00:00 2001
From: Abhishek Pandit-Subedi <abhishekpandit@google.com>
Date: Tue, 28 Feb 2023 15:49:29 -0800
Subject: [PATCH] floss: Refactor le reconnection during suspend

During system suspend, we need to use a separate set of LE scan window
and intervals that are specifically tuned for this purpose. In order to
do this only when suspended, we add |SetSystemSuspendState| to indicate
when we're entering and existing suspend.

We set the suspend state via |AllowWakeByHid| and remove the suspend
state via |RestoreFilterAcceptList|. Currently, we only restore LE hid
devices on resume to the accept list but we should also restore
non-direct gatt connections in the future.

Bug: 271159571
Tag: #floss
Test: Manual test, ChromeOS Autotest and unit tests
Change-Id: I3e67f06f7667dec69379468cc51b8405cf10de10
---
 system/bta/dm/bta_dm_act.cc                |  5 +++--
 system/bta/dm/bta_dm_api.cc                |  6 ++++--
 system/bta/dm/bta_dm_int.h                 |  3 ++-
 system/bta/include/bta_api.h               |  3 ++-
 system/btif/include/btif_dm.h              |  3 ++-
 system/btif/src/bluetooth.cc               |  9 +++++++-
 system/btif/src/btif_dm.cc                 |  5 +++--
 system/gd/hci/acl_manager.cc               |  4 ++++
 system/gd/hci/acl_manager.h                |  1 +
 system/gd/hci/acl_manager/le_impl.h        | 14 ++++++++++++
 system/gd/rust/linux/stack/src/suspend.rs  |  7 +++---
 system/main/shim/acl.cc                    |  8 +++++++
 system/main/shim/acl.h                     | 10 ++++-----
 system/main/shim/btm_api.cc                | 25 +++++++++++++++++++---
 system/main/shim/btm_api.h                 |  3 ++-
 system/test/mock/mock_main_shim_btm_api.cc |  3 ++-
 16 files changed, 84 insertions(+), 25 deletions(-)

diff --git a/system/bta/dm/bta_dm_act.cc b/system/bta/dm/bta_dm_act.cc
index 8d869e592db..de91135d16c 100644
--- a/system/bta/dm/bta_dm_act.cc
+++ b/system/bta/dm/bta_dm_act.cc
@@ -4408,9 +4408,10 @@ void bta_dm_allow_wake_by_hid(
  * Parameters
  *
  *******************************************************************************/
-void bta_dm_restore_filter_accept_list() {
+void bta_dm_restore_filter_accept_list(
+    std::vector<std::pair<RawAddress, uint8_t>> le_devices) {
   // Autoplumbed
-  bluetooth::shim::BTM_RestoreFilterAcceptList();
+  bluetooth::shim::BTM_RestoreFilterAcceptList(le_devices);
 }
 
 /*******************************************************************************
diff --git a/system/bta/dm/bta_dm_api.cc b/system/bta/dm/bta_dm_api.cc
index 002b39b1b7a..ef3e42305b7 100644
--- a/system/bta/dm/bta_dm_api.cc
+++ b/system/bta/dm/bta_dm_api.cc
@@ -742,9 +742,11 @@ void BTA_DmAllowWakeByHid(
                                           std::move(le_hid_devices)));
 }
 
-void BTA_DmRestoreFilterAcceptList() {
+void BTA_DmRestoreFilterAcceptList(
+    std::vector<std::pair<RawAddress, uint8_t>> le_devices) {
   APPL_TRACE_API("BTA_DmRestoreFilterAcceptList");
-  do_in_main_thread(FROM_HERE, base::Bind(bta_dm_restore_filter_accept_list));
+  do_in_main_thread(FROM_HERE, base::Bind(bta_dm_restore_filter_accept_list,
+                                          std::move(le_devices)));
 }
 
 void BTA_DmSetDefaultEventMaskExcept(uint64_t mask, uint64_t le_mask) {
diff --git a/system/bta/dm/bta_dm_int.h b/system/bta/dm/bta_dm_int.h
index 83370cf44b4..277e9511a0f 100644
--- a/system/bta/dm/bta_dm_int.h
+++ b/system/bta/dm/bta_dm_int.h
@@ -585,7 +585,8 @@ extern void bta_dm_set_event_filter_connection_setup_all_devices();
 extern void bta_dm_allow_wake_by_hid(
     std::vector<RawAddress> classic_hid_devices,
     std::vector<std::pair<RawAddress, uint8_t>> le_hid_devices);
-extern void bta_dm_restore_filter_accept_list();
+extern void bta_dm_restore_filter_accept_list(
+    std::vector<std::pair<RawAddress, uint8_t>> le_devices);
 extern void bta_dm_set_default_event_mask_except(uint64_t mask,
                                                  uint64_t le_mask);
 extern void bta_dm_set_event_filter_inquiry_result_all_devices();
diff --git a/system/bta/include/bta_api.h b/system/bta/include/bta_api.h
index f93a9285972..cdfa05a7e3b 100644
--- a/system/bta/include/bta_api.h
+++ b/system/bta/include/bta_api.h
@@ -1324,7 +1324,8 @@ extern void BTA_DmAllowWakeByHid(
  * Parameters
  *
  *******************************************************************************/
-extern void BTA_DmRestoreFilterAcceptList();
+extern void BTA_DmRestoreFilterAcceptList(
+    std::vector<std::pair<RawAddress, uint8_t>> le_devices);
 
 /*******************************************************************************
  *
diff --git a/system/btif/include/btif_dm.h b/system/btif/include/btif_dm.h
index 59d8da8810c..e995d68d0ba 100644
--- a/system/btif/include/btif_dm.h
+++ b/system/btif/include/btif_dm.h
@@ -104,7 +104,8 @@ void btif_dm_set_event_filter_connection_setup_all_devices();
 void btif_dm_allow_wake_by_hid(
     std::vector<RawAddress> classic_addrs,
     std::vector<std::pair<RawAddress, uint8_t>> le_addrs);
-void btif_dm_restore_filter_accept_list();
+void btif_dm_restore_filter_accept_list(
+    std::vector<std::pair<RawAddress, uint8_t>> le_devices);
 void btif_dm_set_default_event_mask_except(uint64_t mask, uint64_t le_mask);
 void btif_dm_set_event_filter_inquiry_result_all_devices();
 void btif_dm_metadata_changed(const RawAddress& remote_bd_addr, int key,
diff --git a/system/btif/src/bluetooth.cc b/system/btif/src/bluetooth.cc
index 6f239977e63..e787e09e246 100644
--- a/system/btif/src/bluetooth.cc
+++ b/system/btif/src/bluetooth.cc
@@ -745,8 +745,15 @@ static int set_default_event_mask_except(uint64_t mask, uint64_t le_mask) {
 
 static int restore_filter_accept_list() {
   if (!interface_ready()) return BT_STATUS_NOT_READY;
+  // TODO(b/260922031) - When restoring the filter accept list after a system
+  // suspend, we need to re-arm the LE connections that had `is_direct=False`.
+  // This should be the list of bonded devices and potentially any GATT
+  // connections that have `is_direct=False`. Currently, we only restore LE hid
+  // devices.
+  auto le_hid_addrs = btif_storage_get_le_hid_devices();
   do_in_main_thread(FROM_HERE,
-                    base::BindOnce(btif_dm_restore_filter_accept_list));
+                    base::BindOnce(btif_dm_restore_filter_accept_list,
+                                   std::move(le_hid_addrs)));
   return BT_STATUS_SUCCESS;
 }
 
diff --git a/system/btif/src/btif_dm.cc b/system/btif/src/btif_dm.cc
index f0ba61912a7..d23878a7e2d 100644
--- a/system/btif/src/btif_dm.cc
+++ b/system/btif/src/btif_dm.cc
@@ -3887,9 +3887,10 @@ void btif_dm_allow_wake_by_hid(
   BTA_DmAllowWakeByHid(std::move(classic_addrs), std::move(le_addrs));
 }
 
-void btif_dm_restore_filter_accept_list() {
+void btif_dm_restore_filter_accept_list(
+    std::vector<std::pair<RawAddress, uint8_t>> le_devices) {
   // Autoplumbed
-  BTA_DmRestoreFilterAcceptList();
+  BTA_DmRestoreFilterAcceptList(std::move(le_devices));
 }
 
 void btif_dm_set_default_event_mask_except(uint64_t mask, uint64_t le_mask) {
diff --git a/system/gd/hci/acl_manager.cc b/system/gd/hci/acl_manager.cc
index d321091d695..1f978e4adeb 100644
--- a/system/gd/hci/acl_manager.cc
+++ b/system/gd/hci/acl_manager.cc
@@ -393,6 +393,10 @@ void AclManager::OnLeSuspendInitiatedDisconnect(uint16_t handle, ErrorCode reaso
   CallOn(pimpl_->le_impl_, &le_impl::on_le_disconnect, handle, reason);
 }
 
+void AclManager::SetSystemSuspendState(bool suspended) {
+  CallOn(pimpl_->le_impl_, &le_impl::set_system_suspend_state, suspended);
+}
+
 LeAddressManager* AclManager::GetLeAddressManager() {
   return pimpl_->le_impl_->le_address_manager_;
 }
diff --git a/system/gd/hci/acl_manager.h b/system/gd/hci/acl_manager.h
index e82b7bd3142..5e4efcf800e 100644
--- a/system/gd/hci/acl_manager.h
+++ b/system/gd/hci/acl_manager.h
@@ -146,6 +146,7 @@ public:
  // Virtual ACL disconnect emitted during suspend.
  virtual void OnClassicSuspendInitiatedDisconnect(uint16_t handle, ErrorCode reason);
  virtual void OnLeSuspendInitiatedDisconnect(uint16_t handle, ErrorCode reason);
+ virtual void SetSystemSuspendState(bool suspended);
 
  static const ModuleFactory Factory;
 
diff --git a/system/gd/hci/acl_manager/le_impl.h b/system/gd/hci/acl_manager/le_impl.h
index b0917804f10..776a2ec49cd 100644
--- a/system/gd/hci/acl_manager/le_impl.h
+++ b/system/gd/hci/acl_manager/le_impl.h
@@ -59,6 +59,8 @@ constexpr uint16_t kScanWindow2mFast = 0x0018;    /* 15 ms = 24 *0.625 */
 constexpr uint16_t kScanWindowCodedFast = 0x0018; /* 15 ms = 24 *0.625 */
 constexpr uint16_t kScanIntervalSlow = 0x0800;    /* 1.28 s = 2048 *0.625 */
 constexpr uint16_t kScanWindowSlow = 0x0030;      /* 30 ms = 48 *0.625 */
+constexpr uint16_t kScanIntervalSystemSuspend = 0x0400; /* 640 ms = 1024 * 0.625 */
+constexpr uint16_t kScanWindowSystemSuspend = 0x0012;   /* 11.25ms = 18 * 0.625 */
 constexpr uint32_t kCreateConnectionTimeoutMs = 30 * 1000;
 constexpr uint8_t PHY_LE_NO_PACKET = 0x00;
 constexpr uint8_t PHY_LE_1M = 0x01;
@@ -887,6 +889,13 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback {
       le_scan_window_2m = os::GetSystemPropertyUint32(kPropertyConnScanWindow2mFast, kScanWindow2mFast);
       le_scan_window_coded = os::GetSystemPropertyUint32(kPropertyConnScanWindowCodedFast, kScanWindowCodedFast);
     }
+    // Use specific parameters when in system suspend.
+    if (system_suspend_) {
+      le_scan_interval = kScanIntervalSystemSuspend;
+      le_scan_window = kScanWindowSystemSuspend;
+      le_scan_window_2m = le_scan_window;
+      le_scan_window_coded = le_scan_window;
+    }
     InitiatorFilterPolicy initiator_filter_policy = InitiatorFilterPolicy::USE_FILTER_ACCEPT_LIST;
     OwnAddressType own_address_type =
         static_cast<OwnAddressType>(le_address_manager_->GetInitiatorAddress().GetAddressType());
@@ -1260,6 +1269,10 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback {
     }
   }
 
+  void set_system_suspend_state(bool suspended) {
+    system_suspend_ = suspended;
+  }
+
   static constexpr uint16_t kMinimumCeLength = 0x0002;
   static constexpr uint16_t kMaximumCeLength = 0x0C00;
   HciLayer* hci_layer_ = nullptr;
@@ -1281,6 +1294,7 @@ struct le_impl : public bluetooth::hci::LeAddressManagerCallback {
   bool ready_to_unregister = false;
   bool pause_connection = false;
   bool disarmed_while_arming_ = false;
+  bool system_suspend_ = false;
   ConnectabilityState connectability_state_{ConnectabilityState::DISARMED};
   std::map<AddressWithType, os::Alarm> create_connection_timeout_alarms_{};
 };
diff --git a/system/gd/rust/linux/stack/src/suspend.rs b/system/gd/rust/linux/stack/src/suspend.rs
index 3ea1ed1e94e..5c82fde916a 100644
--- a/system/gd/rust/linux/stack/src/suspend.rs
+++ b/system/gd/rust/linux/stack/src/suspend.rs
@@ -242,11 +242,10 @@ impl ISuspend for Suspend {
     fn resume(&mut self) -> bool {
         self.intf.lock().unwrap().set_default_event_mask_except(0u64, 0u64);
 
-        // TODO(b/260922031) - This needs to be generalized and handled by LE
-        //                     manager to allow other devices to reconnect.
-        //                     Needs to be before `clear_event_filter`.
-        self.intf.lock().unwrap().allow_wake_by_hid();
+        // Restore event filter and accept list to normal.
         self.intf.lock().unwrap().clear_event_filter();
+        self.intf.lock().unwrap().clear_filter_accept_list();
+        self.intf.lock().unwrap().restore_filter_accept_list();
 
         if !self.audio_reconnect_list.is_empty() {
             let reconnect_list = self.audio_reconnect_list.clone();
diff --git a/system/main/shim/acl.cc b/system/main/shim/acl.cc
index f622b8d82ad..482e6b5672f 100644
--- a/system/main/shim/acl.cc
+++ b/system/main/shim/acl.cc
@@ -1135,6 +1135,10 @@ struct shim::legacy::Acl::impl {
     GetAclManager()->AddDeviceToFilterAcceptList(address_with_type);
   }
 
+  void SetSystemSuspendState(bool suspended) {
+    GetAclManager()->SetSystemSuspendState(suspended);
+  }
+
   void DumpConnectionHistory() const {
     std::vector<std::string> history =
         connection_history_.ReadElementsAsString();
@@ -1865,3 +1869,7 @@ void shim::legacy::Acl::AddDeviceToFilterAcceptList(
   handler_->CallOn(pimpl_.get(), &Acl::impl::AddDeviceToFilterAcceptList,
                    address_with_type);
 }
+
+void shim::legacy::Acl::SetSystemSuspendState(bool suspended) {
+  handler_->CallOn(pimpl_.get(), &Acl::impl::SetSystemSuspendState, suspended);
+}
diff --git a/system/main/shim/acl.h b/system/main/shim/acl.h
index cff1e29de7e..cb6ff3bf3c4 100644
--- a/system/main/shim/acl.h
+++ b/system/main/shim/acl.h
@@ -118,17 +118,15 @@ 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();
+  void ClearFilterAcceptList();
+  void DisconnectAllForSuspend();
+  void LeRand(LeRandCallback cb);
+  void SetSystemSuspendState(bool suspended);
 
  protected:
   void on_incoming_acl_credits(uint16_t handle, uint16_t credits);
diff --git a/system/main/shim/btm_api.cc b/system/main/shim/btm_api.cc
index 607ffe3fa88..484b841d925 100644
--- a/system/main/shim/btm_api.cc
+++ b/system/main/shim/btm_api.cc
@@ -1357,6 +1357,9 @@ tBTM_STATUS bluetooth::shim::BTM_SetEventFilterConnectionSetupAllDevices() {
 tBTM_STATUS bluetooth::shim::BTM_AllowWakeByHid(
     std::vector<RawAddress> classic_hid_devices,
     std::vector<std::pair<RawAddress, uint8_t>> le_hid_devices) {
+  // First set ACL to suspended state.
+  Stack::GetInstance()->GetAcl()->SetSystemSuspendState(/*suspended=*/true);
+
   // Allow classic HID wake.
   controller_get_interface()->set_event_filter_allow_device_connection(
       std::move(classic_hid_devices));
@@ -1372,12 +1375,28 @@ tBTM_STATUS bluetooth::shim::BTM_AllowWakeByHid(
 
     accept_future.wait();
   }
+
   return BTM_SUCCESS;
 }
 
-tBTM_STATUS bluetooth::shim::BTM_RestoreFilterAcceptList() {
-  LOG_ERROR("%s: TODO(230604670): Figure out what address for A2DP Connected Resume", __func__);
-  // TODO(230604670): Figure out what address for A2DP Connected Resume
+tBTM_STATUS bluetooth::shim::BTM_RestoreFilterAcceptList(
+    std::vector<std::pair<RawAddress, uint8_t>> le_devices) {
+  // First, mark ACL as no longer suspended.
+  Stack::GetInstance()->GetAcl()->SetSystemSuspendState(/*suspended=*/false);
+
+  // Next, Allow BLE connection from all devices that need to be restored.
+  // This will also re-arm the LE connection.
+  for (auto address_pair : le_devices) {
+    std::promise<bool> accept_promise;
+    auto accept_future = accept_promise.get_future();
+
+    Stack::GetInstance()->GetAcl()->AcceptLeConnectionFrom(
+        ToAddressWithType(address_pair.first, address_pair.second),
+        /*is_direct=*/false, std::move(accept_promise));
+
+    accept_future.wait();
+  }
+
   return BTM_SUCCESS;
 }
 
diff --git a/system/main/shim/btm_api.h b/system/main/shim/btm_api.h
index 632ed091d58..f56b4429c59 100644
--- a/system/main/shim/btm_api.h
+++ b/system/main/shim/btm_api.h
@@ -1862,7 +1862,8 @@ tBTM_STATUS BTM_AllowWakeByHid(
  * Parameters
  *
  *******************************************************************************/
-tBTM_STATUS BTM_RestoreFilterAcceptList(void);
+tBTM_STATUS BTM_RestoreFilterAcceptList(
+    std::vector<std::pair<RawAddress, uint8_t>> le_devices);
 
 /*******************************************************************************
  *
diff --git a/system/test/mock/mock_main_shim_btm_api.cc b/system/test/mock/mock_main_shim_btm_api.cc
index 9ab395a0262..c7f2e3faf79 100644
--- a/system/test/mock/mock_main_shim_btm_api.cc
+++ b/system/test/mock/mock_main_shim_btm_api.cc
@@ -450,7 +450,8 @@ tBTM_STATUS bluetooth::shim::BTM_AllowWakeByHid(
   return BTM_SUCCESS;
 }
 
-tBTM_STATUS bluetooth::shim::BTM_RestoreFilterAcceptList() {
+tBTM_STATUS bluetooth::shim::BTM_RestoreFilterAcceptList(
+    std::vector<std::pair<RawAddress, uint8_t>> le_devices) {
   inc_func_call_count(__func__);
   return BTM_SUCCESS;
 }
-- 
GitLab