#ifndef DEVICE_BLUETOOTH_FLOSS_FLOSS_DBUS_CLIENT_H_
#define DEVICE_BLUETOOTH_FLOSS_FLOSS_DBUS_CLIENT_H_
#include <map>
#include <memory>
#include <optional>
#include <ostream>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include "base/containers/contains.h"
#include "base/functional/callback.h"
#include "base/logging.h"
#include "base/no_destructor.h"
#include "base/strings/strcat.h"
#include "base/task/single_thread_task_runner.h"
#include "base/types/expected.h"
#include "dbus/bus.h"
#include "dbus/exported_object.h"
#include "dbus/message.h"
#include "dbus/object_proxy.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_export.h"
#include "device/bluetooth/floss/floss_version.h"
namespace floss {
extern DEVICE_BLUETOOTH_EXPORT int kDBusTimeoutMs;
extern DEVICE_BLUETOOTH_EXPORT int kAdapterEnabledTimeoutMs;
inline constexpr char kAdapterService[] = "org.chromium.bluetooth";
inline constexpr char kManagerService[] = "org.chromium.bluetooth.Manager";
inline constexpr char kAdapterLoggingObjectFormat[] =
"/org/chromium/bluetooth/hci%d/logging";
inline constexpr char kAdapterObjectFormat[] =
"/org/chromium/bluetooth/hci%d/adapter";
inline constexpr char kAdminObjectFormat[] =
"/org/chromium/bluetooth/hci%d/admin";
inline constexpr char kBatteryManagerObjectFormat[] =
"/org/chromium/bluetooth/hci%d/battery_manager";
inline constexpr char kBluetoothTelephonyObjectFormat[] =
"/org/chromium/bluetooth/hci%d/telephony";
inline constexpr char kGattObjectFormat[] =
"/org/chromium/bluetooth/hci%d/gatt";
inline constexpr char kManagerObject[] = "/org/chromium/bluetooth/Manager";
inline constexpr char kMediaObjectFormat[] =
"/org/chromium/bluetooth/hci%d/media";
inline constexpr char kAdapterInterface[] = "org.chromium.bluetooth.Bluetooth";
inline constexpr char kAdapterLoggingInterface[] =
"org.chromium.bluetooth.Logging";
inline constexpr char kAdminInterface[] =
"org.chromium.bluetooth.BluetoothAdmin";
inline constexpr char kBatteryManagerInterface[] =
"org.chromium.bluetooth.BatteryManager";
inline constexpr char kBluetoothTelephonyInterface[] =
"org.chromium.bluetooth.BluetoothTelephony";
inline constexpr char kExperimentalInterface[] =
"org.chromium.bluetooth.Experimental";
inline constexpr char kGattInterface[] = "org.chromium.bluetooth.BluetoothGatt";
inline constexpr char kManagerInterface[] = "org.chromium.bluetooth.Manager";
inline constexpr char kSocketManagerInterface[] =
"org.chromium.bluetooth.SocketManager";
namespace adapter {
inline constexpr char kGetAddress[] = "GetAddress";
inline constexpr char kGetName[] = "GetName";
inline constexpr char kSetName[] = "SetName";
inline constexpr char kGetDiscoverable[] = "GetDiscoverable";
inline constexpr char kGetDiscoverableTimeout[] = "GetDiscoverableTimeout";
inline constexpr char kSetDiscoverable[] = "SetDiscoverable";
inline constexpr char kIsLeExtendedAdvertisingSupported[] =
"IsLeExtendedAdvertisingSupported";
inline constexpr char kStartDiscovery[] = "StartDiscovery";
inline constexpr char kCancelDiscovery[] = "CancelDiscovery";
inline constexpr char kCreateBond[] = "CreateBond";
inline constexpr char kCancelBondProcess[] = "CancelBondProcess";
inline constexpr char kRemoveBond[] = "RemoveBond";
inline constexpr char kGetRemoteType[] = "GetRemoteType";
inline constexpr char kGetRemoteClass[] = "GetRemoteClass";
inline constexpr char kGetRemoteAppearance[] = "GetRemoteAppearance";
inline constexpr char kGetRemoteVendorProductInfo[] =
"GetRemoteVendorProductInfo";
inline constexpr char kGetRemoteAddressType[] = "GetRemoteAddressType";
inline constexpr char kGetConnectionState[] = "GetConnectionState";
inline constexpr char kGetRemoteUuids[] = "GetRemoteUuids";
inline constexpr char kFetchRemoteUuids[] = "FetchRemoteUuids";
inline constexpr char kGetBondState[] = "GetBondState";
inline constexpr char kConnectAllEnabledProfiles[] =
"ConnectAllEnabledProfiles";
inline constexpr char kDisconnectAllEnabledProfiles[] =
"DisconnectAllEnabledProfiles";
inline constexpr char kRegisterCallback[] = "RegisterCallback";
inline constexpr char kUnregisterCallback[] = "UnregisterCallback";
inline constexpr char kRegisterConnectionCallback[] =
"RegisterConnectionCallback";
inline constexpr char kUnregisterConnectionCallback[] =
"UnregisterConnectionCallback";
inline constexpr char kRegisterScanner[] = "RegisterScanner";
inline constexpr char kUnregisterScanner[] = "UnregisterScanner";
inline constexpr char kRegisterScannerCallback[] = "RegisterScannerCallback";
inline constexpr char kUnregisterScannerCallback[] =
"UnregisterScannerCallback";
inline constexpr char kStartScan[] = "StartScan";
inline constexpr char kStopScan[] = "StopScan";
inline constexpr char kSetPairingConfirmation[] = "SetPairingConfirmation";
inline constexpr char kSetPin[] = "SetPin";
inline constexpr char kSetPasskey[] = "SetPasskey";
inline constexpr char kGetBondedDevices[] = "GetBondedDevices";
inline constexpr char kGetConnectedDevices[] = "GetConnectedDevices";
inline constexpr char kSdpSearch[] = "SdpSearch";
inline constexpr char kCreateSdpRecord[] = "CreateSdpRecord";
inline constexpr char kRemoveSdpRecord[] = "RemoveSdpRecord";
inline constexpr char kGetSupportedRoles[] = "GetSupportedRoles";
inline constexpr char kCallbackInterface[] =
"org.chromium.bluetooth.BluetoothCallback";
inline constexpr char kConnectionCallbackInterface[] =
"org.chromium.bluetooth.BluetoothConnectionCallback";
inline constexpr char kOnAdapterPropertyChanged[] = "OnAdapterPropertyChanged";
inline constexpr char kOnAddressChanged[] = "OnAddressChanged";
inline constexpr char kOnNameChanged[] = "OnNameChanged";
inline constexpr char kOnDiscoverableChanged[] = "OnDiscoverableChanged";
inline constexpr char kOnDeviceFound[] = "OnDeviceFound";
inline constexpr char kOnDeviceCleared[] = "OnDeviceCleared";
inline constexpr char kOnDeviceKeyMissing[] = "OnDeviceKeyMissing";
inline constexpr char kOnDevicePropertiesChanged[] =
"OnDevicePropertiesChanged";
inline constexpr char kOnDiscoveringChanged[] = "OnDiscoveringChanged";
inline constexpr char kOnSspRequest[] = "OnSspRequest";
inline constexpr char kOnPinDisplay[] = "OnPinDisplay";
inline constexpr char kOnPinRequest[] = "OnPinRequest";
inline constexpr char kOnBondStateChanged[] = "OnBondStateChanged";
inline constexpr char kOnSdpSearchComplete[] = "OnSdpSearchComplete";
inline constexpr char kOnSdpRecordCreated[] = "OnSdpRecordCreated";
inline constexpr char kOnDeviceConnected[] = "OnDeviceConnected";
inline constexpr char kOnDeviceDisconnected[] = "OnDeviceDisconnected";
inline constexpr char kOnDeviceConnectionFailed[] = "OnDeviceConnectionFailed";
inline constexpr char kOnScannerRegistered[] = "OnScannerRegistered";
inline constexpr char kOnScanResult[] = "OnScanResult";
inline constexpr char kOnAdvertisementFound[] = "OnAdvertisementFound";
inline constexpr char kOnAdvertisementLost[] = "OnAdvertisementLost";
}
namespace manager {
inline constexpr char kStart[] = "Start";
inline constexpr char kStop[] = "Stop";
inline constexpr char kGetAdapterEnabled[] = "GetAdapterEnabled";
inline constexpr char kGetFlossEnabled[] = "GetFlossEnabled";
inline constexpr char kSetFlossEnabled[] = "SetFlossEnabled";
inline constexpr char kGetState[] = "GetState";
inline constexpr char kGetAvailableAdapters[] = "GetAvailableAdapters";
inline constexpr char kGetDefaultAdapter[] = "GetDefaultAdapter";
inline constexpr char kSetDesiredDefaultAdapter[] = "SetDesiredDefaultAdapter";
inline constexpr char kGetFlossApiVersion[] = "GetFlossApiVersion";
inline constexpr char kRegisterCallback[] = "RegisterCallback";
inline constexpr char kCallbackInterface[] =
"org.chromium.bluetooth.ManagerCallback";
inline constexpr char kOnHciDeviceChanged[] = "OnHciDeviceChanged";
inline constexpr char kOnHciEnabledChanged[] = "OnHciEnabledChanged";
inline constexpr char kOnDefaultAdapterChanged[] = "OnDefaultAdapterChanged";
}
namespace socket_manager {
inline constexpr char kRegisterCallback[] = "RegisterCallback";
inline constexpr char kUnregisterCallback[] = "UnregisterCallback";
inline constexpr char kListenUsingInsecureL2capChannel[] =
"ListenUsingInsecureL2capChannel";
inline constexpr char kListenUsingInsecureL2capLeChannel[] =
"ListenUsingInsecureL2capLeChannel";
inline constexpr char kListenUsingInsecureRfcommWithServiceRecord[] =
"ListenUsingInsecureRfcommWithServiceRecord";
inline constexpr char kListenUsingL2capChannel[] = "ListenUsingL2capChannel";
inline constexpr char kListenUsingL2capLeChannel[] =
"ListenUsingL2capLeChannel";
inline constexpr char kListenUsingRfcomm[] = "ListenUsingRfcomm";
inline constexpr char kListenUsingRfcommWithServiceRecord[] =
"ListenUsingRfcommWithServiceRecord";
inline constexpr char kCreateInsecureL2capChannel[] =
"CreateInsecureL2capChannel";
inline constexpr char kCreateInsecureL2capLeChannel[] =
"CreateInsecureL2capLeChannel";
inline constexpr char kCreateInsecureRfcommSocketToServiceRecord[] =
"CreateInsecureRfcommSocketToServiceRecord";
inline constexpr char kCreateL2capChannel[] = "CreateL2capChannel";
inline constexpr char kCreateL2capLeChannel[] = "CreateL2capLeChannel";
inline constexpr char kCreateRfcommSocketToServiceRecord[] =
"CreateRfcommSocketToServiceRecord";
inline constexpr char kAccept[] = "Accept";
inline constexpr char kClose[] = "Close";
inline constexpr char kCallbackInterface[] =
"org.chromium.bluetooth.SocketManagerCallback";
inline constexpr char kOnIncomingSocketReady[] = "OnIncomingSocketReady";
inline constexpr char kOnIncomingSocketClosed[] = "OnIncomingSocketClosed";
inline constexpr char kOnHandleIncomingConnection[] =
"OnHandleIncomingConnection";
inline constexpr char kOnOutgoingConnectionResult[] =
"OnOutgoingConnectionResult";
}
namespace gatt {
inline constexpr char kRegisterClient[] = "RegisterClient";
inline constexpr char kUnregisterClient[] = "UnregisterClient";
inline constexpr char kClientConnect[] = "ClientConnect";
inline constexpr char kClientDisconnect[] = "ClientDisconnect";
inline constexpr char kRefreshDevice[] = "RefreshDevice";
inline constexpr char kDiscoverServices[] = "DiscoverServices";
inline constexpr char kDiscoverServiceByUuid[] = "DiscoverServiceByUuid";
inline constexpr char kReadCharacteristic[] = "ReadCharacteristic";
inline constexpr char kReadUsingCharacteristicUuid[] =
"ReadUsingCharacteristicUuid";
inline constexpr char kWriteCharacteristic[] = "WriteCharacteristic";
inline constexpr char kReadDescriptor[] = "ReadDescriptor";
inline constexpr char kWriteDescriptor[] = "WriteDescriptor";
inline constexpr char kRegisterForNotification[] = "RegisterForNotification";
inline constexpr char kBeginReliableWrite[] = "BeginReliableWrite";
inline constexpr char kEndReliableWrite[] = "EndReliableWrite";
inline constexpr char kReadRemoteRssi[] = "ReadRemoteRssi";
inline constexpr char kConfigureMtu[] = "ConfigureMtu";
inline constexpr char kConnectionParameterUpdate[] =
"ConnectionParameterUpdate";
inline constexpr char kCallbackInterface[] =
"org.chromium.bluetooth.BluetoothGattCallback";
inline constexpr char kServerCallbackInterface[] =
"org.chromium.bluetooth.BluetoothGattServerCallback";
inline constexpr char kOnClientRegistered[] = "OnClientRegistered";
inline constexpr char kOnClientConnectionState[] = "OnClientConnectionState";
inline constexpr char kOnPhyUpdate[] = "OnPhyUpdate";
inline constexpr char kOnPhyRead[] = "OnPhyRead";
inline constexpr char kOnSearchComplete[] = "OnSearchComplete";
inline constexpr char kOnCharacteristicRead[] = "OnCharacteristicRead";
inline constexpr char kOnCharacteristicWrite[] = "OnCharacteristicWrite";
inline constexpr char kOnExecuteWrite[] = "OnExecuteWrite";
inline constexpr char kOnDescriptorRead[] = "OnDescriptorRead";
inline constexpr char kOnDescriptorWrite[] = "OnDescriptorWrite";
inline constexpr char kOnNotify[] = "OnNotify";
inline constexpr char kOnReadRemoteRssi[] = "OnReadRemoteRssi";
inline constexpr char kOnConfigureMtu[] = "OnConfigureMtu";
inline constexpr char kOnConnectionUpdated[] = "OnConnectionUpdated";
inline constexpr char kOnServiceChanged[] = "OnServiceChanged";
inline constexpr char kRegisterServer[] = "RegisterServer";
inline constexpr char kUnregisterServer[] = "UnregisterServer";
inline constexpr char kServerConnect[] = "ServerConnect";
inline constexpr char kServerDisconnect[] = "ServerDisconnect";
inline constexpr char kServerSetPreferredPhy[] = "ServerSetPreferredPhy";
inline constexpr char kServerReadPhy[] = "ServerReadPhy";
inline constexpr char kAddService[] = "AddService";
inline constexpr char kRemoveService[] = "RemoveService";
inline constexpr char kClearServices[] = "ClearServices";
inline constexpr char kSendResponse[] = "SendResponse";
inline constexpr char kServerSendNotification[] = "SendNotification";
inline constexpr char kOnServerRegistered[] = "OnServerRegistered";
inline constexpr char kOnServerConnectionState[] = "OnServerConnectionState";
inline constexpr char kOnServerServiceAdded[] = "OnServiceAdded";
inline constexpr char kOnServerServiceRemoved[] = "OnServiceRemoved";
inline constexpr char kOnServerCharacteristicReadRequest[] =
"OnCharacteristicReadRequest";
inline constexpr char kOnServerDescriptorReadRequest[] =
"OnDescriptorReadRequest";
inline constexpr char kOnServerCharacteristicWriteRequest[] =
"OnCharacteristicWriteRequest";
inline constexpr char kOnServerDescriptorWriteRequest[] =
"OnDescriptorWriteRequest";
inline constexpr char kOnServerNotificationSent[] = "OnNotificationSent";
inline constexpr char kOnServerMtuChanged[] = "OnMtuChanged";
inline constexpr char kOnServerSubrateChange[] = "OnSubrateChange";
}
namespace advertiser {
inline constexpr char kRegisterCallback[] = "RegisterAdvertiserCallback";
inline constexpr char kUnregisterCallback[] = "UnregisterAdvertiserCallback";
inline constexpr char kStartAdvertisingSet[] = "StartAdvertisingSet";
inline constexpr char kStopAdvertisingSet[] = "StopAdvertisingSet";
inline constexpr char kGetOwnAddress[] = "GetOwnAddress";
inline constexpr char kEnableAdvertisingSet[] = "EnableAdvertisingSet";
inline constexpr char kSetAdvertisingData[] = "SetAdvertisingData";
inline constexpr char kSetScanResponseData[] = "SetScanResponseData";
inline constexpr char kSetAdvertisingParameters[] = "SetAdvertisingParameters";
inline constexpr char kSetPeriodicAdvertisingParameters[] =
"SetPeriodicAdvertisingParameters";
inline constexpr char kSetPeriodicAdvertisingData[] =
"SetPeriodicAdvertisingData";
inline constexpr char kSetPeriodicAdvertisingEnable[] =
"SetPeriodicAdvertisingEnable";
inline constexpr char kCallbackInterface[] =
"org.chromium.bluetooth.AdvertisingSetCallback";
inline constexpr char kOnAdvertisingSetStarted[] = "OnAdvertisingSetStarted";
inline constexpr char kOnOwnAddressRead[] = "OnOwnAddressRead";
inline constexpr char kOnAdvertisingSetStopped[] = "OnAdvertisingSetStopped";
inline constexpr char kOnAdvertisingEnabled[] = "OnAdvertisingEnabled";
inline constexpr char kOnAdvertisingDataSet[] = "OnAdvertisingDataSet";
inline constexpr char kOnScanResponseDataSet[] = "OnScanResponseDataSet";
inline constexpr char kOnAdvertisingParametersUpdated[] =
"OnAdvertisingParametersUpdated";
inline constexpr char kOnPeriodicAdvertisingParametersUpdated[] =
"OnPeriodicAdvertisingParametersUpdated";
inline constexpr char kOnPeriodicAdvertisingDataSet[] =
"OnPeriodicAdvertisingDataSet";
inline constexpr char kOnPeriodicAdvertisingEnabled[] =
"OnPeriodicAdvertisingEnabled";
}
namespace battery_manager {
inline constexpr char kCallbackInterface[] =
"org.chromium.bluetooth.BatteryManagerCallback";
inline constexpr char kRegisterBatteryCallback[] = "RegisterBatteryCallback";
inline constexpr char kUnregisterBatteryCallback[] =
"UnregisterBatteryCallback";
inline constexpr char kGetBatteryInformation[] = "GetBatteryInformation";
inline constexpr char kOnBatteryInfoUpdated[] = "OnBatteryInfoUpdated";
}
namespace bluetooth_telephony {
inline constexpr char kSetPhoneOpsEnabled[] = "SetPhoneOpsEnabled";
}
namespace admin {
inline constexpr char kRegisterCallback[] = "RegisterAdminPolicyCallback";
inline constexpr char kUnregisterCallback[] = "UnregisterAdminPolicyCallback";
inline constexpr char kCallbackInterface[] =
"org.chromium.bluetooth.AdminPolicyCallback";
inline constexpr char kOnServiceAllowlistChanged[] =
"OnServiceAllowlistChanged";
inline constexpr char kOnDevicePolicyEffectChanged[] =
"OnDevicePolicyEffectChanged";
inline constexpr char kSetAllowedServices[] = "SetAllowedServices";
inline constexpr char kGetAllowedServices[] = "GetAllowedServices";
inline constexpr char kGetDevicePolicyEffect[] = "GetDevicePolicyEffect";
inline constexpr char kSetSimpleSecurePairingEnabled[] = "SetAcceptSspRequest";
}
namespace adapter_logging {
inline constexpr char kIsDebugEnabled[] = "IsDebugEnabled";
inline constexpr char kSetDebugLogging[] = "SetDebugLogging";
}
namespace experimental {
inline constexpr char kSetLLPrivacy[] = "SetLLPrivacy";
}
struct DEVICE_BLUETOOTH_EXPORT FlossDeviceId {
std::string address;
std::string name;
inline bool operator==(const FlossDeviceId& rhs) const {
return address == rhs.address && name == rhs.name;
}
friend std::ostream& operator<<(std::ostream& os, const FlossDeviceId& id) {
return os << "FlossDeviceId(" << id.address << ", " << id.name << ")";
}
static const char kDeviceIdNameKey[];
static const char kDeviceIdAddressKey[];
};
struct DEVICE_BLUETOOTH_EXPORT Error {
Error(const std::string& name, const std::string& message);
friend std::ostream& operator<<(std::ostream& os, const Error& error);
std::string ToString();
std::string name;
std::string message;
};
struct DEVICE_BLUETOOTH_EXPORT Void {};
template <typename T>
using DBusResult = base::expected<T, Error>;
template <typename T>
using ResponseCallback = base::OnceCallback<void(DBusResult<T>)>;
template <typename T>
class WeaklyOwnedCallback {
public:
explicit WeaklyOwnedCallback(base::OnceCallback<void(T)> cb)
: cb_(std::move(cb)) {}
~WeaklyOwnedCallback() = default;
static std::unique_ptr<WeaklyOwnedCallback> Create(
base::OnceCallback<void(T)> cb) {
return std::make_unique<WeaklyOwnedCallback>(std::move(cb));
}
static std::unique_ptr<WeaklyOwnedCallback> CreateWithTimeout(
base::OnceCallback<void(T)> cb,
int timeout_ms,
T error_ret) {
std::unique_ptr<WeaklyOwnedCallback> self = Create(std::move(cb));
self->PostDelayed(timeout_ms, error_ret);
return self;
}
void Run(T ret) {
if (cb_) {
std::move(cb_).Run(std::move(ret));
}
}
base::WeakPtr<WeaklyOwnedCallback> GetWeakPtr() const {
return weak_ptr_factory_.GetWeakPtr();
}
private:
void PostDelayed(int timeout_ms, T error_ret) {
base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&WeaklyOwnedCallback<T>::Run,
weak_ptr_factory_.GetWeakPtr(), error_ret),
base::Milliseconds(timeout_ms));
}
base::OnceCallback<void(T)> cb_;
base::WeakPtrFactory<WeaklyOwnedCallback> weak_ptr_factory_{this};
};
template <typename T>
using WeaklyOwnedResponseCallback = WeaklyOwnedCallback<DBusResult<T>>;
struct DBusTypeInfo {
const std::string dbus_signature;
const std::string type_name;
};
template <typename T>
DEVICE_BLUETOOTH_EXPORT const DBusTypeInfo& GetDBusTypeInfo(const T*);
template <typename T>
const DBusTypeInfo& GetDBusTypeInfo(const std::vector<T>*) {
static const base::NoDestructor<DBusTypeInfo> elem_info(
GetDBusTypeInfo(static_cast<T*>(nullptr)));
static const base::NoDestructor<DBusTypeInfo> info{
{base::StrCat({"a", elem_info->dbus_signature}),
base::StrCat({"vector<", elem_info->type_name, ">"})}};
return *info;
}
template <typename T, typename U>
const DBusTypeInfo& GetDBusTypeInfo(const std::map<T, U>*) {
static const base::NoDestructor<DBusTypeInfo> key_info(
GetDBusTypeInfo(static_cast<T*>(nullptr)));
static const base::NoDestructor<DBusTypeInfo> val_info(
GetDBusTypeInfo(static_cast<U*>(nullptr)));
static const base::NoDestructor<DBusTypeInfo> info{
{base::StrCat(
{"a{", key_info->dbus_signature, val_info->dbus_signature, "}"}),
base::StrCat(
{"map<", key_info->type_name, ", ", val_info->type_name, ">"})}};
return *info;
}
template <typename T>
const DBusTypeInfo& GetDBusTypeInfo(const std::optional<T>*) {
static const base::NoDestructor<DBusTypeInfo> elem_info(
GetDBusTypeInfo(static_cast<T*>(nullptr)));
static const base::NoDestructor<DBusTypeInfo> info{
{"a{sv}", base::StrCat({"optional<", elem_info->type_name, ">"})}};
return *info;
}
class DEVICE_BLUETOOTH_EXPORT FlossDBusClient {
public:
enum class BtifStatus : uint32_t {
kSuccess = 0,
kFail,
kNotReady,
kNomem,
kBusy,
kDone,
kUnsupported,
kParmInvalid,
kUnhandled,
kAuthFailure,
kRmtDevDown,
kAuthRejected,
kJniEnvironmentError,
kJniThreadAttachError,
kWakelockError,
kTimeout,
kDeviceNotFound,
kUnexpectedState,
kSocketError,
};
enum class BluetoothTransport {
kAuto = 0,
kBrEdr = 1,
kLe = 2,
};
static const char kErrorDBus[];
static const char kErrorNoResponse[];
static const char kErrorInvalidParameters[];
static const char kErrorInvalidReturn[];
static const char kOptionalValueKey[];
static const char DEVICE_BLUETOOTH_EXPORT kErrorDoesNotExist[];
static dbus::ObjectPath GenerateAdapterPath(int adapter_index);
static dbus::ObjectPath GenerateGattPath(int adapter_index);
static dbus::ObjectPath GenerateBatteryManagerPath(int adapter_index);
static dbus::ObjectPath GenerateBluetoothTelephonyPath(int adapter_index);
static dbus::ObjectPath GenerateAdminPath(int adapter_index);
static dbus::ObjectPath GenerateLoggingPath(int adapter_index);
static device::BluetoothDevice::ConnectErrorCode BtifStatusToConnectErrorCode(
FlossDBusClient::BtifStatus status);
template <typename T>
static void WriteDBusParam(dbus::MessageWriter* writer, const T& data);
template <typename T>
static void WriteDBusParamIntoVariant(dbus::MessageWriter* writer,
const T& data) {
dbus::MessageWriter variant(nullptr);
writer->OpenVariant(GetDBusTypeInfo(&data).dbus_signature, &variant);
WriteDBusParam(&variant, data);
writer->CloseContainer(&variant);
}
template <typename T>
static void WriteDBusParam(dbus::MessageWriter* writer,
const std::vector<T>& value) {
dbus::MessageWriter array_writer(nullptr);
writer->OpenArray(GetDBusTypeInfo(static_cast<T*>(nullptr)).dbus_signature,
&array_writer);
for (const auto& entry : value) {
WriteDBusParam<>(&array_writer, entry);
}
writer->CloseContainer(&array_writer);
}
template <typename T, typename U>
static void WriteDBusParam(dbus::MessageWriter* writer,
const std::map<T, U>& data) {
std::string signature = base::StrCat(
{"{", GetDBusTypeInfo(static_cast<T*>(nullptr)).dbus_signature,
GetDBusTypeInfo(static_cast<U*>(nullptr)).dbus_signature, "}"});
dbus::MessageWriter array(nullptr);
writer->OpenArray(signature, &array);
for (auto const& [key, val] : data) {
dbus::MessageWriter dict(nullptr);
array.OpenDictEntry(&dict);
WriteDBusParam<>(&dict, key);
WriteDBusParam<>(&dict, val);
array.CloseContainer(&dict);
}
writer->CloseContainer(&array);
}
static void WriteDBusParam(dbus::MessageWriter* writer,
base::span<const uint8_t> value) {
writer->AppendArrayOfBytes(value);
}
template <typename T>
static void WriteDBusParam(dbus::MessageWriter* writer,
const std::optional<T>& data) {
dbus::MessageWriter array(nullptr);
dbus::MessageWriter dict(nullptr);
writer->OpenArray("{sv}", &array);
if (data) {
array.OpenDictEntry(&dict);
dict.AppendString(kOptionalValueKey);
WriteDBusParamIntoVariant<T>(&dict, *data);
array.CloseContainer(&dict);
}
writer->CloseContainer(&array);
}
template <typename T>
static void WriteDBusParamIntoVariant(dbus::MessageWriter* writer,
const std::optional<T>& data) {
dbus::MessageWriter variant(nullptr);
writer->OpenVariant("a{sv}", &variant);
WriteDBusParam(&variant, data);
writer->CloseContainer(&variant);
}
static void WriteAllDBusParams(dbus::MessageWriter* writer) {}
template <typename T, typename... Args>
static void WriteAllDBusParams(dbus::MessageWriter* writer,
const T& first,
const Args&... args) {
WriteDBusParam(writer, first);
WriteAllDBusParams(writer, args...);
}
template <typename T>
static void WriteDictEntry(dbus::MessageWriter* writer,
const std::string& key,
const T& value) {
dbus::MessageWriter dict(nullptr);
writer->OpenDictEntry(&dict);
dict.AppendString(key);
WriteDBusParamIntoVariant(&dict, value);
writer->CloseContainer(&dict);
}
template <typename T>
static bool ReadDBusParam(dbus::MessageReader* reader, T* value);
template <typename T>
static bool ReadDBusParamFromVariant(dbus::MessageReader* reader, T* value) {
dbus::MessageReader variant_reader(nullptr);
if (!reader->PopVariant(&variant_reader)) {
return false;
}
return ReadDBusParam(&variant_reader, value);
}
template <typename T>
static bool ReadDBusParam(dbus::MessageReader* reader,
std::vector<T>* value) {
dbus::MessageReader subreader(nullptr);
if (!reader->PopArray(&subreader))
return false;
while (subreader.HasMoreData()) {
T element;
if (!ReadDBusParam<>(&subreader, &element))
return false;
value->emplace_back(std::move(element));
}
return true;
}
template <typename T, typename U>
static bool ReadDBusParam(dbus::MessageReader* reader, std::map<T, U>* data) {
dbus::MessageReader array_reader(nullptr);
if (!reader->PopArray(&array_reader))
return false;
while (array_reader.HasMoreData()) {
dbus::MessageReader dict_entry_reader(nullptr);
if (!array_reader.PopDictEntry(&dict_entry_reader))
return false;
T key;
U value;
if (!ReadDBusParam<>(&dict_entry_reader, &key) ||
!ReadDBusParam<>(&dict_entry_reader, &value))
return false;
data->insert({key, value});
}
return true;
}
template <typename T>
static bool ReadDBusParam(dbus::MessageReader* reader,
std::optional<T>* value) {
dbus::MessageReader array(nullptr);
dbus::MessageReader dict(nullptr);
T inner;
if (!reader->PopArray(&array)) {
return false;
}
while (array.PopDictEntry(&dict)) {
std::string key;
dict.PopString(&key);
if (key == kOptionalValueKey) {
if (!ReadDBusParamFromVariant<T>(&dict, &inner)) {
return false;
}
*value = std::move(std::optional<T>(std::move(inner)));
}
}
return true;
}
static bool ReadAllDBusParams(dbus::MessageReader* reader) { return true; }
template <typename T, typename... Args>
static bool ReadAllDBusParams(dbus::MessageReader* reader,
T* first,
Args*... args) {
return ReadDBusParam(reader, first) && ReadAllDBusParams(reader, args...);
}
template <typename T>
using FieldReader = std::function<bool(dbus::MessageReader*, T* data)>;
template <typename T>
class StructReader {
private:
std::unordered_map<std::string, FieldReader<T>> fields_;
public:
explicit StructReader(
std::vector<std::pair<std::string, FieldReader<T>>> fields) {
for (auto const& kv : fields) {
fields_.insert(kv);
}
}
bool ReadDBusParam(dbus::MessageReader* reader, T* data) {
std::unordered_set<std::string> parsed_fields;
dbus::MessageReader array_reader(nullptr);
if (!reader->PopArray(&array_reader))
return false;
while (array_reader.HasMoreData()) {
dbus::MessageReader entry_reader(nullptr);
if (!array_reader.PopDictEntry(&entry_reader))
return false;
std::string key;
if (!entry_reader.PopString(&key))
return false;
if (base::Contains(fields_, key)) {
dbus::MessageReader variant_reader(nullptr);
entry_reader.PopVariant(&variant_reader);
if (!fields_[key](&variant_reader, data))
return false;
if (base::Contains(parsed_fields, key))
return false;
parsed_fields.insert(key);
} else {
DBusTypeInfo type_info = GetDBusTypeInfo(data);
VLOG(3) << "Does not know how to read field " << type_info.type_name
<< "." << key;
}
}
return parsed_fields.size() == fields_.size();
}
};
template <typename S, typename T>
static FieldReader<S> CreateFieldReader(T S::*field) {
return [field](dbus::MessageReader* reader, S* container) -> bool {
return FlossDBusClient::ReadDBusParam(reader, &(container->*field));
};
}
template <typename R, typename... Args>
void CallMethod(ResponseCallback<R> callback,
dbus::Bus* bus,
const std::string& service_name,
const std::string& interface_name,
const dbus::ObjectPath& object_path,
const char* method_name,
Args... args) {
if (bus == nullptr) {
LOG(ERROR) << "D-Bus is not initialized, cannot call method "
<< method_name << " on " << object_path.value();
std::move(callback).Run(base::unexpected(
Error(std::string(kErrorDBus), "DBus not initialized")));
return;
}
dbus::ObjectProxy* object_proxy =
bus->GetObjectProxy(service_name, object_path);
if (!object_proxy) {
VLOG(1) << "Object proxy does not exist when trying to call "
<< method_name;
std::move(callback).Run(base::unexpected(
Error(std::string(kErrorDBus), "Invalid object proxy")));
return;
}
dbus::MethodCall method_call(interface_name, method_name);
dbus::MessageWriter writer(&method_call);
FlossDBusClient::WriteAllDBusParams(&writer, args...);
object_proxy->CallMethodWithErrorResponse(
&method_call, kDBusTimeoutMs,
base::BindOnce(&FlossDBusClient::DefaultResponseWithCallback<R>,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
FlossDBusClient(const FlossDBusClient&) = delete;
FlossDBusClient& operator=(const FlossDBusClient&) = delete;
virtual void Init(dbus::Bus* bus,
const std::string& bluetooth_service_name,
const int adapter_index,
base::Version version,
base::OnceClosure on_ready) = 0;
protected:
static Error ErrorResponseToError(const std::string& default_name,
const std::string& default_message,
dbus::ErrorResponse* error);
FlossDBusClient();
virtual ~FlossDBusClient();
void LogErrorResponse(const std::string& message, dbus::ErrorResponse* error);
template <typename T>
void DefaultResponseWithCallback(ResponseCallback<T> callback,
dbus::Response* response,
dbus::ErrorResponse* error_response) {
if (response) {
T ret;
dbus::MessageReader reader(response);
if (!FlossDBusClient::ReadAllDBusParams<T>(&reader, &ret)) {
LOG(ERROR) << "Failed reading return from response";
std::move(callback).Run(
base::unexpected(Error(kErrorInvalidReturn, "")));
return;
}
std::move(callback).Run(ret);
return;
}
std::move(callback).Run(base::unexpected(ErrorResponseToError(
kErrorNoResponse, std::string(), error_response)));
}
void DefaultResponse(const std::string& caller,
dbus::Response* response,
dbus::ErrorResponse* error_response);
base::Version version_;
private:
base::WeakPtrFactory<FlossDBusClient> weak_ptr_factory_{this};
};
template <typename T>
class FlossProperty {
public:
FlossProperty(const char* interface,
const char* callback_interface,
const char* getter,
const char* on_update)
: interface_(interface),
callback_interface_(callback_interface),
getter_(getter),
on_update_(on_update) {}
void Init(FlossDBusClient* client,
dbus::Bus* bus,
const std::string& service_name,
const dbus::ObjectPath& path,
const dbus::ObjectPath& callback_path,
base::RepeatingCallback<void(const T&)> update_callback) {
update_callback_ = update_callback;
client->CallMethod(base::BindOnce(&FlossProperty::OnGetInitialValue,
weak_ptr_factory_.GetWeakPtr()),
bus, service_name, interface_, path, getter_);
if (!on_update_) {
return;
}
dbus::ExportedObject* exported_object =
bus->GetExportedObject(callback_path);
if (!exported_object) {
LOG(ERROR) << "Could not export callback to listen for property updates"
<< callback_path.value();
return;
}
exported_object->ExportMethod(
callback_interface_, on_update_,
base::BindRepeating(&FlossProperty::OnValueUpdated,
weak_ptr_factory_.GetWeakPtr()),
base::DoNothing());
}
const T& Get() const { return value_; }
private:
void OnGetInitialValue(DBusResult<T> ret) {
if (!ret.has_value()) {
LOG(ERROR) << "Error getting initial value";
return;
}
UpdateValue(std::move(*ret));
}
void OnValueUpdated(dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender) {
T data;
dbus::MessageReader reader(method_call);
if (!FlossDBusClient::ReadDBusParam(&reader, &data)) {
std::move(response_sender)
.Run(dbus::ErrorResponse::FromMethodCall(
method_call, floss::FlossDBusClient::kErrorInvalidParameters,
"Error parsing property value"));
return;
}
UpdateValue(std::move(data));
std::move(response_sender).Run(dbus::Response::FromMethodCall(method_call));
}
void UpdateValue(T val) {
value_ = std::move(val);
update_callback_.Run(value_);
}
const char* interface_;
const char* callback_interface_;
const char* getter_;
const char* on_update_;
T value_ = T();
base::RepeatingCallback<void(const T&)> update_callback_;
base::WeakPtrFactory<FlossProperty> weak_ptr_factory_{this};
};
}
#endif