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

Commit c62ebda0 authored by Archie Pusaka's avatar Archie Pusaka
Browse files

floss: Send ACL connection state metrics

This is called upon ACL connection and disconnection, recording the
status, direction, and initiator of the transaction.

One caveat in Floss is that we don't know the transport to be used
(classic | le) on initiating a connection, therefore we don't
immediately report the "connecting" event, but rather group it
together with the "connected" event, where the transport is conveyed
to floss.

For symmetry simplicity, that is done as well for disconnection.

Bug: 240782154
Tag: #floss
Test: Verify the ACL send metric message is correctly logged
BYPASS_LONG_LINES_REASON: Bluetooth likes 120 lines

Change-Id: I564b0f7be2addf7ce33be2efe8946eecc33fb3de
parent 5c8aec51
Loading
Loading
Loading
Loading
+77 −0
Original line number Diff line number Diff line
@@ -207,5 +207,82 @@ void LogMetricsProfileConnectionStateChanged(RawAddress* addr, uint32_t profile,
      .Record();
}

void LogMetricsAclConnectAttempt(RawAddress* addr, uint32_t acl_state) {
  int64_t boot_time = bluetooth::common::time_get_os_boottime_us();
  std::string addr_string = addr->ToString();

  // At this time we don't know the transport layer, therefore pending on sending the event
  PendingAclConnectAttemptEvent(addr_string, boot_time, acl_state);
}

void LogMetricsAclConnectionStateChanged(
    RawAddress* addr,
    uint32_t transport,
    uint32_t acl_status,
    uint32_t acl_state,
    uint32_t direction,
    uint32_t hci_reason) {
  int64_t boot_time;
  std::string addr_string;
  std::string boot_id;
  bool attempt_found;
  AclConnectionEvent event;

  boot_time = bluetooth::common::time_get_os_boottime_us();
  addr_string = addr->ToString();

  event = ToAclConnectionEvent(addr_string, boot_time, acl_status, acl_state, direction, hci_reason);

  if (!GetBootId(&boot_id)) {
    return;
  }

  LOG_DEBUG(
      "AclConnectionStateChanged: %s, %d, %s, %d, %d, %d, %d, %d",
      boot_id.c_str(),
      event.start_time,
      addr_string.c_str(),
      transport,
      event.direction,
      event.initiator,
      event.state,
      event.start_status);

  ::metrics::structured::events::bluetooth::BluetoothAclConnectionStateChanged()
      .SetBootId(boot_id)
      .SetSystemTime(event.start_time)
      .SetIsFloss(true)
      .SetDeviceId(addr_string)
      .SetDeviceType(transport)
      .SetConnectionDirection(event.direction)
      .SetConnectionInitiator(event.initiator)
      .SetStateChangeType(event.state)
      .SetAclConnectionState(event.start_status)
      .Record();

  LOG_DEBUG(
      "AclConnectionStateChanged: %s, %d, %s, %d, %d, %d, %d, %d",
      boot_id.c_str(),
      boot_time,
      addr_string.c_str(),
      transport,
      event.direction,
      event.initiator,
      event.state,
      event.status);

  ::metrics::structured::events::bluetooth::BluetoothAclConnectionStateChanged()
      .SetBootId(boot_id)
      .SetSystemTime(boot_time)
      .SetIsFloss(true)
      .SetDeviceId(addr_string)
      .SetDeviceType(transport)
      .SetConnectionDirection(event.direction)
      .SetConnectionInitiator(event.initiator)
      .SetStateChangeType(event.state)
      .SetAclConnectionState(event.status)
      .Record();
}

}  // namespace metrics
}  // namespace bluetooth
+117 −0
Original line number Diff line number Diff line
@@ -23,12 +23,17 @@
#include "include/hardware/bt_av.h"
#include "include/hardware/bt_hf.h"
#include "include/hardware/bt_hh.h"
#include "stack/include/hci_error_code.h"

