mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 14:46:12 -04:00
fixed device lost callback path for async callbacks in ble. implemented startscanning for fast init manager
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
9.0.1
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
#include "internal/platform/implementation/linux/bluez_advertisement_monitor.h"
|
#include "internal/platform/implementation/linux/bluez_advertisement_monitor.h"
|
||||||
|
|
||||||
#include <regex>
|
|
||||||
|
|
||||||
#include "internal/platform/byte_array.h"
|
#include "internal/platform/byte_array.h"
|
||||||
#include "internal/platform/implementation/ble.h"
|
#include "internal/platform/implementation/ble.h"
|
||||||
#include "internal/platform/implementation/linux/dbus.h"
|
#include "internal/platform/implementation/linux/dbus.h"
|
||||||
@@ -11,7 +9,7 @@ namespace nearby {
|
|||||||
namespace linux {
|
namespace linux {
|
||||||
namespace bluez {
|
namespace bluez {
|
||||||
AdvertisementMonitor::AdvertisementMonitor(
|
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,
|
api::ble::TxPowerLevel tx_power_level, absl::string_view type,
|
||||||
std::shared_ptr<BluetoothDevices> devices,
|
std::shared_ptr<BluetoothDevices> devices,
|
||||||
api::ble::BleMedium::ScanCallback scan_callback)
|
api::ble::BleMedium::ScanCallback scan_callback)
|
||||||
@@ -23,30 +21,38 @@ AdvertisementMonitor::AdvertisementMonitor(
|
|||||||
std::move(scan_callback.advertisement_found_cb)}) {}
|
std::move(scan_callback.advertisement_found_cb)}) {}
|
||||||
|
|
||||||
AdvertisementMonitor::AdvertisementMonitor(
|
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,
|
api::ble::TxPowerLevel tx_power_level, absl::string_view type,
|
||||||
std::shared_ptr<BluetoothDevices> devices,
|
std::shared_ptr<BluetoothDevices> devices,
|
||||||
api::ble::BleMedium::ScanningCallback scan_callback)
|
api::ble::BleMedium::ScanningCallback scan_callback)
|
||||||
: AdaptorInterfaces(system_bus, bluez::advertisement_monitor_path(
|
: AdvertisementMonitor(
|
||||||
std::string{service_uuid})),
|
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)),
|
devices_(std::move(devices)),
|
||||||
scan_callback_{std::move(scan_callback.advertisement_found_cb)},
|
scan_callback_(std::move(scan_callback)),
|
||||||
start_scanning_result_callback_(
|
|
||||||
std::move(scan_callback.start_scanning_result)),
|
|
||||||
type_(type),
|
type_(type),
|
||||||
service_uuid_(service_uuid),
|
service_uuid_(service_uuid),
|
||||||
tx_power_level_(tx_power_level) {
|
tx_power_level_(tx_power_level) {
|
||||||
registerAdaptor();
|
registerAdaptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvertisementMonitor::DeviceFound(const sdbus::ObjectPath &device) {
|
void AdvertisementMonitor::DeviceFound(const sdbus::ObjectPath& device) {
|
||||||
devices_->cleanup_lost_peripherals();
|
devices_->cleanup_lost_peripherals();
|
||||||
auto peripheral = devices_->add_new_device(device);
|
auto peripheral = devices_->add_new_device(device);
|
||||||
auto service_data = peripheral->ServiceData();
|
auto service_data = peripheral->ServiceData();
|
||||||
if (!service_data.has_value()) return;
|
if (!service_data.has_value()) return;
|
||||||
|
|
||||||
struct api::ble::BleAdvertisementData adv_data;
|
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);
|
auto uuid = UuidFromString(uuid_str);
|
||||||
if (!uuid.has_value()) {
|
if (!uuid.has_value()) {
|
||||||
LOG(ERROR)
|
LOG(ERROR)
|
||||||
@@ -60,12 +66,15 @@ void AdvertisementMonitor::DeviceFound(const sdbus::ObjectPath &device) {
|
|||||||
adv_data.service_data.emplace(*uuid,
|
adv_data.service_data.emplace(*uuid,
|
||||||
std::string(bytes.begin(), bytes.end()));
|
std::string(bytes.begin(), bytes.end()));
|
||||||
}
|
}
|
||||||
auto id = std::stoull(std::regex_replace(peripheral->GetMacAddress().ToString(),
|
auto id = peripheral->GetMacAddress().address();
|
||||||
std::regex("[:\\-]"), ""), nullptr, 16);
|
|
||||||
scan_callback_.advertisement_found_cb(id, adv_data);
|
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);
|
devices_->mark_peripheral_lost(device);
|
||||||
}
|
}
|
||||||
} // namespace bluez
|
} // namespace bluez
|
||||||
|
|||||||
@@ -47,16 +47,22 @@ class AdvertisementMonitor final
|
|||||||
absl::string_view type,
|
absl::string_view type,
|
||||||
std::shared_ptr<BluetoothDevices> devices,
|
std::shared_ptr<BluetoothDevices> devices,
|
||||||
api::ble::BleMedium::ScanningCallback scan_callback);
|
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(); }
|
~AdvertisementMonitor() { unregisterAdaptor(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Methods
|
// Methods
|
||||||
void Release() override {}
|
void Release() override {}
|
||||||
void Activate() override {
|
void Activate() override {
|
||||||
LOG(INFO) <<__func__ << ": bluez advertisement monitor activated at path: "
|
LOG(INFO) << __func__ << ": bluez advertisement monitor activated at path: "
|
||||||
<< getObject().getObjectPath();
|
<< getObject().getObjectPath();
|
||||||
if (start_scanning_result_callback_ != nullptr) {
|
if (scan_callback_.start_scanning_result != nullptr) {
|
||||||
start_scanning_result_callback_(absl::OkStatus());
|
scan_callback_.start_scanning_result(absl::OkStatus());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,9 +72,7 @@ class AdvertisementMonitor final
|
|||||||
// Properties
|
// Properties
|
||||||
std::string Type() override { return type_; };
|
std::string Type() override { return type_; };
|
||||||
int16_t RSSILowThreshold() override { return 127; };
|
int16_t RSSILowThreshold() override { return 127; };
|
||||||
int16_t RSSIHighThreshold() override {
|
int16_t RSSIHighThreshold() override { return 127; }
|
||||||
return 127;
|
|
||||||
}
|
|
||||||
uint16_t RSSISamplingPeriod() override {
|
uint16_t RSSISamplingPeriod() override {
|
||||||
// The Windows implementation uses a sampling interval of 2 seconds.
|
// The Windows implementation uses a sampling interval of 2 seconds.
|
||||||
return 20;
|
return 20;
|
||||||
@@ -79,13 +83,11 @@ class AdvertisementMonitor final
|
|||||||
return {{0,
|
return {{0,
|
||||||
0x16,
|
0x16,
|
||||||
{static_cast<uint8_t>(service_id_data[3] & 0xFF),
|
{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_;
|
std::shared_ptr<BluetoothDevices> devices_;
|
||||||
api::ble::BleMedium::ScanCallback scan_callback_;
|
api::ble::BleMedium::ScanningCallback scan_callback_;
|
||||||
absl::AnyInvocable<void(absl::Status)> start_scanning_result_callback_;
|
|
||||||
|
|
||||||
std::string type_;
|
std::string type_;
|
||||||
Uuid service_uuid_;
|
Uuid service_uuid_;
|
||||||
|
|||||||
@@ -61,6 +61,19 @@ cc_binary(
|
|||||||
deps = [":fast_init"],
|
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(
|
cc_binary(
|
||||||
name = "nearby_sharing_cli",
|
name = "nearby_sharing_cli",
|
||||||
|
|||||||
@@ -1,17 +1,64 @@
|
|||||||
|
#include <algorithm>
|
||||||
#include <functional>
|
#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_init_ble_beacon.h"
|
||||||
#include "sharing/internal/api/fast_initiation_manager.h"
|
#include "sharing/internal/api/fast_initiation_manager.h"
|
||||||
|
|
||||||
#include "internal/platform/implementation/linux/bluetooth_adapter.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.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/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 nearby {
|
||||||
namespace sharing {
|
namespace sharing {
|
||||||
namespace linux {
|
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(
|
void LinuxFastInitiationManager::StartAdvertising(
|
||||||
nearby::api::FastInitBleBeacon::FastInitType type,
|
nearby::api::FastInitBleBeacon::FastInitType type,
|
||||||
std::function<void()> callback,
|
std::function<void()> callback,
|
||||||
@@ -121,22 +168,301 @@ void LinuxFastInitiationManager::StopAdvertising(
|
|||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void StopScanning(std::function<void()> callback) {
|
|
||||||
if (callback) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void LinuxFastInitiationManager::StartScanning(
|
void LinuxFastInitiationManager::StartScanning(
|
||||||
std::function<void()> devices_discovered_callback,
|
std::function<void()> devices_discovered_callback,
|
||||||
std::function<void()> devices_not_discovered_callback,
|
std::function<void()> devices_not_discovered_callback,
|
||||||
std::function<void(nearby::api::FastInitiationManager::Error)>
|
std::function<void(nearby::api::FastInitiationManager::Error)>
|
||||||
error_callback) {
|
error_callback) {
|
||||||
if (error_callback) {
|
std::optional<nearby::api::FastInitiationManager::Error> error;
|
||||||
error_callback(
|
{
|
||||||
nearby::api::FastInitiationManager::Error::kHardwareNotSupported);
|
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(
|
||||||
|
[®istration_complete,
|
||||||
|
®istration_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 linux
|
||||||
} // namespace sharing
|
} // namespace sharing
|
||||||
} // namespace nearby
|
} // namespace nearby
|
||||||
|
|
||||||
|
|||||||
@@ -16,13 +16,22 @@
|
|||||||
#ifndef LINUX_NEARBY_SHARING_INTERNAL_API_FAST_INITIATION_MANAGER_H_
|
#ifndef LINUX_NEARBY_SHARING_INTERNAL_API_FAST_INITIATION_MANAGER_H_
|
||||||
#define LINUX_NEARBY_SHARING_INTERNAL_API_FAST_INITIATION_MANAGER_H_
|
#define LINUX_NEARBY_SHARING_INTERNAL_API_FAST_INITIATION_MANAGER_H_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <functional>
|
#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_init_ble_beacon.h"
|
||||||
#include "sharing/internal/api/fast_initiation_manager.h"
|
#include "sharing/internal/api/fast_initiation_manager.h"
|
||||||
|
|
||||||
#include "internal/platform/implementation/linux/bluetooth_adapter.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.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/bluez_le_advertisement.h"
|
||||||
|
|
||||||
constexpr char kFastInitServiceUuid[] = "0000fe2c-0000-1000-8000-00805f9b34fb";
|
constexpr char kFastInitServiceUuid[] = "0000fe2c-0000-1000-8000-00805f9b34fb";
|
||||||
@@ -36,7 +45,7 @@ class LinuxFastInitiationManager final
|
|||||||
public:
|
public:
|
||||||
explicit LinuxFastInitiationManager(
|
explicit LinuxFastInitiationManager(
|
||||||
nearby::api::FastInitBleBeacon& beacon,
|
nearby::api::FastInitBleBeacon& beacon,
|
||||||
std::shared_ptr<::nearby::linux::BluetoothAdapter> bluetooth_adapter)
|
std::shared_ptr<::nearby::linux::BluetoothAdapter> bluetooth_adapter)
|
||||||
: beacon_(beacon), adapter_(std::move(bluetooth_adapter)) {
|
: beacon_(beacon), adapter_(std::move(bluetooth_adapter)) {
|
||||||
if (adapter_ != nullptr) {
|
if (adapter_ != nullptr) {
|
||||||
adv_manager_ =
|
adv_manager_ =
|
||||||
@@ -44,12 +53,13 @@ class LinuxFastInitiationManager final
|
|||||||
*adapter_->GetConnection(), *adapter_);
|
*adapter_->GetConnection(), *adapter_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
~LinuxFastInitiationManager() override;
|
||||||
|
|
||||||
void StartAdvertising(
|
void StartAdvertising(
|
||||||
nearby::api::FastInitBleBeacon::FastInitType type,
|
nearby::api::FastInitBleBeacon::FastInitType type,
|
||||||
std::function<void()> callback,
|
std::function<void()> callback,
|
||||||
std::function<void(nearby::api::FastInitiationManager::Error)>
|
std::function<void(nearby::api::FastInitiationManager::Error)>
|
||||||
error_callback) override ;
|
error_callback) override;
|
||||||
|
|
||||||
void StopAdvertising(std::function<void()> 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_discovered_callback,
|
||||||
std::function<void()> devices_not_discovered_callback,
|
std::function<void()> devices_not_discovered_callback,
|
||||||
std::function<void(nearby::api::FastInitiationManager::Error)>
|
std::function<void(nearby::api::FastInitiationManager::Error)>
|
||||||
error_callback) override ;
|
error_callback) override;
|
||||||
|
|
||||||
void StopScanning(std::function<void()> callback) override {
|
void StopScanning(std::function<void()> callback) override;
|
||||||
if (callback) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsAdvertising() override {
|
bool IsAdvertising() override {
|
||||||
absl::MutexLock lock(&mutex_);
|
absl::MutexLock lock(&mutex_);
|
||||||
return advertisement_ != nullptr;
|
return advertisement_ != nullptr;
|
||||||
}
|
}
|
||||||
bool IsScanning() override { return false; }
|
bool IsScanning() override;
|
||||||
|
|
||||||
private:
|
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_;
|
nearby::api::FastInitBleBeacon& beacon_;
|
||||||
std::shared_ptr<::nearby::linux::BluetoothAdapter> adapter_;
|
std::shared_ptr<::nearby::linux::BluetoothAdapter> adapter_;
|
||||||
std::unique_ptr<::nearby::linux::bluez::LEAdvertisementManager> adv_manager_;
|
std::unique_ptr<::nearby::linux::bluez::LEAdvertisementManager> adv_manager_;
|
||||||
|
absl::Mutex scan_operation_mutex_;
|
||||||
absl::Mutex mutex_;
|
absl::Mutex mutex_;
|
||||||
std::unique_ptr<::nearby::linux::bluez::LEAdvertisement> advertisement_
|
std::unique_ptr<::nearby::linux::bluez::LEAdvertisement> advertisement_
|
||||||
ABSL_GUARDED_BY(mutex_);
|
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
|
} // 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
|
||||||
Reference in New Issue
Block a user