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

Commit f2e9257b authored by Michael Sun's avatar Michael Sun
Browse files

floss: metrics: HID profiles connection state handling

Route the HID/HOG (dis)connect requests and states to the metrics
processing unit. Then, parse the HID/HOG connection event into
structured metrics compatible format.

BUG: 240781725
Tag: #floss
Test: emerge-${BOARD} floss
BYPASS_LONG_LINES_REASON: Bluetooth likes 120 lines

Change-Id: I1a3317841f95325cb5880004a7c91290e85e2ad1
parent 7acdbab0
Loading
Loading
Loading
Loading
+72 −6
Original line number Original line Diff line number Diff line
@@ -15,19 +15,22 @@
 */
 */
#include "gd/metrics/chromeos/metrics_event.h"
#include "gd/metrics/chromeos/metrics_event.h"


#include <map>
#include <utility>
#include <utility>


#include "hci/hci_packets.h"
#include "hci/hci_packets.h"
#include "include/hardware/bluetooth.h"
#include "include/hardware/bluetooth.h"
#include "include/hardware/bt_hh.h"


namespace bluetooth {
namespace bluetooth {
namespace metrics {
namespace metrics {


// topshim::btif::BtBondState is a copy of hardware/bluetooth.h/bt_bond_state_t
// topshim::btif::BtBondState is a copy of hardware/bluetooth.h:bt_bond_state_t
typedef bt_bond_state_t BtBondState;
typedef bt_bond_state_t BtBondState;

// topshim::btif::BtStatus is a copy of hardware/bluetooth.h:bt_status_t
// topshim::btif::BtStatus is a copy of hardware/bluetooth.h/bt_bond_state_t
typedef bt_status_t BtStatus;
typedef bt_status_t BtStatus;
// topshim::profile::hid_host::BthhConnectionState is a copy of hardware/bluetooth.h:bthh_connection_state_t
typedef bthh_connection_state_t BthhConnectionState;


// A normalized connection state ENUM definition all profiles
// A normalized connection state ENUM definition all profiles
enum class ProfilesConnectionState {
enum class ProfilesConnectionState {
@@ -298,8 +301,27 @@ static std::pair<uint32_t, uint32_t> ToProfileConnectionState(uint32_t profile,
    // case ProfilesFloss::AvrcpController:
    // case ProfilesFloss::AvrcpController:
    // case ProfilesFloss::AvrcpTarget:
    // case ProfilesFloss::AvrcpTarget:
    // case ProfilesFloss::ObexObjectPush:
    // case ProfilesFloss::ObexObjectPush:
    // case ProfilesFloss::Hid:
    case ProfilesFloss::Hid:
    // case ProfilesFloss::Hogp:
    case ProfilesFloss::Hogp:
      output.first = (uint32_t)Profile::HID;
      switch ((BthhConnectionState)state) {
        case BthhConnectionState::BTHH_CONN_STATE_CONNECTED:
          output.second = (uint32_t)ProfilesConnectionState::CONNECTED;
          break;
        case BthhConnectionState::BTHH_CONN_STATE_CONNECTING:
          output.second = (uint32_t)ProfilesConnectionState::CONNECTING;
          break;
        case BthhConnectionState::BTHH_CONN_STATE_DISCONNECTED:
          output.second = (uint32_t)ProfilesConnectionState::DISCONNECTED;
          break;
        case BthhConnectionState::BTHH_CONN_STATE_DISCONNECTING:
          output.second = (uint32_t)ProfilesConnectionState::DISCONNECTING;
          break;
        case BthhConnectionState::BTHH_CONN_STATE_UNKNOWN:
          output.second = (uint32_t)ProfilesConnectionState::UNKNOWN;
          break;
      }
      break;
    // case ProfilesFloss::Panu:
    // case ProfilesFloss::Panu:
    // case ProfilesFloss::Nap:
    // case ProfilesFloss::Nap:
    // case ProfilesFloss::Bnep:
    // case ProfilesFloss::Bnep:
@@ -325,7 +347,51 @@ static std::pair<uint32_t, uint32_t> ToProfileConnectionState(uint32_t profile,
}
}


ProfileConnectionEvent ToProfileConnectionEvent(std::string addr, uint32_t profile, uint32_t status, uint32_t state) {
ProfileConnectionEvent ToProfileConnectionEvent(std::string addr, uint32_t profile, uint32_t status, uint32_t state) {
  return ProfileConnectionEvent();
  ProfileConnectionEvent event;
  // A map stores the pending StateChangeType used to match a (dis)connection event with unknown type.
  // map<std::pair<address, profile>, type>
  static std::map<std::pair<std::string, uint32_t>, StateChangeType> pending_type;

  auto profile_state_pair = ToProfileConnectionState(profile, state);
  auto key = std::make_pair(addr, profile_state_pair.first);
  event.profile = (int64_t)profile_state_pair.first;

  switch ((ProfilesConnectionState)profile_state_pair.second) {
    case ProfilesConnectionState::CONNECTED:
      event.type = (int64_t)StateChangeType::STATE_CHANGE_TYPE_CONNECT;
      event.state = (int64_t)MetricProfileConnectionStatus::PROFILE_CONN_STATE_SUCCEED;
      pending_type.erase(key);
      break;
    case ProfilesConnectionState::CONNECTING:
      event.type = (int64_t)StateChangeType::STATE_CHANGE_TYPE_CONNECT;
      event.state = (int64_t)MetricProfileConnectionStatus::PROFILE_CONN_STATE_STARTING;
      pending_type[key] = StateChangeType::STATE_CHANGE_TYPE_CONNECT;
      break;
    case ProfilesConnectionState::DISCONNECTED:
      event.type = pending_type.find(key) != pending_type.end()
                       ? (int64_t)pending_type[key]
                       : (int64_t)StateChangeType::STATE_CHANGE_TYPE_DISCONNECT;
      // If the profile successfully disconnected for a connect intent, i.e., a connection is attempted but received a
      // disconnection state update. Report this as an unknown error.
      if (StateChangeType::STATE_CHANGE_TYPE_CONNECT == (StateChangeType)event.type &&
          BtStatus::BT_STATUS_SUCCESS == (BtStatus)status) {
        event.state = (int64_t)MetricProfileConnectionStatus::PROFILE_CONN_STATE_UNKNOWN_ERROR;
      } else {
        event.state = StatusToProfileConnectionState(status, (StateChangeType)event.type);
      }
      pending_type.erase(key);
      break;
    case ProfilesConnectionState::DISCONNECTING:
      event.type = (int64_t)StateChangeType::STATE_CHANGE_TYPE_DISCONNECT;
      event.state = (int64_t)MetricProfileDisconnectionStatus::PROFILE_DISCONN_STATE_STARTING;
      pending_type[key] = StateChangeType::STATE_CHANGE_TYPE_DISCONNECT;
      break;
    default:
      event.profile = (int64_t)Profile::UNKNOWN;
      break;
  }

  return event;
}
}


}  // namespace metrics
}  // namespace metrics
+40 −2
Original line number Original line Diff line number Diff line
@@ -33,7 +33,7 @@ use tokio::time;


use crate::bluetooth_media::{BluetoothMedia, IBluetoothMedia, MediaActions};
use crate::bluetooth_media::{BluetoothMedia, IBluetoothMedia, MediaActions};
use crate::callbacks::Callbacks;
use crate::callbacks::Callbacks;
use crate::uuid::{Profile, UuidHelper};
use crate::uuid::{Profile, UuidHelper, HOGP};
use crate::{Message, RPCProxy};
use crate::{Message, RPCProxy};


const DEFAULT_DISCOVERY_TIMEOUT_MS: u64 = 12800;
const DEFAULT_DISCOVERY_TIMEOUT_MS: u64 = 12800;
@@ -1512,7 +1512,22 @@ impl IBluetooth for Bluetooth {
                    if self.uuid_helper.is_profile_enabled(&p) {
                    if self.uuid_helper.is_profile_enabled(&p) {
                        match p {
                        match p {
                            Profile::Hid | Profile::Hogp => {
                            Profile::Hid | Profile::Hogp => {
                                self.hh.as_ref().unwrap().connect(&mut addr.unwrap());
                                let status = self.hh.as_ref().unwrap().connect(&mut addr.unwrap());
                                metrics::profile_connection_state_changed(
                                    addr.unwrap(),
                                    *p as u32,
                                    BtStatus::Success,
                                    BthhConnectionState::Connecting as u32,
                                );

                                if status != BtStatus::Success {
                                    metrics::profile_connection_state_changed(
                                        addr.unwrap(),
                                        *p as u32,
                                        status,
                                        BthhConnectionState::Disconnected as u32,
                                    );
                                }
                            }
                            }


                            Profile::A2dpSink | Profile::A2dpSource | Profile::Hfp => {
                            Profile::A2dpSink | Profile::A2dpSource | Profile::Hfp => {
@@ -1606,6 +1621,29 @@ impl BtifSdpCallbacks for Bluetooth {
impl BtifHHCallbacks for Bluetooth {
impl BtifHHCallbacks for Bluetooth {
    fn connection_state(&mut self, address: RawAddress, state: BthhConnectionState) {
    fn connection_state(&mut self, address: RawAddress, state: BthhConnectionState) {
        debug!("Hid host connection state updated: Address({:?}) State({:?})", address, state);
        debug!("Hid host connection state updated: Address({:?}) State({:?})", address, state);

        // HID or HOG is not differentiated by the hid host when callback this function. Assume HOG
        // if the device is LE only and HID if classic only. And assume HOG if UUID said so when
        // device type is dual or unknown.
        let device = BluetoothDevice::new(address.to_string(), "".to_string());
        let profile = match self.get_remote_type(device.clone()) {
            BtDeviceType::Ble => Profile::Hogp,
            BtDeviceType::Bredr => Profile::Hid,
            _ => {
                if self.get_remote_uuids(device).contains(&UuidHelper::from_string(HOGP).unwrap()) {
                    Profile::Hogp
                } else {
                    Profile::Hid
                }
            }
        };

        metrics::profile_connection_state_changed(
            address,
            profile as u32,
            BtStatus::Success,
            state as u32,
        );
    }
    }


    fn hid_info(&mut self, address: RawAddress, info: BthhHidInfo) {
    fn hid_info(&mut self, address: RawAddress, info: BthhHidInfo) {