namespace bluetooth {
namespace metrics {

// topshim::btif::BtBondState is a copy of hardware/bluetooth.h:bt_bond_state_t
typedef bt_bond_state_t BtBondState;
// topshim::btif::BtAclState is a copy of hardware/bluetooth.h:bt_acl_state_t
typedef bt_acl_state_t BtAclState;
// topshim::btif::BtConnectionDirection is a copy of hardware/bluetooth.h:bt_conn_direction_t
typedef bt_conn_direction_t BtConnectionDirection;
// topshim::btif::BtStatus is a copy of hardware/bluetooth.h:bt_status_t
typedef bt_status_t BtStatus;
// topshim::profile::a2dp::BtavConnectionState is a copy of hardware/bt_av.h:btav_connection_state_t
@@ -495,5 +500,117 @@ ProfileConnectionEvent ToProfileConnectionEvent(std::string addr, uint32_t profi
  return event;
}

static int64_t ToAclConnectionStatus(uint32_t status, StateChangeType type, uint32_t hci_reason) {
  int64_t state;
  if (StateChangeType::STATE_CHANGE_TYPE_CONNECT == type) {
    switch ((BtStatus)status) {
      case BtStatus::BT_STATUS_SUCCESS:
        state = (int64_t)MetricAclConnectionStatus::ACL_CONN_STATE_SUCCEED;
        break;
      case BtStatus::BT_STATUS_BUSY:
        state = (int64_t)MetricAclConnectionStatus::ACL_CONN_STATE_BUSY;
        break;
      case BtStatus::BT_STATUS_DONE:
        state = (int64_t)MetricAclConnectionStatus::ACL_CONN_STATE_ALREADY;
        break;
      case BtStatus::BT_STATUS_UNSUPPORTED:
        state = (int64_t)MetricAclConnectionStatus::ACL_CONN_STATE_NOT_SUPPORTED;
        break;
      case BtStatus::BT_STATUS_PARM_INVALID:
        state = (int64_t)MetricAclConnectionStatus::ACL_CONN_STATE_INVALID_PARAMS;
        break;
      case BtStatus::BT_STATUS_AUTH_FAILURE:
        state = (int64_t)MetricAclConnectionStatus::ACL_CONN_STATE_AUTH_FAILED;
        break;
      case BtStatus::BT_STATUS_RMT_DEV_DOWN:
        state = (int64_t)MetricAclConnectionStatus::ACL_CONN_STATE_DISCONNECTED;
        break;
      case BtStatus::BT_STATUS_AUTH_REJECTED:
      case BtStatus::BT_STATUS_FAIL:
      case BtStatus::BT_STATUS_NOT_READY:
      case BtStatus::BT_STATUS_NOMEM:
      case BtStatus::BT_STATUS_UNHANDLED:
      default:
        state = (int64_t)MetricAclConnectionStatus::ACL_CONN_STATE_UNKNOWN;
        break;
    }
  } else {
    switch (hci_reason) {
      case HCI_ERR_CONNECTION_TOUT:
        state = (int64_t)MetricAclDisconnectionStatus::ACL_DISCONN_STATE_TIMEOUT;
        break;
      case HCI_ERR_PEER_USER:
      case HCI_ERR_REMOTE_LOW_RESOURCE:
      case HCI_ERR_REMOTE_POWER_OFF:
        state = (int64_t)MetricAclDisconnectionStatus::ACL_DISCONN_STATE_REMOTE;
        break;
      case HCI_ERR_CONN_CAUSE_LOCAL_HOST:
        state = (int64_t)MetricAclDisconnectionStatus::ACL_DISCONN_STATE_LOCAL_HOST;
        // TODO: distinguish from ACL_DISCONN_STATE_LOCAL_HOST_SUSPEND
        break;
      case HCI_ERR_AUTH_FAILURE:
      case HCI_ERR_KEY_MISSING:
      case HCI_ERR_HOST_REJECT_SECURITY:
        state = (int64_t)MetricAclDisconnectionStatus::ACL_DISCONN_STATE_AUTH_FAILURE;
        break;
      default:
        state = (int64_t)MetricAclDisconnectionStatus::ACL_DISCONN_STATE_UNKNOWN;
        break;
    }
  }

  return state;
}

// pending acl conn event is map<addr, pair<state, time>>
static std::map<std::string, std::pair<uint32_t, int64_t>> pending_acl_events;

void PendingAclConnectAttemptEvent(std::string addr, int64_t time, uint32_t acl_state) {
  pending_acl_events[addr] = std::make_pair(acl_state, time);
}

AclConnectionEvent ToAclConnectionEvent(
    std::string addr, int64_t time, uint32_t acl_status, uint32_t acl_state, uint32_t direction, uint32_t hci_reason) {
  AclConnectionEvent event;

  if (pending_acl_events.find(addr) == pending_acl_events.end()) {
    // No attempt found! Assume initiated by system.
    event.initiator = (int64_t)MetricAclConnectionInitiator::ACL_CONNECTION_INITIATOR_SYSTEM;
    event.direction = direction;
    event.start_time = time;

    // There is no failed disconnection. Therefore on failure, assume it's a connection attempt.
    if (acl_state == (uint32_t)BtAclState::BT_ACL_STATE_CONNECTED ||
        acl_status != (uint32_t)BtStatus::BT_STATUS_SUCCESS) {
      event.state = (int64_t)StateChangeType::STATE_CHANGE_TYPE_CONNECT;
    } else {
      event.state = (int64_t)StateChangeType::STATE_CHANGE_TYPE_DISCONNECT;
    }
  } else {
    // connection attempt found. Assume initiated by client.
    std::pair<uint32_t, int64_t> pending_event = pending_acl_events[addr];
    pending_acl_events.erase(addr);
    event.initiator = (int64_t)MetricAclConnectionInitiator::ACL_CONNECTION_INITIATOR_CLIENT;
    event.direction = (int64_t)MetricAclConnectionDirection::ACL_CONNECTION_OUTGOING;
    event.start_time = pending_event.second;

    if (pending_event.first == (uint32_t)BtAclState::BT_ACL_STATE_CONNECTED) {
      event.state = (int64_t)StateChangeType::STATE_CHANGE_TYPE_CONNECT;
    } else {
      event.state = (int64_t)StateChangeType::STATE_CHANGE_TYPE_DISCONNECT;
    }
  }

  if (event.state == (int64_t)StateChangeType::STATE_CHANGE_TYPE_CONNECT) {
    event.start_status = (int64_t)MetricAclConnectionStatus::ACL_CONN_STATE_STARTING;
  } else {
    event.start_status = (int64_t)MetricAclDisconnectionStatus::ACL_DISCONN_STATE_STARTING;
  }

  event.status = ToAclConnectionStatus(acl_status, (StateChangeType)event.state, hci_reason);

  return event;
}

}  // namespace metrics
}  // namespace bluetooth
 No newline at end of file
