blob: c631f4daebb3eb6fa259616f6074f7ca2dda04b0 [file] [log] [blame]
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/bluetooth/bluetooth_adapter_factory_wrapper.h"
#include <stddef.h>
#include <utility>
#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/no_destructor.h"
#include "base/task/single_thread_task_runner.h"
#include "content/browser/bluetooth/web_bluetooth_service_impl.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
namespace content {
namespace {
using ::device::BluetoothAdapter;
using ::device::BluetoothAdapterFactory;
} // namespace
BluetoothAdapterFactoryWrapper::BluetoothAdapterFactoryWrapper() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
}
BluetoothAdapterFactoryWrapper::~BluetoothAdapterFactoryWrapper() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// All observers should have been removed already.
DCHECK(adapter_observers_.empty());
// Clear adapters.
SetAdapterInternal(/*adapter=*/nullptr, /*is_override_adapter=*/true);
SetAdapterInternal(/*adapter=*/nullptr, /*is_override_adapter=*/false);
}
// static
BluetoothAdapterFactoryWrapper& BluetoothAdapterFactoryWrapper::Get() {
static base::NoDestructor<BluetoothAdapterFactoryWrapper> singleton;
return *singleton;
}
bool BluetoothAdapterFactoryWrapper::IsLowEnergySupported() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (GetActiveAdapter() || pending_override_adapter_) {
return true;
}
return BluetoothAdapterFactory::Get()->IsLowEnergySupported();
}
void BluetoothAdapterFactoryWrapper::AcquireAdapter(
WebBluetoothServiceImpl* service,
AcquireAdapterCallback callback) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(!GetAdapter(service));
MaybeAddAdapterObserver(service);
scoped_refptr<BluetoothAdapter> active_adapter = GetActiveAdapter();
if (active_adapter) {
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback), std::move(active_adapter)));
return;
}
// Simulate the normally asynchronous process of acquiring the adapter in
// tests.
if (pending_override_adapter_) {
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(&BluetoothAdapterFactoryWrapper::OnGetOverrideAdapter,
weak_ptr_factory_.GetWeakPtr(), std::move(callback),
pending_override_adapter_));
return;
}
DCHECK(BluetoothAdapterFactory::Get()->IsLowEnergySupported());
BluetoothAdapterFactory::Get()->GetAdapter(
base::BindOnce(&BluetoothAdapterFactoryWrapper::OnGetAdapter,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void BluetoothAdapterFactoryWrapper::ReleaseAdapter(
WebBluetoothServiceImpl* service) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (!HasAdapter(service)) {
return;
}
RemoveAdapterObserver(service);
if (adapter_observers_.empty()) {
SetAdapterInternal(/*adapter=*/nullptr, /*is_override_adapter=*/true);
SetAdapterInternal(/*adapter=*/nullptr, /*is_override_adapter=*/false);
}
}
BluetoothAdapter* BluetoothAdapterFactoryWrapper::GetAdapter(
WebBluetoothServiceImpl* service) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (HasAdapter(service)) {
return GetActiveAdapter().get();
}
return nullptr;
}
scoped_refptr<BluetoothAdapter>
BluetoothAdapterFactoryWrapper::GetActiveAdapter() {
if (override_adapter_) {
return override_adapter_;
}
if (adapter_) {
return adapter_;
}
return nullptr;
}
void BluetoothAdapterFactoryWrapper::SetBluetoothAdapterOverride(
scoped_refptr<BluetoothAdapter> override_adapter) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// If an adapter has already been acquired allow the adapter to be swapped out
// synchronously.
if (GetActiveAdapter()) {
SetAdapterInternal(std::move(override_adapter),
/*is_override_adapter=*/true);
return;
}
pending_override_adapter_ = std::move(override_adapter);
}
void BluetoothAdapterFactoryWrapper::OnGetAdapter(
AcquireAdapterCallback continuation,
scoped_refptr<BluetoothAdapter> adapter) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
SetAdapterInternal(adapter, /*is_override_adapter=*/false);
std::move(continuation).Run(GetActiveAdapter());
}
void BluetoothAdapterFactoryWrapper::OnGetOverrideAdapter(
AcquireAdapterCallback continuation,
scoped_refptr<BluetoothAdapter> override_adapter) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// Clear the adapter configured for override now that it has been acquired.
pending_override_adapter_.reset();
SetAdapterInternal(override_adapter, /*is_override_adapter=*/true);
std::move(continuation).Run(GetActiveAdapter());
}
bool BluetoothAdapterFactoryWrapper::HasAdapter(
WebBluetoothServiceImpl* service) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return base::Contains(adapter_observers_, service);
}
void BluetoothAdapterFactoryWrapper::MaybeAddAdapterObserver(
WebBluetoothServiceImpl* service) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// The same WebBluetoothServiceImpl might acquire the adapter multiple times
// if it gets multiple requests in parallel before the adapter is ready but is
// guaranteed to only call ReleaseAdapter() once on destruction.
auto [it, inserted] = adapter_observers_.insert(service);
scoped_refptr<BluetoothAdapter> active_adapter = GetActiveAdapter();
if (inserted && active_adapter) {
active_adapter->AddObserver(service);
}
}
void BluetoothAdapterFactoryWrapper::RemoveAdapterObserver(
WebBluetoothServiceImpl* service) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
size_t removed = adapter_observers_.erase(service);
DCHECK(removed);
scoped_refptr<BluetoothAdapter> active_adapter = GetActiveAdapter();
if (active_adapter) {
active_adapter->RemoveObserver(service);
}
}
void BluetoothAdapterFactoryWrapper::SetAdapterInternal(
scoped_refptr<BluetoothAdapter> adapter,
bool is_override_adapter) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// There might be extra unnecessary calls to this method if multiple requests
// to acquire an adapter were in flight at once.
scoped_refptr<BluetoothAdapter> active_adapter = GetActiveAdapter();
if (adapter == active_adapter) {
return;
}
if (active_adapter) {
for (WebBluetoothServiceImpl* service : adapter_observers_) {
active_adapter->RemoveObserver(service);
}
}
if (is_override_adapter) {
override_adapter_ = std::move(adapter);
} else {
adapter_ = std::move(adapter);
}
// Update active adapter as it might have changed.
active_adapter = GetActiveAdapter();
if (active_adapter) {
for (WebBluetoothServiceImpl* service : adapter_observers_) {
active_adapter->AddObserver(service);
}
}
}
} // namespace content