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

Commit fc19f134 authored by Ray Kuo's avatar Ray Kuo
Browse files

BQR: Add Bluetooth Quality Report v2 feature

The BQR is designed to be separated into two parts, one is for the
stack/framework to be aware/handle (Quality_Event_Mask bit 0 ~ 15, event
triggering) and another one is the stack/framework does not need to
handle further (Quality_Event_Mask bit 16 ~ 31).

The BQR v2 adds four new events:
Bit 4 - Root Inflammation:
When the controller encounters an error it shall report Root
Inflammation event indicating the error code to the host.

Bit 16 - LMP/LL message trace:
The controller sends the LMP/LL message handshaking with the remote
device to the host.

Bit 17 - Bluetooth Multi-profile/Coex scheduling trace:
The controller sends its scheduling information on handling the
Bluetooth multiple profiles and wireless coexistence in the 2.4 Ghz band
to the host.

Bit 18 - Enable the Controller Debug Information mechanism:
After enabling the Controller Debug Information mechanism, the
controller just can autonomously report debug logging information via
the controller Debug Info sub-event to the host.

Bug: 136079361
Test: Verified four new added events.
Change-Id: Ie393606143f0158fbcc607e1f41ceceb00abd461
parent 3057c398
Loading
Loading
Loading
Loading
+181 −67
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@

#include "btm_api_types.h"
#include "common/leaky_bonded_queue.h"
#include "osi/include/osi.h"