+75 −4
Original line number Diff line number Diff line
@@ -98,10 +98,9 @@ enum class Profile : int64_t {
  PHONEHUB = 12,
};

// ENUM definition for profile connection state that in sync with ChromeOS structured metrics
// ENUM definition for profile connection status that in sync with ChromeOS structured metrics
// MetricProfileConnectionStatus and BlueZ's metrics_profile_conn_state.
enum class MetricProfileConnectionStatus : int64_t {
  // Common states for connecting and disconnecting a profile
  PROFILE_CONN_STATE_STARTING = 0,
  PROFILE_CONN_STATE_SUCCEED = 1,
  PROFILE_CONN_STATE_ALREADY_CONNECTED = 2,
@@ -114,10 +113,9 @@ enum class MetricProfileConnectionStatus : int64_t {

};

// ENUM definition for profile disconnection state that in sync with ChromeOS structured metrics
// ENUM definition for profile disconnection status that in sync with ChromeOS structured metrics
// MetricProfileDisconnectionStatus and BlueZ's metrics_profile_disconn_state.
enum class MetricProfileDisconnectionStatus : int64_t {
  // Common states for connecting and disconnecting a profile
  PROFILE_DISCONN_STATE_STARTING = 0,
  PROFILE_DISCONN_STATE_SUCCEED = 1,
  PROFILE_DISCONN_STATE_ALREADY_DISCONNECTED = 2,
@@ -129,9 +127,65 @@ enum class MetricProfileDisconnectionStatus : int64_t {
  PROFILE_DISCONN_STATE_UNKNOWN_ERROR = 8,
};

// ENUM definition for ACL connection status that in sync with ChromeOS structured metrics
// MetricAclConnectionStatus and BlueZ's metrics_conn_state.
enum class MetricAclConnectionStatus : int64_t {
  ACL_CONN_STATE_STARTING = 0,
  ACL_CONN_STATE_SUCCEED = 1,
  ACL_CONN_STATE_ALREADY = 2,
  ACL_CONN_STATE_BUSY = 3,
  ACL_CONN_STATE_NONPOWERED = 4,
  ACL_CONN_STATE_TIMEOUT = 5,
  ACL_CONN_STATE_PROFILE_UNAVAILABLE = 6,
  ACL_CONN_STATE_NOT_CONNECTED = 7,
  ACL_CONN_STATE_NOT_PERMITTED = 8,
  ACL_CONN_STATE_INVALID_PARAMS = 9,
  ACL_CONN_STATE_CONNECTION_REFUSED = 10,
  ACL_CONN_STATE_CANCELED = 11,
  ACL_CONN_STATE_EVENT_INVALID = 12,
  ACL_CONN_STATE_DEVICE_NOT_FOUND = 13,
  ACL_CONN_STATE_BT_IO_CONNECT_ERROR = 14,
  ACL_CONN_STATE_UNKNOWN_COMMAND = 15,
  ACL_CONN_STATE_DISCONNECTED = 16,
  ACL_CONN_STATE_CONNECT_FAILED = 17,
  ACL_CONN_STATE_NOT_SUPPORTED = 18,
  ACL_CONN_STATE_NO_RESOURCES = 19,
  ACL_CONN_STATE_AUTH_FAILED = 20,
  ACL_CONN_STATE_FAILED = 21,
  ACL_CONN_STATE_UNKNOWN = 22,
};

// ENUM definition for ACL disconnection status that in sync with ChromeOS structured metrics
// MetricAclDisconnectionStatus and BlueZ's metrics_disconn_state.
enum class MetricAclDisconnectionStatus : int64_t {
  ACL_DISCONN_STATE_STARTING = 0,
  ACL_DISCONN_STATE_TIMEOUT = 1,
  ACL_DISCONN_STATE_LOCAL_HOST = 2,
  ACL_DISCONN_STATE_REMOTE = 3,
  ACL_DISCONN_STATE_AUTH_FAILURE = 4,
  ACL_DISCONN_STATE_LOCAL_HOST_SUSPEND = 5,
  ACL_DISCONN_STATE_UNKNOWN = 6,
};

// A binary ENUM defines the metrics event is logged for: either for an attempt to connect or to disconnect.
enum class StateChangeType : int64_t { STATE_CHANGE_TYPE_DISCONNECT = 0, STATE_CHANGE_TYPE_CONNECT = 1 };

// ENUM definition for ACL disconnection status that in sync with ChromeOS structured metrics
// MetricAclConnectionDirection and BlueZ's metrics_acl_connection_direction.
enum class MetricAclConnectionDirection : int64_t {
  ACL_CONNECTION_DIRECTION_UNKNOWN = 0,
  ACL_CONNECTION_OUTGOING = 1,
  ACL_CONNECTION_INCOMING = 2,
};

// ENUM definition for ACL disconnection status that in sync with ChromeOS structured metrics
// MetricAclConnectionInitiator and BlueZ's metrics_acl_connection_initiator.
enum class MetricAclConnectionInitiator : int64_t {
  ACL_CONNECTION_INITIATOR_UNKNOWN = 0,
  ACL_CONNECTION_INITIATOR_CLIENT = 1,
  ACL_CONNECTION_INITIATOR_SYSTEM = 2,
};

// A struct holds the parsed profile connection event.
struct ProfileConnectionEvent {
  int64_t type;
@@ -151,5 +205,22 @@ PairingState ToPairingState(uint32_t status, uint32_t bond_state, int32_t fail_r
// Convert Floss profile connection info to ProfileConnectionEvent
ProfileConnectionEvent ToProfileConnectionEvent(std::string addr, uint32_t profile, uint32_t status, uint32_t state);

// A struct holds the parsed ACL connection event.
struct AclConnectionEvent {
  int64_t start_time;
  int64_t state;
  int64_t initiator;
  int64_t direction;
  int64_t start_status;
  int64_t status;
};

// Initialize a (dis)connection attempt event.
void PendingAclConnectAttemptEvent(std::string addr, int64_t time, uint32_t acl_state);

// Convert Floss ACL connection info to AclConnectionEvent.
AclConnectionEvent ToAclConnectionEvent(
    std::string addr, int64_t time, uint32_t acl_status, uint32_t acl_state, uint32_t direction, uint32_t hci_reason);

}  // namespace metrics
}  // namespace bluetooth
+10 −0
Original line number Diff line number Diff line
@@ -39,5 +39,15 @@ void LogMetricsDeviceInfoReport(

void LogMetricsProfileConnectionStateChanged(RawAddress* addr, uint32_t profile, uint32_t status, uint32_t state) {}

void LogMetricsAclConnectAttempt(RawAddress* addr, uint32_t acl_state) {}

void LogMetricsAclConnectionStateChanged(
    RawAddress* addr,
    uint32_t transport,
    uint32_t status,
    uint32_t acl_state,
    uint32_t direction,
    uint32_t hci_reason) {}

}  // namespace metrics
}  // namespace bluetooth
+3 −0
Original line number Diff line number Diff line
@@ -36,6 +36,9 @@ void LogMetricsDeviceInfoReport(
    uint32_t product_id,
    uint32_t version);
void LogMetricsProfileConnectionStateChanged(RawAddress* addr, uint32_t profile, uint32_t status, uint32_t state);
void LogMetricsAclConnectAttempt(RawAddress* addr, uint32_t acl_state);
void LogMetricsAclConnectionStateChanged(
    RawAddress* addr, uint32_t transport, uint32_t status, uint32_t acl_state, uint32_t direction, uint32_t hci_reason);

}  // namespace metrics
}  // namespace bluetooth
Loading