blob: be535054fc57f3b468fa4f752b3cb74f91655e7d [file] [log] [blame]
// Copyright (c) 2012 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/bluetooth_device_win.h"
#include <string>
#include <unordered_map>
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/stringprintf.h"
#include "device/bluetooth/bluetooth_adapter_win.h"
#include "device/bluetooth/bluetooth_remote_gatt_service_win.h"
#include "device/bluetooth/bluetooth_service_record_win.h"
#include "device/bluetooth/bluetooth_socket_thread.h"
#include "device/bluetooth/bluetooth_socket_win.h"
#include "device/bluetooth/bluetooth_task_manager_win.h"
#include "device/bluetooth/bluetooth_uuid.h"
namespace {
const char kApiUnavailable[] = "This API is not implemented on this platform.";
} // namespace
namespace device {
BluetoothDeviceWin::BluetoothDeviceWin(
BluetoothAdapterWin* adapter,
const BluetoothTaskManagerWin::DeviceState& device_state,
scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
scoped_refptr<BluetoothSocketThread> socket_thread)
: BluetoothDevice(adapter),
ui_task_runner_(std::move(ui_task_runner)),
socket_thread_(std::move(socket_thread)) {
Update(device_state);
}
BluetoothDeviceWin::~BluetoothDeviceWin() {
// Explicitly take and erase GATT services one by one to ensure that calling
// GetGattService on removed service in GattServiceRemoved returns null.
std::vector<std::string> service_keys;
for (const auto& gatt_service : gatt_services_) {
service_keys.push_back(gatt_service.first);
}
for (const auto& key : service_keys) {
std::unique_ptr<BluetoothRemoteGattService> service =
std::move(gatt_services_[key]);
gatt_services_.erase(key);
}
}
uint32_t BluetoothDeviceWin::GetBluetoothClass() const {
return bluetooth_class_;
}
std::string BluetoothDeviceWin::GetAddress() const {
return address_;
}
BluetoothDevice::VendorIDSource
BluetoothDeviceWin::GetVendorIDSource() const {
return VENDOR_ID_UNKNOWN;
}
uint16_t BluetoothDeviceWin::GetVendorID() const {
return 0;
}
uint16_t BluetoothDeviceWin::GetProductID() const {
return 0;
}
uint16_t BluetoothDeviceWin::GetDeviceID() const {
return 0;
}
uint16_t BluetoothDeviceWin::GetAppearance() const {
// TODO(crbug.com/588083): Implementing GetAppearance()
// on mac, win, and android platforms for chrome
NOTIMPLEMENTED();
return 0;
}
base::Optional<std::string> BluetoothDeviceWin::GetName() const {
return name_;
}
bool BluetoothDeviceWin::IsPaired() const {
return paired_;
}
bool BluetoothDeviceWin::IsConnected() const {
return connected_;
}
bool BluetoothDeviceWin::IsGattConnected() const {
return gatt_connected_;
}
bool BluetoothDeviceWin::IsConnectable() const {
return false;
}
bool BluetoothDeviceWin::IsConnecting() const {
return false;
}
BluetoothDevice::UUIDSet BluetoothDeviceWin::GetUUIDs() const {
return uuids_;
}
base::Optional<int8_t> BluetoothDeviceWin::GetInquiryRSSI() const {
// In windows, we can only get connected devices and connected
// devices don't have an Inquiry RSSI.
return base::nullopt;
}
base::Optional<int8_t> BluetoothDeviceWin::GetInquiryTxPower() const {
// In windows, we can only get connected devices and connected
// devices don't have an Inquiry Tx Power.
return base::nullopt;
}
bool BluetoothDeviceWin::ExpectingPinCode() const {
NOTIMPLEMENTED();
return false;
}
bool BluetoothDeviceWin::ExpectingPasskey() const {
NOTIMPLEMENTED();
return false;
}
bool BluetoothDeviceWin::ExpectingConfirmation() const {
NOTIMPLEMENTED();
return false;
}
void BluetoothDeviceWin::GetConnectionInfo(
const ConnectionInfoCallback& callback) {
NOTIMPLEMENTED();
callback.Run(ConnectionInfo());
}
void BluetoothDeviceWin::SetConnectionLatency(
ConnectionLatency connection_latency,
const base::Closure& callback,
const ErrorCallback& error_callback) {
NOTIMPLEMENTED();
}
void BluetoothDeviceWin::Connect(
PairingDelegate* pairing_delegate,
const base::Closure& callback,
const ConnectErrorCallback& error_callback) {
NOTIMPLEMENTED();
}
void BluetoothDeviceWin::SetPinCode(const std::string& pincode) {
NOTIMPLEMENTED();
}
void BluetoothDeviceWin::SetPasskey(uint32_t passkey) {
NOTIMPLEMENTED();
}
void BluetoothDeviceWin::ConfirmPairing() {
NOTIMPLEMENTED();
}
void BluetoothDeviceWin::RejectPairing() {
NOTIMPLEMENTED();
}
void BluetoothDeviceWin::CancelPairing() {
NOTIMPLEMENTED();
}
void BluetoothDeviceWin::Disconnect(
const base::Closure& callback,
const ErrorCallback& error_callback) {
NOTIMPLEMENTED();
}
void BluetoothDeviceWin::Forget(const base::Closure& callback,
const ErrorCallback& error_callback) {
NOTIMPLEMENTED();
}
void BluetoothDeviceWin::ConnectToService(
const BluetoothUUID& uuid,
const ConnectToServiceCallback& callback,
const ConnectToServiceErrorCallback& error_callback) {
scoped_refptr<BluetoothSocketWin> socket(
BluetoothSocketWin::CreateBluetoothSocket(
ui_task_runner_, socket_thread_));
socket->Connect(this, uuid, base::Bind(callback, socket), error_callback);
}
void BluetoothDeviceWin::ConnectToServiceInsecurely(
const BluetoothUUID& uuid,
const ConnectToServiceCallback& callback,
const ConnectToServiceErrorCallback& error_callback) {
error_callback.Run(kApiUnavailable);
}
const BluetoothServiceRecordWin* BluetoothDeviceWin::GetServiceRecord(
const device::BluetoothUUID& uuid) const {
for (const auto& record : service_record_list_)
if (record->uuid() == uuid)
return record.get();
return nullptr;
}
bool BluetoothDeviceWin::IsEqual(
const BluetoothTaskManagerWin::DeviceState& device_state) {
if (address_ != device_state.address || name_ != device_state.name ||
bluetooth_class_ != device_state.bluetooth_class ||
visible_ != device_state.visible ||
connected_ != device_state.connected ||
gatt_connected_ == device_state.is_bluetooth_classic() ||
paired_ != device_state.authenticated) {
return false;
}
// Checks service collection
UUIDSet new_services;
std::unordered_map<std::string, std::unique_ptr<BluetoothServiceRecordWin>>
new_service_records;
for (auto iter = device_state.service_record_states.begin();
iter != device_state.service_record_states.end(); ++iter) {
auto service_record = std::make_unique<BluetoothServiceRecordWin>(
address_, (*iter)->name, (*iter)->sdp_bytes, (*iter)->gatt_uuid);
new_services.insert(service_record->uuid());
new_service_records[service_record->uuid().canonical_value()] =
std::move(service_record);
}
// Check that no new services have been added or removed.
if (uuids_ != new_services) {
return false;
}
for (const auto& service_record : service_record_list_) {
BluetoothServiceRecordWin* new_service_record =
new_service_records[service_record->uuid().canonical_value()].get();
if (!service_record->IsEqual(*new_service_record))
return false;
}
return true;
}
void BluetoothDeviceWin::Update(
const BluetoothTaskManagerWin::DeviceState& device_state) {
address_ = device_state.address;
// Note: Callers are responsible for providing a canonicalized address.
DCHECK_EQ(address_, BluetoothDevice::CanonicalizeAddress(address_));
name_ = device_state.name;
bluetooth_class_ = device_state.bluetooth_class;
visible_ = device_state.visible;
connected_ = device_state.connected;
// If a BLE device is not GATT connected, Windows will automatically
// reconnect.
gatt_connected_ = !device_state.is_bluetooth_classic();
paired_ = device_state.authenticated;
UpdateServices(device_state);
}
void BluetoothDeviceWin::GattServiceDiscoveryComplete(
BluetoothRemoteGattServiceWin* service) {
DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
DCHECK(BluetoothDeviceWin::IsGattServiceDiscovered(
service->GetUUID(), service->GetAttributeHandle()));
discovery_completed_included_services_.insert(
{service->GetUUID(), service->GetAttributeHandle()});
if (discovery_completed_included_services_.size() != gatt_services_.size())
return;
SetGattServicesDiscoveryComplete(true);
adapter_->NotifyGattServicesDiscovered(this);
}
void BluetoothDeviceWin::CreateGattConnectionImpl() {
// Windows will create the Gatt connection as needed. See:
// https://docs.microsoft.com/en-us/windows/uwp/devices-sensors/gatt-client#connecting-to-the-device
}
void BluetoothDeviceWin::DisconnectGatt() {
// On Windows, the adapter cannot force a disconnection.
}
void BluetoothDeviceWin::SetVisible(bool visible) {
visible_ = visible;
}
void BluetoothDeviceWin::UpdateServices(
const BluetoothTaskManagerWin::DeviceState& device_state) {
uuids_.clear();
service_record_list_.clear();
for (const auto& record_state : device_state.service_record_states) {
auto service_record = std::make_unique<BluetoothServiceRecordWin>(
device_state.address, record_state->name, record_state->sdp_bytes,
record_state->gatt_uuid);
uuids_.insert(service_record->uuid());
service_record_list_.push_back(std::move(service_record));
}
if (!device_state.is_bluetooth_classic())
UpdateGattServices(device_state.service_record_states);
}
bool BluetoothDeviceWin::IsGattServiceDiscovered(const BluetoothUUID& uuid,
uint16_t attribute_handle) {
for (const auto& gatt_service : gatt_services_) {
uint16_t it_att_handle =
static_cast<BluetoothRemoteGattServiceWin*>(gatt_service.second.get())
->GetAttributeHandle();
BluetoothUUID it_uuid = gatt_service.second->GetUUID();
if (attribute_handle == it_att_handle && uuid == it_uuid) {
return true;
}
}
return false;
}
bool BluetoothDeviceWin::DoesGattServiceExist(
const std::vector<std::unique_ptr<
BluetoothTaskManagerWin::ServiceRecordState>>& service_state,
BluetoothRemoteGattService* service) {
uint16_t attribute_handle =
static_cast<BluetoothRemoteGattServiceWin*>(service)
->GetAttributeHandle();
BluetoothUUID uuid = service->GetUUID();
for (const auto& record_state : service_state) {
if (attribute_handle == record_state->attribute_handle &&
uuid == record_state->gatt_uuid) {
return true;
}
}
return false;
}
void BluetoothDeviceWin::UpdateGattServices(
const std::vector<
std::unique_ptr<BluetoothTaskManagerWin::ServiceRecordState>>&
service_state) {
// First, remove no longer existent GATT service.
{
std::vector<std::string> to_be_removed_services;
for (const auto& gatt_service : gatt_services_) {
if (!DoesGattServiceExist(service_state, gatt_service.second.get())) {
to_be_removed_services.push_back(gatt_service.first);
}
}
for (const auto& service : to_be_removed_services) {
std::unique_ptr<BluetoothRemoteGattService> service_ptr =
std::move(gatt_services_[service]);
gatt_services_.erase(service);
}
// Update previously discovered services.
for (const auto& gatt_service : gatt_services_) {
static_cast<BluetoothRemoteGattServiceWin*>(gatt_service.second.get())
->Update();
}
}
// Return if no new services have been added.
if (gatt_services_.size() == service_state.size())
return;
// Add new services.
for (const auto& record_state : service_state) {
if (!IsGattServiceDiscovered(record_state->gatt_uuid,
record_state->attribute_handle)) {
BluetoothRemoteGattServiceWin* primary_service =
new BluetoothRemoteGattServiceWin(
this, record_state->path, record_state->gatt_uuid,
record_state->attribute_handle, true, nullptr, ui_task_runner_);
gatt_services_[primary_service->GetIdentifier()] =
base::WrapUnique(primary_service);
adapter_->NotifyGattServiceAdded(primary_service);
}
}
}
} // namespace device