namespace bluetooth {
namespace bqr {
@@ -44,6 +45,25 @@ namespace bqr {
//   [(e)SCO Voice Choppy]
//     When the controller detects the factors which will cause voice choppy,
//     the controller shall report (e)SCO Voice Choppy event to the host.
//
//   [Root Inflammation]
//     When the controller encounters an error it shall report Root Inflammation
//     event indicating the error code to the host.
//
//   [LMP/LL message trace]
//     The controller sends the LMP/LL message handshaking with the remote
//     device to the host.
//
//   [Bluetooth Multi-profile/Coex scheduling trace]
//     The controller sends its scheduling information on handling the Bluetooth
//     multiple profiles and wireless coexistence in the 2.4 Ghz band to the
//     host.
//
//   [Enable the Controller Debug Information mechanism]
//     After enabling the Controller Debug Information mechanism, the controller
//     just can autonomously report debug logging information via the Controller
//     Debug Info sub-event to the host.
//

// Bit masks for the selected quality event reporting.
static constexpr uint32_t kQualityEventMaskAllOff = 0;
@@ -51,33 +71,64 @@ static constexpr uint32_t kQualityEventMaskMonitorMode = 0x00000001;
static constexpr uint32_t kQualityEventMaskApproachLsto = 0x00000002;
static constexpr uint32_t kQualityEventMaskA2dpAudioChoppy = 0x00000004;
static constexpr uint32_t kQualityEventMaskScoVoiceChoppy = 0x00000008;
static constexpr uint32_t kQualityEventMaskRootInflammation = 0x00000010;
static constexpr uint32_t kQualityEventMaskLmpMessageTrace = 0x00010000;
static constexpr uint32_t kQualityEventMaskBtSchedulingTrace = 0x00020000;
static constexpr uint32_t kQualityEventMaskControllerDbgInfo = 0x00040000;
static constexpr uint32_t kQualityEventMaskAll =
    kQualityEventMaskMonitorMode | kQualityEventMaskApproachLsto |
    kQualityEventMaskA2dpAudioChoppy | kQualityEventMaskScoVoiceChoppy;
    kQualityEventMaskA2dpAudioChoppy | kQualityEventMaskScoVoiceChoppy |
    kQualityEventMaskRootInflammation | kQualityEventMaskLmpMessageTrace |
    kQualityEventMaskBtSchedulingTrace | kQualityEventMaskControllerDbgInfo;
// Define the minimum time interval (in ms) of quality event reporting for the
// selected quality event(s). Controller Firmware should not report the next
// event within the defined time interval.
static constexpr uint16_t kMinReportIntervalNoLimit = 0;
static constexpr uint16_t kMinReportIntervalMaxMs = 0xFFFF;
// Total length of all BQR parameters except Vendor Specific Parameters.
static constexpr uint8_t kBqrParamTotalLen = 48;
// The maximum count of Log Dump related event can be written in the log file.
static constexpr uint16_t kLogDumpEventPerFile = 0x00FF;
// Total length of all parameters of the link Quality related event except
// Vendor Specific Parameters.
static constexpr uint8_t kLinkQualityParamTotalLen = 48;
// Total length of all parameters of the ROOT_INFLAMMATION event except Vendor
// Specific Parameters.
static constexpr uint8_t kRootInflammationParamTotalLen = 3;
// Total length of all parameters of the Log Dump related event except Vendor
// Specific Parameters.
static constexpr uint8_t kLogDumpParamTotalLen = 3;
// Warning criteria of the RSSI value.
static constexpr int8_t kCriWarnRssi = -80;
// Warning criteria of the unused AFH channel count.
static constexpr uint8_t kCriWarnUnusedCh = 55;
// The queue size of recording the BQR events.
static constexpr uint8_t kBqrEventQueueSize = 25;
// The minimum size of the ROOT_INFLAMMATION event
// HCI_VENDOR_SPECIFIC_EVT(1) + BQR sub event(1) + BQR report ID(1) +
// error code(1) + vendor error code(1) = 5
static constexpr uint8_t kRootInflammationPacketMinSize = 5;

// The Property of BQR event mask configuration.
static constexpr const char* kpPropertyEventMask =
    "persist.bluetooth.bqr.event_mask";
// The Property of BQR minimum report interval configuration.
static constexpr const char* kpPropertyMinReportIntervalMs =
    "persist.bluetooth.bqr.min_interval_ms";
// Path of the LMP/LL message trace log file.
static constexpr const char* kpLmpLlMessageTraceLogPath =
    "/data/misc/bluetooth/logs/lmp_ll_message_trace.log";
// Path of the last LMP/LL message trace log file.
static constexpr const char* kpLmpLlMessageTraceLastLogPath =
    "/data/misc/bluetooth/logs/lmp_ll_message_trace.log.last";
// Path of the Bluetooth Multi-profile/Coex scheduling trace log file.
static constexpr const char* kpBtSchedulingTraceLogPath =
    "/data/misc/bluetooth/logs/bt_scheduling_trace.log";
// Path of the last Bluetooth Multi-profile/Coex scheduling trace log file.
static constexpr const char* kpBtSchedulingTraceLastLogPath =
    "/data/misc/bluetooth/logs/bt_scheduling_trace.log.last";

// File Descriptor of LMP/LL message trace log
static int LmpLlMessageTraceLogFd = INVALID_FD;
// File Descriptor of Bluetooth Multi-profile/Coex scheduling trace log
static int BtSchedulingTraceLogFd = INVALID_FD;
// Counter of LMP/LL message trace
static uint16_t LmpLlMessageTraceCounter = 0;
// Counter of Bluetooth Multi-profile/Coex scheduling trace
static uint16_t BtSchedulingTraceCounter = 0;

// Action definition
//
@@ -96,7 +147,10 @@ enum BqrQualityReportId : uint8_t {
  QUALITY_REPORT_ID_APPROACH_LSTO = 0x02,
  QUALITY_REPORT_ID_A2DP_AUDIO_CHOPPY = 0x03,
  QUALITY_REPORT_ID_SCO_VOICE_CHOPPY = 0x04,
  QUALITY_REPORT_ID_ROOT_INFLAMMATION = 0x05
  QUALITY_REPORT_ID_ROOT_INFLAMMATION = 0x05,
  QUALITY_REPORT_ID_LMP_LL_MESSAGE_TRACE = 0x11,
  QUALITY_REPORT_ID_BT_SCHEDULING_TRACE = 0x12,
  QUALITY_REPORT_ID_CONTROLLER_DBG_INFO = 0x13
};

// Packet Type definition
@@ -138,77 +192,106 @@ typedef struct {
  uint16_t minimum_report_interval_ms;
} BqrConfiguration;

// BQR sub-event of Vendor Specific Event
class BqrVseSubEvt {
 public:
  // Parse the Bluetooth Quality Report VSE sub-event.
  //
  // @param length Total length of all parameters contained in the sub-event.
  // @param p_param_buf A pointer to the parameters contained in the sub-event.
  // @return false If the parameter total length is abnormal.
  //         true If all parameters are parsed successfully.
  bool ParseBqrEvt(uint8_t length, uint8_t* p_param_buf);

  // Get a string representation of the Bluetooth Quality event.
  //
  // @return a string representation of the Bluetooth Quality event.
  std::string ToString() const;

  friend std::ostream& operator<<(std::ostream& os, const BqrVseSubEvt& a) {
    return os << a.ToString();
  }

  virtual ~BqrVseSubEvt() = default;

// Link quality related BQR event
typedef struct {
  // Quality report ID.
  uint8_t quality_report_id_ = 0;
  uint8_t quality_report_id;
  // Packet type of the connection.
  uint8_t packet_types_ = 0;
  uint8_t packet_types;
  // Connection handle of the connection.
  uint16_t connection_handle_ = 0;
  uint16_t connection_handle;
  // Performing Role for the connection.
  uint8_t connection_role_ = 0;
  uint8_t connection_role;
  // Current Transmit Power Level for the connection. This value is the same as
  // the controller's response to the HCI_Read_Transmit_Power_Level HCI command.
  uint8_t tx_power_level_ = 0;
  uint8_t tx_power_level;
  // Received Signal Strength Indication (RSSI) value for the connection. This
  // value is an absolute receiver signal strength value.
  int8_t rssi_ = 0;
  int8_t rssi;
  // Signal-to-Noise Ratio (SNR) value for the connection. It is the average
  // SNR of all the channels used by the link currently.
  uint8_t snr_ = 0;
  uint8_t snr;
  // Indicates the number of unused channels in AFH_channel_map.
  uint8_t unused_afh_channel_count_ = 0;
  uint8_t unused_afh_channel_count;
  // Indicates the number of the channels which are interfered and quality is
  // bad but are still selected for AFH.
  uint8_t afh_select_unideal_channel_count_ = 0;
  uint8_t afh_select_unideal_channel_count;
  // Current Link Supervision Timeout Setting.
  // Unit: N * 0.3125 ms (1 Bluetooth Clock)
  uint16_t lsto_ = 0;
  uint16_t lsto;
  // Piconet Clock for the specified Connection_Handle. This value is the same
  // as the controller's response to HCI_Read_Clock HCI command with the
  // parameter "Which_Clock" of 0x01 (Piconet Clock).
  // Unit: N * 0.3125 ms (1 Bluetooth Clock)
  uint32_t connection_piconet_clock_ = 0;
  uint32_t connection_piconet_clock;
  // The count of retransmission.
  uint32_t retransmission_count_ = 0;
  uint32_t retransmission_count;
  // The count of no RX.
  uint32_t no_rx_count_ = 0;
  uint32_t no_rx_count;
  // The count of NAK (Negative Acknowledge).
  uint32_t nak_count_ = 0;
  uint32_t nak_count;
  // Timestamp of last TX ACK.
  // Unit: N * 0.3125 ms (1 Bluetooth Clock)
  uint32_t last_tx_ack_timestamp_ = 0;
  uint32_t last_tx_ack_timestamp;
  // The count of Flow-off (STOP).
  uint32_t flow_off_count_ = 0;
  uint32_t flow_off_count;
  // Timestamp of last Flow-on (GO).
  // Unit: N * 0.3125 ms (1 Bluetooth Clock)
  uint32_t last_flow_on_timestamp_ = 0;
  uint32_t last_flow_on_timestamp;
  // Buffer overflow count (how many bytes of TX data are dropped) since the
  // last event.
  uint32_t buffer_overflow_bytes_ = 0;
  uint32_t buffer_overflow_bytes;
  // Buffer underflow count (in byte).
  uint32_t buffer_underflow_bytes_ = 0;
  uint32_t buffer_underflow_bytes;
  // For the controller vendor to obtain more vendor specific parameters.
  uint8_t* vendor_specific_parameter;
} BqrLinkQualityEvent;

// Log dump related BQR event
typedef struct {
  // Quality report ID.
  uint8_t quality_report_id;
  // Connection handle of the connection.
  uint16_t connection_handle;
  // For the controller vendor to obtain more vendor specific parameters.
  uint8_t* vendor_specific_parameter;
} BqrLogDumpEvent;

// BQR sub-event of Vendor Specific Event
class BqrVseSubEvt {
 public:
  // Parse the Link Quality related BQR event.
  //
  // @param length Total length of all parameters contained in the sub-event.
  // @param p_param_buf A pointer to the parameters contained in the sub-event.
  void ParseBqrLinkQualityEvt(uint8_t length, uint8_t* p_param_buf);
  // Write the LMP/LL message trace to the log file.
  //
  // @param fd The File Descriptor of the log file.
  // @param length Total length of all parameters contained in the sub-event.
  // @param p_param_buf A pointer to the parameters contained in the sub-event.
  void WriteLmpLlTraceLogFile(int fd, uint8_t length, uint8_t* p_param_buf);
  // Write the Bluetooth Multi-profile/Coex scheduling trace to the log file.
  //
  // @param fd The File Descriptor of the log file.
  // @param length Total length of all parameters contained in the sub-event.
  // @param p_param_buf A pointer to the parameters contained in the sub-event.
  void WriteBtSchedulingTraceLogFile(int fd, uint8_t length,
                                     uint8_t* p_param_buf);
  // Get a string representation of the Bluetooth Quality event.
  //
  // @return a string representation of the Bluetooth Quality event.
  std::string ToString() const;

  friend std::ostream& operator<<(std::ostream& os, const BqrVseSubEvt& a) {
    return os << a.ToString();
  }

  virtual ~BqrVseSubEvt() = default;
  // Link Quality related BQR event
  BqrLinkQualityEvent bqr_link_quality_event_ = {};
  // Log Dump related BQR event
  BqrLogDumpEvent bqr_log_dump_event_ = {};
  // Local wall clock timestamp of receiving BQR VSE sub-event
  std::tm tm_timestamp_ = {};
};
@@ -236,23 +319,11 @@ std::string PacketTypeToString(uint8_t packet_type);
//   mechanism in the Bluetooth controller.
void EnableBtQualityReport(bool is_enable);

// Dump Bluetooth Quality Report information.
//
// @param fd The file descriptor to use for dumping information.
void DebugDump(int fd);

// Configure Bluetooth Quality Report setting to the Bluetooth controller.
//
// @param bqr_config The struct of configuration parameters.
void ConfigureBqr(const BqrConfiguration& bqr_config);

// Invoked on completion of Bluetooth Quality Report configuration. Then it will
// Register/Unregister for receiving VSE - Bluetooth Quality Report sub event.
//
// @param current_evt_mask Indicates current quality event bit mask setting in
//   the Bluetooth controller.
void ConfigureBqrCmpl(uint32_t current_evt_mask);

// Callback invoked on completion of vendor specific Bluetooth Quality Report
// command.
//
@@ -260,13 +331,56 @@ void ConfigureBqrCmpl(uint32_t current_evt_mask);
//   specific command complete event.
void BqrVscCompleteCallback(tBTM_VSC_CMPL* p_vsc_cmpl_params);

// Record a new incoming Bluetooth Quality Report in quality event queue.
// Invoked on completion of Bluetooth Quality Report configuration. Then it will
// Register/Unregister for receiving VSE - Bluetooth Quality Report sub-event.
//
// @param current_evt_mask Indicates current quality event bit mask setting in
//   the Bluetooth controller.
void ConfigureBqrCmpl(uint32_t current_evt_mask);

// Categorize the incoming Bluetooth Quality Report.
//
// @param len Lengths of the quality report sent from the Bluetooth
// @param length Lengths of the quality report sent from the Bluetooth
//   controller.
// @param p_quality_report A pointer to the quality report which is sent from
//   the Bluetooth controller via Vendor Specific Event.
void AddBqrEventToQueue(uint8_t length, uint8_t* p_stream);
// @param p_bqr_event A pointer to the BQR VSE sub-event which is sent from the
//   Bluetooth controller.
void CategorizeBqrEvent(uint8_t length, uint8_t* p_bqr_event);

// Record a new incoming Link Quality related BQR event in quality event queue.
//
// @param length Lengths of the Link Quality related BQR event.
// @param p_link_quality_event A pointer to the Link Quality related BQR event.
void AddLinkQualityEventToQueue(uint8_t length, uint8_t* p_link_quality_event);

// Dump the LMP/LL message handshaking with the remote device to a log file.
//
// @param length Lengths of the LMP/LL message trace event.
// @param p_lmp_ll_message_event A pointer to the LMP/LL message trace event.
void DumpLmpLlMessage(uint8_t length, uint8_t* p_lmp_ll_message_event);

// Open the LMP/LL message trace log file.
//
// @return a file descriptor of the LMP/LL message trace log file.
int OpenLmpLlTraceLogFile();

// Dump the Bluetooth Multi-profile/Coex scheduling information to a log file.
//
// @param length Lengths of the Bluetooth Multi-profile/Coex scheduling trace
//   event.
// @param p_bt_scheduling_event A pointer to the Bluetooth Multi-profile/Coex
//   scheduling trace event.
void DumpBtScheduling(uint8_t length, uint8_t* p_bt_scheduling_event);

// Open the Bluetooth Multi-profile/Coex scheduling trace log file.
//
// @return a file descriptor of the Bluetooth Multi-profile/Coex scheduling
//   trace log file.
int OpenBtSchedulingTraceLogFile();

// Dump Bluetooth Quality Report information.
//
// @param fd The file descriptor to use for dumping information.
void DebugDump(int fd);

}  // namespace bqr
}  // namespace bluetooth
+286 −102

File changed.

Preview size limit exceeded, changes collapsed.

+64 −11
Original line number Diff line number Diff line
@@ -139,6 +139,8 @@ static void transmit_fragment(BT_HDR* packet, bool send_transmit_finished);
static void dispatch_reassembled(BT_HDR* packet);
static void fragmenter_transmit_finished(BT_HDR* packet,
                                         bool all_fragments_sent);
static bool filter_bqr_event(int16_t bqr_parameter_length,
                             uint8_t* p_bqr_event);

static const packet_fragmenter_callbacks_t packet_fragmenter_callbacks = {
    transmit_fragment, dispatch_reassembled, fragmenter_transmit_finished};
@@ -689,17 +691,12 @@ static bool filter_incoming_event(BT_HDR* packet) {
      buffer_allocator->free(packet);
      return true;
    } else if (sub_event_code == HCI_VSE_SUBCODE_BQR_SUB_EVT) {
      uint8_t bqr_report_id;
      STREAM_TO_UINT8(bqr_report_id, stream);

      if (bqr_report_id ==
              bluetooth::bqr::QUALITY_REPORT_ID_ROOT_INFLAMMATION &&
          packet->len >= bluetooth::bqr::kRootInflammationPacketMinSize) {
        uint8_t error_code;
        uint8_t vendor_error_code;
        STREAM_TO_UINT8(error_code, stream);
        STREAM_TO_UINT8(vendor_error_code, stream);
        handle_root_inflammation_event(error_code, vendor_error_code);
      // Excluding the HCI Event packet header and 1 octet sub-event code
      int16_t bqr_parameter_length = packet->len - HCIE_PREAMBLE_SIZE - 1;
      // The stream currently points to the BQR sub-event parameters
      if (filter_bqr_event(bqr_parameter_length, stream)) {
        buffer_allocator->free(packet);
        return true;
      }
    }
  }
@@ -774,6 +771,62 @@ static void update_command_response_timer(void) {
  }
}

// Returns true if the BQR event is handled and should not proceed to
// higher layers.
static bool filter_bqr_event(int16_t bqr_parameter_length,
                             uint8_t* p_bqr_event) {
  if (bqr_parameter_length <= 0) {
    LOG(ERROR) << __func__ << ": Invalid parameter length : "
               << std::to_string(bqr_parameter_length);
    return true;
  }

  bool intercepted = false;
  uint8_t quality_report_id = p_bqr_event[0];
  switch (quality_report_id) {
    case bluetooth::bqr::QUALITY_REPORT_ID_ROOT_INFLAMMATION:
      if (bqr_parameter_length >=
          bluetooth::bqr::kRootInflammationParamTotalLen) {
        uint8_t error_code;
        uint8_t vendor_error_code;
        STREAM_TO_UINT8(quality_report_id, p_bqr_event);
        STREAM_TO_UINT8(error_code, p_bqr_event);
        STREAM_TO_UINT8(vendor_error_code, p_bqr_event);
        handle_root_inflammation_event(error_code, vendor_error_code);
      }
      intercepted = true;
      break;

    case bluetooth::bqr::QUALITY_REPORT_ID_LMP_LL_MESSAGE_TRACE:
      if (bqr_parameter_length >= bluetooth::bqr::kLogDumpParamTotalLen) {
        bluetooth::bqr::DumpLmpLlMessage(bqr_parameter_length, p_bqr_event);
      }
      intercepted = true;
      break;

    case bluetooth::bqr::QUALITY_REPORT_ID_BT_SCHEDULING_TRACE:
      if (bqr_parameter_length >= bluetooth::bqr::kLogDumpParamTotalLen) {
        bluetooth::bqr::DumpBtScheduling(bqr_parameter_length, p_bqr_event);
      }
      intercepted = true;
      break;

    case bluetooth::bqr::QUALITY_REPORT_ID_CONTROLLER_DBG_INFO:
      // TODO: Integrate with the HCI_VSE_SUBCODE_DEBUG_INFO_SUB_EVT
      intercepted = true;
      break;

    case bluetooth::bqr::QUALITY_REPORT_ID_MONITOR_MODE:
    case bluetooth::bqr::QUALITY_REPORT_ID_APPROACH_LSTO:
    case bluetooth::bqr::QUALITY_REPORT_ID_A2DP_AUDIO_CHOPPY:
    case bluetooth::bqr::QUALITY_REPORT_ID_SCO_VOICE_CHOPPY:
    default:
      break;
  }

  return intercepted;
}

static void init_layer_interface() {
  if (!interface_created) {
    // It's probably ok for this to live forever. It's small and
+0 −3
Original line number Diff line number Diff line
@@ -901,9 +901,6 @@ static void BTM_BT_Quality_Report_VSE_CBack(uint8_t length, uint8_t* p_stream) {
  length--;

  if (sub_event == HCI_VSE_SUBCODE_BQR_SUB_EVT) {
    LOG(INFO) << __func__
              << ": BQR sub event, report length: " << std::to_string(length);

    if (btm_cb.p_bqr_report_receiver == nullptr) {
      LOG(WARNING) << __func__ << ": No registered report receiver.";
      return;