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

Commit 128d1813 authored by Jakub Pawlowski's avatar Jakub Pawlowski
Browse files

Client support for Characteristic Extended Properties

Read value of Characteristic Extended Properties descirptors as part of
GATT service discovery process. Also store this value as part of GATT
Cache.

Test: updated GattDatabaseTest.serialize_deserialize_binary_test added
 GattCacheTest.stored_attribute_to_binary_characteristic_extended_properties_test
 Added sl4a GattExtendedPropertiesTest
Bug: 110864501
Change-Id: Iccd8aa378c14e75f91d761a675c7c23f096ce2da
parent 5f9ea0fa
Loading
Loading
Loading
Loading
+0 −8
Original line number Diff line number Diff line
@@ -965,14 +965,6 @@ void bta_gattc_op_cmpl(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
  }
}

/** operation completed */
void bta_gattc_ignore_op_cmpl(UNUSED_ATTR tBTA_GATTC_CLCB* p_clcb,
                              tBTA_GATTC_DATA* p_data) {
  /* receive op complete when discovery is started, ignore the response,
      and wait for discovery finish and resent */
  VLOG(1) << __func__ << ": op = " << +p_data->hdr.layer_specific;
}

/** start a search in the local server cache */
void bta_gattc_search(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
  tGATT_STATUS status = GATT_INTERNAL_ERROR;
+85 −8
Original line number Diff line number Diff line
@@ -46,6 +46,8 @@
#include "sdpdefs.h"
#include "utl.h"

#include <base/strings/string_number_conversions.h>

using base::StringPrintf;
using bluetooth::Uuid;
using gatt::Characteristic;
@@ -70,7 +72,7 @@ static void bta_gattc_explore_srvc_finished(uint16_t conn_id,
#define BTA_GATT_SDP_DB_SIZE 4096

#define GATT_CACHE_PREFIX "/data/misc/bluetooth/gatt_cache_"
#define GATT_CACHE_VERSION 5
#define GATT_CACHE_VERSION 6

static void bta_gattc_generate_cache_file_name(char* buffer, size_t buffer_len,
                                               const RawAddress& bda) {
@@ -153,16 +155,44 @@ static void bta_gattc_explore_next_service(uint16_t conn_id,
    return;
  }

  if (!p_srvc_cb->pending_discovery.StartNextServiceExploration()) {
    bta_gattc_explore_srvc_finished(conn_id, p_srvc_cb);
    return;
  }

  const auto& service = p_srvc_cb->pending_discovery.CurrentlyExploredService();
  if (p_srvc_cb->pending_discovery.StartNextServiceExploration()) {
    const auto& service =
        p_srvc_cb->pending_discovery.CurrentlyExploredService();
    VLOG(1) << "Start service discovery";

    /* start discovering included services */
    GATTC_Discover(conn_id, GATT_DISC_INC_SRVC, service.first, service.second);
    return;
  }
  // No more services to discover

  // As part of service discovery, read the values of "Characteristic Extended
  // Properties" descriptor
  const auto& descriptors =
      p_srvc_cb->pending_discovery.DescriptorHandlesToRead();
  if (!descriptors.empty()) {
    // TODO(jpawlowski): as a limit we should use MTU/2 rather than
    // GATT_MAX_READ_MULTI_HANDLES
    /* each descriptor contains just 2 bytes, so response size is same as
     * request size */
    size_t num_handles =
        std::min(descriptors.size(), (size_t)GATT_MAX_READ_MULTI_HANDLES);

    tGATT_READ_PARAM read_param;
    memset(&read_param, 0, sizeof(tGATT_READ_PARAM));

    read_param.read_multiple.num_handles = num_handles;
    read_param.read_multiple.auth_req = GATT_AUTH_REQ_NONE;
    memcpy(&read_param.read_multiple.handles, descriptors.data(),
           sizeof(uint16_t) * num_handles);
    GATTC_Read(conn_id, GATT_READ_MULTIPLE, &read_param);

    // asynchronous continuation in bta_gattc_op_cmpl_during_discovery, when
    // read is finished
    return;
  }

  bta_gattc_explore_srvc_finished(conn_id, p_srvc_cb);
}

static void bta_gattc_explore_srvc_finished(uint16_t conn_id,
@@ -315,6 +345,53 @@ static tGATT_STATUS bta_gattc_sdp_service_disc(uint16_t conn_id,
  return GATT_SUCCESS;
}

/** operation completed */
void bta_gattc_op_cmpl_during_discovery(UNUSED_ATTR tBTA_GATTC_CLCB* p_clcb,
                                        tBTA_GATTC_DATA* p_data) {
  uint8_t op = (uint8_t)p_data->op_cmpl.op_code;

  if (op != GATTC_OPTYPE_READ) {
    /* receive op complete when discovery is started, ignore the response,
       and wait for discovery finish and resent */
    VLOG(1) << __func__ << ": op = " << +p_data->hdr.layer_specific;
    return;
  }

  // our read operation is finished.
  // TODO: check if we can get here when any other read operation i.e. initiated
  // by upper layer apps, can get us there.
  const uint8_t status = p_data->op_cmpl.status;
  if (status != GATT_SUCCESS) {
    if (status == GATT_REQ_NOT_SUPPORTED) {
      // TODO: handle case when read multiple is not supported on remote device.
    }
    LOG(WARNING) << "Discovery on server failed: " << loghex(status);
    bta_gattc_reset_discover_st(p_clcb->p_srcb, GATT_ERROR);
  }

  const tGATT_VALUE& att_value = p_data->op_cmpl.p_cmpl->att_value;

  const uint8_t* p = att_value.value;
  std::vector<uint16_t> value_of_descriptors;
  while (p < att_value.value + att_value.len) {
    uint16_t extended_properties;
    STREAM_TO_UINT16(extended_properties, p);
    value_of_descriptors.push_back(extended_properties);
  }

  tBTA_GATTC_SERV* p_srvc_cb = p_clcb->p_srcb;
  bool ret =
      p_srvc_cb->pending_discovery.SetValueOfDescriptors(value_of_descriptors);
  if (!ret) {
    LOG(WARNING) << __func__
                 << " Problem setting Extended Properties descriptors values";
    bta_gattc_reset_discover_st(p_clcb->p_srcb, GATT_ERROR);
  }

  // Continue service discovery
  bta_gattc_explore_next_service(p_clcb->bta_conn_id, p_srvc_cb);
}

/** callback function to GATT client stack */
void bta_gattc_disc_res_cback(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
                              tGATT_DISC_RES* p_data) {
+2 −2
Original line number Diff line number Diff line
@@ -363,7 +363,7 @@ extern void bta_gattc_read_multi(tBTA_GATTC_CLCB* p_clcb,
extern void bta_gattc_ci_open(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
extern void bta_gattc_ci_close(tBTA_GATTC_CLCB* p_clcb,
                               tBTA_GATTC_DATA* p_data);
extern void bta_gattc_ignore_op_cmpl(tBTA_GATTC_CLCB* p_clcb,
extern void bta_gattc_op_cmpl_during_discovery(tBTA_GATTC_CLCB* p_clcb,
                                               tBTA_GATTC_DATA* p_data);
extern void bta_gattc_restart_discover(tBTA_GATTC_CLCB* p_clcb,
                                       tBTA_GATTC_DATA* p_msg);
+26 −26
Original line number Diff line number Diff line
@@ -57,7 +57,7 @@ enum {
  BTA_GATTC_CONFIRM,
  BTA_GATTC_EXEC,
  BTA_GATTC_READ_MULTI,
  BTA_GATTC_IGNORE_OP_CMPL,
  BTA_GATTC_OP_CMPL_DURING_DISCOVERY,
  BTA_GATTC_DISC_CLOSE,
  BTA_GATTC_RESTART_DISCOVER,
  BTA_GATTC_CFG_MTU,
@@ -90,7 +90,7 @@ const tBTA_GATTC_ACTION bta_gattc_action[] = {
    bta_gattc_confirm,                  /* BTA_GATTC_CONFIRM */
    bta_gattc_execute,                  /* BTA_GATTC_EXEC */
    bta_gattc_read_multi,               /* BTA_GATTC_READ_MULTI */
    bta_gattc_ignore_op_cmpl,    /* BTA_GATTC_IGNORE_OP_CMPL */
    bta_gattc_op_cmpl_during_discovery, /* BTA_GATTC_OP_CMPL_DURING_DISCOVERY */
    bta_gattc_disc_close,               /* BTA_GATTC_DISC_CLOSE */
    bta_gattc_restart_discover,         /* BTA_GATTC_RESTART_DISCOVER */
    bta_gattc_cfg_mtu                   /* BTA_GATTC_CFG_MTU */
@@ -256,7 +256,7 @@ static const uint8_t bta_gattc_st_discover[][BTA_GATTC_NUM_COLS] = {
                                            BTA_GATTC_DISCOVER_ST},
    /* BTA_GATTC_DISCOVER_CMPL_EVT      */ {BTA_GATTC_DISC_CMPL,
                                            BTA_GATTC_CONN_ST},
    /* BTA_GATTC_OP_CMPL_EVT            */ {BTA_GATTC_IGNORE_OP_CMPL,
    /* BTA_GATTC_OP_CMPL_EVT            */ {BTA_GATTC_OP_CMPL_DURING_DISCOVERY,
                                            BTA_GATTC_DISCOVER_ST},
    /* BTA_GATTC_INT_DISCONN_EVT        */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST},

+21 −3
Original line number Diff line number Diff line
@@ -35,6 +35,8 @@ const Uuid PRIMARY_SERVICE = Uuid::From16Bit(GATT_UUID_PRI_SERVICE);
const Uuid SECONDARY_SERVICE = Uuid::From16Bit(GATT_UUID_SEC_SERVICE);
const Uuid INCLUDE = Uuid::From16Bit(GATT_UUID_INCLUDE_SERVICE);
const Uuid CHARACTERISTIC = Uuid::From16Bit(GATT_UUID_CHAR_DECLARE);
const Uuid CHARACTERISTIC_EXTENDED_PROPERTIES =
    Uuid::From16Bit(GATT_UUID_CHAR_EXT_PROP);

bool HandleInRange(const Service& svc, uint16_t handle) {
  return handle >= svc.handle && handle <= svc.end_handle;
@@ -116,10 +118,17 @@ std::vector<StoredAttribute> Database::Serialize() const {
                               .uuid = charac.uuid}}});

      for (const Descriptor& desc : charac.descriptors) {
        if (desc.uuid == CHARACTERISTIC_EXTENDED_PROPERTIES) {
          nv_attr.push_back({desc.handle,
                             desc.uuid,
                             {.characteristic_extended_properties =
                                  desc.characteristic_extended_properties}});
        } else {
          nv_attr.push_back({desc.handle, desc.uuid, {}});
        }
      }
    }
  }

  return nv_attr;
}
@@ -182,11 +191,20 @@ Database Database::Deserialize(const std::vector<StoredAttribute>& nv_attr,
          .properties = attr.value.characteristic.properties,
      });

    } else {
      if (attr.type == CHARACTERISTIC_EXTENDED_PROPERTIES) {
        current_service_it->characteristics.back().descriptors.emplace_back(
            Descriptor{.handle = attr.handle,
                       .uuid = attr.type,
                       .characteristic_extended_properties =
                           attr.value.characteristic_extended_properties});

      } else {
        current_service_it->characteristics.back().descriptors.emplace_back(
            Descriptor{.handle = attr.handle, .uuid = attr.type});
      }
    }
  }
  *success = true;
  return result;
}
Loading