fixed device lost callback path for async callbacks in ble. implemented startscanning for fast init manager

This commit is contained in:
Lasan Mahaliyana
2026-07-31 21:47:34 +05:30
parent 060700c120
commit 1dda9b431d
7 changed files with 554 additions and 43 deletions
+1
View File
@@ -0,0 +1 @@
9.0.1
@@ -1,7 +1,5 @@
#include "internal/platform/implementation/linux/bluez_advertisement_monitor.h"
#include <regex>
#include "internal/platform/byte_array.h"
#include "internal/platform/implementation/ble.h"
#include "internal/platform/implementation/linux/dbus.h"
@@ -11,7 +9,7 @@ namespace nearby {
namespace linux {
namespace bluez {
AdvertisementMonitor::AdvertisementMonitor(
sdbus::IConnection &system_bus, Uuid service_uuid,
sdbus::IConnection& system_bus, Uuid service_uuid,
api::ble::TxPowerLevel tx_power_level, absl::string_view type,
std::shared_ptr<BluetoothDevices> devices,
api::ble::BleMedium::ScanCallback scan_callback)
@@ -23,30 +21,38 @@ AdvertisementMonitor::AdvertisementMonitor(
std::move(scan_callback.advertisement_found_cb)}) {}
AdvertisementMonitor::AdvertisementMonitor(
sdbus::IConnection &system_bus, Uuid service_uuid,
sdbus::IConnection& system_bus, Uuid service_uuid,
api::ble::TxPowerLevel tx_power_level, absl::string_view type,
std::shared_ptr<BluetoothDevices> devices,
api::ble::BleMedium::ScanningCallback scan_callback)
: AdaptorInterfaces(system_bus, bluez::advertisement_monitor_path(
std::string{service_uuid})),
: AdvertisementMonitor(
system_bus,
bluez::advertisement_monitor_path(std::string{service_uuid}),
service_uuid, tx_power_level, type, std::move(devices),
std::move(scan_callback)) {}
AdvertisementMonitor::AdvertisementMonitor(
sdbus::IConnection& system_bus, sdbus::ObjectPath object_path,
Uuid service_uuid, api::ble::TxPowerLevel tx_power_level,
absl::string_view type, std::shared_ptr<BluetoothDevices> devices,
api::ble::BleMedium::ScanningCallback scan_callback)
: AdaptorInterfaces(system_bus, std::move(object_path)),
devices_(std::move(devices)),
scan_callback_{std::move(scan_callback.advertisement_found_cb)},
start_scanning_result_callback_(
std::move(scan_callback.start_scanning_result)),
scan_callback_(std::move(scan_callback)),
type_(type),
service_uuid_(service_uuid),
tx_power_level_(tx_power_level) {
registerAdaptor();
}
void AdvertisementMonitor::DeviceFound(const sdbus::ObjectPath &device) {
void AdvertisementMonitor::DeviceFound(const sdbus::ObjectPath& device) {
devices_->cleanup_lost_peripherals();
auto peripheral = devices_->add_new_device(device);
auto service_data = peripheral->ServiceData();
if (!service_data.has_value()) return;
struct api::ble::BleAdvertisementData adv_data;
for (const auto &[uuid_str, data] : *service_data) {
for (const auto& [uuid_str, data] : *service_data) {
auto uuid = UuidFromString(uuid_str);
if (!uuid.has_value()) {
LOG(ERROR)
@@ -60,12 +66,15 @@ void AdvertisementMonitor::DeviceFound(const sdbus::ObjectPath &device) {
adv_data.service_data.emplace(*uuid,
std::string(bytes.begin(), bytes.end()));
}
auto id = std::stoull(std::regex_replace(peripheral->GetMacAddress().ToString(),
std::regex("[:\\-]"), ""), nullptr, 16);
auto id = peripheral->GetMacAddress().address();
scan_callback_.advertisement_found_cb(id, adv_data);
}
void AdvertisementMonitor::DeviceLost(const sdbus::ObjectPath &device) {
void AdvertisementMonitor::DeviceLost(const sdbus::ObjectPath& device) {
auto peripheral = devices_->get_device_by_path(device);
if (peripheral != nullptr) {
scan_callback_.advertisement_lost_cb(peripheral->GetMacAddress().address());
}
devices_->mark_peripheral_lost(device);
}
} // namespace bluez
@@ -47,16 +47,22 @@ class AdvertisementMonitor final
absl::string_view type,
std::shared_ptr<BluetoothDevices> devices,
api::ble::BleMedium::ScanningCallback scan_callback);
AdvertisementMonitor(sdbus::IConnection& system_bus,
sdbus::ObjectPath object_path, Uuid service_uuid,
api::ble::TxPowerLevel tx_power_level,
absl::string_view type,
std::shared_ptr<BluetoothDevices> devices,
api::ble::BleMedium::ScanningCallback scan_callback);
~AdvertisementMonitor() { unregisterAdaptor(); }
private:
// Methods
void Release() override {}
void Activate() override {
LOG(INFO) <<__func__ << ": bluez advertisement monitor activated at path: "
LOG(INFO) << __func__ << ": bluez advertisement monitor activated at path: "
<< getObject().getObjectPath();
if (start_scanning_result_callback_ != nullptr) {
start_scanning_result_callback_(absl::OkStatus());
if (scan_callback_.start_scanning_result != nullptr) {
scan_callback_.start_scanning_result(absl::OkStatus());
}
}
@@ -66,9 +72,7 @@ class AdvertisementMonitor final
// Properties
std::string Type() override { return type_; };
int16_t RSSILowThreshold() override { return 127; };
int16_t RSSIHighThreshold() override {
return 127;
}
int16_t RSSIHighThreshold() override { return 127; }
uint16_t RSSISamplingPeriod() override {
// The Windows implementation uses a sampling interval of 2 seconds.
return 20;
@@ -79,13 +83,11 @@ class AdvertisementMonitor final
return {{0,
0x16,
{static_cast<uint8_t>(service_id_data[3] & 0xFF),
static_cast<uint8_t>(service_id_data[2] & 0xFF)}
}};
static_cast<uint8_t>(service_id_data[2] & 0xFF)}}};
};
std::shared_ptr<BluetoothDevices> devices_;
api::ble::BleMedium::ScanCallback scan_callback_;
absl::AnyInvocable<void(absl::Status)> start_scanning_result_callback_;
api::ble::BleMedium::ScanningCallback scan_callback_;
std::string type_;
Uuid service_uuid_;
+13
View File
@@ -61,6 +61,19 @@ cc_binary(
deps = [":fast_init"],
)
cc_test(
name = "nearby_fast_init_manager_test",
size = "small",
srcs = ["nearby_fast_init_manager_test.cc"],
deps = [
":fast_init",
"//internal/platform:base",
"//internal/platform/implementation:types",
"//internal/platform/implementation/linux",
"@com_google_googletest//:gtest_main",
],
)
cc_binary(
name = "nearby_sharing_cli",
+336 -10
View File
@@ -1,17 +1,64 @@
#include <algorithm>
#include <functional>
#include <map>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "absl/synchronization/mutex.h"
#include "absl/synchronization/notification.h"
#include "internal/platform/implementation/ble.h"
#include "sharing/internal/api/fast_init_ble_beacon.h"
#include "sharing/internal/api/fast_initiation_manager.h"
#include "internal/platform/implementation/linux/bluetooth_adapter.h"
#include "sharing/linux/nearby_fast_init_manager.h"
#include "internal/platform/implementation/linux/bluetooth_devices.h"
#include "internal/platform/implementation/linux/bluez.h"
#include "internal/platform/implementation/linux/bluez_advertisement_monitor.h"
#include "internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h"
#include "internal/platform/implementation/linux/bluez_le_advertisement.h"
#include "internal/platform/implementation/linux/dbus.h"
#include "internal/platform/uuid.h"
#include "sharing/linux/nearby_fast_init_manager.h"
namespace nearby {
namespace sharing {
namespace linux {
namespace {
constexpr char kFastInitMonitorRootPath[] =
"/com/google/nearby/sharing/fast_init/monitor";
constexpr char kFastInitMonitorPath[] =
"/com/google/nearby/sharing/fast_init/monitor/fe2c";
constexpr size_t kFastInitServiceDataSize =
nearby::api::FastInitBleBeacon::kAdvertiseDataTotalSize -
nearby::api::FastInitBleBeacon::kFastInitServiceUuidSize;
nearby::api::FastInitiationManager::Error MapBluezError(
const std::string& error_name) {
if (error_name == "org.bluez.Error.AlreadyExists" ||
error_name == "org.bluez.Error.InProgress") {
return nearby::api::FastInitiationManager::Error::kResourceInUse;
}
if (error_name == "org.bluez.Error.NotPermitted" ||
error_name == "org.bluez.Error.NotAuthorized") {
return nearby::api::FastInitiationManager::Error::kDisabledByUser;
}
if (error_name == "org.bluez.Error.NotSupported") {
return nearby::api::FastInitiationManager::Error::kHardwareNotSupported;
}
return nearby::api::FastInitiationManager::Error::kUnknown;
}
} // namespace
LinuxFastInitiationManager::~LinuxFastInitiationManager() {
StopScanning(nullptr);
StopAdvertising(nullptr);
}
void LinuxFastInitiationManager::StartAdvertising(
nearby::api::FastInitBleBeacon::FastInitType type,
std::function<void()> callback,
@@ -121,22 +168,301 @@ void LinuxFastInitiationManager::StopAdvertising(
callback();
}
}
void StopScanning(std::function<void()> callback) {
if (callback) {
callback();
}
}
void LinuxFastInitiationManager::StartScanning(
std::function<void()> devices_discovered_callback,
std::function<void()> devices_not_discovered_callback,
std::function<void(nearby::api::FastInitiationManager::Error)>
error_callback) {
if (error_callback) {
error_callback(
nearby::api::FastInitiationManager::Error::kHardwareNotSupported);
std::optional<nearby::api::FastInitiationManager::Error> error;
{
absl::MutexLock operation_lock(&scan_operation_mutex_);
error = StartScanningInternal(std::move(devices_discovered_callback),
std::move(devices_not_discovered_callback));
}
if (error.has_value() && error_callback) {
error_callback(*error);
}
}
std::optional<nearby::api::FastInitiationManager::Error>
LinuxFastInitiationManager::StartScanningInternal(
std::function<void()> devices_discovered_callback,
std::function<void()> devices_not_discovered_callback) {
bool already_scanning = false;
{
absl::MutexLock lock(&mutex_);
already_scanning = is_scanning_;
}
if (already_scanning) {
return nearby::api::FastInitiationManager::Error::kResourceInUse;
}
if (adapter_ == nullptr || !adapter_->IsEnabled()) {
return nearby::api::FastInitiationManager::Error::
kBluetoothRadioUnavailable;
}
auto fast_init_uuid = Uuid::FromString(kFastInitServiceUuid);
if (!fast_init_uuid.has_value()) {
return nearby::api::FastInitiationManager::Error::kUnknown;
}
auto connection = adapter_->GetConnection();
auto monitor_manager = ::nearby::linux::bluez::AdvertisementMonitorManager::
DiscoverAdvertisementMonitorManager(*connection, *adapter_);
if (monitor_manager == nullptr) {
return nearby::api::FastInitiationManager::Error::kHardwareNotSupported;
}
try {
const std::vector<std::string> supported_types =
monitor_manager->SupportedMonitorTypes();
if (std::find(supported_types.begin(), supported_types.end(),
"or_patterns") == supported_types.end()) {
return nearby::api::FastInitiationManager::Error::kHardwareNotSupported;
}
} catch (const sdbus::Error& error) {
return MapBluezError(error.getName());
}
uint64_t generation;
try {
{
absl::MutexLock lock(&mutex_);
is_scanning_ = true;
generation = ++scan_generation_;
devices_discovered_callback_ = std::move(devices_discovered_callback);
devices_not_discovered_callback_ =
std::move(devices_not_discovered_callback);
discovered_peripherals_.clear();
}
scan_devices_ = ::nearby::linux::GetSharedBluetoothDevices(
connection, adapter_->GetObjectPath());
scan_root_object_manager_ =
std::make_unique<::nearby::linux::RootObjectManager>(
*connection, sdbus::ObjectPath(kFastInitMonitorRootPath));
scan_monitor_ =
std::make_unique<::nearby::linux::bluez::AdvertisementMonitor>(
*connection, sdbus::ObjectPath(kFastInitMonitorPath),
*fast_init_uuid, nearby::api::ble::TxPowerLevel::kLow,
"or_patterns", scan_devices_,
nearby::api::ble::BleMedium::ScanningCallback{
.advertisement_found_cb =
[this, generation](
nearby::api::ble::BlePeripheral::UniqueId peripheral_id,
nearby::api::ble::BleAdvertisementData data) {
OnAdvertisementFound(generation, peripheral_id,
std::move(data));
},
.advertisement_lost_cb =
[this,
generation](nearby::api::ble::BlePeripheral::UniqueId id) {
OnAdvertisementLost(generation, id);
},
});
scan_monitor_manager_ = std::move(monitor_manager);
} catch (const sdbus::Error& error) {
{
absl::MutexLock lock(&mutex_);
is_scanning_ = false;
devices_discovered_callback_ = nullptr;
devices_not_discovered_callback_ = nullptr;
}
scan_monitor_.reset();
scan_root_object_manager_.reset();
scan_devices_.reset();
return MapBluezError(error.getName());
}
absl::Notification registration_complete;
std::string registration_error_name;
scan_monitor_manager_->SetRegisterMonitorReplyCallback(
[&registration_complete,
&registration_error_name](std::optional<sdbus::Error> error) {
if (error.has_value() && error->isValid()) {
registration_error_name = error->getName();
}
registration_complete.Notify();
});
try {
scan_monitor_manager_->RegisterMonitor(
scan_root_object_manager_->getObject().getObjectPath());
registration_complete.WaitForNotification();
} catch (const sdbus::Error& error) {
registration_error_name = error.getName();
}
if (!registration_error_name.empty()) {
{
absl::MutexLock lock(&mutex_);
is_scanning_ = false;
++scan_generation_;
devices_discovered_callback_ = nullptr;
devices_not_discovered_callback_ = nullptr;
discovered_peripherals_.clear();
}
scan_monitor_.reset();
scan_root_object_manager_.reset();
scan_monitor_manager_.reset();
scan_devices_.reset();
return MapBluezError(registration_error_name);
}
try {
auto& bluez_adapter = adapter_->GetBluezAdapterObject();
if (!bluez_adapter.Discovering()) {
std::map<std::string, sdbus::Variant> filter;
filter["Transport"] = sdbus::Variant("le");
filter["DuplicateData"] = sdbus::Variant(true);
bluez_adapter.SetDiscoveryFilter(filter);
bluez_adapter.StartDiscovery();
absl::MutexLock lock(&mutex_);
owns_bluez_discovery_ = true;
}
} catch (const sdbus::Error& error) {
// Release the scan application before reporting a failed start.
StopScanningInternal();
return MapBluezError(error.getName());
}
return std::nullopt;
}
void LinuxFastInitiationManager::StopScanning(std::function<void()> callback) {
{
absl::MutexLock operation_lock(&scan_operation_mutex_);
StopScanningInternal();
}
if (callback) {
callback();
}
}
void LinuxFastInitiationManager::StopScanningInternal() {
bool owns_discovery = false;
{
absl::MutexLock lock(&mutex_);
if (!is_scanning_) {
return;
}
is_scanning_ = false;
owns_discovery = owns_bluez_discovery_;
owns_bluez_discovery_ = false;
++scan_generation_;
devices_discovered_callback_ = nullptr;
devices_not_discovered_callback_ = nullptr;
discovered_peripherals_.clear();
}
if (owns_discovery && adapter_ != nullptr) {
try {
adapter_->GetBluezAdapterObject().StopDiscovery();
} catch (const sdbus::Error& error) {
DBUS_LOG_METHOD_CALL_ERROR(&adapter_->GetBluezAdapterObject(),
"StopDiscovery", error);
}
}
if (scan_monitor_manager_ != nullptr &&
scan_root_object_manager_ != nullptr) {
absl::Notification unregistration_complete;
scan_monitor_manager_->SetUnregisterMonitorReplyCallback(
[&unregistration_complete](std::optional<sdbus::Error>) {
unregistration_complete.Notify();
});
try {
scan_monitor_manager_->UnregisterMonitor(
scan_root_object_manager_->getObject().getObjectPath());
unregistration_complete.WaitForNotification();
} catch (const sdbus::Error& error) {
DBUS_LOG_METHOD_CALL_ERROR(scan_monitor_manager_.get(),
"UnregisterMonitor", error);
}
}
scan_monitor_.reset();
scan_root_object_manager_.reset();
scan_monitor_manager_.reset();
scan_devices_.reset();
}
bool LinuxFastInitiationManager::IsScanning() {
absl::MutexLock lock(&mutex_);
return is_scanning_;
}
void LinuxFastInitiationManager::OnAdvertisementFound(
uint64_t scan_generation,
nearby::api::ble::BlePeripheral::UniqueId peripheral_id,
nearby::api::ble::BleAdvertisementData advertisement_data) {
if (!IsFastInitAdvertisement(advertisement_data)) {
return;
}
std::function<void()> callback;
{
absl::MutexLock lock(&mutex_);
if (!is_scanning_ || scan_generation != scan_generation_) {
return;
}
auto [unused, inserted] = discovered_peripherals_.insert(peripheral_id);
if (inserted && discovered_peripherals_.size() == 1) {
callback = devices_discovered_callback_;
}
}
if (callback) {
callback();
}
}
void LinuxFastInitiationManager::OnAdvertisementLost(
uint64_t scan_generation,
nearby::api::ble::BlePeripheral::UniqueId peripheral_id) {
std::function<void()> callback;
{
absl::MutexLock lock(&mutex_);
if (!is_scanning_ || scan_generation != scan_generation_ ||
discovered_peripherals_.erase(peripheral_id) == 0) {
return;
}
if (discovered_peripherals_.empty()) {
callback = devices_not_discovered_callback_;
}
}
if (callback) {
callback();
}
}
bool LinuxFastInitiationManager::IsFastInitAdvertisement(
const nearby::api::ble::BleAdvertisementData& advertisement_data) const {
auto fast_init_uuid = Uuid::FromString(kFastInitServiceUuid);
if (!fast_init_uuid.has_value()) {
return false;
}
auto service_data = advertisement_data.service_data.find(*fast_init_uuid);
if (service_data == advertisement_data.service_data.end() ||
service_data->second.size() != kFastInitServiceDataSize) {
return false;
}
const auto bytes = service_data->second.AsStringView();
for (size_t i = 0; i < nearby::api::FastInitBleBeacon::kFastInitModelIdSize;
++i) {
if (static_cast<uint8_t>(bytes[i]) !=
nearby::api::FastInitBleBeacon::kFastInitModelId[i]) {
return false;
}
}
const uint8_t metadata = static_cast<uint8_t>(
bytes[nearby::api::FastInitBleBeacon::kFastInitModelIdSize]);
const uint8_t version = (metadata >> 5) & 0x07;
const uint8_t type = (metadata >> 2) & 0x07;
return version == static_cast<uint8_t>(
nearby::api::FastInitBleBeacon::FastInitVersion::kV1) &&
type <= static_cast<uint8_t>(
nearby::api::FastInitBleBeacon::FastInitType::kSilent);
}
} // namespace linux
} // namespace sharing
} // namespace nearby
+52 -8
View File
@@ -16,13 +16,22 @@
#ifndef LINUX_NEARBY_SHARING_INTERNAL_API_FAST_INITIATION_MANAGER_H_
#define LINUX_NEARBY_SHARING_INTERNAL_API_FAST_INITIATION_MANAGER_H_
#include <cstdint>
#include <functional>
#include <memory>
#include <optional>
#include "absl/container/flat_hash_set.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/ble.h"
#include "sharing/internal/api/fast_init_ble_beacon.h"
#include "sharing/internal/api/fast_initiation_manager.h"
#include "internal/platform/implementation/linux/bluetooth_adapter.h"
#include "internal/platform/implementation/linux/bluetooth_devices.h"
#include "internal/platform/implementation/linux/bluez.h"
#include "internal/platform/implementation/linux/bluez_advertisement_monitor.h"
#include "internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h"
#include "internal/platform/implementation/linux/bluez_le_advertisement.h"
constexpr char kFastInitServiceUuid[] = "0000fe2c-0000-1000-8000-00805f9b34fb";
@@ -44,12 +53,13 @@ class LinuxFastInitiationManager final
*adapter_->GetConnection(), *adapter_);
}
}
~LinuxFastInitiationManager() override;
void StartAdvertising(
nearby::api::FastInitBleBeacon::FastInitType type,
std::function<void()> callback,
std::function<void(nearby::api::FastInitiationManager::Error)>
error_callback) override ;
error_callback) override;
void StopAdvertising(std::function<void()> callback) override;
@@ -57,27 +67,61 @@ class LinuxFastInitiationManager final
std::function<void()> devices_discovered_callback,
std::function<void()> devices_not_discovered_callback,
std::function<void(nearby::api::FastInitiationManager::Error)>
error_callback) override ;
error_callback) override;
void StopScanning(std::function<void()> callback) override {
if (callback) {
callback();
}
}
void StopScanning(std::function<void()> callback) override;
bool IsAdvertising() override {
absl::MutexLock lock(&mutex_);
return advertisement_ != nullptr;
}
bool IsScanning() override { return false; }
bool IsScanning() override;
private:
friend class LinuxFastInitiationManagerTestPeer;
void OnAdvertisementFound(
uint64_t scan_generation,
::nearby::api::ble::BlePeripheral::UniqueId peripheral_id,
::nearby::api::ble::BleAdvertisementData advertisement_data);
void OnAdvertisementLost(
uint64_t scan_generation,
::nearby::api::ble::BlePeripheral::UniqueId peripheral_id);
bool IsFastInitAdvertisement(
const ::nearby::api::ble::BleAdvertisementData& advertisement_data) const;
std::optional<nearby::api::FastInitiationManager::Error>
StartScanningInternal(std::function<void()> devices_discovered_callback,
std::function<void()> devices_not_discovered_callback)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(scan_operation_mutex_);
void StopScanningInternal()
ABSL_EXCLUSIVE_LOCKS_REQUIRED(scan_operation_mutex_);
nearby::api::FastInitBleBeacon& beacon_;
std::shared_ptr<::nearby::linux::BluetoothAdapter> adapter_;
std::unique_ptr<::nearby::linux::bluez::LEAdvertisementManager> adv_manager_;
absl::Mutex scan_operation_mutex_;
absl::Mutex mutex_;
std::unique_ptr<::nearby::linux::bluez::LEAdvertisement> advertisement_
ABSL_GUARDED_BY(mutex_);
bool is_scanning_ ABSL_GUARDED_BY(mutex_) = false;
bool owns_bluez_discovery_ ABSL_GUARDED_BY(mutex_) = false;
// Incremented for every start/stop so delayed BlueZ callbacks from an old
// scan cannot update the device set or notify callbacks for a newer scan.
uint64_t scan_generation_ ABSL_GUARDED_BY(mutex_) = 0;
std::function<void()> devices_discovered_callback_ ABSL_GUARDED_BY(mutex_);
std::function<void()> devices_not_discovered_callback_
ABSL_GUARDED_BY(mutex_);
absl::flat_hash_set<::nearby::api::ble::BlePeripheral::UniqueId>
discovered_peripherals_ ABSL_GUARDED_BY(mutex_);
std::shared_ptr<::nearby::linux::BluetoothDevices> scan_devices_
ABSL_GUARDED_BY(scan_operation_mutex_);
std::unique_ptr<::nearby::linux::RootObjectManager> scan_root_object_manager_
ABSL_GUARDED_BY(scan_operation_mutex_);
std::unique_ptr<::nearby::linux::bluez::AdvertisementMonitorManager>
scan_monitor_manager_ ABSL_GUARDED_BY(scan_operation_mutex_);
std::unique_ptr<::nearby::linux::bluez::AdvertisementMonitor> scan_monitor_
ABSL_GUARDED_BY(scan_operation_mutex_);
};
} // namespace linux
@@ -0,0 +1,116 @@
#include "sharing/linux/nearby_fast_init_manager.h"
#include <cstdint>
#include <functional>
#include <string>
#include <utility>
#include "absl/synchronization/mutex.h"
#include "gtest/gtest.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/implementation/ble.h"
#include "internal/platform/uuid.h"
#include "sharing/linux/nearby_fast_init_ble_beacon.h"
namespace nearby::sharing::linux {
class LinuxFastInitiationManagerTestPeer {
public:
static void BeginScan(LinuxFastInitiationManager& manager,
std::function<void()> discovered,
std::function<void()> not_discovered) {
absl::MutexLock lock(&manager.mutex_);
manager.is_scanning_ = true;
manager.scan_generation_ = 1;
manager.devices_discovered_callback_ = std::move(discovered);
manager.devices_not_discovered_callback_ = std::move(not_discovered);
manager.discovered_peripherals_.clear();
}
static void Found(LinuxFastInitiationManager& manager, uint64_t id,
api::ble::BleAdvertisementData data) {
manager.OnAdvertisementFound(1, id, std::move(data));
}
static void Lost(LinuxFastInitiationManager& manager, uint64_t id) {
manager.OnAdvertisementLost(1, id);
}
static bool IsValid(LinuxFastInitiationManager& manager,
const api::ble::BleAdvertisementData& data) {
return manager.IsFastInitAdvertisement(data);
}
};
namespace {
api::ble::BleAdvertisementData FastInitAdvertisement(
api::FastInitBleBeacon::FastInitType type =
api::FastInitBleBeacon::FastInitType::kNotify) {
std::string bytes(api::FastInitBleBeacon::kAdvertiseDataTotalSize -
api::FastInitBleBeacon::kFastInitServiceUuidSize,
'\0');
for (size_t i = 0; i < api::FastInitBleBeacon::kFastInitModelIdSize; ++i) {
bytes[i] = static_cast<char>(api::FastInitBleBeacon::kFastInitModelId[i]);
}
bytes[api::FastInitBleBeacon::kFastInitModelIdSize] =
static_cast<char>(static_cast<uint8_t>(type) << 2);
api::ble::BleAdvertisementData data;
data.service_data.emplace(*Uuid::FromString(kFastInitServiceUuid),
ByteArray(bytes));
return data;
}
TEST(LinuxFastInitiationManagerTest, ValidatesFastInitServiceData) {
LinuxFastInitBleBeacon beacon;
LinuxFastInitiationManager manager(beacon, nullptr);
EXPECT_TRUE(LinuxFastInitiationManagerTestPeer::IsValid(
manager, FastInitAdvertisement()));
EXPECT_TRUE(LinuxFastInitiationManagerTestPeer::IsValid(
manager,
FastInitAdvertisement(api::FastInitBleBeacon::FastInitType::kSilent)));
auto malformed = FastInitAdvertisement();
malformed.service_data.begin()->second.data()[0] = '\0';
EXPECT_FALSE(LinuxFastInitiationManagerTestPeer::IsValid(manager, malformed));
}
TEST(LinuxFastInitiationManagerTest, ReportsOnlyPresenceTransitions) {
LinuxFastInitBleBeacon beacon;
LinuxFastInitiationManager manager(beacon, nullptr);
int discovered_count = 0;
int not_discovered_count = 0;
LinuxFastInitiationManagerTestPeer::BeginScan(
manager, [&] { ++discovered_count; }, [&] { ++not_discovered_count; });
LinuxFastInitiationManagerTestPeer::Found(manager, 1,
FastInitAdvertisement());
LinuxFastInitiationManagerTestPeer::Found(manager, 1,
FastInitAdvertisement());
LinuxFastInitiationManagerTestPeer::Found(manager, 2,
FastInitAdvertisement());
EXPECT_EQ(discovered_count, 1);
LinuxFastInitiationManagerTestPeer::Lost(manager, 99);
LinuxFastInitiationManagerTestPeer::Lost(manager, 1);
EXPECT_EQ(not_discovered_count, 0);
LinuxFastInitiationManagerTestPeer::Lost(manager, 2);
EXPECT_EQ(not_discovered_count, 1);
}
TEST(LinuxFastInitiationManagerTest, StopScanningClearsLogicalState) {
LinuxFastInitBleBeacon beacon;
LinuxFastInitiationManager manager(beacon, nullptr);
LinuxFastInitiationManagerTestPeer::BeginScan(manager, [] {}, [] {});
bool stopped = false;
manager.StopScanning([&] { stopped = true; });
EXPECT_TRUE(stopped);
EXPECT_FALSE(manager.IsScanning());
}
} // namespace
} // namespace nearby::sharing::linux