[BLE Refactor] Implement CreateAdvertisementHeader in BleV2 medium.
PiperOrigin-RevId: 429550598
diff --git a/connections/implementation/mediums/BUILD b/connections/implementation/mediums/BUILD
index 3784a44..95c21cb 100644
--- a/connections/implementation/mediums/BUILD
+++ b/connections/implementation/mediums/BUILD
@@ -17,6 +17,7 @@
name = "mediums",
srcs = [
"ble.cc",
+ "ble_v2.cc",
"bluetooth_classic.cc",
"bluetooth_radio.cc",
"mediums.cc",
@@ -26,6 +27,7 @@
],
hdrs = [
"ble.h",
+ "ble_v2.h",
"bluetooth_classic.h",
"bluetooth_radio.h",
"lost_entity_tracker.h",
diff --git a/connections/implementation/mediums/ble_v2.cc b/connections/implementation/mediums/ble_v2.cc
new file mode 100644
index 0000000..f22a93f
--- /dev/null
+++ b/connections/implementation/mediums/ble_v2.cc
@@ -0,0 +1,84 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "connections/implementation/mediums/ble_v2.h"
+
+#include <string>
+#include <string_view>
+
+#include "absl/strings/str_cat.h"
+#include "connections/implementation/mediums/ble_v2/ble_advertisement.h"
+#include "connections/implementation/mediums/ble_v2/ble_advertisement_header.h"
+#include "connections/implementation/mediums/ble_v2/bloom_filter.h"
+#include "connections/implementation/mediums/utils.h"
+#include "internal/platform/prng.h"
+
+namespace location {
+namespace nearby {
+namespace connections {
+
+namespace {
+
+constexpr int kDummyServiceIdLength = 128;
+
+ByteArray GenerateAdvertisementHash(const ByteArray& advertisement_bytes) {
+ return Utils::Sha256Hash(
+ advertisement_bytes,
+ mediums::BleAdvertisementHeader::kAdvertisementHashLength);
+}
+
+} // namespace
+
+BleV2::BleV2(BluetoothRadio& radio)
+ : radio_(radio), adapter_(radio_.GetBluetoothAdapter()) {}
+
+ByteArray BleV2::CreateAdvertisementHeader() {
+ // Create a randomized dummy service id to anonymize the header with.
+ ByteArray dummy_service_id_bytes =
+ Utils::GenerateRandomBytes(kDummyServiceIdLength);
+ std::string dummy_service_id{dummy_service_id_bytes};
+
+ mediums::BloomFilter<
+ mediums::BleAdvertisementHeader::kServiceIdBloomFilterLength>
+ bloom_filter;
+ bloom_filter.Add(dummy_service_id);
+
+ ByteArray advertisement_hash =
+ GenerateAdvertisementHash(dummy_service_id_bytes);
+ for (const auto& item : gatt_advertisements_) {
+ const std::string& service_id = item.second.first;
+ const ByteArray& gatt_advertisement = item.second.second;
+ bloom_filter.Add(service_id);
+
+ // Compute the next hash according to the algorithm in
+ // https://source.corp.google.com/piper///depot/google3/java/com/google/android/gmscore/integ/modules/nearby/src/com/google/android/gms/nearby/mediums/bluetooth/BluetoothLowEnergy.java;rcl=428397891;l=1043
+ ByteArray previous_advertisement_hash = advertisement_hash;
+ std::string advertisement_bodies =
+ absl::StrCat(previous_advertisement_hash.AsStringView(),
+ gatt_advertisement.AsStringView());
+
+ advertisement_hash =
+ GenerateAdvertisementHash(ByteArray(std::move(advertisement_bodies)));
+ }
+
+ return ByteArray(mediums::BleAdvertisementHeader(
+ mediums::BleAdvertisementHeader::Version::kV2,
+ /*extended_advertisement=*/false,
+ /*num_slots=*/gatt_advertisements_.size(), ByteArray(bloom_filter),
+ advertisement_hash, /*psm=*/0));
+}
+
+} // namespace connections
+} // namespace nearby
+} // namespace location
diff --git a/connections/implementation/mediums/ble_v2.h b/connections/implementation/mediums/ble_v2.h
new file mode 100644
index 0000000..2edc01b
--- /dev/null
+++ b/connections/implementation/mediums/ble_v2.h
@@ -0,0 +1,52 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CORE_INTERNAL_MEDIUMS_BLE_V2_H_
+#define CORE_INTERNAL_MEDIUMS_BLE_V2_H_
+
+#include <cstdint>
+#include <string>
+#include <utility>
+
+#include "absl/container/flat_hash_map.h"
+#include "connections/implementation/mediums/bluetooth_radio.h"
+#include "internal/platform/byte_array.h"
+#include "internal/platform/mutex.h"
+
+namespace location {
+namespace nearby {
+namespace connections {
+
+// TODO(b/213691253): Add BleV2 medium tests after more functions are ready.
+// Provides the operations that can be performed on the Bluetooth Low Energy
+// (BLE) medium.
+class BleV2 {
+ public:
+ explicit BleV2(BluetoothRadio& bluetooth_radio);
+
+ private:
+ ByteArray CreateAdvertisementHeader() ABSL_SHARED_LOCKS_REQUIRED(mutex_);
+
+ mutable Mutex mutex_;
+ BluetoothRadio& radio_ ABSL_GUARDED_BY(mutex_);
+ BluetoothAdapter& adapter_ ABSL_GUARDED_BY(mutex_);
+ absl::flat_hash_map<int, std::pair<std::string, ByteArray>>
+ gatt_advertisements_ ABSL_GUARDED_BY(mutex_);
+};
+
+} // namespace connections
+} // namespace nearby
+} // namespace location
+
+#endif // CORE_INTERNAL_MEDIUMS_BLE_V2_H_
diff --git a/connections/implementation/mediums/ble_v2/ble_advertisement_header.cc b/connections/implementation/mediums/ble_v2/ble_advertisement_header.cc
index a1379c1..30b440c 100644
--- a/connections/implementation/mediums/ble_v2/ble_advertisement_header.cc
+++ b/connections/implementation/mediums/ble_v2/ble_advertisement_header.cc
@@ -26,6 +26,10 @@
namespace connections {
namespace mediums {
+// These definitions are necessary before C++17.
+constexpr int BleAdvertisementHeader::kAdvertisementHashLength;
+constexpr int BleAdvertisementHeader::kServiceIdBloomFilterLength;
+
BleAdvertisementHeader::BleAdvertisementHeader(
Version version, bool extended_advertisement, int num_slots,
const ByteArray &service_id_bloom_filter,
diff --git a/connections/implementation/mediums/ble_v2/ble_advertisement_header.h b/connections/implementation/mediums/ble_v2/ble_advertisement_header.h
index 24dd358..b3f8355 100644
--- a/connections/implementation/mediums/ble_v2/ble_advertisement_header.h
+++ b/connections/implementation/mediums/ble_v2/ble_advertisement_header.h
@@ -51,6 +51,9 @@
// characteristic so the two are not compatible.
};
+ static constexpr int kAdvertisementHashLength = 4;
+ static constexpr int kServiceIdBloomFilterLength = 10;
+
BleAdvertisementHeader() = default;
BleAdvertisementHeader(Version version, bool extended_advertisement,
int num_slots,
@@ -76,8 +79,6 @@
private:
static constexpr int kVersionAndNumSlotsLength = 1;
- static constexpr int kServiceIdBloomFilterLength = 10;
- static constexpr int kAdvertisementHashLength = 4;
static constexpr int kMinAdvertisementHeaderLength =
kVersionAndNumSlotsLength + kServiceIdBloomFilterLength +
kAdvertisementHashLength;
diff --git a/cpp/core/internal/mediums/BUILD b/cpp/core/internal/mediums/BUILD
new file mode 100644
index 0000000..9167825
--- /dev/null
+++ b/cpp/core/internal/mediums/BUILD
@@ -0,0 +1,14 @@
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+licenses(["notice"])
diff --git a/cpp/core/internal/mediums/ble_v2.cc b/cpp/core/internal/mediums/ble_v2.cc
new file mode 100644
index 0000000..a1e0f5a
--- /dev/null
+++ b/cpp/core/internal/mediums/ble_v2.cc
@@ -0,0 +1,90 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "third_party/nearby/cpp/core/internal/mediums/ble_v2.h"
+
+#include <string>
+
+#include "absl/strings/str_cat.h"
+#include "third_party/nearby/cpp/core/internal/mediums/ble_v2/ble_advertisement.h"
+#include "third_party/nearby/cpp/core/internal/mediums/ble_v2/ble_advertisement_header.h"
+#include "third_party/nearby/cpp/core/internal/mediums/ble_v2/bloom_filter.h"
+#include "third_party/nearby/cpp/core/internal/mediums/utils.h"
+#include "third_party/nearby/cpp/platform/base/prng.h"
+
+namespace location {
+namespace nearby {
+namespace connections {
+
+ByteArray BleV2::GenerateAdvertisementHash(
+ const ByteArray& advertisement_bytes) {
+ return Utils::Sha256Hash(
+ advertisement_bytes,
+ mediums::BleAdvertisementHeader::kAdvertisementHashLength);
+}
+
+ByteArray BleV2::GenerateHash(const std::string& source, size_t size) {
+ return Utils::Sha256Hash(source, size);
+}
+
+ByteArray BleV2::GenerateDeviceToken() {
+ return Utils::Sha256Hash(std::to_string(Prng().NextUint32()),
+ mediums::BleAdvertisement::kDeviceTokenLength);
+}
+
+BleV2::BleV2(BluetoothRadio& radio) : radio_(radio) {}
+
+ByteArray BleV2::CreateAdvertisementHeader() {
+ // Create a randomized dummy service id to anonymize the header with.
+ ByteArray dummy_service_id_bytes =
+ Utils::GenerateRandomBytes(kDummyServiceIdLength);
+ std::string dummy_service_id{dummy_service_id_bytes};
+
+ // Create a bloom filter with the dummy service id.
+ mediums::BloomFilter<
+ mediums::BleAdvertisementHeader::kServiceIdBloomFilterLength>
+ bloom_filter;
+ bloom_filter.Add(dummy_service_id);
+
+ // Add the service id for each GATT advertisement into the bloom filter, while
+ // also creating a hash of dummyServiceIdBytes + all GATT advertisements.
+ ByteArray advertisement_hash =
+ GenerateAdvertisementHash(dummy_service_id_bytes);
+ int num_slots = 0;
+ for (const auto& item : gatt_advertisement_info.gatt_advertisements) {
+ std::string service_id = item.second.first;
+ ByteArray gatt_advertisment = item.second.second;
+ bloom_filter.Add(service_id);
+
+ // Compute the next hash by taking the hash of [previous hash] + [next
+ // advertisement data].
+ ByteArray previous_advertisement_hash = advertisement_hash;
+ std::string advertisement_bodies =
+ absl::StrCat(std::string(previous_advertisement_hash),
+ std::string(gatt_advertisment));
+
+ advertisement_hash =
+ GenerateAdvertisementHash(ByteArray{std::move(advertisement_bodies)});
+ num_slots++;
+ }
+
+ return ByteArray(mediums::BleAdvertisementHeader(
+ mediums::BleAdvertisementHeader::Version::kV2,
+ /*extended_advertisement=*/false, num_slots, ByteArray(bloom_filter),
+ advertisement_hash, /*psm=*/0));
+}
+
+} // namespace connections
+} // namespace nearby
+} // namespace location
diff --git a/cpp/core/internal/mediums/ble_v2.h b/cpp/core/internal/mediums/ble_v2.h
new file mode 100644
index 0000000..ac40080
--- /dev/null
+++ b/cpp/core/internal/mediums/ble_v2.h
@@ -0,0 +1,82 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CORE_INTERNAL_MEDIUMS_BLE_V2_H_
+#define CORE_INTERNAL_MEDIUMS_BLE_V2_H_
+
+#include <cstdint>
+#include <string>
+#include <utility>
+
+#include "absl/container/flat_hash_map.h"
+#include "third_party/nearby/cpp/core/internal/mediums/bluetooth_radio.h"
+#include "third_party/nearby/cpp/platform/base/byte_array.h"
+#include "third_party/nearby/cpp/platform/public/mutex.h"
+
+namespace location {
+namespace nearby {
+namespace connections {
+
+class BleV2 {
+ public:
+ explicit BleV2(BluetoothRadio& bluetooth_radio);
+ ~BleV2() = default;
+
+ private:
+ // Container that stores info about a GATT advertisement.
+ struct GattAdvertisementInfo {
+ bool Empty() const { return gatt_advertisements.empty(); }
+ void Clear() { gatt_advertisements.clear(); }
+ void Add(int slot, std::pair<std::string, ByteArray> gatt_advertisement) {
+ gatt_advertisements.insert({slot, gatt_advertisement});
+ }
+ void Remove(int slot) { gatt_advertisements.erase(slot); }
+ bool Existed(int slot) const {
+ return gatt_advertisements.contains(slot);
+ }
+ std::pair<std::string, ByteArray> GetAdvertisement(int slot) {
+ const auto& it = gatt_advertisements.find(slot);
+ if (it == gatt_advertisements.end()) {
+ return {};
+ }
+ return it->second;
+ }
+
+ // A map of slot -> pair of {service_id, gatt_advertisement}
+ absl::flat_hash_map<int, std::pair<std::string, ByteArray>>
+ gatt_advertisements;
+ };
+
+ static constexpr int kMaxAdvertisementLength = 512;
+ static constexpr int kDummyServiceIdLength = 128;
+
+ static ByteArray GenerateAdvertisementHash(
+ const ByteArray& advertisement_bytes);
+ static ByteArray GenerateHash(const std::string& source, size_t size);
+ static ByteArray GenerateDeviceToken();
+
+ ByteArray CreateAdvertisementHeader() ABSL_SHARED_LOCKS_REQUIRED(mutex_);
+
+ mutable Mutex mutex_;
+ BluetoothRadio& radio_ ABSL_GUARDED_BY(mutex_);
+ BluetoothAdapter& adapter_ ABSL_GUARDED_BY(mutex_){
+ radio_.GetBluetoothAdapter()};
+ GattAdvertisementInfo gatt_advertisement_info ABSL_GUARDED_BY(mutex_);
+};
+
+} // namespace connections
+} // namespace nearby
+} // namespace location
+
+#endif // CORE_INTERNAL_MEDIUMS_BLE_V2_H_
diff --git a/cpp/core/internal/mediums/ble_v2/ble_advertisement_header.cc b/cpp/core/internal/mediums/ble_v2/ble_advertisement_header.cc
new file mode 100644
index 0000000..3f12355
--- /dev/null
+++ b/cpp/core/internal/mediums/ble_v2/ble_advertisement_header.cc
@@ -0,0 +1,142 @@
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "third_party/nearby/cpp/core/internal/mediums/ble_v2/ble_advertisement_header.h"
+
+#include <inttypes.h>
+
+#include "absl/strings/str_cat.h"
+#include "third_party/nearby/cpp/platform/base/base64_utils.h"
+#include "third_party/nearby/cpp/platform/base/base_input_stream.h"
+#include "third_party/nearby/cpp/platform/public/logging.h"
+
+namespace location {
+namespace nearby {
+namespace connections {
+namespace mediums {
+
+// These definitions are necessary before C++17.
+constexpr int BleAdvertisementHeader::kAdvertisementHashLength;
+constexpr int BleAdvertisementHeader::kServiceIdBloomFilterLength;
+
+BleAdvertisementHeader::BleAdvertisementHeader(
+ Version version, bool extended_advertisement, int num_slots,
+ const ByteArray &service_id_bloom_filter,
+ const ByteArray &advertisement_hash, int psm) {
+ if (version != Version::kV2 || num_slots <= 0 ||
+ service_id_bloom_filter.size() != kServiceIdBloomFilterLength ||
+ advertisement_hash.size() != kAdvertisementHashLength) {
+ return;
+ }
+
+ version_ = version;
+ extended_advertisement_ = extended_advertisement;
+ num_slots_ = num_slots;
+ service_id_bloom_filter_ = service_id_bloom_filter;
+ advertisement_hash_ = advertisement_hash;
+ psm_ = psm;
+}
+
+BleAdvertisementHeader::BleAdvertisementHeader(
+ const ByteArray &ble_advertisement_header_bytes) {
+ if (ble_advertisement_header_bytes.Empty()) {
+ NEARBY_LOG(
+ ERROR,
+ "Cannot deserialize BLEAdvertisementHeader: failed Base64 decoding");
+ return;
+ }
+
+ if (ble_advertisement_header_bytes.size() < kMinAdvertisementHeaderLength) {
+ NEARBY_LOG(ERROR,
+ "Cannot deserialize BleAdvertisementHeader: expecting min %u "
+ "raw bytes, got %" PRIu64 " instead",
+ kMinAdvertisementHeaderLength,
+ ble_advertisement_header_bytes.size());
+ return;
+ }
+
+ ByteArray advertisement_header_bytes{ble_advertisement_header_bytes};
+ BaseInputStream base_input_stream{advertisement_header_bytes};
+ // The first 1 byte is supposed to be the version and number of slots.
+ auto version_and_num_slots_byte =
+ static_cast<char>(base_input_stream.ReadUint8());
+ // The upper 3 bits are supposed to be the version.
+ version_ =
+ static_cast<Version>((version_and_num_slots_byte & kVersionBitmask) >> 5);
+ if (version_ != Version::kV2) {
+ NEARBY_LOG(
+ ERROR,
+ "Cannot deserialize BleAdvertisementHeader: unsupported Version %d",
+ version_);
+ return;
+ }
+ // The next 1 bit is supposed to be the extended advertisement flag.
+ extended_advertisement_ =
+ ((version_and_num_slots_byte & kExtendedAdvertismentBitMask) >> 4) == 1;
+ // The lower 4 bits are supposed to be the number of slots.
+ num_slots_ = static_cast<int>(version_and_num_slots_byte & kNumSlotsBitmask);
+ if (num_slots_ <= 0) {
+ version_ = Version::kUndefined;
+ return;
+ }
+
+ // The next 10 bytes are supposed to be the service_id_bloom_filter.
+ service_id_bloom_filter_ =
+ base_input_stream.ReadBytes(kServiceIdBloomFilterLength);
+
+ // The next 4 bytes are supposed to be the advertisement_hash.
+ advertisement_hash_ = base_input_stream.ReadBytes(kAdvertisementHashLength);
+
+ // The next 2 bytes are PSM value.
+ if (base_input_stream.IsAvailable(sizeof(std::uint16_t))) {
+ psm_ = static_cast<int>(base_input_stream.ReadUint16());
+ }
+}
+
+BleAdvertisementHeader::operator ByteArray() const {
+ if (!IsValid()) {
+ return ByteArray();
+ }
+
+ // The first 3 bits are the Version.
+ char version_and_num_slots_byte =
+ (static_cast<char>(version_) << 5) & kVersionBitmask;
+ // The next 1 bit is extended advertisement flag.
+ version_and_num_slots_byte |=
+ (static_cast<char>(extended_advertisement_) << 4) &
+ kExtendedAdvertismentBitMask;
+ // The next 5 bits are the number of slots.
+ version_and_num_slots_byte |=
+ static_cast<char>(num_slots_) & kNumSlotsBitmask;
+
+ // Convert psm_ value to 2-bytes.
+ ByteArray psm_byte{sizeof(std::uint16_t)};
+ char *data = psm_byte.data();
+ data[0] = psm_ & 0xFF00;
+ data[1] = psm_ & 0x00FF;
+
+ // clang-format off
+ std::string out = absl::StrCat(std::string(1, version_and_num_slots_byte),
+ std::string(service_id_bloom_filter_),
+ std::string(advertisement_hash_),
+ std::string(psm_byte));
+ // clang-format on
+
+ return ByteArray(std::move(out));
+}
+
+} // namespace mediums
+} // namespace connections
+} // namespace nearby
+} // namespace location
diff --git a/cpp/core/internal/mediums/ble_v2/ble_advertisement_header.h b/cpp/core/internal/mediums/ble_v2/ble_advertisement_header.h
new file mode 100644
index 0000000..15ba4aa
--- /dev/null
+++ b/cpp/core/internal/mediums/ble_v2/ble_advertisement_header.h
@@ -0,0 +1,102 @@
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CORE_INTERNAL_MEDIUMS_BLE_V2_BLE_ADVERTISEMENT_HEADER_H_
+#define CORE_INTERNAL_MEDIUMS_BLE_V2_BLE_ADVERTISEMENT_HEADER_H_
+
+#include <string>
+
+#include "third_party/nearby/cpp/platform/base/byte_array.h"
+
+namespace location {
+namespace nearby {
+namespace connections {
+namespace mediums {
+
+// Represents the format of the Mediums BLE Advertisement Header used in
+// Advertising + Discovery.
+//
+// [VERSION][NUM_SLOTS][SERVICE_ID_BLOOM_FILTER][ADVERTISEMENT_HASH][L2_CAP_PSM]
+//
+// See go/nearby-ble-design for more information.
+//
+// Note. The object constructed by default constructor or the parameterized
+// constructor with invalid value(s) is treated as invalid instance. Caller
+// should be responsible to call IsValid() to check the instance is invalid in
+// advance before continue on.
+class BleAdvertisementHeader {
+ public:
+ // Versions of the BleAdvertisementHeader.
+ enum class Version {
+ kUndefined = 0,
+ kV1 = 1,
+ kV2 = 2,
+ // Version is only allocated 3 bits in the BleAdvertisementHeader, so this
+ // can never go beyond V7.
+ //
+ // V1 is not present because it's an old format used in Nearby Connections
+ // before this logic was pushed down into Nearby Mediums. V1 put
+ // everything in the service data, while V2 puts the data inside a GATT
+ // characteristic so the two are not compatible.
+ };
+
+ static constexpr int kAdvertisementHashLength = 4;
+ static constexpr int kServiceIdBloomFilterLength = 10;
+
+ BleAdvertisementHeader() = default;
+ BleAdvertisementHeader(Version version, bool extended_advertisement,
+ int num_slots,
+ const ByteArray &service_id_bloom_filter,
+ const ByteArray &advertisement_hash, int psm);
+ explicit BleAdvertisementHeader(
+ const ByteArray &ble_advertisement_header_bytes);
+ BleAdvertisementHeader(const BleAdvertisementHeader &) = default;
+ BleAdvertisementHeader &operator=(const BleAdvertisementHeader &) = default;
+ BleAdvertisementHeader(BleAdvertisementHeader &&) = default;
+ BleAdvertisementHeader &operator=(BleAdvertisementHeader &&) = default;
+ ~BleAdvertisementHeader() = default;
+
+ explicit operator ByteArray() const;
+
+ bool IsValid() const { return version_ == Version::kV2; }
+ Version GetVersion() const { return version_; }
+ bool IsExtendedAdvertisement() const { return extended_advertisement_; }
+ int GetNumSlots() const { return num_slots_; }
+ ByteArray GetServiceIdBloomFilter() const { return service_id_bloom_filter_; }
+ ByteArray GetAdvertisementHash() const { return advertisement_hash_; }
+ int GetPsmValue() const { return psm_; }
+
+ private:
+ static constexpr int kVersionAndNumSlotsLength = 1;
+ static constexpr int kMinAdvertisementHeaderLength =
+ kVersionAndNumSlotsLength + kServiceIdBloomFilterLength +
+ kAdvertisementHashLength;
+ static constexpr int kVersionBitmask = 0x0E0;
+ static constexpr int kExtendedAdvertismentBitMask = 0x010;
+ static constexpr int kNumSlotsBitmask = 0x00F;
+
+ Version version_ = Version::kUndefined;
+ bool extended_advertisement_ = false;
+ int num_slots_ = 0;
+ ByteArray service_id_bloom_filter_;
+ ByteArray advertisement_hash_;
+ int psm_ = 0;
+};
+
+} // namespace mediums
+} // namespace connections
+} // namespace nearby
+} // namespace location
+
+#endif // CORE_INTERNAL_MEDIUMS_BLE_V2_BLE_ADVERTISEMENT_HEADER_H_
diff --git a/internal/platform/byte_array.h b/internal/platform/byte_array.h
index b9dba2d..221961b 100644
--- a/internal/platform/byte_array.h
+++ b/internal/platform/byte_array.h
@@ -23,6 +23,8 @@
#include <type_traits>
#include <utility>
+#include "absl/strings/str_cat.h"
+
namespace location {
namespace nearby {
@@ -92,6 +94,11 @@
// operation.
explicit operator std::string() && { return std::move(data_); }
+ // Returns the representation of the underlying data as a string view.
+ absl::string_view AsStringView() const {
+ return absl::string_view(data(), size());
+ }
+
private:
std::string data_;
};
diff --git a/internal/platform/byte_array_test.cc b/internal/platform/byte_array_test.cc
index 0084f02..366a319 100644
--- a/internal/platform/byte_array_test.cc
+++ b/internal/platform/byte_array_test.cc
@@ -87,4 +87,12 @@
EXPECT_EQ(std::string(bytes), std::string(data.data(), data.size()));
}
+TEST(ByteArrayTest, CreateFromAbslStringReturnsTheSame) {
+ const absl::string_view kTestString = "Test String";
+ ByteArray bytes{std::string(kTestString)};
+
+ EXPECT_EQ(bytes.size(), kTestString.size());
+ EXPECT_EQ(bytes.AsStringView(), kTestString);
+}
+
} // namespace