#include "device/bluetooth/dbus/bluetooth_agent_service_provider.h"
#include <memory>
#include <utility>
#include "base/functional/bind.h"
#include "base/functional/callback.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_agent_service_provider.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
namespace bluez {
namespace {
using Delegate = BluetoothAgentServiceProvider::Delegate;
void OnPinCode(base::PlatformThreadId origin_thread_id,
dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender,
Delegate::Status status,
const std::string& pincode) {
DCHECK_EQ(origin_thread_id, base::PlatformThread::CurrentId());
switch (status) {
case Delegate::SUCCESS: {
std::unique_ptr<dbus::Response> response(
dbus::Response::FromMethodCall(method_call));
dbus::MessageWriter writer(response.get());
writer.AppendString(pincode);
std::move(response_sender).Run(std::move(response));
break;
}
case Delegate::REJECTED: {
std::move(response_sender)
.Run(dbus::ErrorResponse::FromMethodCall(
method_call, bluetooth_agent::kErrorRejected, "rejected"));
break;
}
case Delegate::CANCELLED: {
std::move(response_sender)
.Run(dbus::ErrorResponse::FromMethodCall(
method_call, bluetooth_agent::kErrorCanceled, "canceled"));
break;
}
default:
NOTREACHED() << "Unexpected status code from delegate: " << status;
}
}
void OnPasskey(base::PlatformThreadId origin_thread_id,
dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender,
Delegate::Status status,
uint32_t passkey) {
DCHECK_EQ(origin_thread_id, base::PlatformThread::CurrentId());
switch (status) {
case Delegate::SUCCESS: {
std::unique_ptr<dbus::Response> response(
dbus::Response::FromMethodCall(method_call));
dbus::MessageWriter writer(response.get());
writer.AppendUint32(passkey);
std::move(response_sender).Run(std::move(response));
break;
}
case Delegate::REJECTED: {
std::move(response_sender)
.Run(dbus::ErrorResponse::FromMethodCall(
method_call, bluetooth_agent::kErrorRejected, "rejected"));
break;
}
case Delegate::CANCELLED: {
std::move(response_sender)
.Run(dbus::ErrorResponse::FromMethodCall(
method_call, bluetooth_agent::kErrorCanceled, "canceled"));
break;
}
default:
NOTREACHED() << "Unexpected status code from delegate: " << status;
}
}
void OnConfirmation(base::PlatformThreadId origin_thread_id,
dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender,
Delegate::Status status) {
DCHECK_EQ(origin_thread_id, base::PlatformThread::CurrentId());
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_agent::kErrorRejected, "rejected"));
break;
}
case Delegate::CANCELLED: {
std::move(response_sender)
.Run(dbus::ErrorResponse::FromMethodCall(
method_call, bluetooth_agent::kErrorCanceled, "canceled"));
break;
}
default:
NOTREACHED() << "Unexpected status code from delegate: " << status;
}
}
}
class BluetoothAgentServiceProviderImpl : public BluetoothAgentServiceProvider {
public:
BluetoothAgentServiceProviderImpl(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 Agent: " << object_path_.value();
exported_object_ = bus_->GetExportedObject(object_path_);
exported_object_->ExportMethod(
bluetooth_agent::kBluetoothAgentInterface, bluetooth_agent::kRelease,
base::BindRepeating(&BluetoothAgentServiceProviderImpl::Release,
weak_ptr_factory_.GetWeakPtr()),
base::BindOnce(&BluetoothAgentServiceProviderImpl::OnExported,
weak_ptr_factory_.GetWeakPtr()));
exported_object_->ExportMethod(
bluetooth_agent::kBluetoothAgentInterface,
bluetooth_agent::kRequestPinCode,
base::BindRepeating(&BluetoothAgentServiceProviderImpl::RequestPinCode,
weak_ptr_factory_.GetWeakPtr()),
base::BindOnce(&BluetoothAgentServiceProviderImpl::OnExported,
weak_ptr_factory_.GetWeakPtr()));
exported_object_->ExportMethod(
bluetooth_agent::kBluetoothAgentInterface,
bluetooth_agent::kDisplayPinCode,
base::BindRepeating(&BluetoothAgentServiceProviderImpl::DisplayPinCode,
weak_ptr_factory_.GetWeakPtr()),
base::BindOnce(&BluetoothAgentServiceProviderImpl::OnExported,
weak_ptr_factory_.GetWeakPtr()));
exported_object_->ExportMethod(
bluetooth_agent::kBluetoothAgentInterface,
bluetooth_agent::kRequestPasskey,
base::BindRepeating(&BluetoothAgentServiceProviderImpl::RequestPasskey,
weak_ptr_factory_.GetWeakPtr()),
base::BindOnce(&BluetoothAgentServiceProviderImpl::OnExported,
weak_ptr_factory_.GetWeakPtr()));
exported_object_->ExportMethod(
bluetooth_agent::kBluetoothAgentInterface,
bluetooth_agent::kDisplayPasskey,
base::BindRepeating(&BluetoothAgentServiceProviderImpl::DisplayPasskey,
weak_ptr_factory_.GetWeakPtr()),
base::BindOnce(&BluetoothAgentServiceProviderImpl::OnExported,
weak_ptr_factory_.GetWeakPtr()));
exported_object_->ExportMethod(
bluetooth_agent::kBluetoothAgentInterface,
bluetooth_agent::kRequestConfirmation,
base::BindRepeating(
&BluetoothAgentServiceProviderImpl::RequestConfirmation,
weak_ptr_factory_.GetWeakPtr()),
base::BindOnce(&BluetoothAgentServiceProviderImpl::OnExported,
weak_ptr_factory_.GetWeakPtr()));
exported_object_->ExportMethod(
bluetooth_agent::kBluetoothAgentInterface,
bluetooth_agent::kRequestAuthorization,
base::BindRepeating(
&BluetoothAgentServiceProviderImpl::RequestAuthorization,
weak_ptr_factory_.GetWeakPtr()),
base::BindOnce(&BluetoothAgentServiceProviderImpl::OnExported,
weak_ptr_factory_.GetWeakPtr()));
exported_object_->ExportMethod(
bluetooth_agent::kBluetoothAgentInterface,
bluetooth_agent::kAuthorizeService,
base::BindRepeating(
&BluetoothAgentServiceProviderImpl::AuthorizeService,
weak_ptr_factory_.GetWeakPtr()),
base::BindOnce(&BluetoothAgentServiceProviderImpl::OnExported,
weak_ptr_factory_.GetWeakPtr()));
exported_object_->ExportMethod(
bluetooth_agent::kBluetoothAgentInterface, bluetooth_agent::kCancel,
base::BindRepeating(&BluetoothAgentServiceProviderImpl::Cancel,
weak_ptr_factory_.GetWeakPtr()),
base::BindOnce(&BluetoothAgentServiceProviderImpl::OnExported,
weak_ptr_factory_.GetWeakPtr()));
}
BluetoothAgentServiceProviderImpl(const BluetoothAgentServiceProviderImpl&) =
delete;
BluetoothAgentServiceProviderImpl& operator=(
const BluetoothAgentServiceProviderImpl&) = delete;
~BluetoothAgentServiceProviderImpl() override {
DVLOG(1) << "Cleaning up Bluetooth Agent: " << 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 RequestPinCode(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) << "RequestPinCode 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::PinCodeCallback callback = base::BindOnce(
&OnPinCode, origin_thread_id_, method_call, std::move(response_sender));
delegate_->RequestPinCode(device_path, std::move(callback));
}
void DisplayPinCode(dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender) {
DCHECK(OnOriginThread());
DCHECK(delegate_);
dbus::MessageReader reader(method_call);
dbus::ObjectPath device_path;
std::string pincode;
if (!reader.PopObjectPath(&device_path) || !reader.PopString(&pincode)) {
LOG(WARNING) << "DisplayPinCode 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_->DisplayPinCode(device_path, pincode);
std::move(response_sender).Run(dbus::Response::FromMethodCall(method_call));
}
void RequestPasskey(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) << "RequestPasskey 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::PasskeyCallback callback = base::BindOnce(
&OnPasskey, origin_thread_id_, method_call, std::move(response_sender));
delegate_->RequestPasskey(device_path, std::move(callback));
}
void DisplayPasskey(dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender) {
DCHECK(OnOriginThread());
DCHECK(delegate_);
dbus::MessageReader reader(method_call);
dbus::ObjectPath device_path;
uint32_t passkey;
uint16_t entered;
if (!reader.PopObjectPath(&device_path) || !reader.PopUint32(&passkey) ||
!reader.PopUint16(&entered)) {
LOG(WARNING) << "DisplayPasskey 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_->DisplayPasskey(device_path, passkey, entered);
std::move(response_sender).Run(dbus::Response::FromMethodCall(method_call));
}
void RequestConfirmation(
dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender) {
DCHECK(OnOriginThread());
DCHECK(delegate_);
dbus::MessageReader reader(method_call);
dbus::ObjectPath device_path;
uint32_t passkey;
if (!reader.PopObjectPath(&device_path) || !reader.PopUint32(&passkey)) {
LOG(WARNING) << "RequestConfirmation 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(&OnConfirmation, origin_thread_id_, method_call,
std::move(response_sender));
delegate_->RequestConfirmation(device_path, passkey, std::move(callback));
}
void RequestAuthorization(
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) << "RequestAuthorization 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(&OnConfirmation, origin_thread_id_, method_call,
std::move(response_sender));
delegate_->RequestAuthorization(device_path, std::move(callback));
}
void AuthorizeService(dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender) {
DCHECK(OnOriginThread());
DCHECK(delegate_);
dbus::MessageReader reader(method_call);
dbus::ObjectPath device_path;
std::string uuid;
if (!reader.PopObjectPath(&device_path) || !reader.PopString(&uuid)) {
LOG(WARNING) << "AuthorizeService 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(&OnConfirmation, origin_thread_id_, method_call,
std::move(response_sender));
delegate_->AuthorizeService(device_path, uuid, 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;
}
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<BluetoothAgentServiceProviderImpl> weak_ptr_factory_{
this};
};
BluetoothAgentServiceProvider::BluetoothAgentServiceProvider() = default;
BluetoothAgentServiceProvider::~BluetoothAgentServiceProvider() = default;
BluetoothAgentServiceProvider* BluetoothAgentServiceProvider::Create(
dbus::Bus* bus,
const dbus::ObjectPath& object_path,
Delegate* delegate) {
if (!bluez::BluezDBusManager::Get()->IsUsingFakes()) {
return new BluetoothAgentServiceProviderImpl(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 FakeBluetoothAgentServiceProvider(object_path, delegate);
#endif
}
}