OSDN Git Service

Add service change handle for Hearing Aids
authorweichinweng <weichinweng@google.com>
Wed, 20 Mar 2019 10:53:11 +0000 (18:53 +0800)
committerStanley Tng <stng@google.com>
Tue, 2 Apr 2019 21:59:23 +0000 (21:59 +0000)
When receive service changed indication from Hearing Aid (which indicates
Hearing Aid service changed), it will refresh the hearing aid attribute
handle to ensure the attribute handle is correct.

Bug: 122008481
Test: 1.run unit test
2.After Pair old version FW HearingAid, Disconnect/Reconnect new version
FW HearingAId, then check whether HearingAid is working fine.
3.After Pair old version FW HearingAid, Bluetooth off/on to reconnect
new version FW HearingAId, then check whether HearingAid is working
fine.
Change-Id: I48eae10a3016429f35f4f904752be93bb419d515

bta/gatt/bta_gattc_act.cc
bta/hearing_aid/hearing_aid.cc
bta/include/bta_gatt_api.h
bta/include/bta_hearing_aid_api.h
btif/src/btif_storage.cc

index f5f9c71..5e60049 100644 (file)
@@ -722,6 +722,12 @@ void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB* p_clcb,
      */
     if (p_q_cmd != p_clcb->p_q_cmd) osi_free_and_reset((void**)&p_q_cmd);
   }
+
+  if (p_clcb->p_rcb->p_cback) {
+    tBTA_GATTC bta_gattc;
+    bta_gattc.remote_bda = p_clcb->p_srcb->server_bda;
+    (*p_clcb->p_rcb->p_cback)(BTA_GATTC_SRVC_DISC_DONE_EVT, &bta_gattc);
+  }
 }
 
 /** Read an attribute */
