// 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. #ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_BLUEZ_PROFILE_H_ #define PLATFORM_IMPL_LINUX_BLUETOOTH_BLUEZ_PROFILE_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" #include "internal/platform/implementation/bluetooth_classic.h" #include "internal/platform/implementation/linux/bluetooth_devices.h" #include "internal/platform/implementation/linux/bluez.h" #include "internal/platform/implementation/linux/generated/dbus/bluez/profile_manager_client.h" #include "internal/platform/implementation/linux/generated/dbus/bluez/profile_server.h" #include "internal/platform/logging.h" namespace nearby { namespace linux { class ProfileManager; class Profile final : public sdbus::AdaptorInterfaces { public: Profile(const Profile &) = delete; Profile(Profile &&) = delete; Profile &operator=(const Profile &) = delete; Profile &operator=(Profile &&) = delete; Profile(sdbus::IConnection &system_bus, sdbus::ObjectPath profile_object_path, BluetoothDevices &devices) : AdaptorInterfaces(system_bus, std::move(profile_object_path)), released_(false), devices_(devices) { registerAdaptor(); LOG(INFO) << __func__ << ": Created a new BlueZ profile at :" << getObject().getObjectPath(); } ~Profile() { unregisterAdaptor(); } private: friend class ProfileManager; struct FDProperties { explicit FDProperties(const std::map &fd_props) : version(std::nullopt), features(std::nullopt) { if (fd_props.count("Version") == 1) { version = fd_props.at("Version").get(); } if (fd_props.count("Features") == 1) { features = fd_props.at("Features").get(); } } std::optional version; std::optional features; }; void Release() override; void NewConnection(const sdbus::ObjectPath &, const sdbus::UnixFd &, const std::map &) override ABSL_LOCKS_EXCLUDED(connections_lock_); void RequestDisconnection(const sdbus::ObjectPath &) override ABSL_LOCKS_EXCLUDED(connections_lock_); std::atomic_bool released_; absl::Mutex connections_lock_; std::map>> connections_ ABSL_GUARDED_BY(connections_lock_); // Track pending outgoing connection attempts to avoid race with incoming std::set pending_outgoing_ ABSL_GUARDED_BY(connections_lock_); BluetoothDevices &devices_; }; class ProfileManager final : private sdbus::ProxyInterfaces { public: ProfileManager(const ProfileManager &) = delete; ProfileManager(ProfileManager &&) = delete; ProfileManager &operator=(const ProfileManager &) = delete; ProfileManager &operator=(ProfileManager &&) = delete; ProfileManager(sdbus::IConnection &system_bus, BluetoothDevices &devices) : ProxyInterfaces(system_bus, sdbus::ServiceName(bluez::SERVICE_DEST), sdbus::ObjectPath("/org/bluez")), devices_(devices) { registerProxy(); } ~ProfileManager() { unregisterProxy(); } bool ProfileRegistered(absl::string_view service_uuid) ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_); bool Register(std::optional service_name, absl::string_view service_uuid) ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_); bool Register(absl::string_view service_uuid) ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_) { return Register(std::nullopt, service_uuid); } void Unregister(absl::string_view service_uuid) ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_); std::optional GetServiceRecordFD( api::BluetoothDevice &remote_device, absl::string_view service_uuid, CancellationFlag *cancellation_flag) ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_); std::optional, sdbus::UnixFd>> GetServiceRecordFD(absl::string_view service_uuid, CancellationFlag *cancellation_flag) ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_); void MarkPendingOutgoing(absl::string_view service_uuid, const MacAddress& mac_address) ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_); void ClearPendingOutgoing(absl::string_view service_uuid, const MacAddress& mac_address) ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_); private: BluetoothDevices &devices_; // Maps service UUIDs to RegisteredService absl::Mutex registered_service_uuids_mutex_; std::map> registered_services_ ABSL_GUARDED_BY(registered_service_uuids_mutex_); }; } // namespace linux } // namespace nearby #endif