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

Commit da382c02 authored by Myles Watson's avatar Myles Watson
Browse files

GATT: Interop fix for service changed indications

The Pixel C Keyboard disconnects if it receives an indication
for which it hasn't registered.

Test: Add a GATT service with Pixel C connected
Bug: 34352677
Change-Id: I1f717db40b2ba9ec21feac5fd9e339c09f140d51
parent 84e7cdda
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -69,7 +69,11 @@ typedef enum {

  // Do not use supervision timeout value received from preferred connection
  // parameters, use 3s instead. Use with HID only.
  INTEROP_HID_PREF_CONN_SUP_TIMEOUT_3S
  INTEROP_HID_PREF_CONN_SUP_TIMEOUT_3S,

  // Do not send service changed indications (GATT client).
  // This should be removed after the characteristic is implmeented b/62088395.
  INTEROP_GATTC_NO_SERVICE_CHANGED_IND,
} interop_feature_t;

// Check if a given |addr| matches a known interoperability workaround as
+3 −0
Original line number Diff line number Diff line
@@ -128,4 +128,7 @@ static const interop_name_entry_t interop_name_database[] = {

    // Subaru car kits ("CAR M_MEDIA")
    {"CAR", 3, INTEROP_DISABLE_AUTO_PAIRING},

    // Pixel C Keyboard doesn't respond to service changed indications.
    {"Pixel C Keyboard", 16, INTEROP_GATTC_NO_SERVICE_CHANGED_IND},
};
+1 −0
Original line number Diff line number Diff line
@@ -125,6 +125,7 @@ static const char* interop_feature_string_(const interop_feature_t feature) {
    CASE_RETURN_STR(INTEROP_KEYBOARD_REQUIRES_FIXED_PIN)
    CASE_RETURN_STR(INTEROP_2MBPS_LINK_ONLY)
    CASE_RETURN_STR(INTEROP_HID_PREF_CONN_SUP_TIMEOUT_3S)
    CASE_RETURN_STR(INTEROP_GATTC_NO_SERVICE_CHANGED_IND)
  }

  return "UNKNOWN";
+35 −7
Original line number Diff line number Diff line
@@ -26,8 +26,10 @@

#include "bt_common.h"
#include "bt_utils.h"
#include "btif_storage.h"
#include "btm_ble_int.h"
#include "btm_int.h"
#include "device/include/interop.h"
#include "gatt_int.h"
#include "l2c_api.h"
#include "osi/include/osi.h"
@@ -267,7 +269,8 @@ bool gatt_update_app_hold_link_status(tGATT_IF gatt_if, tGATT_TCB* p_tcb,
                                      bool is_add) {
  for (int i = 0; i < GATT_MAX_APPS; i++) {
    if (p_tcb->app_hold_link[i] == gatt_if && is_add) {
      GATT_TRACE_DEBUG("%s: gatt_if %d already exists at idx %d", __func__, gatt_if, i);
      GATT_TRACE_DEBUG("%s: gatt_if %d already exists at idx %d", __func__,
                       gatt_if, i);
      return true;
    }
  }
@@ -1100,6 +1103,20 @@ void gatt_init_srv_chg(void) {
  }
}

// Get the name of a device from btif for interop database matching.
static bool get_stored_remote_name(BD_ADDR bda, char* name) {
  bt_bdaddr_t bd_addr;
  for (int i = 0; i < 6; i++) bd_addr.address[i] = bda[i];

  bt_property_t property;
  property.type = BT_PROPERTY_BDNAME;
  property.len = BTM_MAX_REM_BD_NAME_LEN;
  property.val = name;

  return (btif_storage_get_remote_device_property(&bd_addr, &property) ==
          BT_STATUS_SUCCESS);
}

/*******************************************************************************
 *
 * Function         gatt_proc_srv_chg
@@ -1112,7 +1129,6 @@ void gatt_init_srv_chg(void) {
void gatt_proc_srv_chg(void) {
  uint8_t start_idx, found_idx;
  BD_ADDR bda;
  bool srv_chg_ind_pending = false;
  tGATT_TCB* p_tcb;
  tBT_TRANSPORT transport;

@@ -1124,14 +1140,26 @@ void gatt_proc_srv_chg(void) {
    while (
        gatt_find_the_connected_bda(start_idx, bda, &found_idx, &transport)) {
      p_tcb = &gatt_cb.tcb[found_idx];
      ;
      srv_chg_ind_pending = gatt_is_srv_chg_ind_pending(p_tcb);

      if (!srv_chg_ind_pending) {
        gatt_send_srv_chg_ind(bda);
      } else {
      bool send_indication = true;

      if (gatt_is_srv_chg_ind_pending(p_tcb)) {
        send_indication = false;
        GATT_TRACE_DEBUG("discard srv chg - already has one in the queue");
      }

      // Some LE GATT clients don't respond to service changed indications.
      char remote_name[BTM_MAX_REM_BD_NAME_LEN] = "";
      if (send_indication && get_stored_remote_name(bda, remote_name)) {
        if (interop_match_name(INTEROP_GATTC_NO_SERVICE_CHANGED_IND,
                               remote_name)) {
          GATT_TRACE_DEBUG("discard srv chg - interop matched %s", remote_name);
          send_indication = false;
        }
      }

      if (send_indication) gatt_send_srv_chg_ind(bda);

      start_idx = ++found_idx;
    }
  }