index 9732e8b..a83392c 100644 (file)
@@ -521,13 +521,16 @@ class HearingAidImpl : public HearingAid {
 
     DVLOG(2) << __func__ << " " << address;
 
-    if (!hearingDevice->first_connection) {
-      // Use cached data, jump to connecting socket
-      ConnectSocket(hearingDevice);
-      return;
+    if (hearingDevice->audio_control_point_handle &&
+        hearingDevice->audio_status_handle &&
+        hearingDevice->audio_status_ccc_handle &&
+        hearingDevice->volume_handle && hearingDevice->read_psm_handle) {
+      // Use cached data, jump to read PSM
+      ReadPSM(hearingDevice);
+    } else {
+      hearingDevice->first_connection = true;
+      BTA_GATTC_ServiceSearchRequest(hearingDevice->conn_id, &HEARING_AID_UUID);
     }
-
-    BTA_GATTC_ServiceSearchRequest(hearingDevice->conn_id, &HEARING_AID_UUID);
   }
 
   void OnServiceChangeEvent(const RawAddress& address) {
@@ -537,16 +540,23 @@ class HearingAidImpl : public HearingAid {
       return;
     }
     LOG(INFO) << __func__ << ": address=" << address;
+    hearingDevice->first_connection = true;
+    hearingDevice->service_changed_rcvd = true;
+    BtaGattQueue::Clean(hearingDevice->conn_id);
+    if (hearingDevice->gap_handle) {
+      GAP_ConnClose(hearingDevice->gap_handle);
+      hearingDevice->gap_handle = 0;
+    }
+  }
 
-    /* Re-register the Audio Status Notification since the Service Change will
-     * clear it */
-    tGATT_STATUS register_status;
-    register_status = BTA_GATTC_RegisterForNotifications(
-        gatt_if, address, hearingDevice->audio_status_handle);
-    if (register_status != GATT_SUCCESS) {
-      LOG(INFO) << __func__
-                << ": BTA_GATTC_RegisterForNotifications failed, status="
-                << loghex(register_status);
+  void OnServiceDiscDoneEvent(const RawAddress& address) {
+    HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
+    if (!hearingDevice) {
+      VLOG(2) << "Skipping unknown device" << address;
+      return;
+    }
+    if (hearingDevice->service_changed_rcvd) {
+      BTA_GATTC_ServiceSearchRequest(hearingDevice->conn_id, &HEARING_AID_UUID);
     }
   }
 
@@ -574,10 +584,15 @@ class HearingAidImpl : public HearingAid {
 
     const gatt::Service* service = nullptr;
     for (const gatt::Service& tmp : *services) {
-      if (tmp.uuid != HEARING_AID_UUID) continue;
-      LOG(INFO) << "Found Hearing Aid service, handle=" << loghex(tmp.handle);
-      service = &tmp;
-      break;
+      if (tmp.uuid == Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER)) {
+        LOG(INFO) << "Found UUID_SERVCLASS_GATT_SERVER, handle="
+                  << loghex(tmp.handle);
+        const gatt::Service* service_changed_service = &tmp;
+        find_server_changed_ccc_handle(conn_id, service_changed_service);
+      } else if (tmp.uuid == HEARING_AID_UUID) {
+        LOG(INFO) << "Found Hearing Aid service, handle=" << loghex(tmp.handle);
+        service = &tmp;
+      }
     }
 
     if (!service) {
@@ -587,7 +602,6 @@ class HearingAidImpl : public HearingAid {
       return;
     }
 
-    uint16_t psm_handle = 0x0000;
     for (const gatt::Characteristic& charac : service->characteristics) {
       if (charac.uuid == READ_ONLY_PROPERTIES_UUID) {
         DVLOG(2) << "Reading read only properties "
@@ -614,16 +628,26 @@ class HearingAidImpl : public HearingAid {
       } else if (charac.uuid == VOLUME_UUID) {
         hearingDevice->volume_handle = charac.value_handle;
       } else if (charac.uuid == LE_PSM_UUID) {
-        psm_handle = charac.value_handle;
+        hearingDevice->read_psm_handle = charac.value_handle;
       } else {
         LOG(WARNING) << "Unknown characteristic found:" << charac.uuid;
       }
     }
 
-    if (psm_handle) {
-      DVLOG(2) << "Reading PSM " << loghex(psm_handle);
+    if (hearingDevice->service_changed_rcvd) {
+      hearingDevice->service_changed_rcvd = false;
+    }
+
+    ReadPSM(hearingDevice);
+  }
+
+  void ReadPSM(HearingDevice* hearingDevice) {
+    if (hearingDevice->read_psm_handle) {
+      LOG(INFO) << "Reading PSM " << loghex(hearingDevice->read_psm_handle)
+                << ", device=" << hearingDevice->address;
       BtaGattQueue::ReadCharacteristic(
-          conn_id, psm_handle, HearingAidImpl::OnPsmReadStatic, nullptr);
+          hearingDevice->conn_id, hearingDevice->read_psm_handle,
+          HearingAidImpl::OnPsmReadStatic, nullptr);
     }
   }
 
@@ -790,24 +814,25 @@ class HearingAidImpl : public HearingAid {
       return;
     }
 
-    uint16_t psm_val = *((uint16_t*)value);
-    hearingDevice->psm = psm_val;
-    VLOG(2) << "read psm:" << loghex(hearingDevice->psm);
+    uint16_t psm = *((uint16_t*)value);
+    VLOG(2) << "read psm:" << loghex(psm);
 
-    ConnectSocket(hearingDevice);
+    ConnectSocket(hearingDevice, psm);
   }
 
-  void ConnectSocket(HearingDevice* hearingDevice) {
+  void ConnectSocket(HearingDevice* hearingDevice, uint16_t psm) {
     tL2CAP_CFG_INFO cfg_info = tL2CAP_CFG_INFO{.mtu = 512};
 
+    SendEnableServiceChangedInd(hearingDevice);
+
     uint8_t service_id = hearingDevice->isLeft()
                              ? BTM_SEC_SERVICE_HEARING_AID_LEFT
                              : BTM_SEC_SERVICE_HEARING_AID_RIGHT;
     uint16_t gap_handle = GAP_ConnOpen(
-        "", service_id, false, &hearingDevice->address, hearingDevice->psm,
-        514 /* MPS */, &cfg_info, nullptr,
-        BTM_SEC_NONE /* TODO: request security ? */, L2CAP_FCR_LE_COC_MODE,
-        HearingAidImpl::GapCallbackStatic, BT_TRANSPORT_LE);
+        "", service_id, false, &hearingDevice->address, psm, 514 /* MPS */,
+        &cfg_info, nullptr, BTM_SEC_NONE /* TODO: request security ? */,
+        L2CAP_FCR_LE_COC_MODE, HearingAidImpl::GapCallbackStatic,
+        BT_TRANSPORT_LE);
     if (gap_handle == GAP_INVALID_HANDLE) {
       LOG(ERROR) << "UNABLE TO GET gap_handle";
       return;
@@ -993,6 +1018,17 @@ class HearingAidImpl : public HearingAid {
     return (OTHER_SIDE_NOT_STREAMING);
   }
 
+  void SendEnableServiceChangedInd(HearingDevice* device) {
+    VLOG(2) << __func__ << " Enable " << device->address
+            << "service changed ind.";
+    std::vector<uint8_t> value(2);
+    uint8_t* ptr = value.data();
+    UINT16_TO_STREAM(ptr, GATT_CHAR_CLIENT_CONFIG_INDICTION);
+    BtaGattQueue::WriteDescriptor(
+        device->conn_id, device->service_changed_ccc_handle, std::move(value),
+        GATT_WRITE, nullptr, nullptr);
+  }
+
   void SendStart(HearingDevice* device) {
     std::vector<uint8_t> start({CONTROL_POINT_OP_START, codec_in_use,
                                 AUDIOTYPE_UNKNOWN, (uint8_t)current_volume,
@@ -1464,6 +1500,29 @@ class HearingAidImpl : public HearingAid {
 
   HearingDevices hearingDevices;
 
+  void find_server_changed_ccc_handle(uint16_t conn_id,
+                                      const gatt::Service* service) {
+    HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
+    if (!hearingDevice) {
+      DVLOG(2) << "Skipping unknown device, conn_id=" << loghex(conn_id);
+      return;
+    }
+    for (const gatt::Characteristic& charac : service->characteristics) {
+      if (charac.uuid == Uuid::From16Bit(GATT_UUID_GATT_SRV_CHGD)) {
+        hearingDevice->service_changed_ccc_handle =
+            find_ccc_handle(conn_id, charac.value_handle);
+        if (!hearingDevice->service_changed_ccc_handle) {
+          LOG(ERROR) << __func__
+                     << ": cannot find service changed CCC descriptor";
+          continue;
+        }
+        LOG(INFO) << __func__ << " service_changed_ccc="
+                  << loghex(hearingDevice->service_changed_ccc_handle);
+        break;
+      }
+    }
+  }
+
   // Find the handle for the client characteristics configuration of a given
   // characteristics
   uint16_t find_ccc_handle(uint16_t conn_id, uint16_t char_handle) {
@@ -1485,6 +1544,12 @@ class HearingAidImpl : public HearingAid {
 
   void send_state_change(HearingDevice* device, std::vector<uint8_t> payload) {
     if (device->conn_id != 0) {
+      if (device->service_changed_rcvd) {
+        LOG(INFO)
+            << __func__
+            << ": service discover is in progress, skip send State Change cmd.";
+        return;
+      }
       // Send the data packet
       LOG(INFO) << __func__ << ": Send State Change. device=" << device->address
                 << ", status=" << loghex(payload[1]);
@@ -1585,6 +1650,11 @@ void hearingaid_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
       instance->OnServiceChangeEvent(p_data->remote_bda);
       break;
 
+    case BTA_GATTC_SRVC_DISC_DONE_EVT:
+      if (!instance) return;
+      instance->OnServiceDiscDoneEvent(p_data->remote_bda);
+      break;
+
     default:
       break;
   }
index 618cb04..9176501 100644 (file)
@@ -54,6 +54,7 @@ typedef struct {
 #define BTA_GATTC_CLOSE_EVT 5        /* GATTC  close request status event */
 #define BTA_GATTC_SEARCH_CMPL_EVT 6  /* GATT discovery complete event */
 #define BTA_GATTC_SEARCH_RES_EVT 7   /* GATT discovery result event */
+#define BTA_GATTC_SRVC_DISC_DONE_EVT 8 /* GATT service discovery done event */
 #define BTA_GATTC_NOTIF_EVT 10       /* GATT attribute notification event */
 #define BTA_GATTC_EXEC_EVT 12        /* execute write complete event */
 #define BTA_GATTC_ACL_EVT 13         /* ACL up event */
index efecdc7..aa8c7c7 100644 (file)
@@ -24,6 +24,8 @@
 #include <future>
 #include <vector>
 
+constexpr uint16_t HEARINGAID_MAX_NUM_UUIDS = 1;
+
 constexpr uint16_t HA_INTERVAL_10_MS = 10;
 constexpr uint16_t HA_INTERVAL_20_MS = 20;
 
@@ -82,6 +84,7 @@ struct HearingDevice {
   /* This is true only during first connection to profile, until we store the
    * device */
   bool first_connection;
+  bool service_changed_rcvd;
 
   /* we are making active attempt to connect to this device, 'direct connect'.
    * This is true only during initial phase of first connection. */
@@ -107,8 +110,9 @@ struct HearingDevice {
   uint16_t audio_control_point_handle;
   uint16_t audio_status_handle;
   uint16_t audio_status_ccc_handle;
+  uint16_t service_changed_ccc_handle;
   uint16_t volume_handle;
-  uint16_t psm;
+  uint16_t read_psm_handle;
 
   uint8_t capabilities;
   uint64_t hi_sync_id;
@@ -131,11 +135,15 @@ struct HearingDevice {
   int read_rssi_count;
   int num_intervals_since_last_rssi_read;
 
-  HearingDevice(const RawAddress& address, uint16_t psm, uint8_t capabilities, uint16_t codecs,
-                uint16_t audio_control_point_handle, uint16_t audio_status_handle, uint16_t audio_status_ccc_handle,
-                uint16_t volume_handle, uint64_t hiSyncId, uint16_t render_delay, uint16_t preparation_delay)
+  HearingDevice(const RawAddress& address, uint8_t capabilities,
+                uint16_t codecs, uint16_t audio_control_point_handle,
+                uint16_t audio_status_handle, uint16_t audio_status_ccc_handle,
+                uint16_t service_changed_ccc_handle, uint16_t volume_handle,
+                uint16_t read_psm_handle, uint64_t hiSyncId,
+                uint16_t render_delay, uint16_t preparation_delay)
       : address(address),
         first_connection(false),
+        service_changed_rcvd(false),
         connecting_actively(false),
         connection_update_status(NONE),
         accepting_audio(false),
@@ -144,8 +152,9 @@ struct HearingDevice {
         audio_control_point_handle(audio_control_point_handle),
         audio_status_handle(audio_status_handle),
         audio_status_ccc_handle(audio_status_ccc_handle),
+        service_changed_ccc_handle(service_changed_ccc_handle),
         volume_handle(volume_handle),
-        psm(psm),
+        read_psm_handle(read_psm_handle),
         capabilities(capabilities),
         hi_sync_id(hiSyncId),
         render_delay(render_delay),
@@ -158,6 +167,7 @@ struct HearingDevice {
   HearingDevice(const RawAddress& address, bool first_connection)
       : address(address),
         first_connection(first_connection),
+        service_changed_rcvd(false),
         connecting_actively(first_connection),
         connection_update_status(NONE),
         accepting_audio(false),
@@ -165,7 +175,8 @@ struct HearingDevice {
         gap_handle(0),
         audio_status_handle(0),
         audio_status_ccc_handle(0),
-        psm(0),
+        service_changed_ccc_handle(0),
+        read_psm_handle(0),
         playback_started(false),
         command_acked(false),
         read_rssi_count(0) {}
index d4cee12..a7462ff 100644 (file)
@@ -1423,7 +1423,7 @@ bt_status_t btif_storage_remove_hid_info(RawAddress* remote_bd_addr) {
   return BT_STATUS_SUCCESS;
 }
 
-constexpr char HEARING_AID_PSM[] = "HearingAidPsm";
+constexpr char HEARING_AID_READ_PSM_HANDLE[] = "HearingAidReadPsmHandle";
 constexpr char HEARING_AID_CAPABILITIES[] = "HearingAidCapabilities";
 constexpr char HEARING_AID_CODECS[] = "HearingAidCodecs";
 constexpr char HEARING_AID_AUDIO_CONTROL_POINT[] =
@@ -1433,6 +1433,8 @@ constexpr char HEARING_AID_AUDIO_STATUS_HANDLE[] =
     "HearingAidAudioStatusHandle";
 constexpr char HEARING_AID_AUDIO_STATUS_CCC_HANDLE[] =
     "HearingAidAudioStatusCccHandle";
+constexpr char HEARING_AID_SERVICE_CHANGED_CCC_HANDLE[] =
+    "HearingAidServiceChangedCccHandle";
 constexpr char HEARING_AID_SYNC_ID[] = "HearingAidSyncId";
 constexpr char HEARING_AID_RENDER_DELAY[] = "HearingAidRenderDelay";
 constexpr char HEARING_AID_PREPARATION_DELAY[] = "HearingAidPreparationDelay";
@@ -1445,7 +1447,10 @@ void btif_storage_add_hearing_aid(const HearingDevice& dev_info) {
           [](const HearingDevice& dev_info) {
             std::string bdstr = dev_info.address.ToString();
             VLOG(2) << "saving hearing aid device: " << bdstr;
-            btif_config_set_int(bdstr, HEARING_AID_PSM, dev_info.psm);
+            btif_config_set_int(bdstr, HEARING_AID_SERVICE_CHANGED_CCC_HANDLE,
+                                dev_info.service_changed_ccc_handle);
+            btif_config_set_int(bdstr, HEARING_AID_READ_PSM_HANDLE,
+                                dev_info.read_psm_handle);
             btif_config_set_int(bdstr, HEARING_AID_CAPABILITIES,
                                 dev_info.capabilities);
             btif_config_set_int(bdstr, HEARING_AID_CODECS, dev_info.codecs);
@@ -1477,11 +1482,26 @@ void btif_storage_load_bonded_hearing_aids() {
     const std::string& name = section.name;
     if (!RawAddress::IsValidAddress(name)) continue;
 
-    BTIF_TRACE_DEBUG("Remote device:%s", name.c_str());
+    int size = STORAGE_UUID_STRING_SIZE * HEARINGAID_MAX_NUM_UUIDS;
+    char uuid_str[size];
+    bool isHearingaidDevice = false;
+    if (btif_config_get_str(name, BTIF_STORAGE_PATH_REMOTE_SERVICE, uuid_str,
+                            &size)) {
+      Uuid p_uuid[HEARINGAID_MAX_NUM_UUIDS];
+      size_t num_uuids =
+          btif_split_uuids_string(uuid_str, p_uuid, HEARINGAID_MAX_NUM_UUIDS);
+      for (size_t i = 0; i < num_uuids; i++) {
+        if (p_uuid[i] == Uuid::FromString("FDF0")) {
+          isHearingaidDevice = true;
+          break;
+        }
+      }
+    }
+    if (!isHearingaidDevice) {
+      continue;
+    }
 
-    int value;
-    if (!btif_config_get_int(name, HEARING_AID_PSM, &value)) continue;
-    uint16_t psm = value;
+    BTIF_TRACE_DEBUG("Remote device:%s", name.c_str());
 
     if (btif_in_fetch_bonded_device(name) != BT_STATUS_SUCCESS) {
       RawAddress bd_addr;
@@ -1490,6 +1510,7 @@ void btif_storage_load_bonded_hearing_aids() {
       continue;
     }
 
+    int value;
     uint8_t capabilities = 0;
     if (btif_config_get_int(name, HEARING_AID_CAPABILITIES, &value))
       capabilities = value;
@@ -1509,10 +1530,19 @@ void btif_storage_load_bonded_hearing_aids() {
     if (btif_config_get_int(name, HEARING_AID_AUDIO_STATUS_CCC_HANDLE, &value))
       audio_status_ccc_handle = value;
 
+    uint16_t service_changed_ccc_handle = 0;
+    if (btif_config_get_int(name, HEARING_AID_SERVICE_CHANGED_CCC_HANDLE,
+                            &value))
+      service_changed_ccc_handle = value;
+
     uint16_t volume_handle = 0;
     if (btif_config_get_int(name, HEARING_AID_VOLUME_HANDLE, &value))
       volume_handle = value;
 
+    uint16_t read_psm_handle = 0;
+    if (btif_config_get_int(name, HEARING_AID_READ_PSM_HANDLE, &value))
+      read_psm_handle = value;
+
     uint64_t lvalue;
     uint64_t hi_sync_id = 0;
     if (btif_config_get_uint64(name, HEARING_AID_SYNC_ID, &lvalue))
@@ -1537,9 +1567,10 @@ void btif_storage_load_bonded_hearing_aids() {
     do_in_main_thread(
         FROM_HERE,
         Bind(&HearingAid::AddFromStorage,
-             HearingDevice(bd_addr, psm, capabilities, codecs,
+             HearingDevice(bd_addr, capabilities, codecs,
                            audio_control_point_handle, audio_status_handle,
-                           audio_status_ccc_handle, volume_handle, hi_sync_id,
+                           audio_status_ccc_handle, service_changed_ccc_handle,
+                           volume_handle, read_psm_handle, hi_sync_id,
                            render_delay, preparation_delay),
              is_white_listed));
   }
@@ -1548,13 +1579,17 @@ void btif_storage_load_bonded_hearing_aids() {
 /** Deletes the bonded hearing aid device info from NVRAM */
 void btif_storage_remove_hearing_aid(const RawAddress& address) {
   std::string addrstr = address.ToString();
-
-  btif_config_remove(addrstr, HEARING_AID_PSM);
+  btif_config_remove(addrstr, HEARING_AID_READ_PSM_HANDLE);
   btif_config_remove(addrstr, HEARING_AID_CAPABILITIES);
   btif_config_remove(addrstr, HEARING_AID_CODECS);
   btif_config_remove(addrstr, HEARING_AID_AUDIO_CONTROL_POINT);
   btif_config_remove(addrstr, HEARING_AID_VOLUME_HANDLE);
+  btif_config_remove(addrstr, HEARING_AID_AUDIO_STATUS_HANDLE);
+  btif_config_remove(addrstr, HEARING_AID_AUDIO_STATUS_CCC_HANDLE);
+  btif_config_remove(addrstr, HEARING_AID_SERVICE_CHANGED_CCC_HANDLE);
   btif_config_remove(addrstr, HEARING_AID_SYNC_ID);
+  btif_config_remove(addrstr, HEARING_AID_RENDER_DELAY);
+  btif_config_remove(addrstr, HEARING_AID_PREPARATION_DELAY);
   btif_config_remove(addrstr, HEARING_AID_IS_WHITE_LISTED);
   btif_config_save();
 }