Loading system/bta/dm/bta_dm_act.cc +176 −3 Original line number Original line Diff line number Diff line Loading @@ -205,6 +205,7 @@ static void bta_dm_deinit_cb(void) { alarm_free(bta_dm_cb.pm_timer[i].timer[j]); alarm_free(bta_dm_cb.pm_timer[i].timer[j]); } } } } bta_dm_cb.pending_removals.clear(); bta_dm_cb = {}; bta_dm_cb = {}; } } Loading Loading @@ -471,8 +472,8 @@ void bta_dm_process_remove_device(const RawAddress& bd_addr) { } } } } /** Removes device, disconnects ACL link if required */ // TODO: Remove when flag wait_for_disconnect_before_unbond is shipped void bta_dm_remove_device(const RawAddress& bd_addr) { static void bta_dm_remove_device_(const RawAddress& bd_addr) { /* If ACL exists for the device in the remove_bond message*/ /* If ACL exists for the device in the remove_bond message*/ bool is_bd_addr_connected = bool is_bd_addr_connected = get_btm_client_interface().peer.BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE) || get_btm_client_interface().peer.BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE) || Loading Loading @@ -564,6 +565,112 @@ void bta_dm_remove_device(const RawAddress& bd_addr) { } } } } /** Removes device, disconnects ACL link if required */ void bta_dm_remove_device(const RawAddress& target) { if (!com::android::bluetooth::flags::wait_for_disconnect_before_unbond()) { bta_dm_remove_device_(target); return; } // Find all aliases and connection status on all transports RawAddress pseudo_addr = target; RawAddress identity_addr = target; bool le_connected = get_btm_client_interface().peer.BTM_ReadConnectedTransportAddress( &pseudo_addr, BT_TRANSPORT_LE); bool bredr_connected = get_btm_client_interface().peer.BTM_ReadConnectedTransportAddress( &identity_addr, BT_TRANSPORT_BR_EDR); /* If connection not found with identity address, check with pseudo address if different */ if (!bredr_connected && identity_addr != pseudo_addr) { identity_addr = pseudo_addr; bredr_connected = get_btm_client_interface().peer.BTM_ReadConnectedTransportAddress( &identity_addr, BT_TRANSPORT_BR_EDR); } // Remove from LE allowlist if (!GATT_CancelConnect(0, pseudo_addr, false)) { if (identity_addr != pseudo_addr && !GATT_CancelConnect(0, identity_addr, false)) { log::warn("Unable to cancel GATT connect peer:{}", pseudo_addr); } } // Disconnect LE transport if (le_connected) { tBTM_STATUS status = btm_remove_acl(pseudo_addr, BT_TRANSPORT_LE); if (status != BTM_SUCCESS && identity_addr != pseudo_addr) { status = btm_remove_acl(identity_addr, BT_TRANSPORT_LE); } if (status != BTM_SUCCESS) { le_connected = false; log::error("Unable to disconnect LE connection {}", pseudo_addr); } } // Disconnect BR/EDR transport if (bredr_connected) { tBTM_STATUS status = btm_remove_acl(identity_addr, BT_TRANSPORT_BR_EDR); if (status != BTM_SUCCESS && identity_addr != pseudo_addr) { status = btm_remove_acl(pseudo_addr, BT_TRANSPORT_BR_EDR); } if (status != BTM_SUCCESS) { bredr_connected = false; log::error("Unable to disconnect BR/EDR connection {}", identity_addr); } } if (le_connected || bredr_connected) { // Wait for all transports to be disconnected tBTA_DM_REMOVE_PENDNIG node = {pseudo_addr, target, le_connected, bredr_connected}; bta_dm_cb.pending_removals.push_back(node); log::info( "Waiting for disconnection over LE:{}, BR/EDR:{} for pseudo address: {}, identity " "address: {}", le_connected, bredr_connected, pseudo_addr, identity_addr); } else { // No existing connection, remove the device right away log::verbose("Not connected, remove the device {}", target); bta_dm_process_remove_device(identity_addr); if (identity_addr != pseudo_addr) { bta_dm_process_remove_device(pseudo_addr); } } } static void bta_dm_remove_on_disconnect(const RawAddress& bd_addr, tBT_TRANSPORT transport) { for (auto it = bta_dm_cb.pending_removals.begin(); it != bta_dm_cb.pending_removals.end(); it++) { if (bd_addr == it->identity_addr || bd_addr == it->pseudo_addr) { if (transport == BT_TRANSPORT_BR_EDR) { it->bredr_connected = false; } else { it->le_connected = false; } if (!it->bredr_connected && !it->le_connected) { log::info("All transports disconnected, remove the device {}", bd_addr); bta_dm_process_remove_device(it->identity_addr); if (it->identity_addr != it->pseudo_addr) { bta_dm_process_remove_device(it->pseudo_addr); } bta_dm_cb.pending_removals.erase(it); } else { log::info("Awaiting {} disconnection over {}", it->le_connected ? "LE" : "BR/EDR", bd_addr); } break; } } } bool bta_dm_removal_pending(const RawAddress& bd_addr) { for (auto it : bta_dm_cb.pending_removals) { if (bd_addr == it.pseudo_addr || bd_addr == it.identity_addr) { return true; } } return false; } /******************************************************************************* /******************************************************************************* * * * Function bta_dm_local_name_cback * Function bta_dm_local_name_cback Loading Loading @@ -677,6 +784,23 @@ static tBTA_DM_PEER_DEVICE* allocate_device_for(const RawAddress& bd_addr, } } static void bta_dm_acl_up(const RawAddress& bd_addr, tBT_TRANSPORT transport, uint16_t acl_handle) { static void bta_dm_acl_up(const RawAddress& bd_addr, tBT_TRANSPORT transport, uint16_t acl_handle) { if (com::android::bluetooth::flags::wait_for_disconnect_before_unbond()) { // Disconnect if the device is being removed for (auto& it : bta_dm_cb.pending_removals) { if (bd_addr == it.identity_addr || bd_addr == it.pseudo_addr) { log::warn("ACL connected while removing the device {} transport: {}", bd_addr, transport); if (transport == BT_TRANSPORT_BR_EDR) { it.bredr_connected = true; } else { it.le_connected = true; } btm_remove_acl(bd_addr, transport); return; } } } auto device = allocate_device_for(bd_addr, transport); auto device = allocate_device_for(bd_addr, transport); if (device == nullptr) { if (device == nullptr) { log::warn("Unable to allocate device resources for new connection"); log::warn("Unable to allocate device resources for new connection"); Loading Loading @@ -730,7 +854,8 @@ void BTA_dm_acl_up_failed(const RawAddress bd_addr, tBT_TRANSPORT transport, tHC do_in_main_thread(base::BindOnce(bta_dm_acl_up_failed, bd_addr, transport, status)); do_in_main_thread(base::BindOnce(bta_dm_acl_up_failed, bd_addr, transport, status)); } } static void bta_dm_acl_down(const RawAddress& bd_addr, tBT_TRANSPORT transport) { // TODO: Remove when flag wait_for_disconnect_before_unbond is shipped static void bta_dm_acl_down_(const RawAddress& bd_addr, tBT_TRANSPORT transport) { bool issue_unpair_cb = false; bool issue_unpair_cb = false; bool remove_device = false; bool remove_device = false; Loading Loading @@ -810,6 +935,54 @@ static void bta_dm_acl_down(const RawAddress& bd_addr, tBT_TRANSPORT transport) bta_dm_adjust_roles(true); bta_dm_adjust_roles(true); } } static void bta_dm_acl_down(const RawAddress& bd_addr, tBT_TRANSPORT transport) { log::verbose("Device {} disconnected over transport {}", bd_addr, bt_transport_text(transport)); if (!com::android::bluetooth::flags::wait_for_disconnect_before_unbond()) { bta_dm_acl_down_(bd_addr, transport); return; } for (uint8_t i = 0; i < bta_dm_cb.device_list.count; i++) { auto device = &bta_dm_cb.device_list.peer_device[i]; if (device->peer_bdaddr == bd_addr && device->transport == transport) { // Move the last item into its place if (i + 1 < bta_dm_cb.device_list.count) { *device = bta_dm_cb.device_list.peer_device[bta_dm_cb.device_list.count - 1]; } bta_dm_cb.device_list.peer_device[bta_dm_cb.device_list.count - 1] = {}; break; } } if (bta_dm_cb.device_list.count > 0) { bta_dm_cb.device_list.count--; } if (transport == BT_TRANSPORT_LE && bta_dm_cb.device_list.le_count > 0) { bta_dm_cb.device_list.le_count--; } bta_dm_disc_acl_down(bd_addr, transport); if (bta_dm_cb.disabling && !BTM_GetNumAclLinks()) { /* * Start a timer to make sure that the profiles * get the disconnect event. */ alarm_set_on_mloop(bta_dm_cb.disable_timer, BTA_DM_DISABLE_CONN_DOWN_TIMER_MS, bta_dm_disable_conn_down_timer_cback, NULL); } if (bta_dm_acl_cb.p_acl_cback) { tBTA_DM_ACL conn{}; conn.link_down.bd_addr = bd_addr; conn.link_down.transport_link_type = transport; bta_dm_acl_cb.p_acl_cback(BTA_DM_LINK_DOWN_EVT, &conn); } bta_dm_adjust_roles(true); bta_dm_remove_on_disconnect(bd_addr, transport); } void BTA_dm_acl_down(const RawAddress bd_addr, tBT_TRANSPORT transport) { void BTA_dm_acl_down(const RawAddress bd_addr, tBT_TRANSPORT transport) { do_in_main_thread(base::BindOnce(bta_dm_acl_down, bd_addr, transport)); do_in_main_thread(base::BindOnce(bta_dm_acl_down, bd_addr, transport)); } } Loading system/bta/dm/bta_dm_int.h +21 −0 Original line number Original line Diff line number Diff line Loading @@ -26,7 +26,9 @@ #include <base/strings/stringprintf.h> #include <base/strings/stringprintf.h> #include <bluetooth/log.h> #include <bluetooth/log.h> #include <com_android_bluetooth_flags.h> #include <list> #include <string> #include <string> #include <vector> #include <vector> Loading Loading @@ -95,9 +97,21 @@ inline std::string device_info_text(tBTA_DM_DEV_INFO info) { #define BTA_DM_PM_EXECUTE 3 #define BTA_DM_PM_EXECUTE 3 typedef uint8_t tBTA_DM_PM_REQ; typedef uint8_t tBTA_DM_PM_REQ; struct tBTA_DM_REMOVE_PENDNIG { RawAddress pseudo_addr; RawAddress identity_addr; bool le_connected; bool bredr_connected; }; bool bta_dm_removal_pending(const RawAddress& bd_addr); struct tBTA_DM_PEER_DEVICE { struct tBTA_DM_PEER_DEVICE { RawAddress peer_bdaddr; RawAddress peer_bdaddr; // TODO: Remove when flag wait_for_disconnect_before_unbond is shipped tBTA_DM_CONN_STATE conn_state{tBTA_DM_CONN_STATE::BTA_DM_CONNECTED}; tBTA_DM_CONN_STATE conn_state{tBTA_DM_CONN_STATE::BTA_DM_CONNECTED}; tBTA_PREF_ROLES pref_role; tBTA_PREF_ROLES pref_role; bool in_use; bool in_use; Loading Loading @@ -135,6 +149,11 @@ public: bool is_ssr_active() const { return info & BTA_DM_DI_USE_SSR; } bool is_ssr_active() const { return info & BTA_DM_DI_USE_SSR; } bool is_connected() const { bool is_connected() const { // Devices getting removed should be treated as disconnected if (com::android::bluetooth::flags::wait_for_disconnect_before_unbond() && bta_dm_removal_pending(peer_bdaddr)) { return false; } return (conn_state == tBTA_DM_CONN_STATE::BTA_DM_CONNECTED); return (conn_state == tBTA_DM_CONN_STATE::BTA_DM_CONNECTED); } } Loading Loading @@ -223,6 +242,8 @@ typedef struct { tBTA_CUSTOM_UUID bta_custom_uuid[BTA_EIR_SERVER_NUM_CUSTOM_UUID]; tBTA_CUSTOM_UUID bta_custom_uuid[BTA_EIR_SERVER_NUM_CUSTOM_UUID]; #endif #endif alarm_t* switch_delay_timer; alarm_t* switch_delay_timer; std::list<tBTA_DM_REMOVE_PENDNIG> pending_removals; } tBTA_DM_CB; } tBTA_DM_CB; /* DI control block */ /* DI control block */ Loading Loading
system/bta/dm/bta_dm_act.cc +176 −3 Original line number Original line Diff line number Diff line Loading @@ -205,6 +205,7 @@ static void bta_dm_deinit_cb(void) { alarm_free(bta_dm_cb.pm_timer[i].timer[j]); alarm_free(bta_dm_cb.pm_timer[i].timer[j]); } } } } bta_dm_cb.pending_removals.clear(); bta_dm_cb = {}; bta_dm_cb = {}; } } Loading Loading @@ -471,8 +472,8 @@ void bta_dm_process_remove_device(const RawAddress& bd_addr) { } } } } /** Removes device, disconnects ACL link if required */ // TODO: Remove when flag wait_for_disconnect_before_unbond is shipped void bta_dm_remove_device(const RawAddress& bd_addr) { static void bta_dm_remove_device_(const RawAddress& bd_addr) { /* If ACL exists for the device in the remove_bond message*/ /* If ACL exists for the device in the remove_bond message*/ bool is_bd_addr_connected = bool is_bd_addr_connected = get_btm_client_interface().peer.BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE) || get_btm_client_interface().peer.BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE) || Loading Loading @@ -564,6 +565,112 @@ void bta_dm_remove_device(const RawAddress& bd_addr) { } } } } /** Removes device, disconnects ACL link if required */ void bta_dm_remove_device(const RawAddress& target) { if (!com::android::bluetooth::flags::wait_for_disconnect_before_unbond()) { bta_dm_remove_device_(target); return; } // Find all aliases and connection status on all transports RawAddress pseudo_addr = target; RawAddress identity_addr = target; bool le_connected = get_btm_client_interface().peer.BTM_ReadConnectedTransportAddress( &pseudo_addr, BT_TRANSPORT_LE); bool bredr_connected = get_btm_client_interface().peer.BTM_ReadConnectedTransportAddress( &identity_addr, BT_TRANSPORT_BR_EDR); /* If connection not found with identity address, check with pseudo address if different */ if (!bredr_connected && identity_addr != pseudo_addr) { identity_addr = pseudo_addr; bredr_connected = get_btm_client_interface().peer.BTM_ReadConnectedTransportAddress( &identity_addr, BT_TRANSPORT_BR_EDR); } // Remove from LE allowlist if (!GATT_CancelConnect(0, pseudo_addr, false)) { if (identity_addr != pseudo_addr && !GATT_CancelConnect(0, identity_addr, false)) { log::warn("Unable to cancel GATT connect peer:{}", pseudo_addr); } } // Disconnect LE transport if (le_connected) { tBTM_STATUS status = btm_remove_acl(pseudo_addr, BT_TRANSPORT_LE); if (status != BTM_SUCCESS && identity_addr != pseudo_addr) { status = btm_remove_acl(identity_addr, BT_TRANSPORT_LE); } if (status != BTM_SUCCESS) { le_connected = false; log::error("Unable to disconnect LE connection {}", pseudo_addr); } } // Disconnect BR/EDR transport if (bredr_connected) { tBTM_STATUS status = btm_remove_acl(identity_addr, BT_TRANSPORT_BR_EDR); if (status != BTM_SUCCESS && identity_addr != pseudo_addr) { status = btm_remove_acl(pseudo_addr, BT_TRANSPORT_BR_EDR); } if (status != BTM_SUCCESS) { bredr_connected = false; log::error("Unable to disconnect BR/EDR connection {}", identity_addr); } } if (le_connected || bredr_connected) { // Wait for all transports to be disconnected tBTA_DM_REMOVE_PENDNIG node = {pseudo_addr, target, le_connected, bredr_connected}; bta_dm_cb.pending_removals.push_back(node); log::info( "Waiting for disconnection over LE:{}, BR/EDR:{} for pseudo address: {}, identity " "address: {}", le_connected, bredr_connected, pseudo_addr, identity_addr); } else { // No existing connection, remove the device right away log::verbose("Not connected, remove the device {}", target); bta_dm_process_remove_device(identity_addr); if (identity_addr != pseudo_addr) { bta_dm_process_remove_device(pseudo_addr); } } } static void bta_dm_remove_on_disconnect(const RawAddress& bd_addr, tBT_TRANSPORT transport) { for (auto it = bta_dm_cb.pending_removals.begin(); it != bta_dm_cb.pending_removals.end(); it++) { if (bd_addr == it->identity_addr || bd_addr == it->pseudo_addr) { if (transport == BT_TRANSPORT_BR_EDR) { it->bredr_connected = false; } else { it->le_connected = false; } if (!it->bredr_connected && !it->le_connected) { log::info("All transports disconnected, remove the device {}", bd_addr); bta_dm_process_remove_device(it->identity_addr); if (it->identity_addr != it->pseudo_addr) { bta_dm_process_remove_device(it->pseudo_addr); } bta_dm_cb.pending_removals.erase(it); } else { log::info("Awaiting {} disconnection over {}", it->le_connected ? "LE" : "BR/EDR", bd_addr); } break; } } } bool bta_dm_removal_pending(const RawAddress& bd_addr) { for (auto it : bta_dm_cb.pending_removals) { if (bd_addr == it.pseudo_addr || bd_addr == it.identity_addr) { return true; } } return false; } /******************************************************************************* /******************************************************************************* * * * Function bta_dm_local_name_cback * Function bta_dm_local_name_cback Loading Loading @@ -677,6 +784,23 @@ static tBTA_DM_PEER_DEVICE* allocate_device_for(const RawAddress& bd_addr, } } static void bta_dm_acl_up(const RawAddress& bd_addr, tBT_TRANSPORT transport, uint16_t acl_handle) { static void bta_dm_acl_up(const RawAddress& bd_addr, tBT_TRANSPORT transport, uint16_t acl_handle) { if (com::android::bluetooth::flags::wait_for_disconnect_before_unbond()) { // Disconnect if the device is being removed for (auto& it : bta_dm_cb.pending_removals) { if (bd_addr == it.identity_addr || bd_addr == it.pseudo_addr) { log::warn("ACL connected while removing the device {} transport: {}", bd_addr, transport); if (transport == BT_TRANSPORT_BR_EDR) { it.bredr_connected = true; } else { it.le_connected = true; } btm_remove_acl(bd_addr, transport); return; } } } auto device = allocate_device_for(bd_addr, transport); auto device = allocate_device_for(bd_addr, transport); if (device == nullptr) { if (device == nullptr) { log::warn("Unable to allocate device resources for new connection"); log::warn("Unable to allocate device resources for new connection"); Loading Loading @@ -730,7 +854,8 @@ void BTA_dm_acl_up_failed(const RawAddress bd_addr, tBT_TRANSPORT transport, tHC do_in_main_thread(base::BindOnce(bta_dm_acl_up_failed, bd_addr, transport, status)); do_in_main_thread(base::BindOnce(bta_dm_acl_up_failed, bd_addr, transport, status)); } } static void bta_dm_acl_down(const RawAddress& bd_addr, tBT_TRANSPORT transport) { // TODO: Remove when flag wait_for_disconnect_before_unbond is shipped static void bta_dm_acl_down_(const RawAddress& bd_addr, tBT_TRANSPORT transport) { bool issue_unpair_cb = false; bool issue_unpair_cb = false; bool remove_device = false; bool remove_device = false; Loading Loading @@ -810,6 +935,54 @@ static void bta_dm_acl_down(const RawAddress& bd_addr, tBT_TRANSPORT transport) bta_dm_adjust_roles(true); bta_dm_adjust_roles(true); } } static void bta_dm_acl_down(const RawAddress& bd_addr, tBT_TRANSPORT transport) { log::verbose("Device {} disconnected over transport {}", bd_addr, bt_transport_text(transport)); if (!com::android::bluetooth::flags::wait_for_disconnect_before_unbond()) { bta_dm_acl_down_(bd_addr, transport); return; } for (uint8_t i = 0; i < bta_dm_cb.device_list.count; i++) { auto device = &bta_dm_cb.device_list.peer_device[i]; if (device->peer_bdaddr == bd_addr && device->transport == transport) { // Move the last item into its place if (i + 1 < bta_dm_cb.device_list.count) { *device = bta_dm_cb.device_list.peer_device[bta_dm_cb.device_list.count - 1]; } bta_dm_cb.device_list.peer_device[bta_dm_cb.device_list.count - 1] = {}; break; } } if (bta_dm_cb.device_list.count > 0) { bta_dm_cb.device_list.count--; } if (transport == BT_TRANSPORT_LE && bta_dm_cb.device_list.le_count > 0) { bta_dm_cb.device_list.le_count--; } bta_dm_disc_acl_down(bd_addr, transport); if (bta_dm_cb.disabling && !BTM_GetNumAclLinks()) { /* * Start a timer to make sure that the profiles * get the disconnect event. */ alarm_set_on_mloop(bta_dm_cb.disable_timer, BTA_DM_DISABLE_CONN_DOWN_TIMER_MS, bta_dm_disable_conn_down_timer_cback, NULL); } if (bta_dm_acl_cb.p_acl_cback) { tBTA_DM_ACL conn{}; conn.link_down.bd_addr = bd_addr; conn.link_down.transport_link_type = transport; bta_dm_acl_cb.p_acl_cback(BTA_DM_LINK_DOWN_EVT, &conn); } bta_dm_adjust_roles(true); bta_dm_remove_on_disconnect(bd_addr, transport); } void BTA_dm_acl_down(const RawAddress bd_addr, tBT_TRANSPORT transport) { void BTA_dm_acl_down(const RawAddress bd_addr, tBT_TRANSPORT transport) { do_in_main_thread(base::BindOnce(bta_dm_acl_down, bd_addr, transport)); do_in_main_thread(base::BindOnce(bta_dm_acl_down, bd_addr, transport)); } } Loading
system/bta/dm/bta_dm_int.h +21 −0 Original line number Original line Diff line number Diff line Loading @@ -26,7 +26,9 @@ #include <base/strings/stringprintf.h> #include <base/strings/stringprintf.h> #include <bluetooth/log.h> #include <bluetooth/log.h> #include <com_android_bluetooth_flags.h> #include <list> #include <string> #include <string> #include <vector> #include <vector> Loading Loading @@ -95,9 +97,21 @@ inline std::string device_info_text(tBTA_DM_DEV_INFO info) { #define BTA_DM_PM_EXECUTE 3 #define BTA_DM_PM_EXECUTE 3 typedef uint8_t tBTA_DM_PM_REQ; typedef uint8_t tBTA_DM_PM_REQ; struct tBTA_DM_REMOVE_PENDNIG { RawAddress pseudo_addr; RawAddress identity_addr; bool le_connected; bool bredr_connected; }; bool bta_dm_removal_pending(const RawAddress& bd_addr); struct tBTA_DM_PEER_DEVICE { struct tBTA_DM_PEER_DEVICE { RawAddress peer_bdaddr; RawAddress peer_bdaddr; // TODO: Remove when flag wait_for_disconnect_before_unbond is shipped tBTA_DM_CONN_STATE conn_state{tBTA_DM_CONN_STATE::BTA_DM_CONNECTED}; tBTA_DM_CONN_STATE conn_state{tBTA_DM_CONN_STATE::BTA_DM_CONNECTED}; tBTA_PREF_ROLES pref_role; tBTA_PREF_ROLES pref_role; bool in_use; bool in_use; Loading Loading @@ -135,6 +149,11 @@ public: bool is_ssr_active() const { return info & BTA_DM_DI_USE_SSR; } bool is_ssr_active() const { return info & BTA_DM_DI_USE_SSR; } bool is_connected() const { bool is_connected() const { // Devices getting removed should be treated as disconnected if (com::android::bluetooth::flags::wait_for_disconnect_before_unbond() && bta_dm_removal_pending(peer_bdaddr)) { return false; } return (conn_state == tBTA_DM_CONN_STATE::BTA_DM_CONNECTED); return (conn_state == tBTA_DM_CONN_STATE::BTA_DM_CONNECTED); } } Loading Loading @@ -223,6 +242,8 @@ typedef struct { tBTA_CUSTOM_UUID bta_custom_uuid[BTA_EIR_SERVER_NUM_CUSTOM_UUID]; tBTA_CUSTOM_UUID bta_custom_uuid[BTA_EIR_SERVER_NUM_CUSTOM_UUID]; #endif #endif alarm_t* switch_delay_timer; alarm_t* switch_delay_timer; std::list<tBTA_DM_REMOVE_PENDNIG> pending_removals; } tBTA_DM_CB; } tBTA_DM_CB; /* DI control block */ /* DI control block */ Loading