From 56299229dddfca09ab4f458c4bc17e44c2c13f30 Mon Sep 17 00:00:00 2001
From: Jakub Pawlowski <jpawlowski@google.com>
Date: Tue, 29 Dec 2020 15:57:38 +0100
Subject: [PATCH] Make it possible to pass multiple BLE services to settings

In BTIF layer, instead of passing just one service when it is discovered,
wait until service discovery is finished, and then go through whole list.

This enables us to pass multiple services from one device. This will be
useful for the LE Audio profile.

Bug: 176477621
Tag: #feature
Test: manually tested with LE and dual mode devices
Change-Id: I58ec5ff1740a6197b1a26ec74d21bd70b2f244d4
---
 system/bta/dm/bta_dm_act.cc  | 99 +++++++++++++++++++++---------------
 system/bta/include/bta_api.h |  3 +-
 system/btif/src/btif_dm.cc   | 78 ++++++++++++++++------------
 3 files changed, 104 insertions(+), 76 deletions(-)

diff --git a/system/bta/dm/bta_dm_act.cc b/system/bta/dm/bta_dm_act.cc
index f0e6e5f1a10..9341946f0da 100644
--- a/system/bta/dm/bta_dm_act.cc
+++ b/system/bta/dm/bta_dm_act.cc
@@ -999,8 +999,6 @@ void bta_dm_sdp_result(tBTA_DM_MSG* p_data) {
   uint16_t service = 0xFFFF;
   tSDP_PROTOCOL_ELEM pe;
 
-  tBTA_DM_SEARCH result;
-
   std::vector<Uuid> uuid_list;
 
   if ((p_data->sdp_event.sdp_result == SDP_SUCCESS) ||
@@ -1025,6 +1023,9 @@ void bta_dm_sdp_result(tBTA_DM_MSG* p_data) {
        * service UUID */
       if (bta_dm_search_cb.service_index == BTA_MAX_SERVICE_ID) {
         /* all GATT based services */
+
+        std::vector<Uuid> gatt_uuids;
+
         do {
           /* find a service record, report it */
           p_sdp_rec =
@@ -1032,16 +1033,23 @@ void bta_dm_sdp_result(tBTA_DM_MSG* p_data) {
           if (p_sdp_rec) {
             Uuid service_uuid;
             if (SDP_FindServiceUUIDInRec(p_sdp_rec, &service_uuid)) {
-              /* send result back to app now, one by one */
-              result.disc_ble_res.bd_addr = bta_dm_search_cb.peer_bdaddr;
-              strlcpy((char*)result.disc_ble_res.bd_name, bta_dm_get_remname(),
-                      BD_NAME_LEN + 1);
-
-              result.disc_ble_res.service = service_uuid;
-              bta_dm_search_cb.p_search_cback(BTA_DM_DISC_BLE_RES_EVT, &result);
+              gatt_uuids.push_back(service_uuid);
             }
           }
         } while (p_sdp_rec);
+
+        if (!gatt_uuids.empty()) {
+          LOG_INFO("GATT services discovered using SDP");
+
+          // send all result back to app
+          tBTA_DM_SEARCH result;
+          result.disc_ble_res.bd_addr = bta_dm_search_cb.peer_bdaddr;
+          strlcpy((char*)result.disc_ble_res.bd_name, bta_dm_get_remname(),
+                  BD_NAME_LEN + 1);
+
+          result.disc_ble_res.services = &gatt_uuids;
+          bta_dm_search_cb.p_search_cback(BTA_DM_DISC_BLE_RES_EVT, &result);
+        }
       } else {
         /* SDP_DB_FULL means some records with the
            required attributes were received */
@@ -1194,7 +1202,46 @@ void bta_dm_sdp_result(tBTA_DM_MSG* p_data) {
  ******************************************************************************/
 void bta_dm_search_cmpl() {
   bta_dm_search_set_state(BTA_DM_SEARCH_IDLE);
-  bta_dm_search_cb.p_search_cback(BTA_DM_DISC_CMPL_EVT, NULL);
+
+  uint16_t conn_id = bta_dm_search_cb.conn_id;
+
+  /* no BLE connection, i.e. Classic service discovery end */
+  if (conn_id == GATT_INVALID_CONN_ID) {
+    bta_dm_search_cb.p_search_cback(BTA_DM_DISC_CMPL_EVT, nullptr);
+    return;
+  }
+
+  btgatt_db_element_t* db = NULL;
+  int count = 0;
+  BTA_GATTC_GetGattDb(conn_id, 0x0000, 0xFFFF, &db, &count);
+
+  if (count == 0) {
+    LOG_INFO("Empty GATT database - no BLE services discovered");
+    bta_dm_search_cb.p_search_cback(BTA_DM_DISC_CMPL_EVT, nullptr);
+    return;
+  }
+
+  std::vector<Uuid> gatt_services;
+
+  for (int i = 0; i < count; i++) {
+    // we process service entries only
+    if (db[i].type == BTGATT_DB_PRIMARY_SERVICE) {
+      gatt_services.push_back(db[i].uuid);
+    }
+  }
+  osi_free(db);
+
+  tBTA_DM_SEARCH result;
+  result.disc_ble_res.services = &gatt_services;
+  result.disc_ble_res.bd_addr = bta_dm_search_cb.peer_bdaddr;
+  strlcpy((char*)result.disc_ble_res.bd_name, (char*)bta_dm_search_cb.peer_name,
+          BD_NAME_LEN + 1);
+
+  LOG_INFO("GATT services discovered using LE Transport");
+  // send all result back to app
+  bta_dm_search_cb.p_search_cback(BTA_DM_DISC_BLE_RES_EVT, &result);
+
+  bta_dm_search_cb.p_search_cback(BTA_DM_DISC_CMPL_EVT, nullptr);
 }
 
 /*******************************************************************************
@@ -3588,37 +3635,6 @@ static void bta_dm_gattc_register(void) {
   }
 }
 
-/*******************************************************************************
- *
- * Function         bta_dm_gatt_disc_result
- *
- * Description      This function process the GATT service search result.
- *
- * Parameters:
- *
- ******************************************************************************/
-static void bta_dm_gatt_disc_result(tBTA_GATT_ID service_id) {
-  tBTA_DM_SEARCH result;
-
-  /*
-   * This logic will not work for gatt case.  We are checking against the
-   * bluetooth profiles here
-   * just copy the GATTID in raw data field and send it across.
-   */
-
-  LOG_INFO("%s service_id_uuid_len=%zu", __func__,
-           service_id.uuid.GetShortestRepresentationSize());
-  if (bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE) {
-    /* send result back to app now, one by one */
-    result.disc_ble_res.bd_addr = bta_dm_search_cb.peer_bdaddr;
-    strlcpy((char*)result.disc_ble_res.bd_name, bta_dm_get_remname(),
-            BD_NAME_LEN + 1);
-    result.disc_ble_res.service = service_id.uuid;
-
-    bta_dm_search_cb.p_search_cback(BTA_DM_DISC_BLE_RES_EVT, &result);
-  }
-}
-
 /*******************************************************************************
  *
  * Function         bta_dm_gatt_disc_complete
@@ -3768,7 +3784,6 @@ static void bta_dm_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
       break;
 
     case BTA_GATTC_SEARCH_RES_EVT:
-      bta_dm_gatt_disc_result(p_data->srvc_res.service_uuid);
       break;
 
     case BTA_GATTC_SEARCH_CMPL_EVT:
diff --git a/system/bta/include/bta_api.h b/system/bta/include/bta_api.h
index 3c58ea7fd93..cbe9706f852 100644
--- a/system/bta/include/bta_api.h
+++ b/system/bta/include/bta_api.h
@@ -419,7 +419,8 @@ typedef struct {
 typedef struct {
   RawAddress bd_addr; /* BD address peer device. */
   BD_NAME bd_name;  /* Name of peer device. */
-  bluetooth::Uuid service; /* GATT based Services UUID found on peer device. */
+  std::vector<bluetooth::Uuid>*
+      services; /* GATT based Services UUID found on peer device. */
 } tBTA_DM_DISC_BLE_RES;
 
 /* Union of all search callback structures */
diff --git a/system/btif/src/btif_dm.cc b/system/btif/src/btif_dm.cc
index 13fbae8ee76..9918f9a519b 100644
--- a/system/btif/src/btif_dm.cc
+++ b/system/btif/src/btif_dm.cc
@@ -1236,6 +1236,11 @@ static void btif_dm_search_devices_evt(tBTA_DM_SEARCH_EVT event,
   }
 }
 
+/* Returns true if |uuid| should be passed as device property */
+static bool btif_is_interesting_le_service(bluetooth::Uuid uuid) {
+  return uuid.As16Bit() == UUID_SERVCLASS_LE_HID || uuid == UUID_HEARING_AID;
+}
+
 /*******************************************************************************
  *
  * Function         btif_dm_search_services_evt
@@ -1334,45 +1339,52 @@ static void btif_dm_search_services_evt(tBTA_DM_SEARCH_EVT event,
       break;
 
     case BTA_DM_DISC_BLE_RES_EVT: {
-      LOG_VERBOSE("service %s",
-                  p_data->disc_ble_res.service.ToString().c_str());
       int num_properties = 0;
-      if (p_data->disc_ble_res.service.As16Bit() == UUID_SERVCLASS_LE_HID ||
-          p_data->disc_ble_res.service == UUID_HEARING_AID) {
-        LOG_INFO("Found HOGP or HEARING AID UUID");
-        bt_property_t prop[2];
-        bt_status_t ret;
-
-        const auto& arr = p_data->disc_ble_res.service.To128BitBE();
-
-        RawAddress& bd_addr = p_data->disc_ble_res.bd_addr;
-        prop[0].type = BT_PROPERTY_UUIDS;
-        prop[0].val = (void*)arr.data();
-        prop[0].len = Uuid::kNumBytes128;
+      bt_property_t prop[2];
+      std::vector<uint8_t> property_value;
+      int num_uuids = 0;
+
+      for (Uuid uuid : *p_data->disc_ble_res.services) {
+        LOG_VERBOSE("service %s", uuid.ToString().c_str());
+        if (btif_is_interesting_le_service(uuid)) {
+          num_uuids++;
+          auto valAsBe = uuid.To128BitBE();
+          property_value.insert(property_value.end(), valAsBe.begin(),
+                                valAsBe.end());
+        }
+      }
 
-        /* Also write this to the NVRAM */
-        ret = btif_storage_set_remote_device_property(&bd_addr, &prop[0]);
-        ASSERTC(ret == BT_STATUS_SUCCESS, "storing remote services failed",
-                ret);
-        num_properties++;
+      if (num_uuids == 0) {
+        LOG_INFO("No well known BLE services discovered");
+        return;
+      }
 
-        /* Remote name update */
-        if (strnlen((const char*)p_data->disc_ble_res.bd_name, BD_NAME_LEN)) {
-          prop[1].type = BT_PROPERTY_BDNAME;
-          prop[1].val = p_data->disc_ble_res.bd_name;
-          prop[1].len =
-              strnlen((char*)p_data->disc_ble_res.bd_name, BD_NAME_LEN);
+      RawAddress& bd_addr = p_data->disc_ble_res.bd_addr;
+      prop[0].type = BT_PROPERTY_UUIDS;
+      prop[0].val = (void*)property_value.data();
+      prop[0].len = Uuid::kNumBytes128 * num_uuids;
 
-          ret = btif_storage_set_remote_device_property(&bd_addr, &prop[1]);
-          ASSERTC(ret == BT_STATUS_SUCCESS,
-                  "failed to save remote device property", ret);
-          num_properties++;
-        }
+      /* Also write this to the NVRAM */
+      bt_status_t ret =
+          btif_storage_set_remote_device_property(&bd_addr, &prop[0]);
+      ASSERTC(ret == BT_STATUS_SUCCESS, "storing remote services failed", ret);
+      num_properties++;
 
-        /* Send the event to the BTIF */
-        invoke_remote_device_properties_cb(BT_STATUS_SUCCESS, bd_addr,
-                                           num_properties, prop);
+      /* Remote name update */
+      if (strnlen((const char*)p_data->disc_ble_res.bd_name, BD_NAME_LEN)) {
+        prop[1].type = BT_PROPERTY_BDNAME;
+        prop[1].val = p_data->disc_ble_res.bd_name;
+        prop[1].len = strnlen((char*)p_data->disc_ble_res.bd_name, BD_NAME_LEN);
+
+        ret = btif_storage_set_remote_device_property(&bd_addr, &prop[1]);
+        ASSERTC(ret == BT_STATUS_SUCCESS,
+                "failed to save remote device property", ret);
+        num_properties++;
       }
+
+      /* Send the event to the BTIF */
+      invoke_remote_device_properties_cb(BT_STATUS_SUCCESS, bd_addr,
+                                         num_properties, prop);
     } break;
 
     default: { ASSERTC(0, "unhandled search services event", event); } break;
-- 
GitLab