blob: 7ec20cb70ac432c175cefad5a55ed052eab0e0ce [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "device/bluetooth/adapter.h"
#include <string>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/memory/ptr_util.h"
#include "build/build_config.h"
#include "device/bluetooth/advertisement.h"
#include "device/bluetooth/bluetooth_socket.h"
#include "device/bluetooth/device.h"
#include "device/bluetooth/discovery_session.h"
#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
#include "device/bluetooth/public/mojom/connect_result_type_converter.h"
#include "device/bluetooth/server_socket.h"
#include "device/bluetooth/socket.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#if defined(OS_CHROMEOS) || defined(OS_LINUX)
#include "device/bluetooth/bluez/metrics_recorder.h"
#endif
namespace bluetooth {
namespace {
const char kMojoReceivingPipeError[] = "Failed to create receiving DataPipe.";
const char kMojoSendingPipeError[] = "Failed to create sending DataPipe.";
#if defined(OS_CHROMEOS) || defined(OS_LINUX)
const char kCannotConnectToDeviceError[] = "Cannot connect to device.";
#endif
} // namespace
Adapter::Adapter(scoped_refptr<device::BluetoothAdapter> adapter)
: adapter_(std::move(adapter)) {
adapter_->AddObserver(this);
}
Adapter::~Adapter() {
adapter_->RemoveObserver(this);
adapter_ = nullptr;
}
void Adapter::ConnectToDevice(const std::string& address,
ConnectToDeviceCallback callback) {
device::BluetoothDevice* device = adapter_->GetDevice(address);
if (!device) {
std::move(callback).Run(mojom::ConnectResult::DEVICE_NO_LONGER_IN_RANGE,
/*device=*/mojo::NullRemote());
return;
}
auto split_callback = base::SplitOnceCallback(std::move(callback));
device->CreateGattConnection(
base::BindOnce(&Adapter::OnGattConnected, weak_ptr_factory_.GetWeakPtr(),
std::move(split_callback.first)),
base::BindOnce(&Adapter::OnConnectError, weak_ptr_factory_.GetWeakPtr(),
std::move(split_callback.second)));
}
void Adapter::GetDevices(GetDevicesCallback callback) {
std::vector<mojom::DeviceInfoPtr> devices;
for (const device::BluetoothDevice* device : adapter_->GetDevices()) {
mojom::DeviceInfoPtr device_info =
Device::ConstructDeviceInfoStruct(device);
devices.push_back(std::move(device_info));
}
std::move(callback).Run(std::move(devices));
}
void Adapter::GetInfo(GetInfoCallback callback) {
mojom::AdapterInfoPtr adapter_info = mojom::AdapterInfo::New();
adapter_info->address = adapter_->GetAddress();
adapter_info->name = adapter_->GetName();
#if defined(OS_CHROMEOS) || defined(OS_LINUX)
adapter_info->system_name = adapter_->GetSystemName();
#endif
adapter_info->initialized = adapter_->IsInitialized();
adapter_info->present = adapter_->IsPresent();
adapter_info->powered = adapter_->IsPowered();
adapter_info->discoverable = adapter_->IsDiscoverable();
adapter_info->discovering = adapter_->IsDiscovering();
std::move(callback).Run(std::move(adapter_info));
}
void Adapter::AddObserver(mojo::PendingRemote<mojom::AdapterObserver> observer,
AddObserverCallback callback) {
observers_.Add(std::move(observer));
std::move(callback).Run();
}
void Adapter::RegisterAdvertisement(const device::BluetoothUUID& service_uuid,
const std::vector<uint8_t>& service_data,
bool use_scan_response,
RegisterAdvertisementCallback callback) {
auto advertisement_data =
std::make_unique<device::BluetoothAdvertisement::Data>(
device::BluetoothAdvertisement::ADVERTISEMENT_TYPE_BROADCAST);
auto uuid_list = std::make_unique<device::BluetoothAdvertisement::UUIDList>();
uuid_list->push_back(service_uuid.value());
advertisement_data->set_service_uuids(std::move(uuid_list));
if (!use_scan_response) {
auto service_data_map =
std::make_unique<device::BluetoothAdvertisement::ServiceData>();
service_data_map->emplace(service_uuid.value(), service_data);
advertisement_data->set_service_data(std::move(service_data_map));
} else {
// Require the service uuid to be in 128-bit format.
DCHECK_EQ(service_uuid.format(),
device::BluetoothUUID::Format::kFormat128Bit);
auto scan_response_data_map =
std::make_unique<device::BluetoothAdvertisement::ScanResponseData>();
// Start with the original scan response data.
std::vector<uint8_t> scan_response_data(service_data.begin(),
service_data.end());
// Now insert in front of the service data the identifying 2-bytes of the
// service id assuming this is a valid 16-bit uuid. For example, the uuid:
// 0000fef3-0000-1000-8000-00805f9b34fb can be uniquely defined by two bytes
// ****fef3-****-****-****-************ the rest is the same for all 16-bit
// uuids as defined by the Bluetooth spec. We insert them in little endian
// ordering 0xf3 first, then 0xfe in for this example.
auto service_id_bytes = service_uuid.GetBytes();
// Take bytes 2 and 3.
auto id_bytes = base::make_span(service_id_bytes).subspan(2, 2);
// Add them in reverse order (little endian).
scan_response_data.insert(scan_response_data.begin(), id_bytes.rbegin(),
id_bytes.rend());
// The platform API only supports AD Type 0x16 "Service Data" which assumes
// as 16-bit service id.
scan_response_data_map->emplace(0x16, scan_response_data);
advertisement_data->set_scan_response_data(
std::move(scan_response_data_map));
}
auto split_callback = base::SplitOnceCallback(std::move(callback));
adapter_->RegisterAdvertisement(
std::move(advertisement_data),
base::BindOnce(&Adapter::OnRegisterAdvertisement,
weak_ptr_factory_.GetWeakPtr(),
std::move(split_callback.first)),
base::BindOnce(&Adapter::OnRegisterAdvertisementError,
weak_ptr_factory_.GetWeakPtr(),
std::move(split_callback.second)));
}
void Adapter::SetDiscoverable(bool discoverable,
SetDiscoverableCallback callback) {
auto split_callback = base::SplitOnceCallback(std::move(callback));
adapter_->SetDiscoverable(discoverable,
base::BindOnce(&Adapter::OnSetDiscoverable,
weak_ptr_factory_.GetWeakPtr(),
std::move(split_callback.first)),
base::BindOnce(&Adapter::OnSetDiscoverableError,
weak_ptr_factory_.GetWeakPtr(),
std::move(split_callback.second)));
}
void Adapter::SetName(const std::string& name, SetNameCallback callback) {
auto split_callback = base::SplitOnceCallback(std::move(callback));
adapter_->SetName(
name,
base::BindOnce(&Adapter::OnSetName, weak_ptr_factory_.GetWeakPtr(),
std::move(split_callback.first)),
base::BindOnce(&Adapter::OnSetNameError, weak_ptr_factory_.GetWeakPtr(),
std::move(split_callback.second)));
}
void Adapter::StartDiscoverySession(StartDiscoverySessionCallback callback) {
auto split_callback = base::SplitOnceCallback(std::move(callback));
adapter_->StartDiscoverySession(
base::BindOnce(&Adapter::OnStartDiscoverySession,
weak_ptr_factory_.GetWeakPtr(),
std::move(split_callback.first)),
base::BindOnce(&Adapter::OnDiscoverySessionError,
weak_ptr_factory_.GetWeakPtr(),
std::move(split_callback.second)));
}
void Adapter::ConnectToServiceInsecurely(
const std::string& address,
const device::BluetoothUUID& service_uuid,
ConnectToServiceInsecurelyCallback callback) {
if (!base::Contains(allowed_uuids_, service_uuid)) {
std::move(callback).Run(/*result=*/nullptr);
return;
}
auto* device = adapter_->GetDevice(address);
if (device) {
OnDeviceFetchedForInsecureServiceConnection(service_uuid,
std::move(callback), device);
return;
}
// This device has neither been discovered, nor has it been paired/connected
// to previously. Use the ConnectDevice() API, if available, to connect to it.
#if defined(OS_CHROMEOS) || defined(OS_LINUX)
auto split_callback = base::SplitOnceCallback(std::move(callback));
adapter_->ConnectDevice(
address, /*address_type=*/base::nullopt,
base::BindOnce(&Adapter::OnDeviceFetchedForInsecureServiceConnection,
weak_ptr_factory_.GetWeakPtr(), service_uuid,
std::move(split_callback.first)),
base::BindOnce(
&Adapter::OnConnectToServiceError, weak_ptr_factory_.GetWeakPtr(),
std::move(split_callback.second), kCannotConnectToDeviceError));
#else
OnConnectToServiceError(std::move(callback), "Device does not exist.");
#endif
}
void Adapter::CreateRfcommServiceInsecurely(
const std::string& service_name,
const device::BluetoothUUID& service_uuid,
CreateRfcommServiceInsecurelyCallback callback) {
if (!base::Contains(allowed_uuids_, service_uuid)) {
std::move(callback).Run(/*server_socket=*/mojo::NullRemote());
return;
}
device::BluetoothAdapter::ServiceOptions service_options;
service_options.name = service_name;
service_options.require_authentication = false;
auto split_callback = base::SplitOnceCallback(std::move(callback));
adapter_->CreateRfcommService(
service_uuid, service_options,
base::BindOnce(&Adapter::OnCreateRfcommServiceInsecurely,
weak_ptr_factory_.GetWeakPtr(),
std::move(split_callback.first)),
base::BindOnce(&Adapter::OnCreateRfcommServiceInsecurelyError,
weak_ptr_factory_.GetWeakPtr(),
std::move(split_callback.second)));
}
void Adapter::AdapterPresentChanged(device::BluetoothAdapter* adapter,
bool present) {
for (auto& observer : observers_)
observer->PresentChanged(present);
}
void Adapter::AdapterPoweredChanged(device::BluetoothAdapter* adapter,
bool powered) {
for (auto& observer : observers_)
observer->PoweredChanged(powered);
}
void Adapter::AdapterDiscoverableChanged(device::BluetoothAdapter* adapter,
bool discoverable) {
for (auto& observer : observers_)
observer->DiscoverableChanged(discoverable);
}
void Adapter::AdapterDiscoveringChanged(device::BluetoothAdapter* adapter,
bool discovering) {
for (auto& observer : observers_)
observer->DiscoveringChanged(discovering);
}
void Adapter::DeviceAdded(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) {
auto device_info = Device::ConstructDeviceInfoStruct(device);
for (auto& observer : observers_)
observer->DeviceAdded(device_info->Clone());
}
void Adapter::DeviceChanged(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) {
// Because paired Bluetooth devices never fire device-removed events, we also
// consider a null RSSI indicative of a device no longer being discoverable.
// In this scenario, we fail any pending connection requests.
if (!device->GetInquiryRSSI()) {
ProcessPendingInsecureServiceConnectionRequest(device->GetAddress(),
/*device=*/nullptr);
}
auto device_info = Device::ConstructDeviceInfoStruct(device);
for (auto& observer : observers_)
observer->DeviceChanged(device_info->Clone());
}
void Adapter::DeviceRemoved(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) {
ProcessPendingInsecureServiceConnectionRequest(device->GetAddress(),
/*device=*/nullptr);
auto device_info = Device::ConstructDeviceInfoStruct(device);
for (auto& observer : observers_)
observer->DeviceRemoved(device_info->Clone());
}
void Adapter::GattServicesDiscovered(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) {
// GattServicesDiscovered() and IsGattServicesDiscoveryComplete() actually
// indicate that all services on the remote device, including SDP, are
// resolved. Once service probing for a device within a cached request (in
// |pending_connect_to_service_args_|) concludes, attempt socket creation
// again via OnDeviceFetchedForInsecureServiceConnection().
if (device->IsGattServicesDiscoveryComplete()) {
ProcessPendingInsecureServiceConnectionRequest(device->GetAddress(),
device);
}
}
void Adapter::AllowConnectionsForUuid(
const device::BluetoothUUID& service_uuid) {
allowed_uuids_.emplace(service_uuid);
}
void Adapter::OnDeviceFetchedForInsecureServiceConnection(
const device::BluetoothUUID& service_uuid,
ConnectToServiceInsecurelyCallback callback,
device::BluetoothDevice* device) {
if (!device) {
std::move(callback).Run(/*result=*/nullptr);
return;
}
if (!device->IsPaired() && device->IsConnected() &&
!device->IsGattServicesDiscoveryComplete()) {
// This provided device is most likely a result of calling ConnectDevice():
// it's connected, but the remote device's services are still being probed
// (IsGattServicesDiscoveryComplete() refers to all services, not just GATT
// services). That means attempting ConnectToServiceInsecurely() right now
// would fail with an "InProgress" error. Wait for GattServicesDiscovered()
// to be called to signal that ConnectToServiceInsecurely() can be called.
pending_connect_to_service_args_.emplace_back(
device->GetAddress(), service_uuid, std::move(callback));
return;
}
auto split_callback = base::SplitOnceCallback(std::move(callback));
device->ConnectToServiceInsecurely(
service_uuid,
base::BindOnce(&Adapter::OnConnectToService,
weak_ptr_factory_.GetWeakPtr(),
std::move(split_callback.first)),
base::BindOnce(&Adapter::OnConnectToServiceError,
weak_ptr_factory_.GetWeakPtr(),
std::move(split_callback.second)));
}
void Adapter::ProcessPendingInsecureServiceConnectionRequest(
const std::string& address,
device::BluetoothDevice* device) {
auto it = pending_connect_to_service_args_.begin();
while (it != pending_connect_to_service_args_.end()) {
if (address == std::get<0>(*it)) {
OnDeviceFetchedForInsecureServiceConnection(
/*service_uuid=*/std::get<1>(*it),
/*callback=*/std::move(std::get<2>(*it)), device);
it = pending_connect_to_service_args_.erase(it);
} else {
++it;
}
}
}
void Adapter::OnGattConnected(
ConnectToDeviceCallback callback,
std::unique_ptr<device::BluetoothGattConnection> connection) {
mojo::PendingRemote<mojom::Device> device;
Device::Create(adapter_, std::move(connection),
device.InitWithNewPipeAndPassReceiver());
std::move(callback).Run(mojom::ConnectResult::SUCCESS, std::move(device));
}
void Adapter::OnConnectError(
ConnectToDeviceCallback callback,
device::BluetoothDevice::ConnectErrorCode error_code) {
std::move(callback).Run(mojo::ConvertTo<mojom::ConnectResult>(error_code),
/*device=*/mojo::NullRemote());
}
void Adapter::OnRegisterAdvertisement(
RegisterAdvertisementCallback callback,
scoped_refptr<device::BluetoothAdvertisement> advertisement) {
mojo::PendingRemote<mojom::Advertisement> pending_advertisement;
mojo::MakeSelfOwnedReceiver(
std::make_unique<Advertisement>(std::move(advertisement)),
pending_advertisement.InitWithNewPipeAndPassReceiver());
std::move(callback).Run(std::move(pending_advertisement));
}
void Adapter::OnRegisterAdvertisementError(
RegisterAdvertisementCallback callback,
device::BluetoothAdvertisement::ErrorCode error_code) {
DLOG(ERROR) << "Failed to register advertisement, error code: " << error_code;
std::move(callback).Run(/*advertisement=*/mojo::NullRemote());
}
void Adapter::OnSetDiscoverable(SetDiscoverableCallback callback) {
std::move(callback).Run(/*success=*/true);
}
void Adapter::OnSetDiscoverableError(SetDiscoverableCallback callback) {
std::move(callback).Run(/*success=*/false);
}
void Adapter::OnSetName(SetNameCallback callback) {
std::move(callback).Run(/*success=*/true);
}
void Adapter::OnSetNameError(SetNameCallback callback) {
std::move(callback).Run(/*success=*/false);
}
void Adapter::OnStartDiscoverySession(
StartDiscoverySessionCallback callback,
std::unique_ptr<device::BluetoothDiscoverySession> session) {
mojo::PendingRemote<mojom::DiscoverySession> pending_session;
mojo::MakeSelfOwnedReceiver(
std::make_unique<DiscoverySession>(std::move(session)),
pending_session.InitWithNewPipeAndPassReceiver());
std::move(callback).Run(std::move(pending_session));
}
void Adapter::OnDiscoverySessionError(StartDiscoverySessionCallback callback) {
std::move(callback).Run(/*session=*/mojo::NullRemote());
}
void Adapter::OnConnectToService(
ConnectToServiceInsecurelyCallback callback,
scoped_refptr<device::BluetoothSocket> socket) {
mojo::ScopedDataPipeProducerHandle receive_pipe_producer_handle;
mojo::ScopedDataPipeConsumerHandle receive_pipe_consumer_handle;
MojoResult result =
mojo::CreateDataPipe(/*options=*/nullptr, receive_pipe_producer_handle,
receive_pipe_consumer_handle);
if (result != MOJO_RESULT_OK) {
socket->Disconnect(base::BindOnce(
&Adapter::OnConnectToServiceError, weak_ptr_factory_.GetWeakPtr(),
std::move(callback), kMojoReceivingPipeError));
return;
}
mojo::ScopedDataPipeProducerHandle send_pipe_producer_handle;
mojo::ScopedDataPipeConsumerHandle send_pipe_consumer_handle;
result = mojo::CreateDataPipe(/*options=*/nullptr, send_pipe_producer_handle,
send_pipe_consumer_handle);
if (result != MOJO_RESULT_OK) {
socket->Disconnect(base::BindOnce(
&Adapter::OnConnectToServiceError, weak_ptr_factory_.GetWeakPtr(),
std::move(callback), kMojoSendingPipeError));
return;
}
mojo::PendingRemote<mojom::Socket> pending_socket;
mojo::MakeSelfOwnedReceiver(
std::make_unique<Socket>(std::move(socket),
std::move(receive_pipe_producer_handle),
std::move(send_pipe_consumer_handle)),
pending_socket.InitWithNewPipeAndPassReceiver());
mojom::ConnectToServiceResultPtr connect_to_service_result =
mojom::ConnectToServiceResult::New();
connect_to_service_result->socket = std::move(pending_socket);
connect_to_service_result->receive_stream =
std::move(receive_pipe_consumer_handle);
connect_to_service_result->send_stream = std::move(send_pipe_producer_handle);
std::move(callback).Run(std::move(connect_to_service_result));
#if defined(OS_CHROMEOS) || defined(OS_LINUX)
RecordConnectToServiceInsecurelyResult(
ConnectToServiceInsecurelyResult::kSuccess);
#endif
}
void Adapter::OnConnectToServiceError(
ConnectToServiceInsecurelyCallback callback,
const std::string& message) {
DLOG(ERROR) << "Failed to connect to service: '" << message << "'";
std::move(callback).Run(/*result=*/nullptr);
#if defined(OS_CHROMEOS) || defined(OS_LINUX)
base::Optional<ConnectToServiceInsecurelyResult> result =
ExtractResultFromErrorString(message);
if (result) {
RecordConnectToServiceInsecurelyResult(*result);
} else if (message == kMojoSendingPipeError) {
RecordConnectToServiceInsecurelyResult(
ConnectToServiceInsecurelyResult::kMojoSendingPipeError);
} else if (message == kMojoReceivingPipeError) {
RecordConnectToServiceInsecurelyResult(
ConnectToServiceInsecurelyResult::kMojoReceivingPipeError);
} else if (message == kCannotConnectToDeviceError) {
RecordConnectToServiceInsecurelyResult(
ConnectToServiceInsecurelyResult::kCouldNotConnectError);
} else {
RecordConnectToServiceInsecurelyResult(
ConnectToServiceInsecurelyResult::kUnknownError);
}
#endif
}
void Adapter::OnCreateRfcommServiceInsecurely(
CreateRfcommServiceInsecurelyCallback callback,
scoped_refptr<device::BluetoothSocket> socket) {
mojo::PendingRemote<mojom::ServerSocket> pending_server_socket;
mojo::MakeSelfOwnedReceiver(
std::make_unique<ServerSocket>(std::move(socket)),
pending_server_socket.InitWithNewPipeAndPassReceiver());
std::move(callback).Run(std::move(pending_server_socket));
}
void Adapter::OnCreateRfcommServiceInsecurelyError(
CreateRfcommServiceInsecurelyCallback callback,
const std::string& message) {
LOG(ERROR) << "Failed to create service: '" << message << "'";
std::move(callback).Run(/*server_socket=*/mojo::NullRemote());
}
} // namespace bluetooth