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

Commit 7a98b40a authored by Jack He's avatar Jack He
Browse files

Metrics: Log L2CAP and RFCOMM socket connection state changes to statsd

* Log L2CAP LE Coc, L2CAP BREDR, and RFCOMM socket connection state
  changes, including port number, socket type, connection states,
  number of bytes sent and received, server port number, uid of socket
  owner
* Address is empty if this is a server port

Bug: 112969790
Test: make, test drive with statsd
Change-Id: Ic0ee93a6d9e4fa4109ddb89dea5e92907c49f2fc
parent 68fd6c2f
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@

#include <base/logging.h>

#include <frameworks/base/core/proto/android/bluetooth/enums.pb.h>
#include <hardware/bluetooth.h>
#include <hardware/bt_sock.h>

@@ -34,6 +35,7 @@
#include "btif_sock_thread.h"
#include "btif_uid.h"
#include "btif_util.h"
#include "common/metrics.h"
#include "device/include/controller.h"
#include "osi/include/thread.h"

@@ -138,6 +140,11 @@ static bt_status_t btsock_listen(btsock_type_t type, const char* service_name,
  bt_status_t status = BT_STATUS_FAIL;
  int original_channel = channel;

  bluetooth::common::LogSocketConnectionState(
      RawAddress::kEmpty, 0, type,
      android::bluetooth::SocketConnectionstateEnum::
          SOCKET_CONNECTION_STATE_LISTENING,
      0, 0, app_uid, channel, android::bluetooth::SOCKET_ROLE_LISTEN);
  switch (type) {
    case BTSOCK_RFCOMM:
      status = btsock_rfc_listen(service_name, service_uuid, channel, sock_fd,
@@ -174,6 +181,13 @@ static bt_status_t btsock_listen(btsock_type_t type, const char* service_name,
      status = BT_STATUS_UNSUPPORTED;
      break;
  }
  if (status != BT_STATUS_SUCCESS) {
    bluetooth::common::LogSocketConnectionState(
        RawAddress::kEmpty, 0, type,
        android::bluetooth::SocketConnectionstateEnum::
            SOCKET_CONNECTION_STATE_DISCONNECTED,
        0, 0, app_uid, channel, android::bluetooth::SOCKET_ROLE_LISTEN);
  }
  return status;
}

@@ -186,6 +200,11 @@ static bt_status_t btsock_connect(const RawAddress* bd_addr, btsock_type_t type,
  *sock_fd = INVALID_FD;
  bt_status_t status = BT_STATUS_FAIL;

  bluetooth::common::LogSocketConnectionState(
      *bd_addr, 0, type,
      android::bluetooth::SocketConnectionstateEnum::
          SOCKET_CONNECTION_STATE_CONNECTING,
      0, 0, app_uid, channel, android::bluetooth::SOCKET_ROLE_CONNECTION);
  switch (type) {
    case BTSOCK_RFCOMM:
      status =
@@ -213,6 +232,13 @@ static bt_status_t btsock_connect(const RawAddress* bd_addr, btsock_type_t type,
      status = BT_STATUS_UNSUPPORTED;
      break;
  }
  if (status != BT_STATUS_SUCCESS) {
    bluetooth::common::LogSocketConnectionState(
        *bd_addr, 0, type,
        android::bluetooth::SocketConnectionstateEnum::
            SOCKET_CONNECTION_STATE_DISCONNECTED,
        0, 0, app_uid, channel, android::bluetooth::SOCKET_ROLE_CONNECTION);
  }
  return status;
}

+71 −5
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@

#include <mutex>

#include <frameworks/base/core/proto/android/bluetooth/enums.pb.h>
#include <hardware/bt_sock.h>

#include "osi/include/allocator.h"
@@ -46,6 +47,7 @@
#include "btm_api.h"
#include "btm_int.h"
#include "btu.h"
#include "common/metrics.h"
#include "hcimsgs.h"
#include "l2c_api.h"
#include "l2c_int.h"
@@ -84,6 +86,10 @@ typedef struct l2cap_socket {
  bool is_le_coc;                 // is le connection oriented channel?
  uint16_t rx_mtu;
  uint16_t tx_mtu;
  // Cumulative number of bytes transmitted on this socket
  int64_t tx_bytes;
  // Cumulative number of bytes received on this socket
  int64_t rx_bytes;
} l2cap_socket;

static void btsock_l2cap_server_listen(l2cap_socket* sock);
@@ -215,6 +221,14 @@ static void btsock_l2cap_free_l(l2cap_socket* sock) {
  if (!t) /* prever double-frees */
    return;

  // Whenever a socket is freed, the connection must be dropped
  bluetooth::common::LogSocketConnectionState(
      sock->addr, sock->id, sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
      android::bluetooth::SOCKET_CONNECTION_STATE_DISCONNECTED, sock->tx_bytes,
      sock->rx_bytes, sock->app_uid, sock->channel,
      sock->server ? android::bluetooth::SOCKET_ROLE_LISTEN
                   : android::bluetooth::SOCKET_ROLE_CONNECTION);

  if (sock->next) sock->next->prev = sock->prev;

  if (sock->prev)
@@ -309,6 +323,8 @@ static l2cap_socket* btsock_l2cap_alloc_l(const char* name,
  sock->prev = NULL;
  if (socks) socks->prev = sock;
  sock->id = (socks ? socks->id : 0) + 1;
  sock->tx_bytes = 0;
  sock->rx_bytes = 0;
  socks = sock;
  /* paranoia cap on: verify no ID duplicates due to overflow and fix as needed
   */
@@ -396,6 +412,14 @@ static void on_srv_l2cap_listen_started(tBTA_JV_L2CAP_START* p_start,
  DVLOG(2) << __func__ << ": sock->handle: " << sock->handle
           << ", id: " << sock->id;

  bluetooth::common::LogSocketConnectionState(
      sock->addr, sock->id, sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
      android::bluetooth::SocketConnectionstateEnum::
          SOCKET_CONNECTION_STATE_LISTENING,
      0, 0, sock->app_uid, sock->channel,
      sock->server ? android::bluetooth::SOCKET_ROLE_LISTEN
                   : android::bluetooth::SOCKET_ROLE_CONNECTION);

  if (!sock->server_psm_sent) {
    if (!send_app_psm_or_chan_l(sock)) {
      // closed
@@ -448,6 +472,14 @@ static void on_srv_l2cap_psm_connect_l(tBTA_JV_L2CAP_OPEN* p_open,
  accept_rs->id = sock->id;
  sock->id = new_listen_id;

  bluetooth::common::LogSocketConnectionState(
      accept_rs->addr, accept_rs->id,
      accept_rs->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
      android::bluetooth::SOCKET_CONNECTION_STATE_CONNECTED, 0, 0,
      accept_rs->app_uid, accept_rs->channel,
      accept_rs->server ? android::bluetooth::SOCKET_ROLE_LISTEN
                        : android::bluetooth::SOCKET_ROLE_CONNECTION);

  // start monitor the socket
  btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP,
                       SOCK_THREAD_FD_EXCEPTION, sock->id);
@@ -489,6 +521,14 @@ static void on_srv_l2cap_le_connect_l(tBTA_JV_L2CAP_LE_OPEN* p_open,
  *(p_open->p_p_cback) = (void*)btsock_l2cap_cbk;
  *(p_open->p_user_data) = UINT_TO_PTR(accept_rs->id);

  bluetooth::common::LogSocketConnectionState(
      accept_rs->addr, accept_rs->id,
      accept_rs->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
      android::bluetooth::SOCKET_CONNECTION_STATE_CONNECTED, 0, 0,
      accept_rs->app_uid, accept_rs->channel,
      accept_rs->server ? android::bluetooth::SOCKET_ROLE_LISTEN
                        : android::bluetooth::SOCKET_ROLE_CONNECTION);

  // start monitor the socket
  btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP,
                       SOCK_THREAD_FD_EXCEPTION, sock->id);
@@ -518,6 +558,13 @@ static void on_cl_l2cap_psm_connect_l(tBTA_JV_L2CAP_OPEN* p_open,
    return;
  }

  bluetooth::common::LogSocketConnectionState(
      sock->addr, sock->id, sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
      android::bluetooth::SOCKET_CONNECTION_STATE_CONNECTED, 0, 0,
      sock->app_uid, sock->channel,
      sock->server ? android::bluetooth::SOCKET_ROLE_LISTEN
                   : android::bluetooth::SOCKET_ROLE_CONNECTION);

  // start monitoring the socketpair to get call back when app writing data
  DVLOG(2) << " connect signal sent, slot id: " << sock->id
           << ", chan: " << sock->channel << ", server: " << sock->server;
@@ -542,6 +589,13 @@ static void on_cl_l2cap_le_connect_l(tBTA_JV_L2CAP_LE_OPEN* p_open,
    return;
  }

  bluetooth::common::LogSocketConnectionState(
      sock->addr, sock->id, sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
      android::bluetooth::SOCKET_CONNECTION_STATE_CONNECTED, 0, 0,
      sock->app_uid, sock->channel,
      sock->server ? android::bluetooth::SOCKET_ROLE_LISTEN
                   : android::bluetooth::SOCKET_ROLE_CONNECTION);

  // start monitoring the socketpair to get call back when app writing data
  DVLOG(2) << " connect signal sent, slot id: " << sock->id
           << ", chan: " << sock->channel << ", server: " << sock->server;
@@ -564,18 +618,21 @@ static void on_l2cap_connect(tBTA_JV* p_data, uint32_t id) {

  sock->tx_mtu = le_open->tx_mtu;
  if (sock->fixed_chan && le_open->status == BTA_JV_SUCCESS) {
    if (!sock->server)
    if (!sock->server) {
      on_cl_l2cap_le_connect_l(le_open, sock);
    else
    } else {
      on_srv_l2cap_le_connect_l(le_open, sock);
    }
  } else if (!sock->fixed_chan && psm_open->status == BTA_JV_SUCCESS) {
    if (!sock->server)
    if (!sock->server) {
      on_cl_l2cap_psm_connect_l(psm_open, sock);
    else
    } else {
      on_srv_l2cap_psm_connect_l(psm_open, sock);
  } else
    }
  } else {
    btsock_l2cap_free_l(sock);
  }
}

static void on_l2cap_close(tBTA_JV_L2CAP_CLOSE* p_close, uint32_t id) {
  l2cap_socket* sock;
@@ -584,6 +641,13 @@ static void on_l2cap_close(tBTA_JV_L2CAP_CLOSE* p_close, uint32_t id) {
  sock = btsock_l2cap_find_by_id_l(id);
  if (!sock) return;

  bluetooth::common::LogSocketConnectionState(
      sock->addr, sock->id, sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
      android::bluetooth::SOCKET_CONNECTION_STATE_DISCONNECTING, 0, 0,
      sock->app_uid, sock->channel,
      sock->server ? android::bluetooth::SOCKET_ROLE_LISTEN
                   : android::bluetooth::SOCKET_ROLE_CONNECTION);

  DVLOG(2) << __func__ << ": slot id: " << sock->id << ", fd: " << sock->our_fd
           << (sock->fixed_chan ? ", fixed_chan:" : ", PSM: ") << sock->channel
           << ", server:" << sock->server;
@@ -624,6 +688,7 @@ static void on_l2cap_write_done(uint16_t len, uint32_t id) {
                         sock->id);
  }

  sock->tx_bytes += len;
  uid_set_add_tx(uid_set, app_uid, len);
}

@@ -677,6 +742,7 @@ static void on_l2cap_data_ind(tBTA_JV* evt, uint32_t id) {
    }
  }

  sock->rx_bytes += bytes_read;
  uid_set_add_rx(uid_set, app_uid, bytes_read);
}

+53 −4
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@

#include <mutex>

#include <frameworks/base/core/proto/android/bluetooth/enums.pb.h>
#include <hardware/bluetooth.h>
#include <hardware/bt_sock.h>

@@ -47,6 +48,7 @@
#include "btm_api.h"
#include "btm_int.h"
#include "btu.h"
#include "common/metrics.h"
#include "hcimsgs.h"
#include "osi/include/compat.h"
#include "osi/include/list.h"
@@ -97,6 +99,10 @@ typedef struct {
  int rfc_port_handle;
  int role;
  list_t* incoming_queue;
  // Cumulative number of bytes transmitted on this socket
  int64_t tx_bytes;
  // Cumulative number of bytes received on this socket
  int64_t rx_bytes;
} rfc_slot_t;

static rfc_slot_t rfc_slots[MAX_RFC_CHANNEL];
@@ -225,11 +231,15 @@ static rfc_slot_t* alloc_rfc_slot(const RawAddress* addr, const char* name,
  } else {
    memset(slot->service_name, 0, sizeof(slot->service_name));
  }
  if (addr) slot->addr = *addr;

  if (addr) {
    slot->addr = *addr;
  } else {
    slot->addr = RawAddress::kEmpty;
  }
  slot->id = rfc_slot_id;
  slot->f.server = server;

  slot->tx_bytes = 0;
  slot->rx_bytes = 0;
  return slot;
}

@@ -411,6 +421,12 @@ static void cleanup_rfc_slot(rfc_slot_t* slot) {
  if (slot->fd != INVALID_FD) {
    shutdown(slot->fd, SHUT_RDWR);
    close(slot->fd);
    bluetooth::common::LogSocketConnectionState(
        slot->addr, slot->id, BTSOCK_RFCOMM,
        android::bluetooth::SOCKET_CONNECTION_STATE_DISCONNECTED,
        slot->tx_bytes, slot->rx_bytes, slot->app_uid, slot->scn,
        slot->f.server ? android::bluetooth::SOCKET_ROLE_LISTEN
                       : android::bluetooth::SOCKET_ROLE_CONNECTION);
    slot->fd = INVALID_FD;
  }

@@ -436,6 +452,8 @@ static void cleanup_rfc_slot(rfc_slot_t* slot) {
  memset(&slot->f, 0, sizeof(slot->f));
  slot->id = 0;
  slot->scn_notified = false;
  slot->tx_bytes = 0;
  slot->rx_bytes = 0;
}

static bool send_app_scn(rfc_slot_t* slot) {
@@ -484,6 +502,13 @@ static void on_srv_rfc_listen_started(tBTA_JV_RFCOMM_START* p_start,

  if (p_start->status == BTA_JV_SUCCESS) {
    slot->rfc_handle = p_start->handle;
    bluetooth::common::LogSocketConnectionState(
        slot->addr, slot->id, BTSOCK_RFCOMM,
        android::bluetooth::SocketConnectionstateEnum::
            SOCKET_CONNECTION_STATE_LISTENING,
        0, 0, slot->app_uid, slot->scn,
        slot->f.server ? android::bluetooth::SOCKET_ROLE_LISTEN
                       : android::bluetooth::SOCKET_ROLE_CONNECTION);
  } else {
    cleanup_rfc_slot(slot);
  }
@@ -500,6 +525,13 @@ static uint32_t on_srv_rfc_connect(tBTA_JV_RFCOMM_SRV_OPEN* p_open,
      srv_rs, &p_open->rem_bda, p_open->handle, p_open->new_listen_handle);
  if (!accept_rs) return 0;

  bluetooth::common::LogSocketConnectionState(
      accept_rs->addr, accept_rs->id, BTSOCK_RFCOMM,
      android::bluetooth::SOCKET_CONNECTION_STATE_CONNECTED, 0, 0,
      accept_rs->app_uid, accept_rs->scn,
      accept_rs->f.server ? android::bluetooth::SOCKET_ROLE_LISTEN
                          : android::bluetooth::SOCKET_ROLE_CONNECTION);

  // Start monitoring the socket.
  btsock_thread_add_fd(pth, srv_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_EXCEPTION,
                       srv_rs->id);
@@ -525,6 +557,13 @@ static void on_cli_rfc_connect(tBTA_JV_RFCOMM_OPEN* p_open, uint32_t id) {
  slot->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_open->handle);
  slot->addr = p_open->rem_bda;

  bluetooth::common::LogSocketConnectionState(
      slot->addr, slot->id, BTSOCK_RFCOMM,
      android::bluetooth::SOCKET_CONNECTION_STATE_CONNECTED, 0, 0,
      slot->app_uid, slot->scn,
      slot->f.server ? android::bluetooth::SOCKET_ROLE_LISTEN
                     : android::bluetooth::SOCKET_ROLE_CONNECTION);

  if (send_app_connect_signal(slot->fd, &slot->addr, slot->scn, 0, -1)) {
    slot->f.connected = true;
  } else {
@@ -539,7 +578,15 @@ static void on_rfc_close(UNUSED_ATTR tBTA_JV_RFCOMM_CLOSE* p_close,

  // rfc_handle already closed when receiving rfcomm close event from stack.
  rfc_slot_t* slot = find_rfc_slot_by_id(id);
  if (slot) cleanup_rfc_slot(slot);
  if (slot) {
    bluetooth::common::LogSocketConnectionState(
        slot->addr, slot->id, BTSOCK_RFCOMM,
        android::bluetooth::SOCKET_CONNECTION_STATE_DISCONNECTING, 0, 0,
        slot->app_uid, slot->scn,
        slot->f.server ? android::bluetooth::SOCKET_ROLE_LISTEN
                       : android::bluetooth::SOCKET_ROLE_CONNECTION);
    cleanup_rfc_slot(slot);
  }
}

static void on_rfc_write_done(tBTA_JV_RFCOMM_WRITE* p, uint32_t id) {
@@ -559,6 +606,7 @@ static void on_rfc_write_done(tBTA_JV_RFCOMM_WRITE* p, uint32_t id) {
      btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD,
                           slot->id);
    }
    slot->tx_bytes += p->len;
  }

  uid_set_add_tx(uid_set, app_uid, p->len);
@@ -877,6 +925,7 @@ int bta_co_rfc_data_incoming(uint32_t id, BT_HDR* p_buf) {
    list_append(slot->incoming_queue, p_buf);
  }

  slot->rx_bytes += bytes_rx;
  uid_set_add_rx(uid_set, app_uid, bytes_rx);

  return ret;  // Return 0 to disable data flow.
+35 −9
Original line number Diff line number Diff line
@@ -572,9 +572,9 @@ void BluetoothMetricsLogger::Reset() {
void LogLinkLayerConnectionEvent(const RawAddress* address,
                                 uint32_t connection_handle,
                                 android::bluetooth::DirectionEnum direction,
                                 uint32_t link_type, uint32_t hci_cmd,
                                 uint32_t hci_event, uint32_t hci_ble_event,
                                 uint32_t cmd_status, uint32_t reason_code) {
                                 uint16_t link_type, uint32_t hci_cmd,
                                 uint16_t hci_event, uint16_t hci_ble_event,
                                 uint16_t cmd_status, uint16_t reason_code) {
  std::string obfuscated_id;
  if (address != nullptr) {
    obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(*address);
@@ -588,12 +588,12 @@ void LogLinkLayerConnectionEvent(const RawAddress* address,
      connection_handle, direction, link_type, hci_cmd, hci_event,
      hci_ble_event, cmd_status, reason_code);
  if (ret < 0) {
    LOG(WARNING) << __func__ << ": failed to log status 0x"
                 << loghex(cmd_status) << ", reason 0x" << loghex(reason_code)
                 << " from cmd 0x" << loghex(hci_cmd) << ", event 0x"
                 << loghex(hci_event) << ", ble_event 0x"
                 << loghex(hci_ble_event) << " for " << address << ", handle "
                 << connection_handle << ", error " << ret;
    LOG(WARNING) << __func__ << ": failed to log status " << loghex(cmd_status)
                 << ", reason " << loghex(reason_code) << " from cmd "
                 << loghex(hci_cmd) << ", event " << loghex(hci_event)
                 << ", ble_event " << loghex(hci_ble_event) << " for "
                 << address << ", handle " << connection_handle << ", type "
                 << loghex(link_type) << ", error " << ret;
  }
}

@@ -801,6 +801,32 @@ void LogSdpAttribute(const RawAddress& address, uint16_t protocol_uuid,
  }
}

void LogSocketConnectionState(
    const RawAddress& address, int port, int type,
    android::bluetooth::SocketConnectionstateEnum connection_state,
    int64_t tx_bytes, int64_t rx_bytes, int uid, int server_port,
    android::bluetooth::SocketRoleEnum socket_role) {
  std::string obfuscated_id;
  if (!address.IsEmpty()) {
    obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(address);
  }
  // nullptr and size 0 represent missing value for obfuscated_id
  android::util::BytesField obfuscated_id_field(
      address.IsEmpty() ? nullptr : obfuscated_id.c_str(),
      address.IsEmpty() ? 0 : obfuscated_id.size());
  int ret = android::util::stats_write(
      android::util::BLUETOOTH_SOCKET_CONNECTION_STATE_CHANGED,
      obfuscated_id_field, port, type, connection_state, tx_bytes, rx_bytes,
      uid, server_port, socket_role);
  if (ret < 0) {
    LOG(WARNING) << __func__ << ": failed for " << address << ", port " << port
                 << ", type " << type << ", state " << connection_state
                 << ", tx_bytes " << tx_bytes << ", rx_bytes " << rx_bytes
                 << ", uid " << uid << ", server_port " << server_port
                 << ", socket_role " << socket_role << ", error " << ret;
  }
}

}  // namespace common

}  // namespace bluetooth
+24 −3
Original line number Diff line number Diff line
@@ -301,9 +301,9 @@ static const uint32_t kUnknownConnectionHandle = 0xFFFF;
void LogLinkLayerConnectionEvent(const RawAddress* address,
                                 uint32_t connection_handle,
                                 android::bluetooth::DirectionEnum direction,
                                 uint32_t link_type, uint32_t hci_cmd,
                                 uint32_t hci_event, uint32_t hci_ble_event,
                                 uint32_t cmd_status, uint32_t reason_code);
                                 uint16_t link_type, uint32_t hci_cmd,
                                 uint16_t hci_event, uint16_t hci_ble_event,
                                 uint16_t cmd_status, uint16_t reason_code);

/**
 * Logs when Bluetooth controller failed to reply with command status within
@@ -439,6 +439,27 @@ void LogClassicPairingEvent(const RawAddress& address, uint16_t handle,
void LogSdpAttribute(const RawAddress& address, uint16_t protocol_uuid,
                     uint16_t attribute_id, size_t attribute_size,
                     const char* attribute_value);

/**
 * Logs when there is a change in Bluetooth socket connection state
 *
 * @param address address of associated device, empty if this is a server port
 * @param port port of this socket connection
 * @param type type of socket
 * @param connection_state socket connection state
 * @param tx_bytes number of bytes transmitted
 * @param rx_bytes number of bytes received
 * @param server_port server port of this socket, if any. When both
 *        |server_port| and |port| fields are populated, |port| must be spawned
 *        by |server_port|
 * @param socket_role role of this socket, server or connection
 * @param uid socket owner's uid
 */
void LogSocketConnectionState(
    const RawAddress& address, int port, int type,
    android::bluetooth::SocketConnectionstateEnum connection_state,
    int64_t tx_bytes, int64_t rx_bytes, int uid, int server_port,
    android::bluetooth::SocketRoleEnum socket_role);
}  // namespace common

}  // namespace bluetooth