blob: 8e66949ced7a487797f7e22dc349b9cfb3a81f7e [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_adapter_win.h"
#include <memory>
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/feature_list.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/sequenced_task_runner.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/win/windows_version.h"
#include "device/base/features.h"
#include "device/bluetooth/bluetooth_adapter_winrt.h"
#include "device/bluetooth/bluetooth_classic_win.h"
#include "device/bluetooth/bluetooth_device_win.h"
#include "device/bluetooth/bluetooth_discovery_session_outcome.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 device {
// static
base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter(
InitCallback init_callback) {
return BluetoothAdapterWin::CreateAdapter(std::move(init_callback));
}
// static
base::WeakPtr<BluetoothAdapter> BluetoothAdapterWin::CreateAdapter(
InitCallback init_callback) {
if (UseNewBLEWinImplementation()) {
auto* adapter = new BluetoothAdapterWinrt();
adapter->Init(std::move(init_callback));
return adapter->weak_ptr_factory_.GetWeakPtr();
}
return BluetoothAdapterWin::CreateClassicAdapter(std::move(init_callback));
}
// static
base::WeakPtr<BluetoothAdapter> BluetoothAdapterWin::CreateClassicAdapter(
InitCallback init_callback) {
auto* adapter = new BluetoothAdapterWin(std::move(init_callback));
adapter->Init();
return adapter->weak_ptr_factory_.GetWeakPtr();
}
// static
bool BluetoothAdapterWin::UseNewBLEWinImplementation() {
return base::FeatureList::IsEnabled(kNewBLEWinImplementation) &&
base::win::GetVersion() >= base::win::Version::WIN10;
}
BluetoothAdapterWin::BluetoothAdapterWin(InitCallback init_callback)
: BluetoothAdapter(),
init_callback_(std::move(init_callback)),
initialized_(false),
powered_(false),
discovery_status_(NOT_DISCOVERING),
num_discovery_listeners_(0),
force_update_device_for_test_(false),
weak_ptr_factory_(this) {}
BluetoothAdapterWin::~BluetoothAdapterWin() {
if (task_manager_.get())
task_manager_->RemoveObserver(this);
}
std::string BluetoothAdapterWin::GetAddress() const {
return address_;
}
std::string BluetoothAdapterWin::GetName() const {
return name_;
}
void BluetoothAdapterWin::SetName(const std::string& name,
const base::Closure& callback,
const ErrorCallback& error_callback) {
NOTIMPLEMENTED();
}
// TODO(youngki): Return true when |task_manager_| initializes the adapter
// state.
bool BluetoothAdapterWin::IsInitialized() const {
return initialized_;
}
bool BluetoothAdapterWin::IsPresent() const {
return !address_.empty();
}
bool BluetoothAdapterWin::IsPowered() const {
return powered_;
}
void BluetoothAdapterWin::SetPowered(
bool powered,
const base::Closure& callback,
const ErrorCallback& error_callback) {
task_manager_->PostSetPoweredBluetoothTask(powered, callback, error_callback);
}
bool BluetoothAdapterWin::IsDiscoverable() const {
NOTIMPLEMENTED();
return false;
}
void BluetoothAdapterWin::SetDiscoverable(
bool discoverable,
const base::Closure& callback,
const ErrorCallback& error_callback) {
NOTIMPLEMENTED();
}
bool BluetoothAdapterWin::IsDiscovering() const {
return discovery_status_ == DISCOVERING ||
discovery_status_ == DISCOVERY_STOPPING;
}
static void RunDiscoverySessionErrorCallback(
base::OnceCallback<void(UMABluetoothDiscoverySessionOutcome)>
error_callback,
UMABluetoothDiscoverySessionOutcome outcome) {
std::move(error_callback).Run(outcome);
}
void BluetoothAdapterWin::DiscoveryStarted(bool success) {
discovery_status_ = success ? DISCOVERING : NOT_DISCOVERING;
for (auto& callbacks : on_start_discovery_callbacks_) {
if (success)
ui_task_runner_->PostTask(FROM_HERE, callbacks.first);
else
ui_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&RunDiscoverySessionErrorCallback,
std::move(callbacks.second),
UMABluetoothDiscoverySessionOutcome::UNKNOWN));
}
num_discovery_listeners_ = on_start_discovery_callbacks_.size();
on_start_discovery_callbacks_.clear();
if (success) {
for (auto& observer : observers_)
observer.AdapterDiscoveringChanged(this, true);
// If there are stop discovery requests, post the stop discovery again.
MaybePostStopDiscoveryTask();
} else if (!on_stop_discovery_callbacks_.empty()) {
// If there are stop discovery requests but start discovery has failed,
// notify that stop discovery has been complete.
DiscoveryStopped();
}
}
void BluetoothAdapterWin::DiscoveryStopped() {
discovered_devices_.clear();
bool was_discovering = IsDiscovering();
discovery_status_ = NOT_DISCOVERING;
for (std::vector<base::Closure>::const_iterator iter =
on_stop_discovery_callbacks_.begin();
iter != on_stop_discovery_callbacks_.end();
++iter) {
ui_task_runner_->PostTask(FROM_HERE, *iter);
}
num_discovery_listeners_ = 0;
on_stop_discovery_callbacks_.clear();
if (was_discovering)
for (auto& observer : observers_)
observer.AdapterDiscoveringChanged(this, false);
// If there are start discovery requests, post the start discovery again.
MaybePostStartDiscoveryTask();
}
BluetoothAdapter::UUIDList BluetoothAdapterWin::GetUUIDs() const {
NOTIMPLEMENTED();
return UUIDList();
}
void BluetoothAdapterWin::CreateRfcommService(
const BluetoothUUID& uuid,
const ServiceOptions& options,
const CreateServiceCallback& callback,
const CreateServiceErrorCallback& error_callback) {
scoped_refptr<BluetoothSocketWin> socket =
BluetoothSocketWin::CreateBluetoothSocket(
ui_task_runner_, socket_thread_);
socket->Listen(this, uuid, options,
base::Bind(callback, socket),
error_callback);
}
void BluetoothAdapterWin::CreateL2capService(
const BluetoothUUID& uuid,
const ServiceOptions& options,
const CreateServiceCallback& callback,
const CreateServiceErrorCallback& error_callback) {
// TODO(keybuk): implement.
NOTIMPLEMENTED();
}
void BluetoothAdapterWin::RegisterAdvertisement(
std::unique_ptr<BluetoothAdvertisement::Data> advertisement_data,
const CreateAdvertisementCallback& callback,
const AdvertisementErrorCallback& error_callback) {
NOTIMPLEMENTED();
error_callback.Run(BluetoothAdvertisement::ERROR_UNSUPPORTED_PLATFORM);
}
BluetoothLocalGattService* BluetoothAdapterWin::GetGattService(
const std::string& identifier) const {
return nullptr;
}
void BluetoothAdapterWin::RemovePairingDelegateInternal(
BluetoothDevice::PairingDelegate* pairing_delegate) {
}
void BluetoothAdapterWin::AdapterStateChanged(
const BluetoothTaskManagerWin::AdapterState& state) {
DCHECK(thread_checker_.CalledOnValidThread());
name_ = state.name;
bool was_present = IsPresent();
bool is_present = !state.address.empty();
address_ = BluetoothDevice::CanonicalizeAddress(state.address);
if (was_present != is_present) {
for (auto& observer : observers_)
observer.AdapterPresentChanged(this, is_present);
}
if (powered_ != state.powered) {
powered_ = state.powered;
for (auto& observer : observers_)
observer.AdapterPoweredChanged(this, powered_);
}
if (!initialized_) {
initialized_ = true;
std::move(init_callback_).Run();
}
}
void BluetoothAdapterWin::DevicesPolled(
const std::vector<std::unique_ptr<BluetoothTaskManagerWin::DeviceState>>&
devices) {
DCHECK(thread_checker_.CalledOnValidThread());
// We are receiving a new list of all devices known to the system. Merge this
// new list with the list we know of (|devices_|) and raise corresponding
// DeviceAdded, DeviceRemoved and DeviceChanged events.
using DeviceAddressSet = std::set<std::string>;
DeviceAddressSet known_devices;
for (const auto& device : devices_)
known_devices.insert(device.first);
DeviceAddressSet new_devices;
for (const auto& device_state : devices)
new_devices.insert(device_state->address);
// Process device removal first.
DeviceAddressSet removed_devices =
base::STLSetDifference<DeviceAddressSet>(known_devices, new_devices);
for (const auto& device : removed_devices) {
auto it = devices_.find(device);
std::unique_ptr<BluetoothDevice> device_win = std::move(it->second);
devices_.erase(it);
for (auto& observer : observers_)
observer.DeviceRemoved(this, device_win.get());
}
// Process added and (maybe) changed devices in one pass.
DeviceAddressSet added_devices =
base::STLSetDifference<DeviceAddressSet>(new_devices, known_devices);
DeviceAddressSet changed_devices =
base::STLSetIntersection<DeviceAddressSet>(known_devices, new_devices);
for (const auto& device_state : devices) {
if (added_devices.find(device_state->address) != added_devices.end()) {
auto device_win = std::make_unique<BluetoothDeviceWin>(
this, *device_state, ui_task_runner_, socket_thread_);
BluetoothDeviceWin* device_win_raw = device_win.get();
devices_[device_state->address] = std::move(device_win);
for (auto& observer : observers_)
observer.DeviceAdded(this, device_win_raw);
} else if (changed_devices.find(device_state->address) !=
changed_devices.end()) {
auto iter = devices_.find(device_state->address);
DCHECK(iter != devices_.end());
BluetoothDeviceWin* device_win =
static_cast<BluetoothDeviceWin*>(iter->second.get());
if (!device_win->IsEqual(*device_state)) {
device_win->Update(*device_state);
for (auto& observer : observers_)
observer.DeviceChanged(this, device_win);
}
// Above IsEqual returns true if device name, address, status and services
// (primary services of BLE device) are the same. However, in BLE tests,
// we may simulate characteristic, descriptor and secondary GATT service
// after device has been initialized.
if (force_update_device_for_test_) {
device_win->Update(*device_state);
}
}
}
}
// BluetoothAdapterWin should override SetPowered() instead.
bool BluetoothAdapterWin::SetPoweredImpl(bool powered) {
NOTREACHED();
return false;
}
void BluetoothAdapterWin::UpdateFilter(
std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter,
DiscoverySessionResultCallback callback) {
auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
// If the status is DISCOVERY_STOPPING then we then we must wait for the OS
// to complete that operation before starting a new discovery session.
// A new call to StartScanWithFilter is queued to perform this operation.
// The |discovery_filter| parameter is currently ignored so nullptr can be
// passed instead. This will be simplified when the RemoveDiscoverySession
// workflow is refactored in an upcoming CL.
if (discovery_status_ == DISCOVERY_STOPPING) {
on_stop_discovery_callbacks_.push_back(base::BindRepeating(
&BluetoothAdapterWin::StartScanWithFilter, base::Unretained(this),
nullptr, copyable_callback));
return;
}
DCHECK(discovery_status_ == DISCOVERING ||
discovery_status_ == DISCOVERY_STARTING);
if (discovery_status_ == DISCOVERING) {
num_discovery_listeners_++;
copyable_callback.Run(false, UMABluetoothDiscoverySessionOutcome::SUCCESS);
return;
}
on_start_discovery_callbacks_.push_back(std::make_pair(
base::BindRepeating(copyable_callback, false,
UMABluetoothDiscoverySessionOutcome::SUCCESS),
base::BindOnce(copyable_callback, true)));
}
void BluetoothAdapterWin::StartScanWithFilter(
std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter,
DiscoverySessionResultCallback callback) {
auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
// If the status is DISCOVERING already then this call was in the
// on_stop_discovery_callbacks_ queue and was called after another StartScan
// in the same queue. Now that the queue is already started we simply have to
// update the filter. This will be cleaned up completely when
// RemoveDiscoveryFilter is refactored.
if (discovery_status_ == DISCOVERING) {
UpdateFilter(std::move(discovery_filter), std::move(callback));
return;
}
on_start_discovery_callbacks_.push_back(std::make_pair(
base::BindRepeating(copyable_callback, false,
UMABluetoothDiscoverySessionOutcome::SUCCESS),
base::BindOnce(copyable_callback, true)));
MaybePostStartDiscoveryTask();
}
void BluetoothAdapterWin::RemoveDiscoverySession(
BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
DiscoverySessionErrorCallback error_callback) {
if (discovery_status_ == NOT_DISCOVERING) {
std::move(error_callback)
.Run(UMABluetoothDiscoverySessionOutcome::NOT_ACTIVE);
return;
}
on_stop_discovery_callbacks_.push_back(callback);
MaybePostStopDiscoveryTask();
}
void BluetoothAdapterWin::SetDiscoveryFilter(
std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter,
const base::Closure& callback,
DiscoverySessionErrorCallback error_callback) {
NOTIMPLEMENTED();
std::move(error_callback)
.Run(UMABluetoothDiscoverySessionOutcome::NOT_IMPLEMENTED);
}
void BluetoothAdapterWin::Init() {
ui_task_runner_ = base::ThreadTaskRunnerHandle::Get();
socket_thread_ = BluetoothSocketThread::Get();
task_manager_ =
base::MakeRefCounted<BluetoothTaskManagerWin>(ui_task_runner_);
task_manager_->AddObserver(this);
task_manager_->Initialize();
}
void BluetoothAdapterWin::InitForTest(
std::unique_ptr<win::BluetoothClassicWrapper> classic_wrapper,
std::unique_ptr<win::BluetoothLowEnergyWrapper> le_wrapper,
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
scoped_refptr<base::SequencedTaskRunner> bluetooth_task_runner) {
ui_task_runner_ = ui_task_runner;
if (!ui_task_runner_)
ui_task_runner_ = base::ThreadTaskRunnerHandle::Get();
task_manager_ = BluetoothTaskManagerWin::CreateForTesting(
std::move(classic_wrapper), std::move(le_wrapper), ui_task_runner_);
task_manager_->AddObserver(this);
task_manager_->InitializeWithBluetoothTaskRunner(bluetooth_task_runner);
}
void BluetoothAdapterWin::MaybePostStartDiscoveryTask() {
if (discovery_status_ == NOT_DISCOVERING &&
!on_start_discovery_callbacks_.empty()) {
discovery_status_ = DISCOVERY_STARTING;
task_manager_->PostStartDiscoveryTask();
}
}
void BluetoothAdapterWin::MaybePostStopDiscoveryTask() {
if (discovery_status_ != DISCOVERING)
return;
if (on_stop_discovery_callbacks_.size() < num_discovery_listeners_) {
for (std::vector<base::Closure>::const_iterator iter =
on_stop_discovery_callbacks_.begin();
iter != on_stop_discovery_callbacks_.end();
++iter) {
ui_task_runner_->PostTask(FROM_HERE, *iter);
}
num_discovery_listeners_ -= on_stop_discovery_callbacks_.size();
on_stop_discovery_callbacks_.clear();
return;
}
discovery_status_ = DISCOVERY_STOPPING;
task_manager_->PostStopDiscoveryTask();
}
} // namespace device