Rewrite dbus code using sdbus-c++

This commit is contained in:
Vibhav Pant
2023-08-15 20:52:51 +05:30
parent aea2e16937
commit c8af59666d
29 changed files with 1632 additions and 738 deletions
@@ -16,6 +16,7 @@ cc_library(
"//internal/platform:logging",
"@com_google_absl//absl/strings",
"@libsystemd//:lib",
"@sdbus_cpp//:lib",
],
)
@@ -1,71 +1,68 @@
#include <systemd/sd-bus.h>
#include <sdbus-c++/ProxyInterfaces.h>
#include <sdbus-c++/Types.h>
#include "internal/platform/implementation/bluetooth_adapter.h"
#include "internal/platform/implementation/linux/bluetooth_adapter.h"
#include "internal/platform/implementation/linux/bluez.h"
#include "internal/platform/implementation/linux/bluez_adapter_client_glue.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace linux {
using namespace api;
bool BluetoothAdapter::SetStatus(Status status) {
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
if (sd_bus_set_property(
system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0",
BLUEZ_ADAPTER_INTERFACE, "Powered", &err, "b",
status == api::BluetoothAdapter::Status::kEnabled ? 1 : 0) < 0) {
NEARBY_LOGS(ERROR) << __func__
<< ": Error setting adaptor status: " << err.message;
try {
bool val = status == api::BluetoothAdapter::Status::kEnabled;
Powered(val);
return true;
} catch (const sdbus::Error &e) {
NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName()
<< "' with message '" << e.getMessage()
<< "' while trying to set Powered status for adapter "
<< getObjectPath();
return false;
}
return true;
}
bool BluetoothAdapter::IsEnabled() const {
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
int enabled = 0;
auto proxy = sdbus::createProxy(getProxy().getConnection(),
bluez::SERVICE_DEST, getObjectPath());
proxy->finishRegistration();
if (sd_bus_get_property_trivial(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0",
BLUEZ_ADAPTER_INTERFACE, "Powered", &err, 'b',
&enabled) < 0) {
NEARBY_LOGS(ERROR) << __func__
<< ": Error getting adaptor status: " << err.message;
try {
return proxy->getProperty("Powered").onInterface(INTERFACE_NAME);
} catch (const sdbus::Error &e) {
NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName()
<< "' with message '" << e.getMessage()
<< "' while trying to get Powered status for adapter "
<< getObjectPath();
return false;
}
return enabled;
}
BluetoothAdapter::ScanMode BluetoothAdapter::GetScanMode() const {
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
int powered = 0;
int discoverable = 0;
if (sd_bus_get_property_trivial(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0",
BLUEZ_ADAPTER_INTERFACE, "Powered", &err, 'b',
&powered) < 0) {
NEARBY_LOGS(ERROR) << __func__
<< ": Error getting adaptor status: " << err.message;
return ScanMode::kUnknown;
}
bool powered = IsEnabled();
if (!powered) {
return ScanMode::kNone;
}
if (sd_bus_get_property_trivial(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0",
BLUEZ_ADAPTER_INTERFACE, "Discoverable", &err,
'b', &powered) < 0) {
NEARBY_LOGS(ERROR) << __func__
<< ": Error getting adaptor's discoverable status: "
<< err.message;
try {
auto proxy = sdbus::createProxy(getProxy().getConnection(),
bluez::SERVICE_DEST, getObjectPath());
proxy->finishRegistration();
bool discoverable =
proxy->getProperty("Discoverable").onInterface(INTERFACE_NAME);
return discoverable ? ScanMode::kConnectableDiscoverable
: ScanMode::kConnectable;
} catch (const sdbus::Error &e) {
NEARBY_LOGS(ERROR)
<< __func__ << ": Got error '" << e.getName() << "' with message '"
<< e.getMessage()
<< "' while trying to get Discoverable status for adapter "
<< getObjectPath();
return ScanMode::kUnknown;
}
return discoverable ? ScanMode::kConnectableDiscoverable
: ScanMode::kConnectable;
}
bool BluetoothAdapter::SetScanMode(ScanMode scan_mode) {
@@ -76,16 +73,18 @@ bool BluetoothAdapter::SetScanMode(ScanMode scan_mode) {
if (!SetStatus(Status::kEnabled)) {
return false;
}
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
if (sd_bus_set_property(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0",
BLUEZ_ADAPTER_INTERFACE, "Discoverable", &err, "b",
1) < 0) {
NEARBY_LOGS(ERROR) << __func__
<< ": Error setting adapter's discoverable status: "
<< err.message;
try {
Discoverable(true);
} catch (const sdbus::Error &e) {
NEARBY_LOGS(ERROR)
<< __func__ << ": Got error '" << e.getName() << "' with message '"
<< e.getMessage()
<< "' while trying to set Discoverable status for adapter "
<< getObjectPath();
return false;
}
return true;
}
case ScanMode::kNone:
@@ -96,65 +95,52 @@ bool BluetoothAdapter::SetScanMode(ScanMode scan_mode) {
}
std::string BluetoothAdapter::GetName() const {
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
char *cname = nullptr;
if (sd_bus_get_property_string(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0",
BLUEZ_ADAPTER_INTERFACE, "Alias", &err,
&cname) < 0) {
NEARBY_LOGS(ERROR) << __func__
<< ": Error getting adapter's name: " << err.message;
auto proxy = sdbus::createProxy(getProxy().getConnection(),
bluez::SERVICE_DEST, getObjectPath());
proxy->finishRegistration();
try {
return proxy->getProperty("Alias").onInterface(INTERFACE_NAME);
} catch (const sdbus::Error &e) {
NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName()
<< "' with message '" << e.getMessage()
<< "' while trying to get Alias for adapter "
<< getObjectPath();
return std::string();
}
std::string name(cname);
free(cname);
return name;
}
bool BluetoothAdapter::SetName(absl::string_view name, bool persist) {
if (persist) {
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
std::string pretty_hostname(name);
if (sd_bus_set_property(system_bus_, "org.freedesktop.hostname1",
"/org/freedesktop/hostname1",
"org.freedesktop.hostname1", "PrettyHostname", &err,
"s", pretty_hostname.c_str()) < 0) {
NEARBY_LOGS(ERROR) << __func__
<< ": Error setting PrettyHostname: " << err.message;
}
}
return SetName(name);
}
bool BluetoothAdapter::SetName(absl::string_view name) {
std::string alias(name);
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
if (sd_bus_set_property(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0",
BLUEZ_ADAPTER_INTERFACE, "Alias", &err, "s",
alias.c_str()) < 0) {
NEARBY_LOGS(ERROR) << __func__
<< ": Error setting adapter's name: " << err.message;
try {
Alias(std::string(name));
return true;
} catch (const sdbus::Error &e) {
NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName()
<< "' with message '" << e.getMessage()
<< "' while trying to set Alias for adapter "
<< getObjectPath();
return false;
}
return true;
}
std::string BluetoothAdapter::GetMacAddress() const {
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
char *caddr = nullptr;
if (sd_bus_get_property_string(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0",
BLUEZ_ADAPTER_INTERFACE, "Address", &err,
&caddr) < 0) {
NEARBY_LOGS(ERROR) << __func__
<< ": Error getting adapter's name: " << err.message;
auto proxy = sdbus::createProxy(getProxy().getConnection(),
bluez::SERVICE_DEST, getObjectPath());
proxy->finishRegistration();
try {
return proxy->getProperty("Address").onInterface(INTERFACE_NAME);
} catch (const sdbus::Error &e) {
NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName()
<< "' with message '" << e.getMessage()
<< "' while trying to get Address for adapter "
<< getObjectPath();
return std::string();
}
std::string addr(caddr);
free(caddr);
return addr;
}
} // namespace linux
@@ -1,18 +1,26 @@
#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_ADAPTER_H_
#define PLATFORM_IMPL_LINUX_BLUETOOTH_ADAPTER_H_
#include <string>
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/ProxyInterfaces.h>
#include "absl/strings/string_view.h"
#include "internal/platform/implementation/bluetooth_adapter.h"
#include <systemd/sd-bus.h>
#include "internal/platform/implementation/linux/bluez.h"
#include "internal/platform/implementation/linux/bluez_adapter_client_glue.h"
namespace nearby {
namespace linux {
class BluetoothAdapter : public api::BluetoothAdapter {
class BluetoothAdapter
: public api::BluetoothAdapter,
public sdbus::ProxyInterfaces<org::bluez::Adapter1_proxy> {
public:
BluetoothAdapter(sd_bus *bus) { system_bus_ = bus; }
~BluetoothAdapter() override { sd_bus_unref(system_bus_); };
BluetoothAdapter(sdbus::IConnection &system_bus,
const sdbus::ObjectPath &adapter_object_path)
: ProxyInterfaces(system_bus, bluez::SERVICE_DEST, adapter_object_path) {
registerProxy();
}
~BluetoothAdapter() override { unregisterProxy(); }
bool SetStatus(Status status) override;
bool IsEnabled() const override;
@@ -25,9 +33,6 @@ public:
bool SetName(absl::string_view name) override;
bool SetName(absl::string_view name, bool persist) override;
std::string GetMacAddress() const override;
private:
sd_bus *system_bus_;
};
} // namespace linux
} // namespace nearby
@@ -1,80 +1,26 @@
#include <fcntl.h>
#include <functional>
#include <map>
#include <memory>
#include <optional>
#include <sdbus-c++/Error.h>
#include <string>
#include <tuple>
#include <systemd/sd-bus-protocol.h>
#include <systemd/sd-bus-vtable.h>
#include <systemd/sd-bus.h>
#include <sdbus-c++/AdaptorInterfaces.h>
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/IObject.h>
#include <sdbus-c++/IProxy.h>
#include <sdbus-c++/Types.h>
#include "absl/strings/substitute.h"
#include "absl/synchronization/mutex.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_devices.h"
#include "internal/platform/implementation/linux/bluez.h"
#include "internal/platform/logging.h"
const char *BLUEZ_PROFILEMANAGER_INTERFACE = "org.bluez.ProfileManager1";
namespace nearby {
namespace linux {
static int profile_release(sd_bus_message *m, void *userdata,
sd_bus_error *error) {
return 0;
}
static int profile_new_connection(sd_bus_message *m, void *userdata,
sd_bus_error *error) {
char *c_device_object = nullptr;
int fd = 0, ret;
ret = sd_bus_message_read(m, "oh", &c_device_object, &fd);
if (ret < 0) {
return ret;
}
std::string device_object(c_device_object);
fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
if (fd < 0) {
return sd_bus_error_set_errno(error, errno);
}
sd_bus *bus;
sd_bus_default_system(&bus);
BluetoothDevice device(bus, device_object);
auto mac_addr = device.GetMacAddress();
if (mac_addr.empty()) {
return -1;
}
struct RegisteredService *service =
static_cast<struct RegisteredService *>(userdata);
service->connections_lock.Lock();
service->connections[mac_addr] = fd;
service->connections_lock.Unlock();
return 0;
}
static int profile_request_disconnection(sd_bus_message *m, void *userdata,
sd_bus_error *error) {
// TODO
return 0;
}
static const sd_bus_vtable vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_METHOD_WITH_ARGS("Release", SD_BUS_NO_ARGS, SD_BUS_NO_RESULT,
profile_release, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_ARGS(
"NewConnection", SD_BUS_ARGS("o", path, "h", fd, "a{sq}", properties),
SD_BUS_NO_RESULT, profile_new_connection, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_ARGS("RequestDisconnection", SD_BUS_ARGS("o", object),
SD_BUS_NO_RESULT, profile_request_disconnection,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END};
bool ProfileManager::ProfileRegistered(absl::string_view service_uuid) {
registered_service_uuids_lock_.ReaderLock();
@@ -83,99 +29,209 @@ bool ProfileManager::ProfileRegistered(absl::string_view service_uuid) {
return registered;
}
bool ProfileManager::RegisterProfile(absl::string_view name,
absl::string_view service_uuid) {
void Profile::Release() {
released_ = true;
NEARBY_LOGS(VERBOSE) << __func__ << "Profile object " << getObjectPath()
<< " has been released";
}
void Profile::NewConnection(
const sdbus::ObjectPath &device_object_path, const sdbus::UnixFd &fd,
const std::map<std::string, sdbus::Variant> &fd_props) {
if (released_) {
NEARBY_LOGS(ERROR) << __func__ << "NewConnection called on released object "
<< getObjectPath();
throw sdbus::Error("org.bluez.Error.Rejected",
"NewConnection called on released object");
}
auto device = devices_.get_device_by_path(device_object_path);
if (!device.has_value()) {
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");
}
auto alias = device->get().Alias();
auto mac_addr = device->get().Address();
NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath()
<< ": Connected to " << device->get().getObjectPath();
FDProperties props(fd_props);
absl::MutexLock l(&connections_lock_);
if (connections_.count(mac_addr) != 0) {
connections_[mac_addr].push_back(std::pair(fd, std::move(props)));
} else {
connections_[mac_addr] = std::vector{std::pair(fd, std::move(props))};
}
}
void Profile::RequestDisconnection(
const sdbus::ObjectPath &device_object_path) {
auto device = devices_.get_device_by_path(device_object_path);
if (!device.has_value()) {
NEARBY_LOGS(ERROR) << __func__ << ": " << getObjectPath()
<< ": RequestDisconnection called with a device object "
"we don't know about: "
<< device_object_path;
throw sdbus::Error("org.bluez.Error.Rejected", "Unknown object");
}
auto mac_addr = device->get().Address();
NEARBY_LOGS(VERBOSE) << __func__ << ": Disconnection requested for device "
<< device_object_path;
absl::MutexLock l(&connections_lock_);
if (connections_.count(mac_addr) == 0) {
NEARBY_LOGS(ERROR)
<< __func__
<< "Disconnection requested, but we are not connected to this device";
return;
}
connections_.erase(mac_addr);
}
bool ProfileManager::Register(std::optional<absl::string_view> name,
absl::string_view service_uuid) {
if (ProfileRegistered(service_uuid)) {
NEARBY_LOGS(WARNING) << __func__ << ": Trying to register profile "
<< service_uuid << " which was already registered.";
return true;
}
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
std::string uuid(service_uuid);
auto profile_object_path =
absl::Substitute("/com/github/google/nearby/profiles/$0", uuid);
struct RegisteredService *service = new struct RegisteredService(uuid);
service->slot = nullptr;
registered_service_uuids_lock_.Lock();
auto ret = sd_bus_add_object_vtable(system_bus_, &service->slot,
profile_object_path.c_str(),
"org.bluez.Profile1", vtable, service);
if (ret < 0) {
sd_bus_error_set_errno(&err, ret);
NEARBY_LOGS(ERROR) << __func__ << "Error adding object "
<< profile_object_path << ": " << err.message;
registered_service_uuids_lock_.Unlock();
auto profile_object_path = bluez::profile_object_path(service_uuid);
try {
std::map<std::string, sdbus::Variant> options;
if (name.has_value()) {
options["Name"] = std::string(*name);
}
RegisterProfile(profile_object_path, std::string(service_uuid), options);
} catch (const sdbus::Error &e) {
BLUEZ_LOG_METHOD_CALL_ERROR(&getProxy(), "RegisterProfile", e);
return false;
}
NEARBY_LOGS(VERBOSE) << __func__
<< "Registered a ProfileManager for service UUID "
<< uuid << " at " << profile_object_path;
if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, "/org/bluez",
BLUEZ_PROFILEMANAGER_INTERFACE, "RegisterProfile",
&err, nullptr, "osa{sq}", "/com/github/google/nearby",
uuid.c_str(), 1, "Name",
std::string(name).c_str()) < 0) {
NEARBY_LOGS(ERROR) << __func__
<< "Error calling RegisterProfile: " << err.name << ": "
<< err.message;
registered_service_uuids_lock_.Unlock();
return false;
{
absl::MutexLock l(&registered_service_uuids_lock_);
registered_services_.emplace(
std::string(service_uuid),
std::make_shared<Profile>(getProxy().getConnection(),
profile_object_path, devices_));
}
registered_services_[uuid] = service;
registered_service_uuids_lock_.Unlock();
NEARBY_LOGS(INFO) << __func__
<< ": Registered profile instancefor service uuid "
<< service_uuid;
return true;
}
std::optional<int>
ProfileManager::GetServiceRecordFD(api::BluetoothDevice &remote_device,
absl::string_view service_uuid) {
void ProfileManager::Unregister(absl::string_view service_uuid) {
if (!ProfileRegistered(service_uuid)) {
NEARBY_LOGS(WARNING)
<< __func__
<< ": attempted to unregister a profile that is not registered";
return;
}
auto profile_object_path = bluez::profile_object_path(service_uuid);
NEARBY_LOGS(VERBOSE) << __func__ << ": Unregistering profile "
<< profile_object_path;
try {
UnregisterProfile(profile_object_path);
} catch (const sdbus::Error &e) {
BLUEZ_LOG_METHOD_CALL_ERROR(&getProxy(), "UnregisterProfile", e);
}
{
absl::MutexLock l(&registered_service_uuids_lock_);
registered_services_.erase(std::string(service_uuid));
}
}
// Get a service record FD for a connected profile (identified by service_uuid)
// to the given device.
std::optional<sdbus::UnixFd>
ProfileManager::GetServiceRecordFD(api::BluetoothDevice &remote_device,
absl::string_view service_uuid,
CancellationFlag *cancellation_flag) {
if (!ProfileRegistered(service_uuid)) {
NEARBY_LOGS(ERROR) << __func__ << ": Service " << service_uuid
<< " is not registered";
return std::nullopt;
}
auto mac_addr = remote_device.GetMacAddress();
registered_service_uuids_lock_.ReaderLock();
auto service = registered_services_[std::string(service_uuid)];
auto profile = registered_services_[std::string(service_uuid)];
registered_service_uuids_lock_.ReaderUnlock();
service->connections_lock.Lock();
auto cond = [mac_addr, service]() {
return service->connections.count(mac_addr) == 1;
NEARBY_LOGS(VERBOSE) << __func__ << ": " << profile->getObjectPath()
<< ": Attempting to get a FD for service "
<< service_uuid << " on device " << mac_addr;
auto cond = [mac_addr, profile, cancellation_flag]() {
return profile->connections_.count(mac_addr) != 0 ||
(cancellation_flag != nullptr && cancellation_flag->Cancelled());
};
service->connections_lock.Await(absl::Condition(&cond));
int fd = service->connections[mac_addr];
service->connections.erase(mac_addr);
service->connections_lock.Unlock();
profile->connections_lock_.Lock();
profile->connections_lock_.Await(absl::Condition(&cond));
if (cancellation_flag != nullptr && cancellation_flag->Cancelled()) {
NEARBY_LOGS(WARNING)
<< __func__ << ": " << profile->getObjectPath() << ": "
<< remote_device.GetMacAddress()
<< ": Cancelled waiting for a service record for profile "
<< service_uuid;
profile->connections_lock_.Unlock();
return std::nullopt;
}
auto [fd, properties] = profile->connections_[mac_addr].back();
profile->connections_[mac_addr].pop_back();
if (profile->connections_[mac_addr].empty())
profile->connections_.erase(mac_addr);
profile->connections_lock_.Unlock();
return fd;
}
std::optional<std::pair<std::string, int>>
// Listen for a connected profile on any device, returning the connected device
// with its FD.
std::optional<std::pair<std::reference_wrapper<BluetoothDevice>, sdbus::UnixFd>>
ProfileManager::GetServiceRecordFD(absl::string_view service_uuid) {
if (!ProfileRegistered(service_uuid)) {
return std::nullopt;
}
registered_service_uuids_lock_.ReaderLock();
auto service = registered_services_[std::string(service_uuid)];
auto profile = registered_services_[std::string(service_uuid)];
registered_service_uuids_lock_.ReaderUnlock();
service->connections_lock.Lock();
auto cond = [service]() { return !service->connections.empty(); };
service->connections_lock.Await(absl::Condition(&cond));
auto it = service->connections.begin();
auto mac_addr = it->first;
auto fd = it->second;
service->connections.erase(it);
service->connections_lock.Unlock();
return std::pair<std::string, int>(mac_addr, fd);
NEARBY_LOGS(VERBOSE) << __func__ << ": " << profile->getObjectPath()
<< ": Attempting to get a FD for service "
<< profile->getObjectPath();
profile->connections_lock_.Lock();
auto cond = [profile]() { return !profile->connections_.empty(); };
profile->connections_lock_.Await(absl::Condition(&cond));
auto it = profile->connections_.begin();
auto mac_addr = it->first;
auto [fd, properties] = it->second.back();
it->second.pop_back();
if (it->second.empty())
profile->connections_.erase(it);
profile->connections_lock_.Unlock();
return std::pair(devices_.get_device_by_address(mac_addr).value(), fd);
}
} // namespace linux
@@ -2,56 +2,102 @@
#define PLATFORM_IMPL_LINUX_BLUETOOTH_BLUEZ_PROFILE_H_
#include <atomic>
#include <cstdint>
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <tuple>
#include <utility>
#include <systemd/sd-bus.h>
#include <sdbus-c++/AdaptorInterfaces.h>
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/IObject.h>
#include <sdbus-c++/IProxy.h>
#include <sdbus-c++/ProxyInterfaces.h>
#include <sdbus-c++/StandardInterfaces.h>
#include <sdbus-c++/Types.h>
#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/bluez_profile_glue.h"
#include "internal/platform/implementation/linux/bluez_profile_manager_client_glue.h"
namespace nearby {
namespace linux {
struct RegisteredService {
class Profile : public sdbus::AdaptorInterfaces<org::bluez::Profile1_adaptor> {
public:
sd_bus_slot *slot;
absl::Mutex connections_lock;
// Maps mac addresses to unclaimed FDs. Probably an awful way to do this, but
// whatever.
std::map<std::string, int> connections;
std::string &uuid;
RegisteredService(std::string &uuid) : uuid(uuid) {}
Profile(sdbus::IConnection &system_bus, absl::string_view profile_object_path,
BluetoothDevices &devices)
: AdaptorInterfaces(system_bus, std::string(profile_object_path)),
released_(false), devices_(devices) {
registerAdaptor();
}
~Profile() { unregisterAdaptor(); }
struct FDProperties {
FDProperties(const std::map<std::string, sdbus::Variant> &fd_props) {
if (fd_props.count("Version") == 1) {
version = fd_props.at("Version");
}
if (fd_props.count("Features") == 1) {
features = fd_props.at("Features");
}
}
std::optional<uint16_t> version;
std::optional<uint16_t> features;
};
void Release() override;
void NewConnection(const sdbus::ObjectPath &, const sdbus::UnixFd &,
const std::map<std::string, sdbus::Variant> &) override;
void RequestDisconnection(const sdbus::ObjectPath &) override;
std::atomic_bool released_;
absl::Mutex connections_lock_;
std::map<std::string, std::vector<std::pair<sdbus::UnixFd, FDProperties>>>
connections_;
BluetoothDevices &devices_;
};
class ProfileManager {
class ProfileManager
: private sdbus::ProxyInterfaces<org::bluez::ProfileManager1_proxy> {
public:
ProfileManager(sd_bus *system_bus) { system_bus_ = system_bus; }
~ProfileManager() { sd_bus_unref(system_bus_); }
ProfileManager(sdbus::IConnection &system_bus, BluetoothDevices &devices)
: ProxyInterfaces(system_bus, bluez::SERVICE_DEST, "/org/bluez"),
devices_(devices) {
registerProxy();
}
~ProfileManager() { unregisterProxy(); }
bool ProfileRegistered(absl::string_view service_uuid);
bool RegisterProfile(absl::string_view service_name,
absl::string_view service_uuid);
bool RegisterProfile(absl::string_view service_uuid) {
return RegisterProfile("", service_uuid);
bool Register(std::optional<absl::string_view> service_name,
absl::string_view service_uuid);
bool Register(absl::string_view service_uuid) {
return Register(std::nullopt, service_uuid);
}
void Unregister(absl::string_view service_uuid);
std::optional<int> GetServiceRecordFD(api::BluetoothDevice &remote_device,
absl::string_view service_uuid);
std::optional<std::pair<std::string, int>>
std::optional<sdbus::UnixFd>
GetServiceRecordFD(api::BluetoothDevice &remote_device,
absl::string_view service_uuid,
CancellationFlag *cancellation_flag);
std::optional<
std::pair<std::reference_wrapper<BluetoothDevice>, sdbus::UnixFd>>
GetServiceRecordFD(absl::string_view service_uuid);
private:
BluetoothDevices &devices_;
// Maps service UUIDs to RegisteredService
std::map<std::string, struct RegisteredService *> registered_services_;
std::map<std::string, std::shared_ptr<Profile>> registered_services_;
absl::Mutex registered_service_uuids_lock_;
sd_bus *system_bus_;
};
} // namespace linux
@@ -1,73 +1,124 @@
#include <sdbus-c++/IObject.h>
#include <sdbus-c++/ProxyInterfaces.h>
#include <systemd/sd-bus.h>
#include "absl/strings/str_replace.h"
#include "absl/strings/string_view.h"
#include "absl/strings/substitute.h"
#include "internal/platform/implementation/linux/bluetooth_classic_device.h"
#include "internal/platform/implementation/linux/bluez.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace linux {
BluetoothDevice::BluetoothDevice(sd_bus *system_bus, absl::string_view adapter,
absl::string_view address) {
mac_addr_ = std::string(address);
object_path_ = absl::Substitute("/org/bluez/$0/dev_$1", adapter,
absl::StrReplaceAll(address, {{":", "_"}}));
system_bus_ = system_bus;
}
BluetoothDevice::BluetoothDevice(sd_bus *system_bus,
absl::string_view device_object_path) {
system_bus_ = system_bus;
object_path_ = device_object_path;
}
BluetoothDevice::BluetoothDevice(const BluetoothDevice &device) {
if (!device.mac_addr_.empty()) {
mac_addr_ = device.mac_addr_;
}
object_path_ = device.object_path_;
system_bus_ = sd_bus_ref(device.system_bus_);
BluetoothDevice::BluetoothDevice(sdbus::IConnection &system_bus,
const sdbus::ObjectPath &device_object_path)
: ProxyInterfaces(system_bus, bluez::SERVICE_DEST,
std::string(device_object_path)) {
registerProxy();
}
std::string BluetoothDevice::GetName() const {
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
char *cname = nullptr;
if (sd_bus_get_property_string(system_bus_, BLUEZ_SERVICE,
object_path_.c_str(), BLUEZ_DEVICE_INTERFACE,
"Alias", &err, &cname) < 0) {
NEARBY_LOGS(ERROR) << __func__ << "Error getting alias for device "
<< object_path_ << " :" << err.message;
auto bluez_device =
sdbus::createProxy(getProxy().getConnection(), bluez::SERVICE_DEST,
getProxy().getObjectPath());
try {
std::string alias =
bluez_device->getProperty("Alias").onInterface(bluez::DEVICE_INTERFACE);
return alias;
} catch (const sdbus::Error &e) {
NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName()
<< "' with message '" << e.getMessage()
<< "' while trying to get Alias for device "
<< bluez_device->getObjectPath();
return std::string();
}
std::string name(cname);
free(cname);
return name;
}
std::string BluetoothDevice::GetMacAddress() const {
if (!mac_addr_.empty()) {
return mac_addr_;
}
auto bluez_device =
sdbus::createProxy(getProxy().getConnection(), bluez::SERVICE_DEST,
getProxy().getObjectPath());
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
char *c_addr = nullptr;
if (sd_bus_get_property_string(system_bus_, BLUEZ_SERVICE,
object_path_.c_str(), BLUEZ_DEVICE_INTERFACE,
"Address", &err, &c_addr) < 0) {
NEARBY_LOGS(ERROR) << __func__ << "Error getting address for device "
<< object_path_ << " :" << err.message;
try {
std::string addr = bluez_device->getProperty("Address").onInterface(
bluez::DEVICE_INTERFACE);
return addr;
} catch (const sdbus::Error &e) {
NEARBY_LOGS(ERROR) << __func__ << "Got error '" << e.getName()
<< "' with message '" << e.getMessage()
<< "' while trying to get Address for device "
<< bluez_device->getObjectPath();
return std::string();
}
}
std::string addr(c_addr);
free(c_addr);
return addr;
void BluetoothDevice::onConnectProfileReply(const sdbus::Error *error) {
if (error != nullptr && error->getName() != "org.bluez.Error.InProgress") {
NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << error->getName()
<< "' with message '" << error->getMessage()
<< " while connecting to profile.";
}
}
bool BluetoothDevice::ConnectToProfile(absl::string_view service_uuid) {
try {
ConnectProfile(std::string(service_uuid));
return true;
} catch (const sdbus::Error &e) {
NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName()
<< "' with message '" << e.getMessage()
<< "' while trying to asynchronously connect to profile "
<< service_uuid << " on device " << getObjectPath();
return false;
}
}
MonitoredBluetoothDevice::MonitoredBluetoothDevice(
sdbus::IConnection &system_bus, const sdbus::ObjectPath &device_object_path,
ObserverList<api::BluetoothClassicMedium::Observer> &observers)
: BluetoothDevice(system_bus, device_object_path),
ProxyInterfaces<sdbus::Properties_proxy>(system_bus, bluez::SERVICE_DEST,
std::string(device_object_path)),
observers_(observers) {
registerProxy();
}
void MonitoredBluetoothDevice::onPropertiesChanged(
const std::string &interfaceName,
const std::map<std::string, sdbus::Variant> &changedProperties,
const std::vector<std::string> &invalidatedProperties) {
if (interfaceName != bluez::DEVICE_INTERFACE) {
return;
}
NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath()
<< ": Received PropertiesChanged signal for interface "
<< interfaceName;
for (auto it = changedProperties.begin(); it != changedProperties.end();
it++) {
if (it->first == bluez::DEVICE_PROP_ADDRESS) {
NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath()
<< ": Notifying observers about address change";
std::string address = it->second;
for (auto &observer : observers_.GetObservers()) {
observer->DeviceAddressChanged(*this, address);
}
} else if (it->first == bluez::DEVICE_PROP_PAIRED) {
NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath()
<< "Notifying observers about paired status change.";
for (auto &observer : observers_.GetObservers()) {
observer->DevicePairedChanged(*this, it->second);
}
} else if (it->first == bluez::DEVICE_PROP_CONNECTED) {
NEARBY_LOGS(VERBOSE)
<< __func__ << ": " << getObjectPath()
<< "Notifying observers about connected status change";
for (auto &observer : observers_.GetObservers()) {
observer->DeviceConnectedStateChanged(*this, it->second);
}
}
}
}
} // namespace linux
@@ -1,23 +1,27 @@
#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_DEVICE_H_
#define PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_DEVICE_H_
#include <systemd/sd-bus.h>
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/IProxy.h>
#include <sdbus-c++/ProxyInterfaces.h>
#include <sdbus-c++/StandardInterfaces.h>
#include <sdbus-c++/Types.h>
#include "absl/functional/any_invocable.h"
#include "absl/strings/string_view.h"
#include "internal/base/observer_list.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/linux/bluez_device_client_glue.h"
namespace nearby {
namespace linux {
const char *BLUEZ_DEVICE_INTERFACE = "org.bluez.Device1";
// https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html.
class BluetoothDevice : public api::BluetoothDevice {
class BluetoothDevice
: public api::BluetoothDevice,
public sdbus::ProxyInterfaces<org::bluez::Device1_proxy> {
public:
BluetoothDevice(sd_bus *system_bus, absl::string_view adapter,
absl::string_view address);
BluetoothDevice(sd_bus *system_bus, absl::string_view device_object_path);
BluetoothDevice(const BluetoothDevice &device);
~BluetoothDevice() override { sd_bus_unref(system_bus_); };
BluetoothDevice(sdbus::IConnection &system_bus, const sdbus::ObjectPath &);
~BluetoothDevice() = default;
// https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getName()
std::string GetName() const override;
@@ -25,11 +29,55 @@ public:
// Returns BT MAC address assigned to this device.
std::string GetMacAddress() const override;
bool ConnectToProfile(absl::string_view service_uuid);
void
set_pair_reply_callback(absl::AnyInvocable<void(const sdbus::Error *)> cb) {
absl::MutexLock l(&pair_callback_lock_);
on_pair_reply_cb_ = std::move(cb);
}
void reset_pair_reply_callback() {
absl::MutexLock l(&pair_callback_lock_);
on_pair_reply_cb_ = DefaultCallback<const sdbus::Error *>();
}
protected:
void onConnectProfileReply(const sdbus::Error *error) override;
void onPairReply(const sdbus::Error *error) override {
absl::ReaderMutexLock l(&pair_callback_lock_);
on_pair_reply_cb_(error);
};
private:
sd_bus *system_bus_;
std::string object_path_;
std::string mac_addr_;
absl::Mutex pair_callback_lock_;
absl::AnyInvocable<void(const sdbus::Error *)> on_pair_reply_cb_ =
DefaultCallback<const sdbus::Error *>();
};
class MonitoredBluetoothDevice
: public BluetoothDevice,
public sdbus::ProxyInterfaces<sdbus::Properties_proxy> {
public:
using sdbus::ProxyInterfaces<sdbus::Properties_proxy>::registerProxy;
using sdbus::ProxyInterfaces<sdbus::Properties_proxy>::unregisterProxy;
using sdbus::ProxyInterfaces<sdbus::Properties_proxy>::getObjectPath;
MonitoredBluetoothDevice(
sdbus::IConnection &system_bus, const sdbus::ObjectPath &,
ObserverList<api::BluetoothClassicMedium::Observer> &observers);
~MonitoredBluetoothDevice() { unregisterProxy(); }
protected:
void onPropertiesChanged(
const std::string &interfaceName,
const std::map<std::string, sdbus::Variant> &changedProperties,
const std::vector<std::string> &invalidatedProperties) override;
private:
ObserverList<api::BluetoothClassicMedium::Observer> &observers_;
};
} // namespace linux
} // namespace nearby
@@ -1,9 +1,9 @@
#include <cstring>
#include <memory>
#include <systemd/sd-bus.h>
#include <sdbus-c++/IProxy.h>
#include <sdbus-c++/Types.h>
#include "absl/strings/str_replace.h"
#include "absl/strings/string_view.h"
#include "absl/strings/substitute.h"
#include "internal/platform/implementation/bluetooth_classic.h"
@@ -18,120 +18,127 @@
namespace nearby {
namespace linux {
int bluez_interfaces_added_signal_handler(sd_bus_message *m, void *userdata,
sd_bus_error *ret_error) {
const sd_bus_error *reply_err = sd_bus_message_get_error(m);
if (reply_err) {
NEARBY_LOGS(ERROR) << __func__
<< "Received error while listening for InterfacesAdded: "
<< reply_err->message;
return 0;
}
struct BluetoothClassicMedium::DiscoveryParams *params =
static_cast<BluetoothClassicMedium::DiscoveryParams *>(userdata);
char *c_object_path = nullptr;
int ret = sd_bus_message_read(m, "o", &c_object_path);
if (ret < 0) {
NEARBY_LOGS(ERROR) << __func__
<< "Error reading object path from message: " << ret;
return ret;
}
std::string object_path(c_object_path);
if (!absl::StrContains(object_path, absl::StrCat(params->adapter_object_path,
"/", "dev_"))) {
// Interface added for an object we dont care about.
return 0;
}
if (params->devices_by_path.count(object_path) != 0) {
// Object already exists
return 0;
}
ret = sd_bus_message_enter_container(m, 'a', "{sa{sv}}");
if (ret < 0) {
NEARBY_LOGS(ERROR) << __func__ << "Error entering container: " << ret;
return ret;
}
while (true) {
const char *interface_name = nullptr;
ret = sd_bus_message_read(m, "s", &interface_name);
if (ret < 0) {
NEARBY_LOGS(ERROR) << __func__ << "Error reading dict entry: " << ret;
return ret;
}
if (ret == 0)
break;
if (strcmp(interface_name, "org.bluez.Device1") == 0) {
NEARBY_LOGS(INFO) << __func__ << "Encountered new device at "
<< object_path;
sd_bus *system_bus = nullptr;
sd_bus_default_system(&system_bus);
auto bluetoothDevice = std::make_unique<BluetoothDevice>(
BluetoothDevice(system_bus, object_path));
params->devices_by_path[object_path] = std::move(bluetoothDevice);
if (params->cb.device_discovered_cb != nullptr) {
params->cb.device_discovered_cb(*params->devices_by_path[object_path]);
}
for (auto &observer : params->observers_.GetObservers()) {
observer->DeviceAdded(*params->devices_by_path[object_path]);
}
return 0;
}
ret = sd_bus_message_skip(m, "a{sv}");
if (ret < 0) {
NEARBY_LOGS(ERROR) << __func__ << "Error skipping dict entry: " << ret;
return -1;
}
}
return 0;
}
BluetoothClassicMedium::BluetoothClassicMedium(sd_bus *system_bus,
BluetoothClassicMedium::BluetoothClassicMedium(sdbus::IConnection &system_bus,
absl::string_view adapter)
: profile_manager_(sd_bus_ref(system_bus)) {
system_bus_ = system_bus;
adapter_object_path_ = absl::Substitute("/org/bluez/$0/", adapter);
: devices_(system_bus, absl::Substitute("/org/bluez/$0/", adapter),
observers_),
profile_manager_(system_bus) {
bluez_adapter_proxy_ = sdbus::createProxy(
"org.bluez", absl::Substitute("/org/bluez/$0/", adapter));
bluez_adapter_proxy_->finishRegistration();
bluez_proxy_ = sdbus::createProxy("org.bluez", "/");
bluez_proxy_->finishRegistration();
}
BluetoothClassicMedium::~BluetoothClassicMedium() {
sd_bus_unref(system_bus_);
if (system_bus_slot_)
sd_bus_slot_unref(system_bus_slot_);
void BluetoothClassicMedium::onInterfacesAdded(sdbus::Signal &signal) {
sdbus::ObjectPath object;
signal >> object;
NEARBY_LOGS(VERBOSE) << __func__ << "New intefaces added at " << object;
auto path_prefix =
absl::Substitute("$0/dev_", bluez_adapter_proxy_->getObjectPath());
if (object.find(path_prefix) != 0) {
return;
}
if (devices_.get_device_by_path(object).has_value()) {
// Device already exists.
return;
}
std::map<std::string, std::map<std::string, sdbus::Variant>> interfaces;
signal >> interfaces;
for (auto it = interfaces.begin(); it != interfaces.end(); it++) {
auto interface = it->first;
if (interface == "org.bluez.Device1") {
NEARBY_LOGS(INFO) << __func__ << "Encountered new device at " << object;
auto &device = devices_.add_new_device(object);
discovery_cb_lock_.ReaderLock();
if (discovery_cb_.has_value() &&
discovery_cb_->device_discovered_cb != nullptr) {
discovery_cb_->device_discovered_cb(device);
}
discovery_cb_lock_.ReaderUnlock();
for (auto &observer : observers_.GetObservers()) {
observer->DeviceAdded(device);
}
}
}
}
void BluetoothClassicMedium::onInterfacesRemoved(sdbus::Signal &signal) {
sdbus::ObjectPath object;
signal >> object;
NEARBY_LOGS(VERBOSE) << __func__ << ": Intefaces removed at " << object;
auto path_prefix =
absl::Substitute("$0/dev_", bluez_adapter_proxy_->getObjectPath());
if (object.find(path_prefix) != 0) {
return;
}
std::vector<std::string> interfaces;
signal >> interfaces;
for (auto &interface : interfaces) {
if (interface == bluez::DEVICE_INTERFACE) {
{
auto device = get_device_by_path(object);
if (!device.has_value()) {
NEARBY_LOGS(WARNING) << __func__
<< ": received InterfacesRemoved for a device "
"we don't know about: "
<< object;
return;
}
NEARBY_LOGS(INFO) << __func__ << ": " << object << " has been removed";
for (auto &observer : observers_.GetObservers()) {
observer->DeviceRemoved(*device);
}
discovery_cb_lock_.ReaderLock();
if (discovery_cb_.has_value() &&
discovery_cb_->device_lost_cb != nullptr) {
discovery_cb_->device_lost_cb(*device);
}
discovery_cb_lock_.ReaderUnlock();
}
remove_device_by_path(object);
}
}
}
bool BluetoothClassicMedium::StartDiscovery(
DiscoveryCallback discovery_callback) {
if (!system_bus_)
return false;
discovery_cb_lock_.Lock();
discovery_cb_ = std::move(discovery_callback);
discovery_cb_lock_.Unlock();
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
__attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *reply =
nullptr;
NEARBY_LOGS(VERBOSE) << __func__
<< ": Subscribing to InterfacesAdded on / at org.bluez";
discovery_params_.cb = std::move(discovery_callback);
discovery_params_.adapter_object_path = adapter_object_path_;
bluez_proxy_->registerSignalHandler(
"org.freedesktop.DBus.ObjectManager", "InterfacesAdded",
[this](sdbus::Signal &signal) { this->onInterfacesAdded(signal); });
bluez_proxy_->registerSignalHandler(
"org.freedesktop.DBus.ObjectManager", "InterfacesRemoved",
[this](sdbus::Signal &signal) { this->onInterfacesRemoved(signal); });
sd_bus_match_signal(system_bus_, &system_bus_slot_, BLUEZ_SERVICE, "/",
"org.freedesktop.DBus.ObjectManager", "InterfacesAdded",
bluez_interfaces_added_signal_handler,
&discovery_params_);
if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE,
adapter_object_path_.c_str(), BLUEZ_ADAPTER_INTERFACE,
"StartDiscovery", &err, &reply, nullptr) < 0) {
NEARBY_LOGS(ERROR) << __func__ << "Error calling StartDiscovery on adapter "
<< adapter_object_path_ << ": " << err.message;
try {
NEARBY_LOGS(INFO) << __func__ << ": Starting discovery on "
<< bluez_adapter_proxy_->getObjectPath();
bluez_adapter_proxy_->callMethod("StartDiscovery")
.onInterface(bluez::ADAPTER_INTERFACE);
} catch (const sdbus::Error &e) {
BLUEZ_LOG_METHOD_CALL_ERROR(bluez_adapter_proxy_, "StartDiscovery", e);
return false;
}
@@ -139,20 +146,24 @@ bool BluetoothClassicMedium::StartDiscovery(
}
bool BluetoothClassicMedium::StopDiscovery() {
if (!system_bus_)
return false;
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
__attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *reply =
nullptr;
int ret = sd_bus_call_method(
system_bus_, BLUEZ_SERVICE, adapter_object_path_.c_str(),
BLUEZ_ADAPTER_INTERFACE, "StopDiscovery", &err, &reply, nullptr);
if (ret < 0) {
NEARBY_LOGS(ERROR) << __func__ << "Error calling StopDiscovery on "
<< adapter_object_path_ << ": " << err.message;
NEARBY_LOGS(VERBOSE)
<< __func__ << ": Unsubscribing to InterfacesAdded on / at org.bluez";
bluez_proxy_->unregisterSignalHandler("org.freedesktop.DBus.ObjectManager",
"InterfacesAdded");
bluez_proxy_->unregisterSignalHandler("org.freedesktop.DBus.ObjectManager",
"InterfacesRemoved");
try {
NEARBY_LOGS(INFO) << __func__ << "Stopping discovery on "
<< bluez_adapter_proxy_->getObjectPath();
bluez_adapter_proxy_->callMethodAsync("StopDiscovery")
.onInterface(bluez::ADAPTER_INTERFACE)
.uponReplyInvoke([this](const sdbus::Error *err) {
this->discovery_cb_lock_.Lock();
this->discovery_cb_.reset();
this->discovery_cb_lock_.Unlock();
});
} catch (const sdbus::Error &e) {
BLUEZ_LOG_METHOD_CALL_ERROR(bluez_adapter_proxy_, "StopDiscovery", e);
return false;
}
@@ -163,24 +174,31 @@ std::unique_ptr<api::BluetoothSocket>
BluetoothClassicMedium::ConnectToService(api::BluetoothDevice &remote_device,
const std::string &service_uuid,
CancellationFlag *cancellation_flag) {
auto device_object_path = GetDeviceObjectPath(remote_device.GetMacAddress());
auto device_object_path = bluez::device_object_path(
bluez_adapter_proxy_->getObjectPath(), remote_device.GetMacAddress());
if (!profile_manager_.ProfileRegistered(service_uuid)) {
if (!profile_manager_.RegisterProfile(service_uuid)) {
NEARBY_LOGS(ERROR) << __func__ << "Could not register profile "
if (!profile_manager_.Register("", service_uuid)) {
NEARBY_LOGS(ERROR) << __func__ << ": Could not register profile "
<< service_uuid << " with Bluez";
return nullptr;
}
}
auto fd = profile_manager_.GetServiceRecordFD(remote_device, service_uuid);
auto &device = devices_.get_device_by_path(device_object_path).value().get();
device.ConnectToProfile(service_uuid);
auto fd = profile_manager_.GetServiceRecordFD(remote_device, service_uuid,
cancellation_flag);
if (!fd.has_value()) {
NEARBY_LOGS(ERROR) << __func__
<< "Failed to get a new connection for profile "
<< service_uuid << " for device " << device_object_path;
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<api::BluetoothSocket>(new BluetoothSocket(
remote_device, device_object_path, service_uuid, fd.value()));
return std::unique_ptr<api::BluetoothSocket>(
new BluetoothSocket(remote_device, fd.value()));
}
std::unique_ptr<api::BluetoothServerSocket>
@@ -188,49 +206,33 @@ BluetoothClassicMedium::ListenForService(const std::string &service_name,
const std::string &service_uuid) {
if (!profile_manager_.ProfileRegistered(service_uuid)) {
if (!profile_manager_.RegisterProfile(service_name, service_uuid)) {
NEARBY_LOGS(ERROR) << __func__ << "Could not register profile "
NEARBY_LOGS(ERROR) << __func__ << ": Could not register profile "
<< service_name << " " << service_uuid
<< " with Bluez";
return nullptr;
}
}
auto pair = profile_manager_.GetServiceRecordFD(service_uuid);
if (!pair.has_value()) {
NEARBY_LOGS(ERROR) << __func__
<< "Failed to get a new connection for profile "
<< service_uuid << " for device ";
return nullptr;
}
auto device_object_path = GetDeviceObjectPath(pair->first);
auto device = BluetoothDevice(sd_bus_ref(system_bus_), device_object_path);
return std::unique_ptr<api::BluetoothServerSocket>(
new BluetoothServerSocket(sd_bus_ref(system_bus_), profile_manager_,
adapter_object_path_, service_uuid));
new BluetoothServerSocket(profile_manager_, service_uuid));
}
api::BluetoothDevice *
BluetoothClassicMedium::GetRemoteDevice(const std::string &mac_address) {
if (devices_by_path_.count(mac_address) == 1) {
return devices_by_path_[mac_address].get();
}
auto device = get_device_by_address(mac_address);
if (device.has_value())
return nullptr;
return nullptr;
return &(device->get());
}
std::unique_ptr<api::BluetoothPairing>
BluetoothClassicMedium::CreatePairing(api::BluetoothDevice &remote_device) {
auto device_object_path = GetDeviceObjectPath(remote_device.GetMacAddress());
auto device_object_path = bluez::device_object_path(
bluez_adapter_proxy_->getObjectPath(), remote_device.GetMacAddress());
return std::unique_ptr<api::BluetoothPairing>(
new BluetoothPairing(sd_bus_ref(system_bus_), device_object_path));
}
std::string
BluetoothClassicMedium::GetDeviceObjectPath(absl::string_view mac_address) {
return absl::Substitute("$0/dev_$1", adapter_object_path_,
absl::StrReplaceAll(mac_address, {{":", "_"}}));
new BluetoothPairing(bluez_adapter_proxy_->getObjectPath(), remote_device,
bluez_adapter_proxy_->getConnection()));
}
} // namespace linux
@@ -1,15 +1,22 @@
#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_MEDIUM_H_
#define PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_MEDIUM_H_
#include <functional>
#include <map>
#include <memory>
#include <optional>
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/IProxy.h>
#include <sdbus-c++/Types.h>
#include <systemd/sd-bus.h>
#include "absl/synchronization/mutex.h"
#include "internal/base/observer_list.h"
#include "internal/platform/implementation/bluetooth_classic.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_devices.h"
namespace nearby {
namespace linux {
@@ -17,8 +24,9 @@ namespace linux {
// medium.
class BluetoothClassicMedium : public api::BluetoothClassicMedium {
public:
BluetoothClassicMedium(sd_bus *system_bus, absl::string_view adapter);
~BluetoothClassicMedium();
BluetoothClassicMedium(sdbus::IConnection &system_bus,
absl::string_view adapter);
~BluetoothClassicMedium() = default;
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startDiscovery()
//
@@ -80,27 +88,28 @@ public:
observers_.RemoveObserver(observer);
};
struct DiscoveryParams {
std::string &adapter_object_path;
std::map<std::string, std::unique_ptr<BluetoothDevice>> &devices_by_path;
ObserverList<Observer> &observers_;
BluetoothClassicMedium::DiscoveryCallback cb;
};
std::optional<std::reference_wrapper<BluetoothDevice>>
get_device_by_path(const sdbus::ObjectPath &);
std::optional<std::reference_wrapper<BluetoothDevice>>
get_device_by_address(const std::string &);
void remove_device_by_path(const sdbus::ObjectPath &);
private:
void onInterfacesAdded(sdbus::Signal &signal);
void onInterfacesRemoved(sdbus::Signal &signal);
BluetoothDevices devices_;
absl::Mutex discovery_cb_lock_;
std::optional<BluetoothClassicMedium::DiscoveryCallback> discovery_cb_;
ProfileManager profile_manager_;
std::string GetDeviceObjectPath(absl::string_view mac_address);
sd_bus *system_bus_ = nullptr;
sd_bus_slot *system_bus_slot_ = nullptr;
std::string adapter_object_path_ = std::string();
std::map<std::string, std::unique_ptr<BluetoothDevice>> devices_by_path_;
ObserverList<Observer> observers_;
DiscoveryParams discovery_params_ = {adapter_object_path_, devices_by_path_,
observers_};
std::unique_ptr<sdbus::IProxy> bluez_adapter_proxy_;
std::unique_ptr<sdbus::IProxy> bluez_proxy_;
};
} // namespace linux
} // namespace nearby
@@ -9,14 +9,9 @@ namespace nearby {
namespace linux {
class BluetoothServerSocket : public api::BluetoothServerSocket {
public:
BluetoothServerSocket(sd_bus *system_bus, ProfileManager &profile_manager,
absl::string_view adapter_object_path,
absl::string_view service_uuid)
: profile_manager_(profile_manager) {
system_bus_ = system_bus;
adapter_object_path_ = adapter_object_path;
service_uuid_ = service_uuid;
}
BluetoothServerSocket(ProfileManager &profile_manager,
const std::string &service_uuid)
: profile_manager_(profile_manager), service_uuid_(service_uuid) {}
~BluetoothServerSocket() = default;
// https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#accept()
@@ -36,10 +31,8 @@ public:
Exception Close() override;
private:
sd_bus *system_bus_;
ProfileManager &profile_manager_;
std::string adapter_object_path_;
std::string service_uuid_;
const std::string &service_uuid_;
};
} // namespace linux
} // namespace nearby
@@ -7,17 +7,18 @@
#include "internal/platform/byte_array.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/linux/bluetooth_classic_device.h"
#include "internal/platform/implementation/linux/bluetooth_classic_socket.h"
#include "internal/platform/implementation/linux/bluez.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace linux {
ExceptionOr<ByteArray> BluetoothInputStream::Read(std::int64_t size) {
if (!fd_.has_value())
return Exception::kIo;
char *data = new char[size];
ssize_t ret = read(fd_, data, size);
ssize_t ret = read(fd_->get(), data, size);
if (ret == 0) {
delete[] data;
return ExceptionOr(ByteArray());
@@ -30,17 +31,23 @@ ExceptionOr<ByteArray> BluetoothInputStream::Read(std::int64_t size) {
}
ExceptionOr<std::size_t> BluetoothInputStream::Skip(std::size_t offset) {
auto off = lseek(fd_, offset, SEEK_CUR);
if (!fd_.has_value())
return Exception::kIo;
auto off = lseek(fd_->get(), offset, SEEK_CUR);
if (off != offset) {
auto end = lseek(fd_, 0, SEEK_END);
auto end = lseek(fd_->get(), 0, SEEK_END);
return off == end ? ExceptionOr((std::size_t)off) : Exception::kIo;
}
return ExceptionOr((std::size_t)(off));
}
ExceptionOr<ByteArray> BluetoothInputStream::ReadExactly(std::size_t size) {
if (!fd_.has_value())
return Exception::kIo;
char *data = new char[size];
ssize_t ret = read(fd_, data, size);
ssize_t ret = read(fd_->get(), data, size);
if (ret < 0) {
delete[] data;
return Exception::kIo;
@@ -50,9 +57,12 @@ ExceptionOr<ByteArray> BluetoothInputStream::ReadExactly(std::size_t size) {
}
Exception BluetoothOutputStream::Write(const ByteArray &data) {
if (!fd_.has_value())
return Exception{Exception::kIo};
ssize_t written = 0;
while (written < data.size()) {
ssize_t ret = write(fd_, data.data(), data.size());
ssize_t ret = write(fd_->get(), data.data(), data.size());
if (ret < 1) {
return Exception{Exception::kIo};
}
@@ -66,32 +76,13 @@ Exception BluetoothOutputStream::Flush() {
}
Exception BluetoothOutputStream::Close() {
return close(fd_) < 0 ? Exception{Exception::kIo}
: Exception{Exception::kSuccess};
return close(fd_->get()) < 0 ? Exception{Exception::kIo}
: Exception{Exception::kSuccess};
}
Exception BluetoothSocket::Close() {
__attribute__((cleanup(sd_bus_unrefp))) sd_bus *system_bus = NULL;
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
if (auto ret = sd_bus_default_system(&system_bus); ret < 0) {
sd_bus_error_set_errno(&err, ret);
NEARBY_LOGS(ERROR) << __func__
<< "Error connecting to system bus: " << err.name << ": "
<< err.message;
return Exception{Exception::kFailed};
}
if (sd_bus_call_method(system_bus, BLUEZ_SERVICE, device_object_path_.c_str(),
BLUEZ_DEVICE_INTERFACE, "DisconnectProfile", &err,
nullptr, "s", connected_profile_uuid_.c_str()) < 0) {
NEARBY_LOGS(ERROR) << __func__ << "Error disconnecting from profile "
<< connected_profile_uuid_ << " on device "
<< device_object_path_ << ": " << err.name << ": "
<< err.message;
return Exception{Exception::kFailed};
}
input_stream_.fd_.reset();
output_stream_.fd_.reset();
return Exception{Exception::kSuccess};
}
@@ -2,7 +2,9 @@
#define PLATFORM_IMPL_LINUX_BLUETOOTH_SOCKET_H_
#include <memory>
#include <optional>
#include <sdbus-c++/Types.h>
#include <systemd/sd-bus.h>
#include "internal/platform/byte_array.h"
@@ -14,7 +16,7 @@ namespace linux {
class BluetoothInputStream : public InputStream {
public:
BluetoothInputStream(int fd) { fd_ = fd; };
BluetoothInputStream(sdbus::UnixFd &fd) : fd_(fd){};
ExceptionOr<ByteArray> Read(std::int64_t size) override;
ExceptionOr<size_t> Skip(size_t offset) override;
@@ -23,33 +25,29 @@ public:
Exception Close() override;
private:
int fd_;
friend class BluetoothSocket;
std::optional<sdbus::UnixFd> fd_;
};
class BluetoothOutputStream : public OutputStream {
public:
BluetoothOutputStream(int fd) { fd_ = fd; };
BluetoothOutputStream(sdbus::UnixFd &fd) : fd_(fd){};
Exception Write(const ByteArray &data) override;
Exception Flush() override;
Exception Close() override;
private:
int fd_;
friend class BluetoothSocket;
std::optional<sdbus::UnixFd> fd_;
};
class BluetoothSocket : public api::BluetoothSocket {
public:
BluetoothSocket(api::BluetoothDevice &device,
absl::string_view device_object_path,
absl::string_view connected_profile_uuid, int fd)
: device_(device) {
fd_ = fd;
device_object_path_ = device_object_path;
connected_profile_uuid_ = connected_profile_uuid;
input_stream_ = BluetoothInputStream(fd_);
output_stream_ = BluetoothOutputStream(fd_);
}
BluetoothSocket(api::BluetoothDevice &device, sdbus::UnixFd fd)
: device_(device), output_stream_(fd), input_stream_(fd) {}
InputStream &GetInputStream() override { return input_stream_; }
OutputStream &GetOutputStream() override { return output_stream_; }
@@ -57,12 +55,9 @@ public:
api::BluetoothDevice *GetRemoteDevice() override { return &device_; };
private:
int fd_;
std::string device_object_path_;
api::BluetoothDevice &device_;
std::string connected_profile_uuid_;
BluetoothInputStream input_stream_ = {-1};
BluetoothOutputStream output_stream_ = {-1};
BluetoothOutputStream output_stream_;
BluetoothInputStream input_stream_;
};
} // namespace linux
} // namespace nearby
@@ -0,0 +1,49 @@
#include <functional>
#include <optional>
#include <sdbus-c++/Types.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 "absl/synchronization/mutex.h"
namespace nearby {
namespace linux {
std::optional<std::reference_wrapper<BluetoothDevice>>
BluetoothDevices::get_device_by_path(
const sdbus::ObjectPath &device_object_path) {
absl::ReaderMutexLock l(&devices_by_path_lock_);
if (devices_by_path_.count(device_object_path) == 0) {
return std::nullopt;
}
auto &device = devices_by_path_[device_object_path];
return device;
}
std::optional<std::reference_wrapper<BluetoothDevice>>
BluetoothDevices::get_device_by_address(const std::string &addr) {
auto device_object_path =
bluez::device_object_path(adapter_object_path_, addr);
return get_device_by_path(device_object_path);
}
void BluetoothDevices::remove_device_by_path(
const sdbus::ObjectPath &device_object_path) {
absl::MutexLock l(&devices_by_path_lock_);
devices_by_path_.erase(device_object_path);
}
BluetoothDevice &
BluetoothDevices::add_new_device(sdbus::ObjectPath device_object_path) {
absl::MutexLock l(&devices_by_path_lock_);
auto pair =
devices_by_path_.emplace(device_object_path, system_bus_,
std::move(device_object_path), observers_);
return pair.first->second;
}
} // namespace linux
} // namespace nearby
@@ -0,0 +1,42 @@
#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_DEVICES_H_
#define PLATFORM_IMPL_LINUX_BLUETOOTH_DEVICES_H_
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/IProxy.h>
#include <sdbus-c++/Types.h>
#include "absl/synchronization/mutex.h"
#include "internal/base/observer_list.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/linux/bluetooth_classic_device.h"
namespace nearby {
namespace linux {
class BluetoothDevices {
public:
BluetoothDevices(
sdbus::IConnection &system_bus,
const sdbus::ObjectPath &adapter_object_path,
ObserverList<api::BluetoothClassicMedium::Observer> &observers)
: system_bus_(system_bus), observers_(observers),
adapter_object_path_(adapter_object_path) {}
std::optional<std::reference_wrapper<BluetoothDevice>>
get_device_by_path(const sdbus::ObjectPath &);
std::optional<std::reference_wrapper<BluetoothDevice>>
get_device_by_address(const std::string &);
void remove_device_by_path(const sdbus::ObjectPath &);
BluetoothDevice &add_new_device(sdbus::ObjectPath);
private:
absl::Mutex devices_by_path_lock_;
std::map<std::string, MonitoredBluetoothDevice> devices_by_path_;
sdbus::IConnection &system_bus_;
ObserverList<api::BluetoothClassicMedium::Observer> &observers_;
sdbus::ObjectPath adapter_object_path_;
};
} // namespace linux
} // namespace nearby
#endif
@@ -1,8 +1,11 @@
#include <sdbus-c++/Error.h>
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/IProxy.h>
#include <systemd/sd-bus.h>
#include <utility>
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/linux/bluetooth_classic_device.h"
#include "internal/platform/implementation/linux/bluetooth_adapter.h"
#include "internal/platform/implementation/linux/bluetooth_pairing.h"
#include "internal/platform/implementation/linux/bluez.h"
#include "internal/platform/logging.h"
@@ -10,117 +13,119 @@
namespace nearby {
namespace linux {
int pairing_reply_handler(sd_bus_message *m, void *userdata,
sd_bus_error *err) {
auto pairing_cb = static_cast<api::BluetoothPairingCallback *>(userdata);
if (sd_bus_message_is_method_error(m, nullptr)) {
if (sd_bus_message_is_method_error(
m, "org.bluez.Error.AuthenticationCanceled")) {
pairing_cb->on_pairing_error_cb(
api::BluetoothPairingCallback::PairingError::kAuthCanceled);
} else if (sd_bus_message_is_method_error(
m, "org.bluez.Error.AuthenticationFailed")) {
pairing_cb->on_pairing_error_cb(
api::BluetoothPairingCallback::PairingError::kAuthFailed);
} else if (sd_bus_message_is_method_error(
m, "org.bluez.Error.AuthenticationRejected")) {
pairing_cb->on_pairing_error_cb(
api::BluetoothPairingCallback::PairingError::kAuthRejected);
} else if (sd_bus_message_is_method_error(
m, "org.bluez.Error.AuthenticationTimeout")) {
pairing_cb->on_pairing_error_cb(
api::BluetoothPairingCallback::PairingError::kAuthTimeout);
void BluetoothPairing::pairing_reply_handler(const sdbus::Error *error) {
if (error != nullptr && error->isValid()) {
auto name = error->getName();
api::BluetoothPairingCallback::PairingError err;
NEARBY_LOGS(ERROR) << __func__ << ": "
<< "Got error '" << error->getName()
<< "' with message '" << error->getMessage()
<< "' while pairing with device "
<< device_.getObjectPath();
if (name == "org.bluez.Error.AuthenticationCanceled") {
err = api::BluetoothPairingCallback::PairingError::kAuthCanceled;
} else if (name == "org.bluez.Error.AuthenticationFailed") {
err = api::BluetoothPairingCallback::PairingError::kAuthFailed;
} else if (name == "org.bluez.Error.AuthenticationRejected") {
err = api::BluetoothPairingCallback::PairingError::kAuthRejected;
} else if (name == "org.bluez.Error.AuthenticationTimeout") {
err = api::BluetoothPairingCallback::PairingError::kAuthTimeout;
} else {
pairing_cb->on_pairing_error_cb(
api::BluetoothPairingCallback::PairingError::kAuthFailed);
err = api::BluetoothPairingCallback::PairingError::kAuthFailed;
}
return 0;
if (pairing_cb_.on_pairing_error_cb != nullptr) {
pairing_cb_.on_pairing_error_cb(err);
}
return;
}
if (err) {
NEARBY_LOGS(ERROR) << __func__
<< "Error pairing with device: " << err->message;
pairing_cb->on_pairing_error_cb(
api::BluetoothPairingCallback::PairingError::kUnknown);
} else {
pairing_cb->on_paired_cb();
if (pairing_cb_.on_paired_cb != nullptr) {
pairing_cb_.on_paired_cb();
}
return 0;
return;
}
BluetoothPairing::BluetoothPairing(const sdbus::ObjectPath &adapter_object_path,
BluetoothDevice &remote_device,
BluetoothAdapter &adapter,
sdbus::IConnection &system_bus)
: device_(remote_device), adapter_(adapter) {}
bool BluetoothPairing::InitiatePairing(
api::BluetoothPairingCallback pairing_cb) {
if (!system_bus_)
return false;
pairing_cb_ = std::move(pairing_cb);
if (pairing_cb_.on_pairing_initiated_cb != nullptr)
pairing_cb_.on_pairing_initiated_cb(api::PairingParams{
api::PairingParams::PairingType::kConsent, std::string()});
if (sd_bus_call_method_async(
system_bus_, nullptr, BLUEZ_SERVICE, device_object_path_.c_str(),
BLUEZ_DEVICE_INTERFACE, "Pair", &pairing_reply_handler, &pairing_cb_,
nullptr) < 0) {
NEARBY_LOGS(ERROR) << __func__ << "Error calling method Pair on device "
<< device_object_path_;
return false;
}
pairing_cb.on_pairing_initiated_cb(api::PairingParams{
api::PairingParams::PairingType::kConsent, std::string()});
return true;
}
bool BluetoothPairing::FinishPairing(
std::optional<absl::string_view> pin_code) {
device_.set_pair_reply_callback([this](const sdbus::Error *error) {
this->pairing_reply_handler(error);
});
try {
pair_async_call_ = device_.Pair();
} catch (const sdbus::Error &e) {
NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName()
<< "' with message '" << e.getMessage()
<< "' while trying to initiate pairing for device "
<< device_.getObjectPath();
return false;
}
return true;
}
bool BluetoothPairing::CancelPairing() {
if (!system_bus_)
return false;
try {
if (pair_async_call_.isPending()) {
pair_async_call_.cancel();
}
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE,
device_object_path_.c_str(), BLUEZ_DEVICE_INTERFACE,
"CancelPairing", &err, nullptr, nullptr) < 0) {
NEARBY_LOGS(ERROR) << __func__
<< "Error calling method CancelPairing on device "
<< device_object_path_ << ": " << err.message;
device_.CancelPairing();
} catch (const sdbus::Error &e) {
NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName()
<< "' with message '" << e.getMessage()
<< "' while trying to cancel pairing for device "
<< device_.getObjectPath();
return false;
}
return true;
}
bool BluetoothPairing::Unpair() {
if (!system_bus_)
return false;
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0",
BLUEZ_ADAPTER_INTERFACE, "RemoveDevice", &err, nullptr,
"o", device_object_path_.c_str()) < 0) {
NEARBY_LOGS(ERROR) << __func__
<< "Error calling method CancelPairing on device "
<< device_object_path_ << ": " << err.message;
try {
adapter_.RemoveDevice(device_.getObjectPath());
return true;
} catch (const sdbus::Error &e) {
NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName()
<< "' with message '" << e.getMessage()
<< "' while trying to unpair device "
<< device_.getObjectPath() << " on adapter "
<< adapter_.getObjectPath();
return false;
}
return true;
}
bool BluetoothPairing::IsPaired() {
if (!system_bus_)
try {
bool bonded = device_.Bonded();
return bonded;
} catch (const sdbus::Error &e) {
NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName()
<< "' with message '" << e.getMessage()
<< "' while trying to get Bonded state for device "
<< device_.getObjectPath();
return false;
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
int paired = 0;
if (sd_bus_get_property_trivial(
system_bus_, BLUEZ_SERVICE, device_object_path_.c_str(),
BLUEZ_DEVICE_INTERFACE, "Bonded", &err, 'b', &paired) < 0) {
NEARBY_LOGS(ERROR) << __func__
<< "Error getting Bonded property for device "
<< device_object_path_ << ": " << err.message;
}
return paired;
}
} // namespace linux
} // namespace nearby
@@ -1,22 +1,26 @@
#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_PROFILE_H_
#define PLATFORM_IMPL_LINUX_BLUETOOTH_PAIRING_H_
#include <memory>
#include <string>
#include <sdbus-c++/Error.h>
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/IProxy.h>
#include <systemd/sd-bus.h>
#include "absl/strings/string_view.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/linux/bluetooth_adapter.h"
#include "internal/platform/implementation/linux/bluetooth_classic_device.h"
namespace nearby {
namespace linux {
class BluetoothPairing : public api::BluetoothPairing {
public:
BluetoothPairing(sd_bus *system_bus, absl::string_view device_object_path) {
system_bus_ = system_bus;
device_object_path_ = device_object_path;
}
~BluetoothPairing() { sd_bus_unref(system_bus_); }
BluetoothPairing(const sdbus::ObjectPath &adapter_object_path,
BluetoothDevice &remote_device, BluetoothAdapter &adapter,
sdbus::IConnection &system_bus);
~BluetoothPairing() override = default;
bool InitiatePairing(api::BluetoothPairingCallback pairing_cb) override;
bool FinishPairing(std::optional<absl::string_view> pin_code) override;
@@ -25,8 +29,14 @@ public:
bool IsPaired() override;
private:
std::string device_object_path_;
sd_bus *system_bus_;
void pairing_reply_handler(const sdbus::Error *e);
sdbus::PendingAsyncCall pair_async_call_;
BluetoothDevice &device_;
BluetoothAdapter &adapter_;
std::unique_ptr<sdbus::IProxy> bluez_adapter_proxy_;
api::BluetoothPairingCallback pairing_cb_;
};
} // namespace linux
@@ -19,27 +19,16 @@ std::unique_ptr<api::BluetoothSocket> BluetoothServerSocket::Accept() {
<< service_uuid_ << " for device ";
return nullptr;
}
auto device_object_path =
absl::Substitute("$0/dev_$1", adapter_object_path_,
absl::StrReplaceAll(pair->first, {{":", "_"}}));
auto device = BluetoothDevice(sd_bus_ref(system_bus_), device_object_path);
return std::unique_ptr<api::BluetoothSocket>(new BluetoothSocket(
device, device_object_path, service_uuid_, pair->second));
auto [device, fd] = *pair;
return std::unique_ptr<api::BluetoothSocket>(new BluetoothSocket(device, fd));
}
Exception BluetoothServerSocket::Close() {
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
auto profile_object_path =
absl::Substitute("/com/github/google/nearby/profiles/$0", service_uuid_);
if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, "/org/bluez",
"org.bluez.ProfileManager1", "UnregisterProfile", &err,
nullptr, "o", profile_object_path.c_str()) < 0) {
NEARBY_LOGS(ERROR) << __func__ << "Error unregistering profile object "
<< profile_object_path << ": " << err.message;
return {Exception::kFailed};
}
profile_manager_.Unregister(service_uuid_);
return {Exception::kSuccess};
}
@@ -0,0 +1,32 @@
#include "absl/strings/substitute.h"
#include "absl/strings/string_view.h"
#include "absl/strings/str_replace.h"
#include "internal/platform/implementation/linux/bluez.h"
#include <sdbus-c++/Types.h>
namespace nearby {
namespace linux {
namespace bluez {
const char *SERVICE = "org.bluez";
const char *ADAPTER_INTEFACE = "org.bluez.Adapter1";
const char *DEVICE_INTERFACE = "org.bluez.Device1";
const char *DEVICE_PROP_ADDRESS = "Address";
const char *DEVICE_PROP_ALIAS = "Alias";
const char *DEVICE_PROP_PAIRED = "Paired";
const char *DEVICE_PROP_CONNECTED = "Connected";
std::string device_object_path(const sdbus::ObjectPath &adapter_object_path,
absl::string_view mac_address) {
return absl::Substitute("$0/dev_$1", adapter_object_path,
absl::StrReplaceAll(mac_address, {{":", "_"}}));
}
sdbus::ObjectPath profile_object_path(absl::string_view service_uuid) {
return absl::Substitute("/com/github/google/nearby/profiles/$0", service_uuid);
}
} // namespace bluez
} // namespace linux
} // namespace nearby
+31 -2
View File
@@ -1,11 +1,40 @@
#ifndef PLATFORM_IMPL_LINUX_BLUEZ_H_
#define PLATFORM_IMPL_LINUX_BLUEZ_H_
#include <sdbus-c++/Types.h>
#include "absl/strings/string_view.h"
#include <string>
#define BLUEZ_LOG_METHOD_CALL_ERROR(proxy, method, err) \
do { \
NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << (err).getName() \
<< "' with message '" << (err).getMessage() \
<< "' while calling " << method << " on object " \
<< (proxy)->getObjectPath(); \
} while (false)
namespace nearby {
namespace linux {
const char *BLUEZ_SERVICE = "org.bluez";
const char *BLUEZ_ADAPTER_INTERFACE = "org.bluez.Adapter1";
namespace bluez {
extern const char *SERVICE_DEST;
extern const char *ADAPTER_INTERFACE;
extern const char *DEVICE_INTERFACE;
extern const char *DEVICE_PROP_ADDRESS;
extern const char *DEVICE_PROP_ALIAS;
extern const char *DEVICE_PROP_PAIRED;
extern const char *DEVICE_PROP_CONNECTED;
extern std::string
device_object_path(const sdbus::ObjectPath &adapter_object_path,
absl::string_view mac_address);
extern sdbus::ObjectPath profile_object_path(absl::string_view service_uuid);
} // namespace bluez
} // namespace linux
} // namespace nearby
@@ -0,0 +1,179 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp__bluez_adapter_client_glue_h__proxy__H__
#define __sdbuscpp__bluez_adapter_client_glue_h__proxy__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace org {
namespace bluez {
class Adapter1_proxy
{
public:
static constexpr const char* INTERFACE_NAME = "org.bluez.Adapter1";
protected:
Adapter1_proxy(sdbus::IProxy& proxy)
: proxy_(proxy)
{
}
~Adapter1_proxy() = default;
public:
void StartDiscovery()
{
proxy_.callMethod("StartDiscovery").onInterface(INTERFACE_NAME);
}
void SetDiscoveryFilter(const std::map<std::string, sdbus::Variant>& properties)
{
proxy_.callMethod("SetDiscoveryFilter").onInterface(INTERFACE_NAME).withArguments(properties);
}
void StopDiscovery()
{
proxy_.callMethod("StopDiscovery").onInterface(INTERFACE_NAME);
}
void RemoveDevice(const sdbus::ObjectPath& device)
{
proxy_.callMethod("RemoveDevice").onInterface(INTERFACE_NAME).withArguments(device);
}
std::vector<std::string> GetDiscoveryFilters()
{
std::vector<std::string> result;
proxy_.callMethod("GetDiscoveryFilters").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
void ConnectDevice(const std::map<std::string, sdbus::Variant>& properties)
{
proxy_.callMethod("ConnectDevice").onInterface(INTERFACE_NAME).withArguments(properties);
}
public:
std::string Address()
{
return proxy_.getProperty("Address").onInterface(INTERFACE_NAME);
}
std::string AddressType()
{
return proxy_.getProperty("AddressType").onInterface(INTERFACE_NAME);
}
std::string Name()
{
return proxy_.getProperty("Name").onInterface(INTERFACE_NAME);
}
std::string Alias()
{
return proxy_.getProperty("Alias").onInterface(INTERFACE_NAME);
}
void Alias(const std::string& value)
{
proxy_.setProperty("Alias").onInterface(INTERFACE_NAME).toValue(value);
}
uint32_t Class()
{
return proxy_.getProperty("Class").onInterface(INTERFACE_NAME);
}
bool Powered()
{
return proxy_.getProperty("Powered").onInterface(INTERFACE_NAME);
}
void Powered(const bool& value)
{
proxy_.setProperty("Powered").onInterface(INTERFACE_NAME).toValue(value);
}
std::string PowerState()
{
return proxy_.getProperty("PowerState").onInterface(INTERFACE_NAME);
}
bool Discoverable()
{
return proxy_.getProperty("Discoverable").onInterface(INTERFACE_NAME);
}
void Discoverable(const bool& value)
{
proxy_.setProperty("Discoverable").onInterface(INTERFACE_NAME).toValue(value);
}
uint32_t DiscoverableTimeout()
{
return proxy_.getProperty("DiscoverableTimeout").onInterface(INTERFACE_NAME);
}
void DiscoverableTimeout(const uint32_t& value)
{
proxy_.setProperty("DiscoverableTimeout").onInterface(INTERFACE_NAME).toValue(value);
}
bool Pairable()
{
return proxy_.getProperty("Pairable").onInterface(INTERFACE_NAME);
}
void Pairable(const bool& value)
{
proxy_.setProperty("Pairable").onInterface(INTERFACE_NAME).toValue(value);
}
uint32_t PairableTimeout()
{
return proxy_.getProperty("PairableTimeout").onInterface(INTERFACE_NAME);
}
void PairableTimeout(const uint32_t& value)
{
proxy_.setProperty("PairableTimeout").onInterface(INTERFACE_NAME).toValue(value);
}
bool Discovering()
{
return proxy_.getProperty("Discovering").onInterface(INTERFACE_NAME);
}
std::vector<std::string> UUIDs()
{
return proxy_.getProperty("UUIDs").onInterface(INTERFACE_NAME);
}
std::string Modalias()
{
return proxy_.getProperty("Modalias").onInterface(INTERFACE_NAME);
}
std::vector<std::string> Roles()
{
return proxy_.getProperty("Roles").onInterface(INTERFACE_NAME);
}
std::vector<std::string> ExperimentalFeatures()
{
return proxy_.getProperty("ExperimentalFeatures").onInterface(INTERFACE_NAME);
}
private:
sdbus::IProxy& proxy_;
};
}} // namespaces
#endif
@@ -0,0 +1,215 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp__bluez_device_client_glue_h__proxy__H__
#define __sdbuscpp__bluez_device_client_glue_h__proxy__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace org {
namespace bluez {
class Device1_proxy
{
public:
static constexpr const char* INTERFACE_NAME = "org.bluez.Device1";
protected:
Device1_proxy(sdbus::IProxy& proxy)
: proxy_(proxy)
{
}
~Device1_proxy() = default;
virtual void onConnectProfileReply(const sdbus::Error* error) = 0;
virtual void onPairReply(const sdbus::Error* error) = 0;
public:
void Disconnect()
{
proxy_.callMethod("Disconnect").onInterface(INTERFACE_NAME);
}
void Connect()
{
proxy_.callMethod("Connect").onInterface(INTERFACE_NAME);
}
sdbus::PendingAsyncCall ConnectProfile(const std::string& UUID)
{
return proxy_.callMethodAsync("ConnectProfile").onInterface(INTERFACE_NAME).withArguments(UUID).uponReplyInvoke([this](const sdbus::Error* error){ this->onConnectProfileReply(error); });
}
void DisconnectProfile(const std::string& UUID)
{
proxy_.callMethod("DisconnectProfile").onInterface(INTERFACE_NAME).withArguments(UUID);
}
sdbus::PendingAsyncCall Pair()
{
return proxy_.callMethodAsync("Pair").onInterface(INTERFACE_NAME).uponReplyInvoke([this](const sdbus::Error* error){ this->onPairReply(error); });
}
void CancelPairing()
{
proxy_.callMethod("CancelPairing").onInterface(INTERFACE_NAME);
}
public:
std::string Address()
{
return proxy_.getProperty("Address").onInterface(INTERFACE_NAME);
}
std::string AddressType()
{
return proxy_.getProperty("AddressType").onInterface(INTERFACE_NAME);
}
std::string Name()
{
return proxy_.getProperty("Name").onInterface(INTERFACE_NAME);
}
std::string Alias()
{
return proxy_.getProperty("Alias").onInterface(INTERFACE_NAME);
}
void Alias(const std::string& value)
{
proxy_.setProperty("Alias").onInterface(INTERFACE_NAME).toValue(value);
}
uint32_t Class()
{
return proxy_.getProperty("Class").onInterface(INTERFACE_NAME);
}
uint16_t Appearance()
{
return proxy_.getProperty("Appearance").onInterface(INTERFACE_NAME);
}
std::string Icon()
{
return proxy_.getProperty("Icon").onInterface(INTERFACE_NAME);
}
bool Paired()
{
return proxy_.getProperty("Paired").onInterface(INTERFACE_NAME);
}
bool Bonded()
{
return proxy_.getProperty("Bonded").onInterface(INTERFACE_NAME);
}
bool Trusted()
{
return proxy_.getProperty("Trusted").onInterface(INTERFACE_NAME);
}
void Trusted(const bool& value)
{
proxy_.setProperty("Trusted").onInterface(INTERFACE_NAME).toValue(value);
}
bool Blocked()
{
return proxy_.getProperty("Blocked").onInterface(INTERFACE_NAME);
}
void Blocked(const bool& value)
{
proxy_.setProperty("Blocked").onInterface(INTERFACE_NAME).toValue(value);
}
bool LegacyPairing()
{
return proxy_.getProperty("LegacyPairing").onInterface(INTERFACE_NAME);
}
int16_t RSSI()
{
return proxy_.getProperty("RSSI").onInterface(INTERFACE_NAME);
}
bool Connected()
{
return proxy_.getProperty("Connected").onInterface(INTERFACE_NAME);
}
std::vector<std::string> UUIDs()
{
return proxy_.getProperty("UUIDs").onInterface(INTERFACE_NAME);
}
std::string Modalias()
{
return proxy_.getProperty("Modalias").onInterface(INTERFACE_NAME);
}
sdbus::ObjectPath Adapter()
{
return proxy_.getProperty("Adapter").onInterface(INTERFACE_NAME);
}
std::map<uint16_t, sdbus::Variant> ManufacturerData()
{
return proxy_.getProperty("ManufacturerData").onInterface(INTERFACE_NAME);
}
std::map<std::string, sdbus::Variant> ServiceData()
{
return proxy_.getProperty("ServiceData").onInterface(INTERFACE_NAME);
}
int16_t TxPower()
{
return proxy_.getProperty("TxPower").onInterface(INTERFACE_NAME);
}
bool ServicesResolved()
{
return proxy_.getProperty("ServicesResolved").onInterface(INTERFACE_NAME);
}
std::vector<uint8_t> AdvertisingFlags()
{
return proxy_.getProperty("AdvertisingFlags").onInterface(INTERFACE_NAME);
}
std::map<uint8_t, sdbus::Variant> AdvertisingData()
{
return proxy_.getProperty("AdvertisingData").onInterface(INTERFACE_NAME);
}
bool WakeAllowed()
{
return proxy_.getProperty("WakeAllowed").onInterface(INTERFACE_NAME);
}
void WakeAllowed(const bool& value)
{
proxy_.setProperty("WakeAllowed").onInterface(INTERFACE_NAME).toValue(value);
}
std::map<sdbus::ObjectPath, std::map<std::string, sdbus::Variant>> Sets()
{
return proxy_.getProperty("Sets").onInterface(INTERFACE_NAME);
}
private:
sdbus::IProxy& proxy_;
};
}} // namespaces
#endif
@@ -0,0 +1,43 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp__bluez_profile_glue_h__adaptor__H__
#define __sdbuscpp__bluez_profile_glue_h__adaptor__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace org {
namespace bluez {
class Profile1_adaptor
{
public:
static constexpr const char* INTERFACE_NAME = "org.bluez.Profile1";
protected:
Profile1_adaptor(sdbus::IObject& object)
: object_(object)
{
object_.registerMethod("Release").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->Release(); });
object_.registerMethod("NewConnection").onInterface(INTERFACE_NAME).withInputParamNames("device", "fd", "fd_properties").implementedAs([this](const sdbus::ObjectPath& device, const sdbus::UnixFd& fd, const std::map<std::string, sdbus::Variant>& fd_properties){ return this->NewConnection(device, fd, fd_properties); });
object_.registerMethod("RequestDisconnection").onInterface(INTERFACE_NAME).withInputParamNames("device").implementedAs([this](const sdbus::ObjectPath& device){ return this->RequestDisconnection(device); });
}
~Profile1_adaptor() = default;
private:
virtual void Release() = 0;
virtual void NewConnection(const sdbus::ObjectPath& device, const sdbus::UnixFd& fd, const std::map<std::string, sdbus::Variant>& fd_properties) = 0;
virtual void RequestDisconnection(const sdbus::ObjectPath& device) = 0;
private:
sdbus::IObject& object_;
};
}} // namespaces
#endif
@@ -0,0 +1,46 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp__bluez_profile_manager_client_glue_h__proxy__H__
#define __sdbuscpp__bluez_profile_manager_client_glue_h__proxy__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace org {
namespace bluez {
class ProfileManager1_proxy
{
public:
static constexpr const char* INTERFACE_NAME = "org.bluez.ProfileManager1";
protected:
ProfileManager1_proxy(sdbus::IProxy& proxy)
: proxy_(proxy)
{
}
~ProfileManager1_proxy() = default;
public:
void RegisterProfile(const sdbus::ObjectPath& profile, const std::string& UUID, const std::map<std::string, sdbus::Variant>& options)
{
proxy_.callMethod("RegisterProfile").onInterface(INTERFACE_NAME).withArguments(profile, UUID, options);
}
void UnregisterProfile(const sdbus::ObjectPath& profile)
{
proxy_.callMethod("UnregisterProfile").onInterface(INTERFACE_NAME).withArguments(profile);
}
private:
sdbus::IProxy& proxy_;
};
}} // namespaces
#endif
@@ -1,12 +1,12 @@
#include <cstdlib>
#include <cstring>
#include <optional>
#include <string>
#include <pwd.h>
#include <string>
#include <sys/types.h>
#include <systemd/sd-bus.h>
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/IProxy.h>
#include <systemd/sd-login.h>
#include "internal/platform/implementation/device_info.h"
@@ -14,7 +14,6 @@
#include "internal/platform/logging.h"
namespace nearby {
namespace linux {
const char *HOSTNAME_DEST = "org.freedesktop.hostname1";
@@ -25,78 +24,49 @@ const char *LOGIN_DEST = "org.freedesktop.login1";
const char *LOGIN_PATH = "/org/freedesktop/login1/session/_";
const char *LOGIN_INTERFACE = "org.freedesktop.login1.Session";
DeviceInfo::DeviceInfo(sdbus::IConnection &system_bus) {
hostname_proxy_ =
sdbus::createProxy(system_bus, HOSTNAME_DEST, HOSTNAME_PATH);
hostname_proxy_->finishRegistration();
login_proxy_ = sdbus::createProxy(system_bus, LOGIN_PATH, LOGIN_PATH);
login_proxy_->finishRegistration();
}
std::optional<std::u16string> DeviceInfo::GetOsDeviceName() const {
__attribute__((cleanup(sd_bus_unrefp))) sd_bus *bus = nullptr;
if (sd_bus_default_system(&bus) < 0) {
NEARBY_LOGS(ERROR) << __func__ << ": Error connecting to systemd bus.";
try {
std::string hostname = hostname_proxy_->getProperty("PrettyHostname")
.onInterface(HOSTNAME_INTERFACE);
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
return convert.from_bytes(hostname);
} catch (const sdbus::Error &e) {
NEARBY_LOGS(ERROR) << __func__ << "Got error '" << e.getName()
<< "' with message '" << e.getMessage()
<< "' while trying to get PrettyHostname";
return std::nullopt;
}
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
char *hostname = nullptr;
if (sd_bus_get_property_string(bus, HOSTNAME_DEST, HOSTNAME_PATH,
HOSTNAME_INTERFACE, "PrettyHostname", &err,
&hostname) < 0) {
NEARBY_LOGS(ERROR)
<< __func__
<< ": Error getting PrettyHostname from org.freedesktop.hostname1: "
<< err.message;
}
if (!hostname || hostname[0] == '\0') {
int ret = sd_bus_get_property_string(bus, HOSTNAME_DEST, HOSTNAME_PATH,
HOSTNAME_INTERFACE, "Hostname", &err,
&hostname);
if (ret < 0) {
NEARBY_LOGS(ERROR)
<< __func__
<< ": Error getting Hostname from org.freedesktop.hostname1: "
<< err.message;
return std::nullopt;
}
}
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
std::u16string name = convert.from_bytes(hostname);
free(hostname);
return name;
}
api::DeviceInfo::DeviceType DeviceInfo::GetDeviceType() const {
__attribute__((cleanup(sd_bus_unrefp))) sd_bus *bus;
if (sd_bus_default_system(&bus) < 0) {
NEARBY_LOGS(ERROR) << __func__ << ": Error connecting to systemd bus.";
try {
std::string chasis = hostname_proxy_->getProperty("PrettyHostname")
.onInterface(HOSTNAME_INTERFACE);
api::DeviceInfo::DeviceType device = api::DeviceInfo::DeviceType::kUnknown;
if (chasis == "phone") {
device = api::DeviceInfo::DeviceType::kPhone;
} else if (chasis == "laptop" || chasis == "desktop") {
device = api::DeviceInfo::DeviceType::kLaptop;
} else if (chasis == "tablet") {
device = api::DeviceInfo::DeviceType::kTablet;
} else if (chasis == "handset") {
device = api::DeviceInfo::DeviceType::kPhone;
}
return device;
} catch (const sdbus::Error &e) {
NEARBY_LOGS(ERROR) << __func__ << "Got error '" << e.getName()
<< "' with message '" << e.getMessage()
<< "' while trying to get PrettyHostname";
return api::DeviceInfo::DeviceType::kUnknown;
}
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
char *chasis = nullptr;
if (sd_bus_get_property_string(bus, HOSTNAME_DEST, HOSTNAME_PATH,
HOSTNAME_INTERFACE, "Chasis", &err,
&chasis) < 0) {
NEARBY_LOGS(ERROR)
<< __func__ << ": Error getting Chasis from org.freedesktop.hostname1: "
<< err.message;
return api::DeviceInfo::DeviceType::kUnknown;
}
api::DeviceInfo::DeviceType device = api::DeviceInfo::DeviceType::kUnknown;
if (strcmp(chasis, "phone") == 0) {
device = api::DeviceInfo::DeviceType::kPhone;
} else if (strcmp(chasis, "laptop") == 0 || strcmp(chasis, "desktop") == 0) {
device = api::DeviceInfo::DeviceType::kLaptop;
} else if (strcmp(chasis, "tablet") == 0) {
device = api::DeviceInfo::DeviceType::kTablet;
} else if (strcmp(chasis, "handset") == 0) {
device = api::DeviceInfo::DeviceType::kPhone;
}
free(chasis);
return device;
}
std::optional<std::u16string> DeviceInfo::GetFullName() const {
@@ -170,34 +140,21 @@ bool DeviceInfo::IsScreenLocked() const {
return false;
}
__attribute__((cleanup(sd_bus_unrefp))) sd_bus *bus;
if (sd_bus_default_system(&bus) < 0) {
NEARBY_LOGS(ERROR) << __func__ << ": Error connecting to systemd bus.";
free(session);
return false;
}
std::string session_path(LOGIN_PATH);
session_path += session;
free(session);
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
bool locked;
if (sd_bus_get_property_trivial(bus, LOGIN_DEST, session_path.c_str(),
LOGIN_INTERFACE, "LockedHint", &err, 'b',
&locked) < 0) {
NEARBY_LOGS(ERROR)
<< __func__
<< ": Error getting LockedState from org.freedesktop.login1: "
<< err.message;
locked = false;
try {
bool locked =
login_proxy_->getProperty("LockedHint").onInterface(LOGIN_INTERFACE);
return locked;
} catch (const sdbus::Error &e) {
NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName()
<< "' with message '" << e.getMessage()
<< "' while trying to get LockedHint for session "
<< session_path;
return false;
}
return locked;
}
} // namespace linux
} // namespace nearby
@@ -1,11 +1,12 @@
#ifndef PLATFORM_IMPL_LINUX_DEVICE_INFO_H_
#define PLATFORM_IMPL_LINUX_DEVICE_INFO_H_
#include <systemd/sd-bus.h>
#include <optional>
#include <string>
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/IProxy.h>
#include "absl/strings/string_view.h"
#include "internal/platform/implementation/device_info.h"
@@ -14,7 +15,8 @@ namespace linux {
class DeviceInfo : public api::DeviceInfo {
public:
~DeviceInfo() override;
DeviceInfo(sdbus::IConnection &system_bus);
~DeviceInfo() override = default;
std::optional<std::u16string> GetOsDeviceName() const override;
api::DeviceInfo::DeviceType GetDeviceType() const override;
@@ -47,7 +49,9 @@ public:
void
UnregisterScreenLockedListener(absl::string_view listener_name) override{};
sd_bus *system_bus;
private:
std::unique_ptr<sdbus::IProxy> hostname_proxy_;
std::unique_ptr<sdbus::IProxy> login_proxy_;
};
} // namespace linux
} // namespace nearby
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.bluez.Adapter1">
<method name="StartDiscovery" />
<method name="SetDiscoveryFilter">
<arg name="properties" type="a{sv}" direction="in" />
</method>
<method name="StopDiscovery" />
<method name="RemoveDevice">
<arg name="device" type="o" direction="in" />
</method>
<method name="GetDiscoveryFilters">
<arg name="filters" type="as" direction="out" />
</method>
<method name="ConnectDevice">
<arg name="properties" type="a{sv}" direction="in" />
</method>
<property name="Address" type="s" access="read" />
<property name="AddressType" type="s" access="read" />
<property name="Name" type="s" access="read" />
<property name="Alias" type="s" access="readwrite" />
<property name="Class" type="u" access="read" />
<property name="Powered" type="b" access="readwrite" />
<property name="PowerState" type="s" access="read" />
<property name="Discoverable" type="b" access="readwrite" />
<property name="DiscoverableTimeout" type="u" access="readwrite" />
<property name="Pairable" type="b" access="readwrite" />
<property name="PairableTimeout" type="u" access="readwrite" />
<property name="Discovering" type="b" access="read" />
<property name="UUIDs" type="as" access="read" />
<property name="Modalias" type="s" access="read" />
<property name="Roles" type="as" access="read" />
<property name="ExperimentalFeatures" type="as" access="read" />
</interface>
</node>
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.bluez.Device1">
<method name="Disconnect" />
<method name="Connect" />
<method name="ConnectProfile">
<annotation name="org.freedesktop.DBus.Method.Async" value="client"/>
<arg name="UUID" type="s" direction="in" />
</method>
<method name="DisconnectProfile">
<arg name="UUID" type="s" direction="in" />
</method>
<method name="Pair">
<annotation name="org.freedesktop.DBus.Method.Async" value="client"/>
</method>
<method name="CancelPairing" />
<property name="Address" type="s" access="read" />
<property name="AddressType" type="s" access="read" />
<property name="Name" type="s" access="read" />
<property name="Alias" type="s" access="readwrite" />
<property name="Class" type="u" access="read" />
<property name="Appearance" type="q" access="read" />
<property name="Icon" type="s" access="read" />
<property name="Paired" type="b" access="read" />
<property name="Bonded" type="b" access="read" />
<property name="Trusted" type="b" access="readwrite" />
<property name="Blocked" type="b" access="readwrite" />
<property name="LegacyPairing" type="b" access="read" />
<property name="RSSI" type="n" access="read" />
<property name="Connected" type="b" access="read" />
<property name="UUIDs" type="as" access="read" />
<property name="Modalias" type="s" access="read" />
<property name="Adapter" type="o" access="read" />
<property name="ManufacturerData" type="a{qv}" access="read" />
<property name="ServiceData" type="a{sv}" access="read" />
<property name="TxPower" type="n" access="read" />
<property name="ServicesResolved" type="b" access="read" />
<property name="AdvertisingFlags" type="ay" access="read" />
<property name="AdvertisingData" type="a{yv}" access="read" />
<property name="WakeAllowed" type="b" access="readwrite" />
<property name="Sets" type="a{oa{sv}}" access="read" />
</interface>
</node>
@@ -0,0 +1,17 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.bluez.Profile1">
<method name='Release'>
</method>
<method name='NewConnection'>
<arg type='o' name='device' direction='in'/>
<arg type='h' name='fd' direction='in'/>
<arg type='a{sv}' name='fd_properties' direction='in'/>
</method>
<method name='RequestDisconnection'>
<arg type='o' name='device' direction='in'/>
</method>
</interface>
</node>
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.bluez.ProfileManager1">
<method name="RegisterProfile">
<arg name="profile" type="o" direction="in" />
<arg name="UUID" type="s" direction="in" />
<arg name="options" type="a{sv}" direction="in" />
</method>
<method name="UnregisterProfile">
<arg name="profile" type="o" direction="in" />
</method>
</interface>
</node>