[BLE Refactor] Refactor GATTClient implementation.

PiperOrigin-RevId: 454290863
This commit is contained in:
edwinwu
2022-06-10 20:20:40 -07:00
committed by Copybara-Service
parent c96875f310
commit 67b318fa6f
8 changed files with 117 additions and 67 deletions
+32 -10
View File
@@ -14,6 +14,7 @@
#include "connections/implementation/mediums/ble_v2.h"
#include <algorithm>
#include <memory>
#include <string>
#include <utility>
@@ -607,15 +608,8 @@ void BleV2::ProcessFetchGattAdvertisementsRequest(
return;
}
// Always use kCopresenceServiceUuid for service uuid.
if (!gatt_client->DiscoverService(
mediums::bleutils::kCopresenceServiceUuid)) {
NEARBY_LOGS(WARNING) << "GATT client can't discover service.";
advertisement_read_result.RecordLastReadStatus(false);
return;
}
// Read all advertisements from all slots that we haven't read from yet.
// Collect service_uuid and its associated characteristic_uuids.
absl::flat_hash_map<int, Uuid> slot_characteristic_uuids = {};
for (int slot = 0; slot < num_slots; ++slot) {
// Make sure we haven't already read this advertisement before.
if (advertisement_read_result.HasAdvertisement(slot)) {
@@ -632,8 +626,36 @@ void BleV2::ProcessFetchGattAdvertisementsRequest(
if (!advertiement_uuid.has_value()) {
continue;
}
slot_characteristic_uuids.insert({slot, *advertiement_uuid});
}
if (slot_characteristic_uuids.empty()) {
// TODO(b/222392304): More test coverage.
NEARBY_LOGS(WARNING) << "Edwin GATT client doesn't have characteristics.";
advertisement_read_result.RecordLastReadStatus(false);
return;
}
// Discover service and characteristics.
std::vector<Uuid> characteristic_uuids;
std::transform(slot_characteristic_uuids.begin(),
slot_characteristic_uuids.end(),
std::back_inserter(characteristic_uuids),
[](auto& kv) { return kv.second; });
if (!gatt_client->DiscoverServiceAndCharacteristics(
mediums::bleutils::kCopresenceServiceUuid, characteristic_uuids)) {
// TODO(b/222392304): More test coverage.
NEARBY_LOGS(WARNING) << "Edwin GATT client doesn't have characteristics.";
advertisement_read_result.RecordLastReadStatus(false);
return;
}
// Read all advertisements from all characteristics that we haven't read from
// yet.
for (const auto& it : slot_characteristic_uuids) {
int slot = it.first;
Uuid characteristic_uuid = it.second;
auto gatt_characteristic = gatt_client->GetCharacteristic(
mediums::bleutils::kCopresenceServiceUuid, *advertiement_uuid);
mediums::bleutils::kCopresenceServiceUuid, characteristic_uuid);
if (!gatt_characteristic.has_value()) {
continue;
}
+5 -2
View File
@@ -192,8 +192,11 @@ class GattClient final {
std::unique_ptr<api::ble_v2::GattClient> client_gatt_connection)
: impl_(std::move(client_gatt_connection)) {}
bool DiscoverService(const Uuid& service_uuid) {
return impl_->DiscoverService(service_uuid);
bool DiscoverServiceAndCharacteristics(
const Uuid& service_uuid,
const std::vector<Uuid>& characteristic_uuids) {
return impl_->DiscoverServiceAndCharacteristics(service_uuid,
characteristic_uuids);
}
// NOLINTNEXTLINE(google3-legacy-absl-backports)
+3 -3
View File
@@ -387,10 +387,10 @@ TEST_F(BleV2MediumTest, GattClientConnectToGattServerWorks) {
ASSERT_NE(gatt_client, nullptr);
// Discover service.
EXPECT_TRUE(gatt_client->DiscoverService(service_uuid));
// Discover service and characteristics.
EXPECT_TRUE(gatt_client->DiscoverServiceAndCharacteristics(
service_uuid, {characteristic_uuid}));
// Discover characteristic.
// NOLINTNEXTLINE(google3-legacy-absl-backports)
absl::optional<GattCharacteristic> client_characteristic =
gatt_client->GetCharacteristic(service_uuid, characteristic_uuid);
+5 -3
View File
@@ -137,15 +137,17 @@ class GattClient {
// Returns whether or not discovery finished successfully.
//
// This function should block until discovery has finished.
virtual bool DiscoverService(const Uuid& service_uuid) = 0;
virtual bool DiscoverServiceAndCharacteristics(
const Uuid& service_uuid,
const std::vector<Uuid>& characteristic_uuids) = 0;
// https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#getService(java.util.UUID)
// https://developer.android.com/reference/android/bluetooth/BluetoothGattService.html#getCharacteristic(java.util.UUID)
//
// Retrieves a GATT characteristic. On error, does not return a value.
//
// DiscoverServices() should be called before this method to fetch all
// available services and characteristics first.
// DiscoverServiceAndCharacteristics() should be called before this method to
// fetch all available services and characteristics first.
//
// It is okay for duplicate services to exist, as long as the specified
// characteristic UUID is unique among all services of the same UUID.
+23 -13
View File
@@ -306,17 +306,18 @@ void BleV2Medium::GattServer::Stop() {
MediumEnvironment::Instance().ClearBleV2MediumGattCharacteristics();
}
bool BleV2Medium::GattClient::DiscoverService(const Uuid& service_uuid) {
bool BleV2Medium::GattClient::DiscoverServiceAndCharacteristics(
const Uuid& service_uuid, const std::vector<Uuid>& characteristic_uuids) {
absl::MutexLock lock(&mutex_);
NEARBY_LOGS(INFO) << "G3 Ble GattClient DiscoverService, service_uuid="
<< service_uuid.Get16BitAsString();
NEARBY_LOGS(INFO)
<< "G3 Ble GattClient DiscoverServiceAndCharacteristics, service_uuid="
<< service_uuid.Get16BitAsString();
if (!is_connection_alive_) {
return false;
}
// Search if the service exists.
return MediumEnvironment::Instance().ContainsBleV2MediumGattCharacteristics(
service_uuid, /*characteristic_uuid=*/{});
return MediumEnvironment::Instance().DiscoverBleV2MediumGattCharacteristics(
service_uuid, characteristic_uuids);
}
std::optional<api::ble_v2::GattCharacteristic>
@@ -331,13 +332,20 @@ BleV2Medium::GattClient::GetCharacteristic(const Uuid& service_uuid,
return std::nullopt;
}
// Search gatt_characteristic by uuid and if found return the
// gatt_characteristic.
api::ble_v2::GattCharacteristic characteristic;
if (MediumEnvironment::Instance().ContainsBleV2MediumGattCharacteristics(
service_uuid, characteristic_uuid)) {
characteristic = {.uuid = characteristic_uuid,
.service_uuid = service_uuid};
// clang-format off
api::ble_v2::GattCharacteristic characteristic = {
.uuid = characteristic_uuid,
.service_uuid = service_uuid};
// clang-format on
ByteArray value =
MediumEnvironment::Instance().ReadBleV2MediumGattCharacteristics(
characteristic);
if (value.Empty()) {
NEARBY_LOGS(WARNING)
<< "G3 Ble GattClient GetCharacteristic, can't find characteristic=("
<< characteristic.service_uuid.Get16BitAsString() << ","
<< std::string(characteristic.uuid) << ")";
return std::nullopt;
}
NEARBY_LOGS(INFO)
<< "G3 Ble GattClient GetCharacteristic, found characteristic=("
@@ -375,6 +383,8 @@ void BleV2Medium::GattClient::Disconnect() {
absl::MutexLock lock(&mutex_);
NEARBY_LOGS(INFO) << "G3 Ble GattClient Disconnect";
is_connection_alive_ = false;
MediumEnvironment::Instance()
.ClearBleV2MediumGattCharacteristicsForDiscovery();
}
std::unique_ptr<api::ble_v2::BleServerSocket> BleV2Medium::OpenServerSocket(
+3 -1
View File
@@ -216,7 +216,9 @@ class BleV2Medium : public api::ble_v2::BleMedium {
// A concrete implemenation for GattClient.
class GattClient : public api::ble_v2::GattClient {
public:
bool DiscoverService(const Uuid& service_uuid) override;
bool DiscoverServiceAndCharacteristics(
const Uuid& service_uuid,
const std::vector<Uuid>& characteristic_uuids) override;
std::optional<api::ble_v2::GattCharacteristic> GetCharacteristic(
const Uuid& service_uuid, const Uuid& characteristic_uuid) override;
+30 -25
View File
@@ -14,6 +14,7 @@
#include "internal/platform/medium_environment.h"
#include <algorithm>
#include <atomic>
#include <cinttypes>
#include <functional>
@@ -615,31 +616,34 @@ void MediumEnvironment::InsertBleV2MediumGattCharacteristics(
latch.Await();
}
bool MediumEnvironment::ContainsBleV2MediumGattCharacteristics(
const Uuid& service_uuid, const Uuid& characteristic_uuid) {
void MediumEnvironment::ClearBleV2MediumGattCharacteristics() {
if (!enabled_) return;
RunOnMediumEnvironmentThread([this]() { gatt_advertisement_bytes_.clear(); });
}
bool MediumEnvironment::DiscoverBleV2MediumGattCharacteristics(
const Uuid& service_uuid, const std::vector<Uuid>& characteristic_uuids) {
if (!enabled_) return false;
bool found_characteristic = false;
CountDownLatch latch(1);
RunOnMediumEnvironmentThread([this, &latch, &service_uuid,
&characteristic_uuid, &found_characteristic]() {
for (const auto& item : gatt_advertisement_bytes_) {
if (item.first.service_uuid == service_uuid) {
if (characteristic_uuid.IsEmpty()) {
// Found the service uuid and no need to search characteristic
// uuid.
found_characteristic = true;
break;
RunOnMediumEnvironmentThread(
[this, &latch, &service_uuid, &characteristic_uuids]() {
for (const auto& item : gatt_advertisement_bytes_) {
if (item.first.service_uuid == service_uuid) {
Uuid char_uuid_key = item.first.uuid;
auto it = std::find_if(characteristic_uuids.rbegin(),
characteristic_uuids.rend(),
[char_uuid_key](const auto& char_uuid) {
return char_uuid == char_uuid_key;
});
if (it != characteristic_uuids.rend()) {
discovered_gatt_advertisement_bytes_[item.first] = item.second;
}
}
}
if (item.first.uuid == characteristic_uuid) {
found_characteristic = true;
break;
}
}
}
latch.CountDown();
});
latch.CountDown();
});
latch.Await();
return found_characteristic;
return true;
}
ByteArray MediumEnvironment::ReadBleV2MediumGattCharacteristics(
@@ -649,8 +653,8 @@ ByteArray MediumEnvironment::ReadBleV2MediumGattCharacteristics(
CountDownLatch latch(1);
RunOnMediumEnvironmentThread(
[this, &latch, &characteristic, &gatt_advertisement_byte]() {
auto it = gatt_advertisement_bytes_.find(characteristic);
if (it != gatt_advertisement_bytes_.end()) {
auto it = discovered_gatt_advertisement_bytes_.find(characteristic);
if (it != discovered_gatt_advertisement_bytes_.end()) {
gatt_advertisement_byte = it->second;
}
latch.CountDown();
@@ -659,9 +663,10 @@ ByteArray MediumEnvironment::ReadBleV2MediumGattCharacteristics(
return gatt_advertisement_byte;
}
void MediumEnvironment::ClearBleV2MediumGattCharacteristics() {
void MediumEnvironment::ClearBleV2MediumGattCharacteristicsForDiscovery() {
if (!enabled_) return;
RunOnMediumEnvironmentThread([this]() { gatt_advertisement_bytes_.clear(); });
RunOnMediumEnvironmentThread(
[this]() { discovered_gatt_advertisement_bytes_.clear(); });
}
void MediumEnvironment::UnregisterBleV2Medium(api::ble_v2::BleMedium& medium) {
+16 -10
View File
@@ -31,12 +31,12 @@
#endif
#include "internal/platform/byte_array.h"
#include "internal/platform/feature_flags.h"
#include "internal/platform/implementation/wifi_lan.h"
#include "internal/platform/wifi_hotspot_credential.h"
#include "internal/platform/implementation/wifi_hotspot.h"
#include "internal/platform/implementation/wifi_lan.h"
#include "internal/platform/mutex.h"
#include "internal/platform/nsd_service_info.h"
#include "internal/platform/single_thread_executor.h"
#include "internal/platform/mutex.h"
#include "internal/platform/wifi_hotspot_credential.h"
namespace location {
namespace nearby {
@@ -241,19 +241,22 @@ class MediumEnvironment {
const api::ble_v2::GattCharacteristic& characteristic,
const ByteArray& gatt_advertisement_byte);
// Check if `service_uuid` and `characteristic_uuid` exists in the map.
//
// `characteristic_uuid` can be empty and to check `service_uuid` only.
bool ContainsBleV2MediumGattCharacteristics(const Uuid& service_uuid,
const Uuid& characteristic_uuid);
// Clears the map `gatt_advertisement_bytes_`.
void ClearBleV2MediumGattCharacteristics();
// Discover `service_uuid` and `characteristic_uuids`. This is to save the
// matched `gatt_advertisement_bytes_` to the
// `discovered_gatt_advertisement_bytes_`.
bool DiscoverBleV2MediumGattCharacteristics(
const Uuid& service_uuid, const std::vector<Uuid>& characteristic_uuids);
// Reads the BLE GATT characteristic value. If the GATT characteristic is not
// existed, return empty byte array.
ByteArray ReadBleV2MediumGattCharacteristics(
const api::ble_v2::GattCharacteristic& characteristic);
// Clears the map `gatt_advertisement_bytes_`.
void ClearBleV2MediumGattCharacteristics();
// Clears the map `discovered_gatt_advertisement_bytes_`.
void ClearBleV2MediumGattCharacteristicsForDiscovery();
// Removes medium-related info. This should correspond to device power off.
void UnregisterBleV2Medium(api::ble_v2::BleMedium& mediumum);
@@ -403,6 +406,9 @@ class MediumEnvironment {
absl::flat_hash_map<api::ble_v2::GattCharacteristic,
location::nearby::ByteArray>
gatt_advertisement_bytes_;
absl::flat_hash_map<api::ble_v2::GattCharacteristic,
location::nearby::ByteArray>
discovered_gatt_advertisement_bytes_;
#ifndef NO_WEBRTC
// Maps peer id to callback for receiving signaling messages.