Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bf1f4c02 authored by Himanshu Rawat's avatar Himanshu Rawat Committed by Gerrit Code Review
Browse files

Merge "Disconnect before removing device" into main

parents 7480a4c6 54f48d3a
Loading
Loading
Loading
Loading
+176 −3
Original line number Original line Diff line number Diff line
@@ -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 = {};
}
}


@@ -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) ||
@@ -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
@@ -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");
@@ -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;


@@ -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));
}
}
+21 −0
Original line number Original line Diff line number Diff line
@@ -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>


@@ -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;


@@ -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);
  }
  }


@@ -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 */