Add AdvertisementData struct.

Define and use an NP private AdvertisementData structure instead of the low level BleAdvertisementData,
The APIs look cleaner this way.

PiperOrigin-RevId: 486224840
This commit is contained in:
Janusz Sobczak
2022-11-04 14:03:24 -07:00
committed by Copybara-Service
parent de4e7a66dc
commit 951945dd5c
10 changed files with 127 additions and 118 deletions
+1
View File
@@ -63,6 +63,7 @@ cc_library(
"//internal/platform:base",
"//internal/platform:logging",
"//internal/proto:credential_cc_proto",
"@com_google_absl//absl/functional:any_invocable",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/types:optional",
"@com_google_absl//absl/types:variant",
+1
View File
@@ -128,6 +128,7 @@ cc_test(
":internal",
"//internal/platform/implementation/g3", # build_cleaner: keep
"//presence:types",
"//presence/implementation/mediums",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
@@ -24,7 +24,7 @@
#include "internal/proto/credential.pb.h"
#include "presence/data_element.h"
#include "presence/implementation/base_broadcast_request.h"
#include "presence/implementation/mediums/ble.h"
#include "presence/implementation/mediums/advertisement_data.h"
namespace nearby {
namespace presence {
@@ -93,9 +93,9 @@ std::string SerializeAction(const Action& action) {
} // namespace
absl::StatusOr<BleAdvertisementData> AdvertisementFactory::CreateAdvertisement(
absl::StatusOr<AdvertisementData> AdvertisementFactory::CreateAdvertisement(
const BaseBroadcastRequest& request) const {
BleAdvertisementData advert = {};
AdvertisementData advert = {};
if (absl::holds_alternative<BaseBroadcastRequest::BasePresence>(
request.variant)) {
return CreateBaseNpAdvertisement(request);
@@ -103,12 +103,11 @@ absl::StatusOr<BleAdvertisementData> AdvertisementFactory::CreateAdvertisement(
return advert;
}
absl::StatusOr<BleAdvertisementData>
absl::StatusOr<AdvertisementData>
AdvertisementFactory::CreateBaseNpAdvertisement(
const BaseBroadcastRequest& request) const {
const auto& presence =
absl::get<BaseBroadcastRequest::BasePresence>(request.variant);
BleAdvertisementData advert{};
std::string payload;
payload.reserve(kMaxBaseNpAdvSize);
payload.push_back(kBaseVersion);
@@ -173,9 +172,8 @@ AdvertisementFactory::CreateBaseNpAdvertisement(
return result;
}
}
advert.service_data.insert(
{kPresenceServiceUuid, location::nearby::ByteArray(payload)});
return advert;
return AdvertisementData{.is_extended_advertisement = false,
.content = payload};
}
} // namespace presence
@@ -19,28 +19,25 @@
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "internal/platform/implementation/ble_v2.h"
#include "presence/implementation/base_broadcast_request.h"
#include "presence/implementation/credential_manager.h"
#include "presence/implementation/mediums/advertisement_data.h"
namespace nearby {
namespace presence {
// An opaque container with the advertisement data.
using ::location::nearby::api::ble_v2::BleAdvertisementData;
/** Builds BLE advertisements from broadcast requests. */
// Builds BLE advertisements from broadcast requests.
class AdvertisementFactory {
public:
explicit AdvertisementFactory(CredentialManager* credential_manager)
: credential_manager_(*credential_manager) {}
/** Returns a BLE advertisement for given `request` */
absl::StatusOr<BleAdvertisementData> CreateAdvertisement(
// Returns a BLE advertisement for given `request.
absl::StatusOr<AdvertisementData> CreateAdvertisement(
const BaseBroadcastRequest& request) const;
private:
absl::StatusOr<BleAdvertisementData> CreateBaseNpAdvertisement(
absl::StatusOr<AdvertisementData> CreateBaseNpAdvertisement(
const BaseBroadcastRequest& request) const;
CredentialManager& credential_manager_;
@@ -25,6 +25,7 @@
#include "presence/data_element.h"
#include "presence/implementation/action_factory.h"
#include "presence/implementation/credential_manager_impl.h"
#include "presence/implementation/mediums/advertisement_data.h"
namespace nearby {
namespace presence {
@@ -66,17 +67,13 @@ TEST(AdvertisementFactory, CreateAdvertisementFromPrivateIdentity) {
.WillOnce(Return(metadata_key + absl::HexStringToBytes("50515253")));
AdvertisementFactory factory(&credential_manager);
absl::StatusOr<BleAdvertisementData> result =
absl::StatusOr<AdvertisementData> result =
factory.CreateAdvertisement(request);
ASSERT_OK(result);
auto service_data = result->service_data;
ASSERT_EQ(service_data.size(), 1);
for (auto i : service_data) {
EXPECT_EQ(i.first.Get16BitAsString(), "FCF1");
auto advertisement = absl::BytesToHexString(i.second.AsStringView());
EXPECT_EQ(advertisement, "00414142101112131415161718192021222350515253");
}
EXPECT_FALSE(result->is_extended_advertisement);
EXPECT_EQ(absl::BytesToHexString(result->content),
"00414142101112131415161718192021222350515253");
}
TEST(AdvertisementFactory, CreateAdvertisementFromPublicIdentity) {
@@ -93,17 +90,12 @@ TEST(AdvertisementFactory, CreateAdvertisementFromPublicIdentity) {
.SetAction(action));
AdvertisementFactory factory(&credential_manager);
absl::StatusOr<BleAdvertisementData> result =
absl::StatusOr<AdvertisementData> result =
factory.CreateAdvertisement(request);
ASSERT_OK(result);
auto service_data = result->service_data;
EXPECT_EQ(service_data.size(), 1);
for (auto i : service_data) {
EXPECT_EQ(i.first.Get16BitAsString(), "FCF1");
auto advertisement = absl::BytesToHexString(i.second.AsStringView());
EXPECT_EQ(advertisement, "000320414236050080");
}
EXPECT_FALSE(result->is_extended_advertisement);
EXPECT_EQ(absl::BytesToHexString(result->content), "000320414236050080");
}
TEST(AdvertisementFactory, CreateAdvertisementFailsWhenEncryptionFails) {
+1
View File
@@ -18,6 +18,7 @@ cc_library(
srcs = [
],
hdrs = [
"advertisement_data.h",
"ble.h",
"mediums.h",
],
@@ -0,0 +1,34 @@
// 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 THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MEDIUMS_ADVERTISEMENT_DATA_H_
#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MEDIUMS_ADVERTISEMENT_DATA_H_
#include <string>
namespace nearby {
namespace presence {
// Nearby Presence advertisement data over the air.
struct AdvertisementData {
// If true, the advertisement needs to be broadcasted over BLE 5.0.
bool is_extended_advertisement;
// The advertised data.
std::string content;
};
} // namespace presence
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MEDIUMS_ADVERTISEMENT_DATA_H_
+6 -6
View File
@@ -21,6 +21,7 @@
#include "internal/platform/ble_v2.h"
#include "internal/platform/bluetooth_adapter.h"
#include "internal/platform/uuid.h"
#include "presence/implementation/mediums/advertisement_data.h"
#include "presence/power_mode.h"
#include "presence/scan_request.h"
@@ -62,13 +63,12 @@ class Ble {
// Starts broadcasting NP advertisement in `payload`. The caller should use
// the returned `AdvertisingSession` to stop the broadcast.
std::unique_ptr<AdvertisingSession> StartAdvertising(
absl::string_view payload, bool is_extended_advertisement,
PowerMode power_mode, AdvertisingCallback callback) {
BleAdvertisementData advertising_data = {.is_extended_advertisement =
is_extended_advertisement};
const AdvertisementData& payload, PowerMode power_mode,
AdvertisingCallback callback) {
BleAdvertisementData advertising_data = {
.is_extended_advertisement = payload.is_extended_advertisement};
advertising_data.service_data.insert(
{kPresenceServiceUuid,
location::nearby::ByteArray(std::string(payload))});
{kPresenceServiceUuid, location::nearby::ByteArray(payload.content)});
AdvertiseParameters advertise_set_parameters = {
.tx_power_level = ConvertPowerModeToPowerLevel(power_mode),
.is_connectable = true,
+5 -4
View File
@@ -28,6 +28,7 @@
#include "internal/platform/medium_environment.h"
#include "internal/platform/uuid.h"
#include "presence/data_element.h"
#include "presence/implementation/mediums/advertisement_data.h"
#include "presence/scan_request.h"
namespace nearby {
@@ -139,7 +140,8 @@ TEST_P(BleTest, AdvertiseAndScan) {
Ble client(client_adapter);
location::nearby::BluetoothAdapter server_adapter;
Ble server(server_adapter);
std::string advert_data = "my advertisement";
AdvertisementData advert_data = {.is_extended_advertisement = false,
.content = "my advertisement"};
ScanRequest scan_request{
.power_mode = PowerMode::kBalanced,
};
@@ -156,8 +158,7 @@ TEST_P(BleTest, AdvertiseAndScan) {
}});
std::unique_ptr<location::nearby::api::ble_v2::BleMedium::AdvertisingSession>
advertising_session = server.StartAdvertising(
advert_data, /*is_extended_advertisement=*/false,
PowerMode::kBalanced,
advert_data, PowerMode::kBalanced,
AdvertisingCallback{
.start_advertising_result = [&](BleOperationStatus status) {
advertise_latch.CountDown();
@@ -172,7 +173,7 @@ TEST_P(BleTest, AdvertiseAndScan) {
EXPECT_EQ(advertisements[0]
.service_data.find(kPresenceServiceUuid)
->second.AsStringView(),
advert_data);
advert_data.content);
env_.Stop();
}
+60 -76
View File
@@ -21,6 +21,8 @@
#include <utility>
#include <vector>
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
#include "absl/random/random.h"
#include "internal/platform/bluetooth_adapter.h"
@@ -36,12 +38,39 @@ namespace nearby {
namespace presence {
namespace {
using BleOperationStatus = location::nearby::api::ble_v2::BleOperationStatus;
using BleOperationStatus = ::location::nearby::api::ble_v2::BleOperationStatus;
using AdvertisingSession =
::location::nearby::api::ble_v2::BleMedium::AdvertisingSession;
using AdvertisingCallback =
::location::nearby::api::ble_v2::BleMedium::AdvertisingCallback;
class ScanManagerTest : public testing::Test {
protected:
void SetUp() override { env_.Start(); }
void TearDown() override { env_.Stop(); }
std::unique_ptr<AdvertisingSession> StartAdvertisingOn(Ble& ble) {
PresenceBroadcast::BroadcastSection section = {
.identity = internal::IDENTITY_TYPE_PUBLIC,
.extended_properties = extended_properties_,
.account_name = "Test account"};
PresenceBroadcast presence_request = {.sections = {section}};
BroadcastRequest input = {.tx_power = 30, .variant = presence_request};
absl::StatusOr<BaseBroadcastRequest> request =
BaseBroadcastRequest::Create(input);
EXPECT_OK(request);
AdvertisementFactory factory(&credential_manager_);
absl::StatusOr<AdvertisementData> advertisement =
factory.CreateAdvertisement(request.value());
EXPECT_OK(advertisement);
std::unique_ptr<AdvertisingSession> session = ble.StartAdvertising(
advertisement.value(), PowerMode::kLowPower,
AdvertisingCallback{
.start_advertising_result = [](BleOperationStatus) {}});
env_.Sync();
return session;
}
std::vector<nearby::internal::IdentityType> identity_types_ = {
nearby::internal::IdentityType::IDENTITY_TYPE_PUBLIC,
};
@@ -64,54 +93,39 @@ class ScanManagerTest : public testing::Test {
CredentialManagerImpl credential_manager_;
location::nearby::MediumEnvironment& env_ = {
location::nearby::MediumEnvironment::Instance()};
location::nearby::api::ble_v2::AdvertiseParameters params_ = {
.tx_power_level = Ble::TxPowerLevel::kHigh,
.is_connectable = true,
};
location::nearby::CountDownLatch start_latch_{1};
location::nearby::CountDownLatch found_latch_{1};
ScanCallback scanning_callback_ = {.start_scan_cb =
[this](Status status) {
NEARBY_LOGS(INFO) << "Scan started "
<< status.Ok();
if (status.Ok()) {
start_latch_.CountDown();
}
},
.on_discovered_cb =
[this](PresenceDevice pd) {
NEARBY_LOGS(INFO) << "Device found";
found_latch_.CountDown();
}};
};
TEST_F(ScanManagerTest, CanStartThenStopScanning) {
Mediums mediums;
ScanManager manager(mediums, credential_manager_);
ScanCallback scanning_callback = {
.start_scan_cb =
[this](Status status) {
if (status.Ok()) {
start_latch_.CountDown();
}
},
.on_discovered_cb =
[this](PresenceDevice pd) { found_latch_.CountDown(); }};
// Set up advertiser
// Create BroadcastRequest
PresenceBroadcast::BroadcastSection section = {
.identity = internal::IDENTITY_TYPE_PUBLIC,
.extended_properties = extended_properties_,
.account_name = "Test account"};
PresenceBroadcast presence_request = {.sections = {section}};
BroadcastRequest input = {.tx_power = 30, .variant = presence_request};
absl::StatusOr<BaseBroadcastRequest> request =
BaseBroadcastRequest::Create(input);
AdvertisementFactory factory(&credential_manager_);
absl::StatusOr<BleAdvertisementData> advertisement =
factory.CreateAdvertisement(request.ValueOrDie());
location::nearby::BluetoothAdapter adapter2;
location::nearby::BleV2Medium ble2(adapter2);
ASSERT_TRUE(ble2.StartAdvertising(advertisement.ValueOrDie(), params_));
location::nearby::BluetoothAdapter server_adapter;
Ble ble2(server_adapter);
std::unique_ptr<AdvertisingSession> advertising_session =
StartAdvertisingOn(ble2);
// Start scanning
ScanSession scan_session =
manager.StartScan(scan_request_, std::move(scanning_callback));
// Ensure that we are in a good state.
env_.Sync();
manager.StartScan(scan_request_, scanning_callback_);
EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 1);
ASSERT_TRUE(ble2.IsValid());
ASSERT_TRUE(mediums.GetBle().IsAvailable());
EXPECT_TRUE(start_latch_.Await(absl::Milliseconds(500)).result());
EXPECT_TRUE(found_latch_.Await(absl::Milliseconds(1500)).result());
EXPECT_TRUE(start_latch_.Await().Ok());
EXPECT_TRUE(found_latch_.Await().Ok());
EXPECT_TRUE(scan_session.StopScan().Ok());
EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 0);
}
@@ -119,19 +133,11 @@ TEST_F(ScanManagerTest, CanStartThenStopScanning) {
TEST_F(ScanManagerTest, CannotStopScanTwice) {
Mediums mediums;
ScanManager manager(mediums, credential_manager_);
ScanCallback scanning_callback = ScanCallback{
.start_scan_cb =
[this](Status status) {
if (status.Ok()) {
start_latch_.CountDown();
}
},
};
auto scan_session =
manager.StartScan(scan_request_, std::move(scanning_callback));
auto scan_session = manager.StartScan(scan_request_, scanning_callback_);
NEARBY_LOGS(INFO) << "Start scan";
EXPECT_TRUE(start_latch_.Await(absl::Milliseconds(1000)).result());
EXPECT_TRUE(start_latch_.Await().Ok());
// Ensure that we have started scanning before we try to stop.
env_.Sync();
NEARBY_LOGS(INFO) << "Stop scan";
@@ -143,32 +149,11 @@ TEST_F(ScanManagerTest, CannotStopScanTwice) {
TEST_F(ScanManagerTest, TestNoFilter) {
Mediums mediums;
ScanManager manager(mediums, credential_manager_);
ScanCallback scanning_callback = {
.start_scan_cb =
[this](Status status) {
if (status.Ok()) {
start_latch_.CountDown();
}
},
.on_discovered_cb =
[this](PresenceDevice pd) { found_latch_.CountDown(); }};
// Set up advertiser
// Create BroadcastRequest
PresenceBroadcast::BroadcastSection section = {
.identity = internal::IDENTITY_TYPE_PUBLIC,
.extended_properties = {},
.account_name = "Test account"};
PresenceBroadcast presence_request = {.sections = {section}};
BroadcastRequest input = {.tx_power = 30, .variant = presence_request};
absl::StatusOr<BaseBroadcastRequest> request =
BaseBroadcastRequest::Create(input);
AdvertisementFactory factory(&credential_manager_);
absl::StatusOr<BleAdvertisementData> advertisement =
factory.CreateAdvertisement(request.ValueOrDie());
location::nearby::BluetoothAdapter adapter2;
location::nearby::BleV2Medium ble2(adapter2);
ASSERT_TRUE(ble2.StartAdvertising(advertisement.ValueOrDie(), params_));
location::nearby::BluetoothAdapter server_adapter;
Ble ble2(server_adapter);
std::unique_ptr<AdvertisingSession> advertising_session =
StartAdvertisingOn(ble2);
// Start scanning
ScanRequest scan_request = {
@@ -181,13 +166,12 @@ TEST_F(ScanManagerTest, TestNoFilter) {
.scan_only_when_screen_on = true,
};
ScanSession scan_session =
manager.StartScan(scan_request, std::move(scanning_callback));
manager.StartScan(scan_request, scanning_callback_);
EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 1);
ASSERT_TRUE(ble2.IsValid());
ASSERT_TRUE(mediums.GetBle().IsAvailable());
EXPECT_TRUE(start_latch_.Await(absl::Milliseconds(500)).result());
EXPECT_TRUE(found_latch_.Await(absl::Milliseconds(1500)).result());
EXPECT_TRUE(start_latch_.Await().Ok());
EXPECT_TRUE(found_latch_.Await().Ok());
EXPECT_TRUE(scan_session.StopScan().Ok());
EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 0);
}