#include "device/bluetooth/dbus/bluetooth_profile_service_provider.h"
#include <memory>
#include <utility>
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/threading/platform_thread.h"
#include "dbus/exported_object.h"
#include "dbus/message.h"
#include "device/bluetooth/dbus/bluez_dbus_manager.h"
#include "device/bluetooth/dbus/fake_bluetooth_profile_service_provider.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
namespace bluez {
class BluetoothProfileServiceProviderImpl
: public BluetoothProfileServiceProvider {
public:
BluetoothProfileServiceProviderImpl(dbus::Bus* bus,
const dbus::ObjectPath& object_path,
Delegate* delegate)
: origin_thread_id_(base::PlatformThread::CurrentId()),
bus_(bus),
delegate_(delegate),
object_path_(object_path) {
DVLOG(1) << "Creating Bluetooth Profile: " << object_path_.value();
exported_object_ = bus_->GetExportedObject(object_path_);
exported_object_->ExportMethod(
bluetooth_profile::kBluetoothProfileInterface,
bluetooth_profile::kRelease,
base::BindRepeating(&BluetoothProfileServiceProviderImpl::Release,
weak_ptr_factory_.GetWeakPtr()),
base::BindOnce(&BluetoothProfileServiceProviderImpl::OnExported,
weak_ptr_factory_.GetWeakPtr()));
exported_object_->ExportMethod(
bluetooth_profile::kBluetoothProfileInterface,
bluetooth_profile::kNewConnection,
base::BindRepeating(&BluetoothProfileServiceProviderImpl::NewConnection,
weak_ptr_factory_.GetWeakPtr()),
base::BindOnce(&BluetoothProfileServiceProviderImpl::OnExported,
weak_ptr_factory_.GetWeakPtr()));
exported_object_->ExportMethod(
bluetooth_profile::kBluetoothProfileInterface,
bluetooth_profile::kRequestDisconnection,
base::BindRepeating(
&BluetoothProfileServiceProviderImpl::RequestDisconnection,
weak_ptr_factory_.GetWeakPtr()),
base::BindOnce(&BluetoothProfileServiceProviderImpl::OnExported,
weak_ptr_factory_.GetWeakPtr()));
exported_object_->ExportMethod(
bluetooth_profile::kBluetoothProfileInterface,
bluetooth_profile::kCancel,
base::BindRepeating(&BluetoothProfileServiceProviderImpl::Cancel,
weak_ptr_factory_.GetWeakPtr()),
base::BindOnce(&BluetoothProfileServiceProviderImpl::OnExported,
weak_ptr_factory_.GetWeakPtr()));
}
BluetoothProfileServiceProviderImpl(
const BluetoothProfileServiceProviderImpl&) = delete;
BluetoothProfileServiceProviderImpl& operator=(
const BluetoothProfileServiceProviderImpl&) = delete;
~BluetoothProfileServiceProviderImpl() override {
DVLOG(1) << "Cleaning up Bluetooth Profile: " << object_path_.value();
bus_->UnregisterExportedObject(object_path_);
}
private:
bool OnOriginThread() {
return base::PlatformThread::CurrentId() == origin_thread_id_;
}
void Release(dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender) {
DCHECK(OnOriginThread());
DCHECK(delegate_);
delegate_->Released();
std::move(response_sender).Run(dbus::Response::FromMethodCall(method_call));
}
void NewConnection(dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender) {
DCHECK(OnOriginThread());
DCHECK(delegate_);
dbus::MessageReader reader(method_call);
dbus::ObjectPath device_path;
base::ScopedFD fd;
dbus::MessageReader array_reader(NULL);
if (!reader.PopObjectPath(&device_path) || !reader.PopFileDescriptor(&fd) ||
!reader.PopArray(&array_reader)) {
LOG(WARNING) << "NewConnection called with incorrect parameters: "
<< method_call->ToString();
std::move(response_sender)
.Run(dbus::ErrorResponse::FromMethodCall(
method_call, DBUS_ERROR_INVALID_ARGS, "Incorrect parameters."));
return;
}
Delegate::Options options;
while (array_reader.HasMoreData()) {
dbus::MessageReader dict_entry_reader(NULL);
std::string key;
if (!array_reader.PopDictEntry(&dict_entry_reader) ||
!dict_entry_reader.PopString(&key)) {
LOG(WARNING) << "NewConnection called with incorrect paramters: "
<< method_call->ToString();
} else {
if (key == bluetooth_profile::kVersionProperty)
dict_entry_reader.PopVariantOfUint16(&options.version);
else if (key == bluetooth_profile::kFeaturesProperty)
dict_entry_reader.PopVariantOfUint16(&options.features);
}
}
Delegate::ConfirmationCallback callback =
base::BindOnce(&BluetoothProfileServiceProviderImpl::OnConfirmation,
weak_ptr_factory_.GetWeakPtr(), method_call,
std::move(response_sender));
delegate_->NewConnection(device_path, std::move(fd), options,
std::move(callback));
}
void RequestDisconnection(
dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender) {
DCHECK(OnOriginThread());
DCHECK(delegate_);
dbus::MessageReader reader(method_call);
dbus::ObjectPath device_path;
if (!reader.PopObjectPath(&device_path)) {
LOG(WARNING) << "RequestDisconnection called with incorrect parameters: "
<< method_call->ToString();
std::move(response_sender)
.Run(dbus::ErrorResponse::FromMethodCall(
method_call, DBUS_ERROR_INVALID_ARGS, "Incorrect parameters."));
return;
}
Delegate::ConfirmationCallback callback =
base::BindOnce(&BluetoothProfileServiceProviderImpl::OnConfirmation,
weak_ptr_factory_.GetWeakPtr(), method_call,
std::move(response_sender));
delegate_->RequestDisconnection(device_path, std::move(callback));
}
void Cancel(dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender) {
DCHECK(OnOriginThread());
DCHECK(delegate_);
delegate_->Cancel();
std::move(response_sender).Run(dbus::Response::FromMethodCall(method_call));
}
void OnExported(const std::string& interface_name,
const std::string& method_name,
bool success) {
DVLOG_IF(1, !success) << "Failed to export " << interface_name << "."
<< method_name;
}
void OnConfirmation(dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender,
Delegate::Status status) {
DCHECK(OnOriginThread());
switch (status) {
case Delegate::SUCCESS: {
std::move(response_sender)
.Run(dbus::Response::FromMethodCall(method_call));
break;
}
case Delegate::REJECTED: {
std::move(response_sender)
.Run(dbus::ErrorResponse::FromMethodCall(
method_call, bluetooth_profile::kErrorRejected, "rejected"));
break;
}
case Delegate::CANCELLED: {
std::move(response_sender)
.Run(dbus::ErrorResponse::FromMethodCall(
method_call, bluetooth_profile::kErrorCanceled, "canceled"));
break;
}
default:
NOTREACHED() << "Unexpected status code from delegate: " << status;
}
}
base::PlatformThreadId origin_thread_id_;
raw_ptr<dbus::Bus> bus_;
raw_ptr<Delegate> delegate_;
dbus::ObjectPath object_path_;
scoped_refptr<dbus::ExportedObject> exported_object_;
base::WeakPtrFactory<BluetoothProfileServiceProviderImpl> weak_ptr_factory_{
this};
};
BluetoothProfileServiceProvider::BluetoothProfileServiceProvider() = default;
BluetoothProfileServiceProvider::~BluetoothProfileServiceProvider() = default;
BluetoothProfileServiceProvider* BluetoothProfileServiceProvider::Create(
dbus::Bus* bus,
const dbus::ObjectPath& object_path,
Delegate* delegate) {
if (!bluez::BluezDBusManager::Get()->IsUsingFakes()) {
return new BluetoothProfileServiceProviderImpl(bus, object_path, delegate);
}
#if defined(USE_REAL_DBUS_CLIENTS)
LOG(FATAL) << "Fake is unavailable if USE_REAL_DBUS_CLIENTS is defined.";
#else
return new FakeBluetoothProfileServiceProvider(object_path, delegate);
#endif
}
}