From d47788392e9388042e24336d3f28794504dd8d79 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sat, 9 Sep 2023 13:00:28 +0530 Subject: [PATCH] Add DeviceWatcher for adding/removing devices. --- .../implementation/linux/ble_v2_medium.cc | 35 +- .../implementation/linux/ble_v2_medium.h | 4 +- .../linux/bluetooth_bluez_profile.cc | 6 +- .../linux/bluetooth_classic_medium.cc | 397 ++++++++---------- .../linux/bluetooth_classic_medium.h | 30 +- .../implementation/linux/bluetooth_devices.cc | 98 +++++ .../implementation/linux/bluetooth_devices.h | 51 +++ 7 files changed, 349 insertions(+), 272 deletions(-) diff --git a/internal/platform/implementation/linux/ble_v2_medium.cc b/internal/platform/implementation/linux/ble_v2_medium.cc index 56289bcc..7b990bed 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.cc +++ b/internal/platform/implementation/linux/ble_v2_medium.cc @@ -23,6 +23,7 @@ #include "internal/platform/implementation/ble_v2.h" #include "internal/platform/implementation/linux/ble_gatt_server.h" #include "internal/platform/implementation/linux/ble_v2_medium.h" +#include "internal/platform/implementation/linux/bluetooth_devices.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" @@ -215,13 +216,16 @@ bool BleV2Medium::StartLEDiscovery() { DBUS_LOG_METHOD_CALL_ERROR(&adapter, "SetDiscoveryFilter", e); return false; } + try { NEARBY_LOGS(INFO) << __func__ << ": Starting LE discovery on " << adapter.getObjectPath(); adapter.StartDiscovery(); } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StartDiscovery", e); - return false; + if (e.getName() != "org.bluez.Error.InProgress") { + DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StartDiscovery", e); + return false; + } } return true; @@ -274,10 +278,13 @@ bool BleV2Medium::StartScanning(const Uuid &service_uuid, return false; } + auto device_watcher = std::make_unique( + system_bus_, adapter_.GetObjectPath(), devices_); if (!StartLEDiscovery()) { NEARBY_LOGS(ERROR) << __func__ << ": Could not start LE discovery on adapter " << adapter_.GetObjectPath(); + device_watcher = nullptr; try { monitor->emitInterfacesRemovedSignal( {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); @@ -291,7 +298,8 @@ bool BleV2Medium::StartScanning(const Uuid &service_uuid, return false; } - active_adv_monitors_[service_uuid] = std::move(monitor); + active_adv_monitors_[service_uuid] = + std::make_pair(std::move(monitor), std::move(device_watcher)); cur_monitored_service_uuid_ = service_uuid; return true; } @@ -320,12 +328,15 @@ bool BleV2Medium::StopScanning() { absl::MutexLock lock(&active_adv_monitors_mutex_); auto monitor_it = active_adv_monitors_.find(*cur_monitored_service_uuid_); assert(monitor_it != active_adv_monitors_.end()); + { + auto &[_uuid, session] = *monitor_it; + auto &[adv_monitor, _watcher] = session; - auto &[_uuid, adv_monitor] = *monitor_it; - NEARBY_LOGS(VERBOSE) << __func__ << ": Removing advertising monitor " - << adv_monitor->getObjectPath(); - adv_monitor->emitInterfacesRemovedSignal( - {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); + NEARBY_LOGS(VERBOSE) << __func__ << ": Removing advertising monitor " + << adv_monitor->getObjectPath(); + adv_monitor->emitInterfacesRemovedSignal( + {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); + } active_adv_monitors_.erase(monitor_it); cur_monitored_service_uuid_ = std::nullopt; @@ -363,6 +374,8 @@ BleV2Medium::StartScanning(const Uuid &service_uuid, return nullptr; } + auto device_watcher = std::make_unique( + system_bus_, adapter_.GetObjectPath(), devices_); if (!StartLEDiscovery()) { NEARBY_LOGS(ERROR) << __func__ << ": Could not start LE discovery on adapter " @@ -380,7 +393,9 @@ BleV2Medium::StartScanning(const Uuid &service_uuid, return nullptr; } - active_adv_monitors_[service_uuid] = std::move(monitor); + active_adv_monitors_[service_uuid] = + std::make_pair(std::move(monitor), std::move(device_watcher)); + return std::make_unique( ScanningSession{.stop_scanning = [this, service_uuid]() { absl::MutexLock lock(&active_adv_monitors_mutex_); @@ -392,7 +407,7 @@ BleV2Medium::StartScanning(const Uuid &service_uuid, "Advertising monitor for this service does not exist"); } - auto &monitor = active_adv_monitors_[service_uuid]; + auto &[monitor, watcher] = active_adv_monitors_[service_uuid]; try { monitor->emitInterfacesRemovedSignal( {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); diff --git a/internal/platform/implementation/linux/ble_v2_medium.h b/internal/platform/implementation/linux/ble_v2_medium.h index 4c627b5b..145f3106 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.h +++ b/internal/platform/implementation/linux/ble_v2_medium.h @@ -120,7 +120,9 @@ class BleV2Medium final : public api::ble_v2::BleMedium { std::unique_ptr adv_monitor_manager_; absl::Mutex active_adv_monitors_mutex_; - absl::flat_hash_map> + absl::flat_hash_map< + Uuid, + std::pair, std::unique_ptr>> active_adv_monitors_ ABSL_GUARDED_BY(active_adv_monitors_mutex_); // Used by the synchronous variant of StartScanning std::optional cur_monitored_service_uuid_; diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc index 2f0e1441..5aa359eb 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc @@ -64,11 +64,7 @@ void Profile::NewConnection( auto device = devices_.get_device_by_path(device_object_path); if (device == nullptr) { - NEARBY_LOGS(ERROR) - << __func__ - << ": NewConection called with a device object we don't know about: " - << device_object_path; - throw sdbus::Error("org.bluez.Error.Rejected", "Unknown object"); + device = devices_.add_new_device(device_object_path); } auto alias = device->Alias(); diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index 6a9ec652..8a795f28 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -1,233 +1,164 @@ -// Copyright 2023 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 -#include - -#include -#include - -#include "absl/strings/string_view.h" -#include "absl/strings/substitute.h" -#include "internal/platform/implementation/bluetooth_classic.h" -#include "internal/platform/implementation/linux/bluetooth_adapter.h" -#include "internal/platform/implementation/linux/bluetooth_bluez_profile.h" -#include "internal/platform/implementation/linux/bluetooth_classic_device.h" -#include "internal/platform/implementation/linux/bluetooth_classic_medium.h" -#include "internal/platform/implementation/linux/bluetooth_classic_server_socket.h" -#include "internal/platform/implementation/linux/bluetooth_classic_socket.h" -#include "internal/platform/implementation/linux/bluetooth_pairing.h" -#include "internal/platform/implementation/linux/bluez.h" -#include "internal/platform/implementation/linux/generated/dbus/bluez/device_client.h" -#include "internal/platform/logging.h" - -namespace nearby { -namespace linux { -BluetoothClassicMedium::BluetoothClassicMedium(sdbus::IConnection &system_bus, - BluetoothAdapter &adapter) - : ProxyInterfaces(system_bus, "org.bluez", "/"), - adapter_(adapter), - devices_(std::make_shared( - system_bus, adapter.GetObjectPath(), observers_)), - profile_manager_( - std::make_unique(system_bus, *devices_)) { - registerProxy(); -} - -void BluetoothClassicMedium::onInterfacesAdded( - const sdbus::ObjectPath &object, - const std::map> - &interfaces) { - auto path_prefix = absl::Substitute( - "$0/dev_", adapter_.GetBluezAdapterObject().getObjectPath()); - if (object.find(path_prefix) != 0) { - return; - } - - if (devices_->get_device_by_path(object) != nullptr) { - // Device already exists. - return; - } - - if (interfaces.count(org::bluez::Device1_proxy::INTERFACE_NAME) == 1) { - NEARBY_LOGS(INFO) << __func__ << ": Encountered new device at " << object; - - auto device = devices_->add_new_device(object); - if (discovery_cb_ != nullptr && - discovery_cb_->device_discovered_cb != nullptr) { - device->SetDiscoveryCallback(discovery_cb_); - discovery_cb_->device_discovered_cb(*device); - } - - for (const auto &observer : observers_.GetObservers()) { - observer->DeviceAdded(*device); - } - } -} - -void BluetoothClassicMedium::onInterfacesRemoved( - const sdbus::ObjectPath &object, - const std::vector &interfaces) { - auto path_prefix = absl::Substitute("$0/dev_", adapter_.GetObjectPath()); - if (object.find(path_prefix) != 0) { - return; - } - - for (const auto &interface : interfaces) { - if (interface == org::bluez::Device1_proxy::INTERFACE_NAME) { - { - auto device = devices_->get_device_by_path(object); - if (device == nullptr) { - NEARBY_LOGS(WARNING) << __func__ - << ": received InterfacesRemoved for a device " - "we don't know about: " - << object; - return; - } - - NEARBY_LOGS(INFO) << __func__ << ": Device " << object - << " has been removed"; - if (discovery_cb_ != nullptr && - discovery_cb_->device_lost_cb != nullptr) { - discovery_cb_->device_lost_cb(*device); - } - - for (const auto &observer : observers_.GetObservers()) { - observer->DeviceRemoved(*device); - } - } - devices_->remove_device_by_path(object); - } - } -} - -bool BluetoothClassicMedium::StartDiscovery( - DiscoveryCallback discovery_callback) { - discovery_cb_ = - std::make_shared(std::move(discovery_callback)); - - std::map filter; - filter["Transport"] = "bredr"; - auto &adapter = adapter_.GetBluezAdapterObject(); - - try { - adapter.SetDiscoveryFilter(filter); - } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(&adapter, "SetDiscoveryFilter", e); - return false; - } - try { - adapter.StartDiscovery(); - } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StartDiscovery", e); - return false; - } - - try { - NEARBY_LOGS(INFO) << __func__ << ": Starting BR/EDR discovery on " - << adapter_.GetObjectPath(); - adapter.StartDiscovery(); - } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StartDiscovery", e); - discovery_cb_.reset(); - return false; - } - - return true; -} - -bool BluetoothClassicMedium::StopDiscovery() { - auto &adapter = adapter_.GetBluezAdapterObject(); - - try { - NEARBY_LOGS(INFO) << __func__ << "Stopping discovery on " - << adapter.getObjectPath(); - - adapter.StopDiscovery(); - this->discovery_cb_.reset(); - } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StopDiscovery", e); - return false; - } - - return true; -} - -std::unique_ptr BluetoothClassicMedium::ConnectToService( - api::BluetoothDevice &remote_device, const std::string &service_uuid, - CancellationFlag *cancellation_flag) { - auto device_object_path = bluez::device_object_path( - adapter_.GetObjectPath(), remote_device.GetMacAddress()); - if (!profile_manager_->ProfileRegistered(service_uuid)) { - if (!profile_manager_->Register("", service_uuid)) { - NEARBY_LOGS(ERROR) << __func__ << ": Could not register profile " - << service_uuid << " with Bluez"; - return nullptr; - } - } - - auto device = devices_->get_device_by_path(device_object_path); - if (device == nullptr) return nullptr; - - device->ConnectToProfile(service_uuid); - - auto fd = profile_manager_->GetServiceRecordFD(remote_device, service_uuid, - cancellation_flag); - if (!fd.has_value()) { - NEARBY_LOGS(WARNING) << __func__ - << ": Failed to get a new connection for profile " - << service_uuid << " for device " - << device_object_path; - return nullptr; - } - - return std::unique_ptr( - new BluetoothSocket(device, fd.value())); -} - -std::unique_ptr -BluetoothClassicMedium::ListenForService(const std::string &service_name, - const std::string &service_uuid) { - if (!profile_manager_->ProfileRegistered(service_uuid)) { - if (!profile_manager_->Register(service_name, service_uuid)) { - NEARBY_LOGS(ERROR) << __func__ << ": Could not register profile " - << service_name << " " << service_uuid - << " with Bluez"; - return nullptr; - } - } - - return std::unique_ptr( - new BluetoothServerSocket(*profile_manager_, service_uuid)); -} - -api::BluetoothDevice *BluetoothClassicMedium::GetRemoteDevice( - const std::string &mac_address) { - auto device = devices_->get_device_by_address(mac_address); - if (device == nullptr) return nullptr; - - return device.get(); -} - -std::unique_ptr BluetoothClassicMedium::CreatePairing( - api::BluetoothDevice &remote_device) { - auto device = devices_->get_device_by_address(remote_device.GetMacAddress()); - if (device == nullptr) return nullptr; - - return std::unique_ptr( - new BluetoothPairing(adapter_, device)); -} - -} // namespace linux -} // namespace nearby +// Copyright 2023 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 +#include + +#include +#include + +#include "absl/strings/string_view.h" +#include "internal/base/observer_list.h" +#include "internal/platform/implementation/bluetooth_classic.h" +#include "internal/platform/implementation/linux/bluetooth_adapter.h" +#include "internal/platform/implementation/linux/bluetooth_bluez_profile.h" +#include "internal/platform/implementation/linux/bluetooth_classic_device.h" +#include "internal/platform/implementation/linux/bluetooth_classic_medium.h" +#include "internal/platform/implementation/linux/bluetooth_classic_server_socket.h" +#include "internal/platform/implementation/linux/bluetooth_classic_socket.h" +#include "internal/platform/implementation/linux/bluetooth_pairing.h" +#include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { +BluetoothClassicMedium::BluetoothClassicMedium(sdbus::IConnection &system_bus, + BluetoothAdapter &adapter) + : system_bus_(system_bus), + adapter_(adapter), + observers_(std::make_shared>()), + devices_(std::make_shared( + system_bus, adapter.GetObjectPath(), *observers_)), + device_watcher_(nullptr), + profile_manager_( + std::make_unique(system_bus, *devices_)) {} + +bool BluetoothClassicMedium::StartDiscovery( + DiscoveryCallback discovery_callback) { + device_watcher_ = std::make_unique( + system_bus_, adapter_.GetObjectPath(), devices_, + std::make_unique(std::move(discovery_callback)), + observers_); + + std::map filter; + filter["Transport"] = "auto"; + auto &adapter = adapter_.GetBluezAdapterObject(); + + try { + adapter.SetDiscoveryFilter(filter); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(&adapter, "SetDiscoveryFilter", e); + device_watcher_ = nullptr; + return false; + } + + try { + NEARBY_LOGS(INFO) << __func__ << ": Starting BR/EDR discovery on " + << adapter_.GetObjectPath(); + adapter.StartDiscovery(); + } catch (const sdbus::Error &e) { + if (e.getName() != "org.bluez.Error.InProgress") { + DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StartDiscovery", e); + device_watcher_ = nullptr; + return false; + } + } + + return true; +} + +bool BluetoothClassicMedium::StopDiscovery() { + auto &adapter = adapter_.GetBluezAdapterObject(); + NEARBY_LOGS(INFO) << __func__ << "Stopping discovery on " + << adapter.getObjectPath(); + device_watcher_ = nullptr; + try { + adapter.StopDiscovery(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StopDiscovery", e); + return false; + } + + return true; +} + +std::unique_ptr BluetoothClassicMedium::ConnectToService( + api::BluetoothDevice &remote_device, const std::string &service_uuid, + CancellationFlag *cancellation_flag) { + auto device_object_path = bluez::device_object_path( + adapter_.GetObjectPath(), remote_device.GetMacAddress()); + if (!profile_manager_->ProfileRegistered(service_uuid)) { + if (!profile_manager_->Register("", service_uuid)) { + NEARBY_LOGS(ERROR) << __func__ << ": Could not register profile " + << service_uuid << " with Bluez"; + return nullptr; + } + } + + auto device = devices_->get_device_by_path(device_object_path); + if (device == nullptr) return nullptr; + + if (!device->ConnectToProfile(service_uuid)) { + return nullptr; + } + + auto fd = profile_manager_->GetServiceRecordFD(remote_device, service_uuid, + cancellation_flag); + if (!fd.has_value()) { + NEARBY_LOGS(WARNING) << __func__ + << ": Failed to get a new connection for profile " + << service_uuid << " for device " + << device_object_path; + return nullptr; + } + + return std::unique_ptr( + new BluetoothSocket(device, fd.value())); +} + +std::unique_ptr +BluetoothClassicMedium::ListenForService(const std::string &service_name, + const std::string &service_uuid) { + if (!profile_manager_->ProfileRegistered(service_uuid)) { + if (!profile_manager_->Register(service_name, service_uuid)) { + NEARBY_LOGS(ERROR) << __func__ << ": Could not register profile " + << service_name << " " << service_uuid + << " with Bluez"; + return nullptr; + } + } + + return std::unique_ptr( + new BluetoothServerSocket(*profile_manager_, service_uuid)); +} + +api::BluetoothDevice *BluetoothClassicMedium::GetRemoteDevice( + const std::string &mac_address) { + auto device = devices_->get_device_by_address(mac_address); + if (device == nullptr) return nullptr; + + return device.get(); +} + +std::unique_ptr BluetoothClassicMedium::CreatePairing( + api::BluetoothDevice &remote_device) { + auto device = devices_->get_device_by_address(remote_device.GetMacAddress()); + if (device == nullptr) return nullptr; + + return std::unique_ptr( + new BluetoothPairing(adapter_, device)); +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.h b/internal/platform/implementation/linux/bluetooth_classic_medium.h index 9a3b120a..18104108 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.h +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.h @@ -36,17 +36,10 @@ namespace nearby { namespace linux { // Container of operations that can be performed over the Bluetooth Classic // medium. -class BluetoothClassicMedium - : public api::BluetoothClassicMedium, - protected sdbus::ProxyInterfaces { +class BluetoothClassicMedium : public api::BluetoothClassicMedium { public: - BluetoothClassicMedium(const BluetoothClassicMedium &) = delete; - BluetoothClassicMedium(BluetoothClassicMedium &&) = delete; - BluetoothClassicMedium &operator=(const BluetoothClassicMedium &) = delete; - BluetoothClassicMedium &operator=(BluetoothClassicMedium &&) = delete; BluetoothClassicMedium(sdbus::IConnection &system_bus, BluetoothAdapter &adapter); - ~BluetoothClassicMedium() override { unregisterProxy(); }; // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startDiscovery() // @@ -101,29 +94,20 @@ class BluetoothClassicMedium const std::string &mac_address) override; void AddObserver(Observer *observer) override { - observers_.AddObserver(observer); + observers_->AddObserver(observer); }; void RemoveObserver(Observer *observer) override { - observers_.RemoveObserver(observer); + observers_->RemoveObserver(observer); }; - protected: - void onInterfacesAdded( - const sdbus::ObjectPath &objectPath, - const std::map> - &interfacesAndProperties) override; - void onInterfacesRemoved(const sdbus::ObjectPath &objectPath, - const std::vector &interfaces) override; - private: + sdbus::IConnection &system_bus_; + BluetoothAdapter adapter_; - ObserverList observers_; - - protected: + std::shared_ptr> observers_; std::shared_ptr devices_; + std::unique_ptr device_watcher_; - private: - std::shared_ptr discovery_cb_; std::unique_ptr profile_manager_; }; diff --git a/internal/platform/implementation/linux/bluetooth_devices.cc b/internal/platform/implementation/linux/bluetooth_devices.cc index 43a0d1e7..7eef3a80 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.cc +++ b/internal/platform/implementation/linux/bluetooth_devices.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include #include #include @@ -19,10 +20,13 @@ #include #include +#include "absl/strings/substitute.h" #include "absl/synchronization/mutex.h" #include "internal/platform/implementation/linux/bluetooth_classic_device.h" #include "internal/platform/implementation/linux/bluetooth_devices.h" #include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/implementation/linux/dbus.h" +#include "internal/platform/implementation/linux/generated/dbus/bluez/device_client.h" #include "internal/platform/logging.h" namespace nearby { @@ -89,5 +93,99 @@ std::shared_ptr BluetoothDevices::add_new_device( if (!inserted) device_it->second->UnmarkLost(); return device_it->second; } + +void DeviceWatcher::onInterfacesAdded( + const sdbus::ObjectPath &object, + const std::map> + &interfaces) { + auto path_prefix = absl::Substitute("$0/dev_", adapter_object_path_); + if (object.find(path_prefix) != 0) { + return; + } + + if (interfaces.count(org::bluez::Device1_proxy::INTERFACE_NAME) == 0) return; + + auto device = devices_->add_new_device(object); + if (discovery_cb_ != nullptr && + discovery_cb_->device_discovered_cb != nullptr) { + device->SetDiscoveryCallback(discovery_cb_); + discovery_cb_->device_discovered_cb(*device); + } + + if (observers_ != nullptr) { + for (const auto &observer : observers_->GetObservers()) { + observer->DeviceAdded(*device); + } + } +} + +void DeviceWatcher::onInterfacesRemoved( + const sdbus::ObjectPath &object, + const std::vector &interfaces) { + auto path_prefix = absl::Substitute("$0/dev_", adapter_object_path_); + if (object.find(path_prefix) != 0) { + return; + } + + for (const auto &interface : interfaces) { + if (interface == org::bluez::Device1_proxy::INTERFACE_NAME) { + auto device = devices_->get_device_by_path(object); + if (device == nullptr) { + NEARBY_LOGS(WARNING) << __func__ + << ": received InterfacesRemoved for a device " + "we don't know about: " + << object; + return; + } + + NEARBY_LOGS(INFO) << __func__ << ": Device " << object + << " has been removed"; + if (discovery_cb_ != nullptr && + discovery_cb_->device_lost_cb != nullptr) { + discovery_cb_->device_lost_cb(*device); + } + + if (observers_ != nullptr) { + for (const auto &observer : observers_->GetObservers()) { + observer->DeviceRemoved(*device); + } + devices_->remove_device_by_path(object); + } else { + devices_->mark_peripheral_lost(object); + } + } + } +} + +void DeviceWatcher::notifyExistingDevices() { + std::map>> + objects; + try { + objects = GetManagedObjects(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(this, "GetManagedObjects", e); + return; + } + auto device_it = std::find_if( + objects.begin(), objects.end(), + [&](std::pair< + sdbus::ObjectPath, + std::map>> + entry) { + auto &[device_path, interfaces] = entry; + + return device_path.find( + absl::Substitute("$0/dev_", adapter_object_path_)) == 0 && + interfaces.count(org::bluez::Device1_proxy::INTERFACE_NAME) == 1; + }); + + for (; device_it != objects.end(); device_it++) { + NEARBY_LOGS(VERBOSE) << __func__ << ": Adding existing device " + << device_it->first; + devices_->add_new_device(device_it->first); + } +} + } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_devices.h b/internal/platform/implementation/linux/bluetooth_devices.h index 448c289c..bebf6c87 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.h +++ b/internal/platform/implementation/linux/bluetooth_devices.h @@ -18,8 +18,11 @@ #include #include +#include #include #include +#include +#include #include #include "absl/container/flat_hash_map.h" @@ -69,6 +72,54 @@ class BluetoothDevices final { std::chrono::time_point last_cleanup_ ABSL_GUARDED_BY(devices_by_path_lock_); }; + +class DeviceWatcher final : sdbus::ProxyInterfaces { + public: + DeviceWatcher(const DeviceWatcher &) = delete; + DeviceWatcher(DeviceWatcher &&) = delete; + DeviceWatcher &operator=(const DeviceWatcher &) = delete; + DeviceWatcher &operator=(DeviceWatcher &&) = delete; + + DeviceWatcher( + sdbus::IConnection &system_bus, + const sdbus::ObjectPath &adapter_object_path, + std::shared_ptr devices, + std::unique_ptr + discovery_callback, + std::shared_ptr> + observers) + : ProxyInterfaces(system_bus, "org.bluez", "/"), + adapter_object_path_(adapter_object_path), + devices_(std::move(devices)), + discovery_cb_(std::move(discovery_callback)), + observers_(std::move(observers)) { + notifyExistingDevices(); + registerProxy(); + } + DeviceWatcher(sdbus::IConnection &system_bus, + const sdbus::ObjectPath &adapter_object_path, + std::shared_ptr devices) + : DeviceWatcher(system_bus, adapter_object_path, std::move(devices), + nullptr, nullptr) {} + ~DeviceWatcher() { unregisterProxy(); } + + void onInterfacesAdded( + const sdbus::ObjectPath &object, + const std::map> + &interfaces) override; + void onInterfacesRemoved(const sdbus::ObjectPath &object, + const std::vector &interfaces) override; + + private: + void notifyExistingDevices(); + + sdbus::ObjectPath adapter_object_path_; + std::shared_ptr devices_; + std::shared_ptr discovery_cb_; + std::shared_ptr> + observers_; +}; + } // namespace linux } // namespace nearby