910e62b5创建于 1月15日历史提交
// 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