OSDN Git Service

GATT: Interop fix for service changed indications
authorMyles Watson <mylesgw@google.com>
Fri, 26 May 2017 00:24:49 +0000 (17:24 -0700)
committerMyles Watson <mylesgw@google.com>
Sat, 27 May 2017 00:02:01 +0000 (00:02 +0000)
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
(cherry picked from commit 43c7f9f4775e589d8fd0604ef4717996696a0321)

device/include/interop.h
device/include/interop_database.h
device/src/interop.cc
stack/gatt/gatt_main.cc

index 352bd4d..6364a1b 100644 (file)
@@ -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
index adbbcbe..a9a958d 100644 (file)
@@ -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},
 };
index f1d6b8e..382fea4 100644 (file)
@@ -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";
index 8ab94ab..ca006a7 100644 (file)
 
 #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;
     }
   }