blob: c20d58152a4a37988703b7e4ba44c416b96fc54e [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "device/bluetooth/floss/bluetooth_adapter_floss.h"
#include "base/containers/contains.h"
#include "base/functional/callback_helpers.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/notreached.h"
#include "base/observer_list.h"
#include "base/strings/string_util.h"
#include "base/task/single_thread_task_runner.h"
#include "components/device_event_log/device_event_log.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_socket_thread.h"
#include "device/bluetooth/floss/bluetooth_advertisement_floss.h"
#include "device/bluetooth/floss/bluetooth_device_floss.h"
#include "device/bluetooth/floss/bluetooth_local_gatt_service_floss.h"
#include "device/bluetooth/floss/bluetooth_low_energy_scan_session_floss.h"
#include "device/bluetooth/floss/bluetooth_socket_floss.h"
#include "device/bluetooth/floss/floss_dbus_manager.h"
#include "device/bluetooth/floss/floss_lescan_client.h"
#include "device/bluetooth/floss/floss_socket_manager.h"
#include "device/bluetooth/public/cpp/bluetooth_address.h"
#if BUILDFLAG(IS_CHROMEOS)
#include "device/bluetooth/chromeos/bluetooth_connection_logger.h"
#include "device/bluetooth/chromeos/bluetooth_utils.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/constants/devicetype.h"
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
namespace floss {
namespace {
using device::UMABluetoothDiscoverySessionOutcome;
UMABluetoothDiscoverySessionOutcome TranslateDiscoveryErrorToUMA(
const Error& error) {
// TODO(b/192289534) - Deal with UMA later
return UMABluetoothDiscoverySessionOutcome::NOT_IMPLEMENTED;
}
// Helper function to gate init behind a check for Object Manager support.
void InitWhenObjectManagerKnown(base::OnceClosure callback) {
FlossDBusManager::Get()->CallWhenObjectManagerSupportIsKnown(
std::move(callback));
}
BluetoothDeviceFloss::ConnectErrorCode BtifStatusToConnectErrorCode(
uint32_t status) {
switch (static_cast<FlossAdapterClient::BtifStatus>(status)) {
case FlossAdapterClient::BtifStatus::kFail:
return BluetoothDeviceFloss::ConnectErrorCode::ERROR_FAILED;
case FlossAdapterClient::BtifStatus::kAuthFailure:
return BluetoothDeviceFloss::ConnectErrorCode::ERROR_AUTH_FAILED;
case FlossAdapterClient::BtifStatus::kAuthRejected:
return BluetoothDeviceFloss::ConnectErrorCode::ERROR_AUTH_REJECTED;
case FlossAdapterClient::BtifStatus::kDone:
case FlossAdapterClient::BtifStatus::kBusy:
return BluetoothDeviceFloss::ConnectErrorCode::ERROR_INPROGRESS;
case FlossAdapterClient::BtifStatus::kUnsupported:
return BluetoothDeviceFloss::ConnectErrorCode::ERROR_UNSUPPORTED_DEVICE;
default:
return BluetoothDeviceFloss::ConnectErrorCode::ERROR_UNKNOWN;
}
}
bool DeviceNeedsToReadProperties(device::BluetoothDevice* device) {
if (device) {
BluetoothDeviceFloss* floss_device =
static_cast<BluetoothDeviceFloss*>(device);
return !(floss_device->HasReadProperties() ||
floss_device->IsReadingProperties());
}
return true;
}
} // namespace
// Empty delegate for BLE scanning used during discovery.
class BleDelegateForDiscovery
: public device::BluetoothLowEnergyScanSession::Delegate {
public:
BleDelegateForDiscovery() = default;
~BleDelegateForDiscovery() override = default;
base::WeakPtr<BleDelegateForDiscovery> GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
// Empty device::BluetoothLowEnergyScanSession::Delegate overrides
void OnSessionStarted(
device::BluetoothLowEnergyScanSession* scan_session,
absl::optional<device::BluetoothLowEnergyScanSession::ErrorCode>
error_code) override {}
void OnDeviceFound(device::BluetoothLowEnergyScanSession* scan_session,
device::BluetoothDevice* device) override {}
void OnDeviceLost(device::BluetoothLowEnergyScanSession* scan_session,
device::BluetoothDevice* device) override {}
void OnSessionInvalidated(
device::BluetoothLowEnergyScanSession* scan_session) override {}
private:
base::WeakPtrFactory<BleDelegateForDiscovery> weak_ptr_factory_{this};
};
// According to the Bluetooth spec, these are the min and max values possible
// for advertising interval. Core 5.3 Spec, Vol 4, Part E, Section 7.8.5.
constexpr uint16_t kMinIntervalMs = 20;
constexpr uint16_t kMaxIntervalMs = 10240;
// static
scoped_refptr<BluetoothAdapterFloss> BluetoothAdapterFloss::CreateAdapter() {
return base::WrapRefCounted(new BluetoothAdapterFloss());
}
BluetoothAdapterFloss::BluetoothAdapterFloss() {
ui_task_runner_ = base::SingleThreadTaskRunner::GetCurrentDefault();
socket_thread_ = device::BluetoothSocketThread::Get();
le_discovery_session_delegate_ = std::make_unique<BleDelegateForDiscovery>();
}
BluetoothAdapterFloss::~BluetoothAdapterFloss() {
Shutdown();
}
void BluetoothAdapterFloss::Initialize(base::OnceClosure callback) {
BLUETOOTH_LOG(EVENT) << "BluetoothAdapterFloss::Initialize";
init_callback_ = std::move(callback);
// Go ahead to Init() if object manager support is already known (e.g. when
// using fake clients), otherwise find out object manager support first below.
if (floss::FlossDBusManager::Get()->IsObjectManagerSupportKnown()) {
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(&BluetoothAdapterFloss::Init,
weak_ptr_factory_.GetWeakPtr()));
return;
}
// Queue a task to check for ObjectManager support and init once the support
// is known.
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(&InitWhenObjectManagerKnown,
base::BindOnce(&BluetoothAdapterFloss::Init,
weak_ptr_factory_.GetWeakPtr())));
}
void BluetoothAdapterFloss::Shutdown() {
BLUETOOTH_LOG(EVENT) << "BluetoothAdapterFloss::Shutdown";
if (dbus_is_shutdown_)
return;
if (!FlossDBusManager::Get()->IsObjectManagerSupported()) {
dbus_is_shutdown_ = true;
return;
}
if (IsPresent())
RemoveAdapter(); // Cleans up devices and adapter observers.
DCHECK(devices_.empty());
// This may call unregister on advertisements that have already been
// unregistered but that's fine. The advertisement object keeps a track of
// the fact that it has been already unregistered and will call our empty
// error callback with an "Already unregistered" error, which we'll ignore.
for (const auto& adv : advertisements_) {
adv->Stop(base::DoNothing(), base::DoNothing());
}
advertisements_.clear();
FlossDBusManager::Get()->GetManagerClient()->RemoveObserver(this);
dbus_is_shutdown_ = true;
for (const auto& [key, scanner] : scanners_) {
scanner->OnRelease();
}
scanners_.clear();
}
void BluetoothAdapterFloss::AddAdapterObservers() {
DCHECK(FlossDBusManager::Get()->HasActiveAdapter());
// Add any observers that depend on a specific observer.
// FlossDBusManager::SwitchAdapter will control what the active adapter is
// that we are controlling.
FlossDBusManager::Get()->GetAdapterClient()->AddObserver(this);
FlossDBusManager::Get()->GetLEScanClient()->AddObserver(this);
FlossDBusManager::Get()->GetBatteryManagerClient()->AddObserver(this);
FlossDBusManager::Get()->GetGattManagerClient()->AddServerObserver(this);
#if BUILDFLAG(IS_CHROMEOS)
FlossDBusManager::Get()->GetAdminClient()->AddObserver(this);
#endif // BUILDFLAG(IS_CHROMEOS)
}
void BluetoothAdapterFloss::RemoveAdapterObservers() {
// Clean up observers
FlossDBusManager::Get()->GetAdapterClient()->RemoveObserver(this);
FlossDBusManager::Get()->GetLEScanClient()->RemoveObserver(this);
FlossDBusManager::Get()->GetGattManagerClient()->RemoveServerObserver(this);
#if BUILDFLAG(IS_CHROMEOS)
FlossDBusManager::Get()->GetAdminClient()->RemoveObserver(this);
#endif // BUILDFLAG(IS_CHROMEOS)
}
void BluetoothAdapterFloss::RemoveAdapter() {
if (!FlossDBusManager::Get()->HasActiveAdapter()) {
return;
}
RemoveAdapterObservers();
ClearAllDevices();
// Remove adapter by switching to an invalid adapter (cleans up DBus clients)
// and then emitting |AdapterPresentChanged| to observers.
FlossDBusManager::Get()->SwitchAdapter(FlossDBusManager::kInvalidAdapter,
base::DoNothing());
PresentChanged(false);
}
void BluetoothAdapterFloss::PopulateInitialDevices() {
FlossDBusManager::Get()->GetAdapterClient()->GetBondedDevices();
FlossDBusManager::Get()->GetAdapterClient()->GetConnectedDevices();
}
void BluetoothAdapterFloss::ClearAllDevices() {
// Move all elements of the original devices list to a new list here,
// leaving the original list empty so that when we send DeviceRemoved(),
// GetDevices() returns no devices.
DevicesMap devices_swapped;
devices_swapped.swap(devices_);
for (auto& iter : devices_swapped) {
for (auto& observer : observers_)
observer.DeviceRemoved(this, iter.second.get());
}
}
void BluetoothAdapterFloss::Init() {
// If dbus is shutdown or ObjectManager isn't supported, we just return
// without initializing anything.
if (dbus_is_shutdown_ ||
!FlossDBusManager::Get()->IsObjectManagerSupported()) {
BLUETOOTH_LOG(ERROR) << "Floss Adapter initialized without object manager";
initialized_ = true;
std::move(init_callback_).Run();
return;
}
BLUETOOTH_LOG(EVENT) << "Floss Adapter Initialized";
// Register for manager callbacks
FlossDBusManager::Get()->GetManagerClient()->AddObserver(this);
// Start with invalid DBus clients. This will return right away so don't need
// to wait for callback.
FlossDBusManager::Get()->SwitchAdapter(FlossDBusManager::kInvalidAdapter,
base::DoNothing());
// Switch to adapter if the default adapter is present and enabled. If it is
// not enabled, wait for upper layers to power it on.
if (IsPresent()) {
FlossManagerClient* manager = FlossDBusManager::Get()->GetManagerClient();
int default_adapter = manager->GetDefaultAdapter();
if (manager->GetAdapterEnabled(default_adapter)) {
AdapterEnabledChanged(default_adapter, /*enabled=*/true);
}
}
VLOG(1) << "BluetoothAdapterFloss::Init completed. Calling init callback.";
initialized_ = true;
std::move(init_callback_).Run();
}
void BluetoothAdapterFloss::NotifyDeviceFound(uint8_t scanner_id,
const std::string& address) {
if (!base::Contains(devices_, address)) {
return;
}
BluetoothDeviceFloss* device_ptr =
static_cast<BluetoothDeviceFloss*>(devices_[address].get());
for (const auto& [key, scanner] : scanners_) {
if (scanner->GetScannerId() == scanner_id) {
scanner->OnDeviceFound(device_ptr);
}
}
}
BluetoothDeviceFloss* BluetoothAdapterFloss::CreateOrGetDeviceForUpdate(
const std::string& address,
const std::string& name) {
BluetoothDeviceFloss* device_ptr;
std::string canonical_address = device::CanonicalizeBluetoothAddress(address);
if (base::Contains(devices_, canonical_address)) {
device_ptr =
static_cast<BluetoothDeviceFloss*>(devices_[canonical_address].get());
device_ptr->UpdateTimestamp();
} else {
auto device = CreateBluetoothDeviceFloss(
FlossDeviceId({.address = address, .name = name}));
device_ptr = device.get();
devices_.emplace(canonical_address, std::move(device));
}
return device_ptr;
}
BluetoothAdapterFloss::UUIDList BluetoothAdapterFloss::GetUUIDs() const {
return {};
}
std::string BluetoothAdapterFloss::GetAddress() const {
if (IsPowered()) {
return FlossDBusManager::Get()->GetAdapterClient()->GetAddress();
}
return std::string();
}
std::string BluetoothAdapterFloss::GetName() const {
if (!IsPresent())
return std::string();
return FlossDBusManager::Get()->GetAdapterClient()->GetName();
}
std::string BluetoothAdapterFloss::GetSystemName() const {
// TODO(b/238230098): Floss should expose system information, i.e. stack name
// and version.
return "Floss";
}
void BluetoothAdapterFloss::SetName(const std::string& name,
base::OnceClosure callback,
ErrorCallback error_callback) {
if (!IsPresent()) {
BLUETOOTH_LOG(ERROR) << "SetName: " << name << ". Not Present!";
std::move(error_callback).Run();
return;
}
FlossDBusManager::Get()->GetAdapterClient()->SetName(
base::BindOnce(&BluetoothAdapterFloss::OnMethodResponse,
weak_ptr_factory_.GetWeakPtr(), std::move(callback),
std::move(error_callback)),
name);
}
bool BluetoothAdapterFloss::IsInitialized() const {
return initialized_;
}
bool BluetoothAdapterFloss::IsPresent() const {
// No clients will be working if object manager isn't supported or dbus is
// shut down
if (dbus_is_shutdown_ ||
!FlossDBusManager::Get()->IsObjectManagerSupported()) {
VLOG(1) << "BluetoothAdapterFloss::IsPresent = false (no object manager "
"support or dbus is shut down)";
return false;
}
FlossManagerClient* manager = FlossDBusManager::Get()->GetManagerClient();
auto present = manager->GetAdapterPresent(manager->GetDefaultAdapter());
return present;
}
bool BluetoothAdapterFloss::IsPowered() const {
auto powered = FlossDBusManager::Get()->HasActiveAdapter();
return powered;
}
void BluetoothAdapterFloss::SetPowered(bool powered,
base::OnceClosure callback,
ErrorCallback error_callback) {
if (!IsPresent()) {
BLUETOOTH_LOG(ERROR) << "SetPowered: " << powered << ". Not Present!";
std::move(error_callback).Run();
return;
}
BLUETOOTH_LOG(EVENT) << __func__ << ": " << powered;
FlossDBusManager::Get()->GetManagerClient()->SetAdapterEnabled(
FlossDBusManager::Get()->GetManagerClient()->GetDefaultAdapter(), powered,
base::BindOnce(&BluetoothAdapterFloss::OnMethodResponse,
weak_ptr_factory_.GetWeakPtr(), std::move(callback),
std::move(error_callback)));
}
bool BluetoothAdapterFloss::IsDiscoverable() const {
if (!IsPresent())
return false;
return FlossDBusManager::Get()->GetAdapterClient()->GetDiscoverable();
}
void BluetoothAdapterFloss::SetDiscoverable(bool discoverable,
base::OnceClosure callback,
ErrorCallback error_callback) {
if (!IsPresent()) {
BLUETOOTH_LOG(ERROR) << "SetDiscoverable: " << discoverable
<< ". Not Present!";
std::move(error_callback).Run();
return;
}
FlossDBusManager::Get()->GetAdapterClient()->SetDiscoverable(
base::BindOnce(&BluetoothAdapterFloss::OnMethodResponse,
weak_ptr_factory_.GetWeakPtr(), std::move(callback),
std::move(error_callback)),
discoverable);
}
base::TimeDelta BluetoothAdapterFloss::GetDiscoverableTimeout() const {
if (!IsPresent()) {
return base::Seconds(0);
}
return base::Seconds(
FlossDBusManager::Get()->GetAdapterClient()->GetDiscoverableTimeout());
}
bool BluetoothAdapterFloss::IsDiscovering() const {
if (!IsPresent())
return false;
return NumScanningDiscoverySessions() > 0;
}
std::unique_ptr<BluetoothDeviceFloss>
BluetoothAdapterFloss::CreateBluetoothDeviceFloss(FlossDeviceId device) {
return std::make_unique<BluetoothDeviceFloss>(this, device, ui_task_runner_,
socket_thread_);
}
void BluetoothAdapterFloss::OnMethodResponse(base::OnceClosure callback,
ErrorCallback error_callback,
DBusResult<Void> ret) {
if (!ret.has_value()) {
std::move(error_callback).Run();
return;
}
std::move(callback).Run();
}
void BluetoothAdapterFloss::OnRepeatedDiscoverySessionResult(
bool start_discovery,
bool is_error,
UMABluetoothDiscoverySessionOutcome outcome) {
BLUETOOTH_LOG(DEBUG) << __func__ << ": Discovery result - is_error( "
<< is_error
<< "), outcome = " << static_cast<int>(outcome);
// If starting discovery failed and we have active discovery sessions, mark
// them as inactive.
if (start_discovery && is_error && NumScanningDiscoverySessions() > 0) {
BLUETOOTH_LOG(DEBUG) << "Marking sessions as inactive.";
MarkDiscoverySessionsAsInactive();
// If we failed to re-start a repeated discovery, that means the discovering
// state is false and needs to be sent to observers (we won't receive
// another discovering changed callback).
for (auto& observer : observers_) {
observer.AdapterDiscoveringChanged(this, /*discovering=*/false);
}
}
}
void BluetoothAdapterFloss::OnStartDiscovery(
DiscoverySessionResultCallback callback,
DBusResult<Void> ret) {
if (!ret.has_value()) {
// Adapter path only exists if active adapter hasn't disappeared
auto adapter_path = FlossDBusManager::Get()->HasActiveAdapter()
? FlossDBusManager::Get()
->GetAdapterClient()
->GetObjectPath()
->value()
: std::string();
BLUETOOTH_LOG(ERROR) << adapter_path
<< ": Failed to start discovery: " << ret.error();
std::move(callback).Run(true, TranslateDiscoveryErrorToUMA(ret.error()));
// Clear any LE discovery session if starting discovery failed.
le_discovery_session_.reset(nullptr);
return;
}
BLUETOOTH_LOG(EVENT) << __func__;
if (IsPresent()) {
std::move(callback).Run(false,
UMABluetoothDiscoverySessionOutcome::SUCCESS);
} else {
std::move(callback).Run(
true, UMABluetoothDiscoverySessionOutcome::ADAPTER_REMOVED);
}
}
void BluetoothAdapterFloss::OnStopDiscovery(
DiscoverySessionResultCallback callback,
DBusResult<Void> ret) {
if (!ret.has_value()) {
// Adapter path only exists if active adapter hasn't disappeared
auto adapter_path = FlossDBusManager::Get()->HasActiveAdapter()
? FlossDBusManager::Get()
->GetAdapterClient()
->GetObjectPath()
->value()
: std::string();
BLUETOOTH_LOG(ERROR) << adapter_path
<< ": Failed to stop discovery: " << ret.error();
std::move(callback).Run(true, TranslateDiscoveryErrorToUMA(ret.error()));
return;
}
BLUETOOTH_LOG(EVENT) << __func__;
DCHECK_GE(NumDiscoverySessions(), 0);
std::move(callback).Run(false, UMABluetoothDiscoverySessionOutcome::SUCCESS);
}
void BluetoothAdapterFloss::OnInitializeDeviceProperties(
BluetoothDeviceFloss* device_ptr) {
for (auto& observer : observers_)
observer.DeviceAdded(this, device_ptr);
}
void BluetoothAdapterFloss::OnGetConnectionState(const FlossDeviceId& device_id,
DBusResult<uint32_t> ret) {
BluetoothDeviceFloss* device =
static_cast<BluetoothDeviceFloss*>(GetDevice(device_id.address));
if (!device) {
LOG(WARNING) << "GetConnectionState returned for a non-existing device "
<< device_id;
return;
}
if (!ret.has_value()) {
LOG(WARNING) << "GetConnectionState returned error: " << ret.error()
<< " on device: " << device_id;
return;
}
// Connected if connection state >= 1:
// https://android.googlesource.com/platform/packages/modules/Bluetooth/+/84eff3217e552cbb3399e6deecdfce6748ae34ef/system/btif/src/btif_dm.cc#693
device->SetConnectionState(*ret);
// If the state is different than what is currently stored, update it.
if ((*ret >= 1) != device->IsConnected()) {
device->SetIsConnected(*ret >= 1);
if (device->HasReadProperties()) {
NotifyDeviceChanged(device);
NotifyDeviceConnectedStateChanged(device, device->IsConnected());
}
}
}
void BluetoothAdapterFloss::OnGetBondState(const FlossDeviceId& device_id,
DBusResult<uint32_t> ret) {
BluetoothDeviceFloss* device =
static_cast<BluetoothDeviceFloss*>(GetDevice(device_id.address));
if (!device) {
LOG(WARNING) << "GetBondState returned for a non-existing device "
<< device_id;
return;
}
if (!ret.has_value()) {
LOG(WARNING) << "GetBondState returned error: " << ret.error()
<< " on device: " << device_id;
return;
}
device->SetBondState(static_cast<FlossAdapterClient::BondState>(*ret),
absl::nullopt);
if (device->HasReadProperties()) {
NotifyDevicePairedChanged(device, device->IsPaired());
}
}
// Announce to observers a change in the adapter state.
void BluetoothAdapterFloss::DiscoverableChanged(bool discoverable) {
for (auto& observer : observers_) {
observer.AdapterDiscoverableChanged(this, discoverable);
}
}
void BluetoothAdapterFloss::DiscoveringChanged(bool discovering) {
// If the adapter stopped discovery due to a reason other than a request by
// us, reset the count to 0.
BLUETOOTH_LOG(EVENT) << "Discovering changed: " << discovering;
// While there are discovery sessions open, keep restarting discovery.
if (!discovering && NumScanningDiscoverySessions() > 0) {
FlossDBusManager::Get()->GetAdapterClient()->StartDiscovery(base::BindOnce(
&BluetoothAdapterFloss::OnStartDiscovery,
weak_ptr_factory_.GetWeakPtr(),
base::BindOnce(&BluetoothAdapterFloss::OnRepeatedDiscoverySessionResult,
weak_ptr_factory_.GetWeakPtr(),
/*start_discovery=*/true)));
} else {
for (auto& observer : observers_) {
observer.AdapterDiscoveringChanged(this, discovering);
}
// No active discovery sessions and we stopped discovering. Make sure the LE
// session is also stopped.
if (!discovering) {
le_discovery_session_.reset(nullptr);
}
}
}
void BluetoothAdapterFloss::PresentChanged(bool present) {
for (auto& observer : observers_) {
observer.AdapterPresentChanged(this, present);
}
}
void BluetoothAdapterFloss::NotifyAdapterPoweredChanged(bool powered) {
for (auto& observer : observers_) {
observer.AdapterPoweredChanged(this, powered);
}
}
void BluetoothAdapterFloss::NotifyDeviceConnectedStateChanged(
BluetoothDeviceFloss* device,
bool is_now_connected) {
DCHECK_EQ(device->IsConnected(), is_now_connected);
#if BUILDFLAG(IS_CHROMEOS)
if (is_now_connected) {
device::BluetoothConnectionLogger::RecordDeviceConnected(
device->GetIdentifier(), device->GetDeviceType());
} else {
device::RecordDeviceDisconnect(device->GetDeviceType());
}
// Also log the total number of connected devices. This uses a sampled
// histogram rather than a enumeration.
int count = 0;
for (auto& [unused_address, current_device] : devices_) {
if (current_device->IsPaired() && current_device->IsConnected()) {
count++;
}
}
UMA_HISTOGRAM_COUNTS_100("Bluetooth.ConnectedDeviceCount", count);
#endif
BluetoothAdapter::NotifyDeviceConnectedStateChanged(device, is_now_connected);
}
// Observers
void BluetoothAdapterFloss::AdapterPresent(int adapter, bool present) {
VLOG(1) << "BluetoothAdapterFloss: Adapter " << adapter
<< ", present: " << present;
// TODO(b/191906229) - Support non-default adapters
if (adapter !=
FlossDBusManager::Get()->GetManagerClient()->GetDefaultAdapter()) {
return;
}
// If default adapter isn't present, we need to clean up the dbus manager
if (!present) {
RemoveAdapter();
} else {
// Notify observers
PresentChanged(present);
}
}
void BluetoothAdapterFloss::AdapterEnabledChanged(int adapter, bool enabled) {
// TODO(b/191906229) - Support non-default adapters
if (adapter !=
FlossDBusManager::Get()->GetManagerClient()->GetDefaultAdapter()) {
VLOG(0) << __func__ << ": Adapter not default: "
<< FlossDBusManager::Get()->GetManagerClient()->GetDefaultAdapter();
return;
}
if (enabled && !FlossDBusManager::Get()->HasActiveAdapter()) {
FlossDBusManager::Get()->SwitchAdapter(
adapter, base::BindOnce(&BluetoothAdapterFloss::OnAdapterClientsReady,
weak_ptr_factory_.GetWeakPtr(), enabled));
} else if (!enabled && FlossDBusManager::Get()->HasActiveAdapter()) {
FlossDBusManager::Get()->SwitchAdapter(
FlossDBusManager::kInvalidAdapter,
base::BindOnce(&BluetoothAdapterFloss::OnAdapterClientsReady,
weak_ptr_factory_.GetWeakPtr(), enabled));
}
}
void BluetoothAdapterFloss::OnAdapterClientsReady(bool enabled) {
if (enabled) {
AddAdapterObservers();
PopulateInitialDevices();
#if BUILDFLAG(IS_CHROMEOS_ASH)
// No need to do this in Lacros because Ash would be around, and would have
// done this already.
SetStandardChromeOSAdapterName();
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
} else {
ClearAllDevices();
RemoveAdapterObservers();
}
NotifyAdapterPoweredChanged(enabled);
}
void BluetoothAdapterFloss::AdapterDiscoveringChanged(bool state) {
DCHECK(IsPresent());
DiscoveringChanged(state);
}
void BluetoothAdapterFloss::AdapterFoundDevice(
const FlossDeviceId& device_found) {
DCHECK(FlossDBusManager::Get());
DCHECK(IsPresent());
BLUETOOTH_LOG(EVENT) << __func__ << device_found;
auto device_floss = CreateBluetoothDeviceFloss(device_found);
BluetoothDeviceFloss* new_device_ptr = nullptr;
std::string canonical_address =
device::CanonicalizeBluetoothAddress(device_floss->GetAddress());
// Devices are newly found if they aren't in the devices_ map or they were
// added via ScanResult (which doesn't trigger property reads).
if (!base::Contains(devices_, canonical_address)) {
new_device_ptr = device_floss.get();
devices_.emplace(canonical_address, std::move(device_floss));
} else if (DeviceNeedsToReadProperties(devices_[canonical_address].get())) {
new_device_ptr =
static_cast<BluetoothDeviceFloss*>(devices_[canonical_address].get());
}
// Trigger property reads for new devices.
if (new_device_ptr) {
new_device_ptr->InitializeDeviceProperties(
base::BindOnce(&BluetoothAdapterFloss::OnInitializeDeviceProperties,
weak_ptr_factory_.GetWeakPtr(), new_device_ptr));
// TODO(b/204708206): Convert "Paired" and "Connected" property into a
// property framework.
FlossDBusManager::Get()->GetAdapterClient()->GetBondState(
base::BindOnce(&BluetoothAdapterFloss::OnGetBondState,
weak_ptr_factory_.GetWeakPtr(), device_found),
device_found);
FlossDBusManager::Get()->GetAdapterClient()->GetConnectionState(
base::BindOnce(&BluetoothAdapterFloss::OnGetConnectionState,
weak_ptr_factory_.GetWeakPtr(), device_found),
device_found);
return;
}
BluetoothDeviceFloss* device =
static_cast<BluetoothDeviceFloss*>(devices_[canonical_address].get());
// If the name has changed, we should also reinitialize the device properties.
// NotifyDeviceChanged will get called after properties are re-init.
if (device_floss->GetName() && device->GetName() != device_floss->GetName()) {
device->SetName(device_floss->GetName().value_or(""));
device->InitializeDeviceProperties(
base::BindOnce(&BluetoothAdapterFloss::NotifyDeviceChanged,
weak_ptr_factory_.GetWeakPtr(), device));
}
}
void BluetoothAdapterFloss::AdapterClearedDevice(
const FlossDeviceId& device_cleared) {
DCHECK(FlossDBusManager::Get());
DCHECK(IsPresent());
auto device_floss = CreateBluetoothDeviceFloss(device_cleared);
std::string canonical_address =
device::CanonicalizeBluetoothAddress(device_floss->GetAddress());
if (base::Contains(devices_, canonical_address)) {
BluetoothDeviceFloss* device_ptr = device_floss.get();
BluetoothDeviceFloss* found_ptr = static_cast<BluetoothDeviceFloss*>(
GetDevice(device_floss->GetAddress()));
// Only remove devices from devices_ that are not paired or connected.
if (!found_ptr || (!found_ptr->IsPaired() && !found_ptr->IsConnected())) {
devices_.erase(canonical_address);
}
for (auto& observer : observers_)
observer.DeviceRemoved(this, device_ptr);
}
BLUETOOTH_LOG(EVENT) << __func__ << device_cleared;
}
void BluetoothAdapterFloss::AdapterSspRequest(
const FlossDeviceId& remote_device,
uint32_t cod,
FlossAdapterClient::BluetoothSspVariant variant,
uint32_t passkey) {
BluetoothDeviceFloss* device =
static_cast<BluetoothDeviceFloss*>(GetDevice(remote_device.address));
if (!device) {
LOG(WARNING) << "SSP request for an unknown device";
return;
}
BluetoothPairingFloss* pairing = device->pairing();
// For incoming bonding which is not "just works", let the user decide whether
// to accept or reject the request. Don't process "just works" requests as
// it will be auto-accepted but it might be originated from a malicious peer.
if (!pairing &&
variant != FlossAdapterClient::BluetoothSspVariant::kConsent) {
device::BluetoothDevice::PairingDelegate* pairing_delegate =
DefaultPairingDelegate();
if (pairing_delegate) {
pairing = device->BeginPairing(pairing_delegate);
}
}
if (!pairing) {
// Reject the request right away to avoid users try to pair with it while
// the remote is waiting reply.
FlossDBusManager::Get()->GetAdapterClient()->SetPairingConfirmation(
base::DoNothing(), remote_device, /*accept=*/false);
return;
}
if (!pairing->active()) {
LOG(WARNING) << "SSP request for an inactive pairing";
return;
}
device::BluetoothDevice::PairingDelegate* pairing_delegate =
pairing->pairing_delegate();
if (!pairing_delegate) {
LOG(WARNING) << "SSP request for an unknown delegate";
return;
}
switch (variant) {
case FlossAdapterClient::BluetoothSspVariant::kPasskeyConfirmation:
pairing->SetPairingExpectation(
BluetoothPairingFloss::PairingExpectation::kConfirmation);
pairing_delegate->ConfirmPasskey(device, passkey);
break;
case FlossAdapterClient::BluetoothSspVariant::kPasskeyEntry:
// TODO(b/202334519): Test with LEGO Mindstorms EV3.
pairing->SetPairingExpectation(
BluetoothPairingFloss::PairingExpectation::kPinCode);
pairing_delegate->RequestPinCode(device);
break;
case FlossAdapterClient::BluetoothSspVariant::kConsent:
// We don't need to ask pairing delegate for consent, because having a
// pairing delegate means that a user is the initiator of this pairing.
FlossDBusManager::Get()->GetAdapterClient()->SetPairingConfirmation(
base::DoNothing(), remote_device, /*accept=*/true);
device->ResetPairing();
break;
case FlossAdapterClient::BluetoothSspVariant::kPasskeyNotification:
pairing_delegate->DisplayPasskey(device, passkey);
break;
default:
LOG(ERROR) << "Unimplemented pairing method "
<< static_cast<int>(variant);
}
}
void BluetoothAdapterFloss::DeviceBondStateChanged(
const FlossDeviceId& remote_device,
uint32_t status,
FlossAdapterClient::BondState bond_state) {
std::string canonical_address =
device::CanonicalizeBluetoothAddress(remote_device.address);
if (!base::Contains(devices_, canonical_address)) {
LOG(WARNING) << "Received BondStateChanged for a non-existent device";
return;
}
BLUETOOTH_LOG(EVENT) << "BondStateChanged " << remote_device.address
<< " state = " << static_cast<uint32_t>(bond_state)
<< " status = " << status;
BluetoothDeviceFloss* device =
static_cast<BluetoothDeviceFloss*>(devices_[canonical_address].get());
if (status != 0) {
if (device->pairing()) {
// Mark that no actions should be triggered for pairing delegate.
device->pairing()->SetActive(false);
}
LOG(ERROR) << "Received BondStateChanged with error status = " << status
<< " for " << remote_device.address;
device->SetBondState(bond_state, BtifStatusToConnectErrorCode(status));
if (bond_state == FlossAdapterClient::BondState::kNotBonded) {
// Since we're no longer bonded, update connection state so that
// ConnectCallback can process the error correctly.
device->SetIsConnected(false);
}
NotifyDeviceChanged(device);
NotifyDevicePairedChanged(device, device->IsPaired());
// TODO(b/192289534): Record status in UMA.
return;
}
if (device->GetBondState() == bond_state) {
return;
}
device->SetBondState(bond_state, absl::nullopt);
NotifyDeviceChanged(device);
NotifyDevicePairedChanged(device, device->IsPaired());
if (bond_state == FlossAdapterClient::BondState::kNotBonded) {
// If we're no longer bonded (or paired/connected), we should clear the
// device so it doesn't show up in found devices list.
AdapterClearedDevice(remote_device);
}
}
void BluetoothAdapterFloss::AdapterDeviceConnected(
const FlossDeviceId& device_id) {
DCHECK(FlossDBusManager::Get());
DCHECK(IsPresent());
BLUETOOTH_LOG(EVENT) << __func__ << ": " << device_id;
BluetoothDeviceFloss* device =
static_cast<BluetoothDeviceFloss*>(GetDevice(device_id.address));
if (!device) {
BLUETOOTH_LOG(EVENT) << "Adding newly connected device to devices_ map: "
<< device_id.address;
AdapterFoundDevice(device_id);
return;
}
// TODO(b/220387308): Querying connection state after connection can be racy
// with pairing state. We may need a separate pairing callback from Floss.
FlossDBusManager::Get()->GetAdapterClient()->GetConnectionState(
base::BindOnce(&BluetoothAdapterFloss::OnGetConnectionState,
weak_ptr_factory_.GetWeakPtr(), device_id),
device_id);
device->SetIsConnected(true);
if (device->HasReadProperties()) {
NotifyDeviceChanged(device);
NotifyDeviceConnectedStateChanged(device, true);
}
}
absl::optional<device::BluetoothDevice::BatteryType> variant_to_battery_type(
const std::string& variant) {
std::unordered_map<std::string, device::BluetoothDevice::BatteryType>
battery_type_lookup = {
{"", device::BluetoothDevice::BatteryType::kDefault},
{"left", device::BluetoothDevice::BatteryType::kLeftBudTrueWireless},
{"right",
device::BluetoothDevice::BatteryType::kRightBudTrueWireless},
{"case", device::BluetoothDevice::BatteryType::kCaseTrueWireless},
};
if (!base::Contains(battery_type_lookup, variant)) {
return absl::nullopt;
}
return battery_type_lookup[variant];
}
void BluetoothAdapterFloss::BatteryInfoUpdated(std::string remote_address,
BatterySet battery_set) {
BluetoothDeviceFloss* device =
static_cast<BluetoothDeviceFloss*>(GetDevice(remote_address));
if (!device) {
LOG(WARNING) << "BatterySet received for unknown device" << remote_address;
return;
}
for (const auto& battery : battery_set.batteries) {
absl::optional<device::BluetoothDevice::BatteryType> battery_type =
variant_to_battery_type(battery.variant);
if (!battery_type) {
LOG(WARNING) << "Unable to convert to battery_type from "
<< battery.variant;
continue;
}
device->SetBatteryInfo(device::BluetoothDevice::BatteryInfo(
battery_type.value(), battery.percentage));
}
}
void BluetoothAdapterFloss::AdapterDeviceDisconnected(
const FlossDeviceId& device_id) {
DCHECK(FlossDBusManager::Get());
DCHECK(IsPresent());
BLUETOOTH_LOG(EVENT) << __func__ << ": " << device_id;
BluetoothDeviceFloss* device =
static_cast<BluetoothDeviceFloss*>(GetDevice(device_id.address));
if (!device) {
LOG(WARNING) << "Device disconnected for an unknown device "
<< device_id.address;
return;
}
device->SetIsConnected(false);
if (device->HasReadProperties()) {
NotifyDeviceChanged(device);
NotifyDeviceConnectedStateChanged(device, false);
}
}
std::unordered_map<device::BluetoothDevice*, device::BluetoothDevice::UUIDSet>
BluetoothAdapterFloss::RetrieveGattConnectedDevicesWithDiscoveryFilter(
const device::BluetoothDiscoveryFilter& discovery_filter) {
NOTIMPLEMENTED();
return {};
}
#if BUILDFLAG(IS_CHROMEOS)
void BluetoothAdapterFloss::DevicePolicyEffectChanged(
const FlossDeviceId& device_id,
const absl::optional<PolicyEffect>& effect) {
BLUETOOTH_LOG(EVENT) << __func__ << ": " << device_id;
BluetoothDeviceFloss* device =
static_cast<BluetoothDeviceFloss*>(GetDevice(device_id.address));
if (!device) {
LOG(WARNING) << "Device disconnected for an unknown device "
<< device_id.address;
return;
}
device->SetIsBlockedByPolicy(effect.has_value() ? effect.value().affected
: false);
}
void BluetoothAdapterFloss::ServiceAllowlistChanged(
const std::vector<device::BluetoothUUID>& allowlist) {
std::vector<std::string> uuid_str(allowlist.size());
base::ranges::transform(
allowlist, uuid_str.begin(),
[](device::BluetoothUUID dev) { return dev.canonical_value(); });
BLUETOOTH_LOG(EVENT) << __func__ << ": " << base::JoinString(uuid_str, ",");
// TODO(b/257877673): Notify observers
}
#endif // BUILDFLAG(IS_CHROMEOS)
void BluetoothAdapterFloss::CreateRfcommService(
const device::BluetoothUUID& uuid,
const ServiceOptions& options,
CreateServiceCallback callback,
CreateServiceErrorCallback error_callback) {
DCHECK(!dbus_is_shutdown_);
BLUETOOTH_LOG(DEBUG) << "Creating RFCOMM service: " << uuid.canonical_value();
scoped_refptr<BluetoothSocketFloss> socket =
BluetoothSocketFloss::CreateBluetoothSocket(ui_task_runner_,
socket_thread_);
socket->Listen(this, FlossSocketManager::SocketType::kRfcomm, uuid, options,
base::BindOnce(std::move(callback), socket),
base::BindOnce(&BluetoothAdapterFloss::OnCreateServiceError,
weak_ptr_factory_.GetWeakPtr(), socket,
std::move(error_callback)));
}
void BluetoothAdapterFloss::CreateL2capService(
const device::BluetoothUUID& uuid,
const ServiceOptions& options,
CreateServiceCallback callback,
CreateServiceErrorCallback error_callback) {
DCHECK(!dbus_is_shutdown_);
BLUETOOTH_LOG(DEBUG) << "Creating L2CAP service: " << uuid.canonical_value();
scoped_refptr<BluetoothSocketFloss> socket =
BluetoothSocketFloss::CreateBluetoothSocket(ui_task_runner_,
socket_thread_);
socket->Listen(this, FlossSocketManager::SocketType::kL2cap, uuid, options,
base::BindOnce(std::move(callback), socket),
base::BindOnce(&BluetoothAdapterFloss::OnCreateServiceError,
weak_ptr_factory_.GetWeakPtr(), socket,
std::move(error_callback)));
}
void BluetoothAdapterFloss::OnCreateServiceError(
scoped_refptr<BluetoothSocketFloss> socket,
CreateServiceErrorCallback error_callback,
const std::string& error_message) {
std::move(error_callback).Run(error_message);
}
void BluetoothAdapterFloss::RegisterAdvertisement(
std::unique_ptr<device::BluetoothAdvertisement::Data> advertisement_data,
CreateAdvertisementCallback callback,
AdvertisementErrorCallback error_callback) {
scoped_refptr<BluetoothAdvertisementFloss> advertisement(
new BluetoothAdvertisementFloss(std::move(advertisement_data),
interval_ms_, this));
advertisement->Start(base::BindOnce(std::move(callback), advertisement),
std::move(error_callback));
advertisements_.emplace_back(advertisement);
}
void BluetoothAdapterFloss::SetAdvertisingInterval(
const base::TimeDelta& min,
const base::TimeDelta& max,
base::OnceClosure callback,
AdvertisementErrorCallback error_callback) {
uint16_t min_ms = static_cast<uint16_t>(
std::min(static_cast<int64_t>(std::numeric_limits<uint16_t>::max()),
min.InMilliseconds()));
uint16_t max_ms = static_cast<uint16_t>(
std::min(static_cast<int64_t>(std::numeric_limits<uint16_t>::max()),
max.InMilliseconds()));
// TODO(b/253718595): Support a 'no preference' option so Floss can choose a
// default value for the advertising interval. We are temporarily performing
// parameter checking to fulfill existing callers' expectations.
if (min_ms < kMinIntervalMs || max_ms > kMaxIntervalMs || min_ms > max_ms) {
std::move(error_callback)
.Run(device::BluetoothAdvertisement::
ERROR_INVALID_ADVERTISEMENT_INTERVAL);
return;
}
interval_ms_ = min_ms;
for (const auto& adv : advertisements_) {
adv->SetAdvertisingInterval(interval_ms_, base::DoNothing(),
base::DoNothing());
}
std::move(callback).Run();
}
void BluetoothAdapterFloss::ResetAdvertising(
base::OnceClosure callback,
AdvertisementErrorCallback error_callback) {
for (const auto& adv : advertisements_) {
adv->Stop(base::DoNothing(), base::DoNothing());
}
std::move(callback).Run();
}
void BluetoothAdapterFloss::ConnectDevice(
const std::string& address,
const absl::optional<device::BluetoothDevice::AddressType>& address_type,
ConnectDeviceCallback callback,
ConnectDeviceErrorCallback error_callback) {
// On Floss, ACL and RFCOMM connection are done with
// createRfcommSocketToServiceRecord(UUID). This should be called after
// ConnectDevice. Since all that is required on Floss for insecure connection
// is an address, this function currently just creates a device pointer.
// TODO(b/269500327): This behavior is actually a better design. We should
// rename this function to CreateDevice which does only device creation and
// let the caller decide what to do with it (Connect, Pair, etc).
BluetoothDeviceFloss* device_ptr;
std::string canonical_address = device::CanonicalizeBluetoothAddress(address);
if (base::Contains(devices_, canonical_address)) {
device_ptr =
static_cast<BluetoothDeviceFloss*>(devices_[canonical_address].get());
} else {
auto device = CreateBluetoothDeviceFloss(
FlossDeviceId({.address = address, .name = ""}));
device_ptr = device.get();
devices_.emplace(canonical_address, std::move(device));
}
std::move(callback).Run(device_ptr);
}
void BluetoothAdapterFloss::AddLocalGattService(
std::unique_ptr<BluetoothLocalGattServiceFloss> service) {
DCHECK(!base::Contains(owned_gatt_services_, service->GetIdentifier()));
owned_gatt_services_[service->GetIdentifier()] = std::move(service);
}
void BluetoothAdapterFloss::RemoveLocalGattService(
BluetoothLocalGattServiceFloss* service) {
auto service_iter = owned_gatt_services_.find(service->GetIdentifier());
if (service_iter == owned_gatt_services_.end()) {
BLUETOOTH_LOG(ERROR)
<< "Trying to remove service: " << service->GetIdentifier()
<< " from adapter: "
<< FlossDBusManager::Get()->GetAdapterClient()->GetObjectPath()->value()
<< " that doesn't own it.";
return;
}
// TODO(@sarveshkalwit): Unregister registered service.
owned_gatt_services_.erase(service_iter);
}
device::BluetoothLocalGattService* BluetoothAdapterFloss::GetGattService(
const std::string& identifier) const {
const auto& service = owned_gatt_services_.find(identifier);
return service == owned_gatt_services_.end() ? nullptr
: service->second.get();
}
void BluetoothAdapterFloss::RegisterGattService(
BluetoothLocalGattServiceFloss* service) {
FlossDBusManager::Get()->GetGattManagerClient()->AddService(
base::BindOnce(&BluetoothAdapterFloss::OnGattServiceAdded,
weak_ptr_factory_.GetWeakPtr(), service),
service->ToGattService());
}
void BluetoothAdapterFloss::OnGattServiceAdded(
BluetoothLocalGattServiceFloss* service,
DBusResult<Void> ret) {
if (!ret.has_value()) {
service->GattServerServiceAdded(GattStatus::kError,
service->ToGattService());
}
}
void BluetoothAdapterFloss::UnregisterGattService(
BluetoothLocalGattServiceFloss* service) {
FlossDBusManager::Get()->GetGattManagerClient()->RemoveService(
base::BindOnce(&BluetoothAdapterFloss::OnGattServiceRemoved,
weak_ptr_factory_.GetWeakPtr(), service),
service->InstanceId());
}
void BluetoothAdapterFloss::OnGattServiceRemoved(
BluetoothLocalGattServiceFloss* service,
DBusResult<Void> ret) {
if (!ret.has_value()) {
service->GattServerServiceRemoved(GattStatus::kError,
service->InstanceId());
}
}
bool BluetoothAdapterFloss::SendValueChanged(
BluetoothLocalGattCharacteristicFloss* characteristic,
const std::vector<uint8_t>& value) {
if (!characteristic->GetService()->IsRegistered()) {
return false;
}
std::string service_name =
FlossDBusManager::Get()->GetGattManagerClient()->ServiceName();
FlossDBusManager::Get()->GetGattManagerClient()->ServerSendNotification(
base::DoNothing(), service_name, characteristic->InstanceId(),
/*confirm=*/false, value);
// TODO(@sarveshkalwit) How to confirm success?
return true;
}
void BluetoothAdapterFloss::GattServerNotificationSent(std::string address,
GattStatus status) {
NOTIMPLEMENTED();
}
#if BUILDFLAG(IS_CHROMEOS)
void BluetoothAdapterFloss::SetServiceAllowList(const UUIDList& uuids,
base::OnceClosure callback,
ErrorCallback error_callback) {
FlossDBusManager::Get()->GetAdminClient()->SetAllowedServices(
base::BindOnce(&BluetoothAdapterFloss::OnMethodResponse,
weak_ptr_factory_.GetWeakPtr(), std::move(callback),
std::move(error_callback)),
uuids);
}
std::unique_ptr<device::BluetoothLowEnergyScanSession>
BluetoothAdapterFloss::StartLowEnergyScanSession(
std::unique_ptr<device::BluetoothLowEnergyScanFilter> filter,
base::WeakPtr<device::BluetoothLowEnergyScanSession::Delegate> delegate) {
auto scan_session = std::make_unique<BluetoothLowEnergyScanSessionFloss>(
std::move(filter), delegate,
base::BindOnce(&BluetoothAdapterFloss::OnLowEnergyScanSessionDestroyed,
weak_ptr_factory_.GetWeakPtr()));
FlossDBusManager::Get()->GetLEScanClient()->RegisterScanner(base::BindOnce(
&BluetoothAdapterFloss::OnRegisterScanner, weak_ptr_factory_.GetWeakPtr(),
scan_session->GetWeakPtr()));
return scan_session;
}
device::BluetoothAdapter::LowEnergyScanSessionHardwareOffloadingStatus
BluetoothAdapterFloss::GetLowEnergyScanSessionHardwareOffloadingStatus() {
if (!IsPowered()) {
BLUETOOTH_LOG(ERROR)
<< "GetLowEnergyScanSessionHardwareOffloadingStatus called when "
<< "adapter is not powered.";
return device::BluetoothAdapter::
LowEnergyScanSessionHardwareOffloadingStatus::kUndetermined;
}
return FlossDBusManager::Get()->GetGattManagerClient()->GetMsftSupported()
? device::BluetoothAdapter::
LowEnergyScanSessionHardwareOffloadingStatus::kSupported
: device::BluetoothAdapter::
LowEnergyScanSessionHardwareOffloadingStatus::kNotSupported;
}
#endif // BUILDFLAG(IS_CHROMEOS)
#if BUILDFLAG(IS_CHROMEOS_ASH)
void BluetoothAdapterFloss::SetStandardChromeOSAdapterName() {
if (!IsPresent()) {
BLUETOOTH_LOG(ERROR)
<< "SetStandardChromeOSAdapterName called when adapter is not present.";
return;
}
std::string alias = ash::GetDeviceBluetoothName(GetAddress());
FlossDBusManager::Get()->GetAdapterClient()->SetName(base::DoNothing(),
alias);
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
void BluetoothAdapterFloss::ScannerRegistered(device::BluetoothUUID uuid,
uint8_t scanner_id,
GattStatus status) {
BLUETOOTH_LOG(EVENT) << "Scanner registered with UUID = " << uuid
<< ", scanner id = " << static_cast<int>(scanner_id)
<< ", status = " << static_cast<int>(status);
if (!base::Contains(scanners_, uuid)) {
VLOG(1) << "ScannerRegistered but no longer exists " << uuid;
return;
}
if (status != GattStatus::kSuccess) {
BLUETOOTH_LOG(ERROR) << "Error registering scanner " << uuid
<< ", status: " << static_cast<int>(status);
scanners_[uuid]->OnActivate(scanner_id, /*success=*/false);
return;
}
FlossDBusManager::Get()->GetLEScanClient()->StartScan(
base::BindOnce(&BluetoothAdapterFloss::OnStartScan,
weak_ptr_factory_.GetWeakPtr(), uuid, scanner_id),
scanner_id, ScanSettings{}, scanners_[uuid]->GetFlossScanFilter());
}
void BluetoothAdapterFloss::ScanResultReceived(ScanResult scan_result) {
BLUETOOTH_LOG(DEBUG) << __func__ << ": " << scan_result.address;
BluetoothDeviceFloss* device_ptr =
CreateOrGetDeviceForUpdate(scan_result.address, scan_result.name);
device::BluetoothDevice::ServiceDataMap service_data_map;
for (const auto& [uuid, bytes] : scan_result.service_data) {
service_data_map[device::BluetoothUUID(uuid)] = bytes;
}
device_ptr->UpdateAdvertisementData(
scan_result.rssi, scan_result.flags, scan_result.service_uuids,
scan_result.tx_power, service_data_map,
device::BluetoothDevice::ManufacturerDataMap(
scan_result.manufacturer_data.begin(),
scan_result.manufacturer_data.end()));
for (auto& observer : observers_)
observer.DeviceAdvertisementReceived(this, device_ptr, scan_result.rssi,
scan_result.adv_data);
// We are currently in an LE discovery session. Also emit a DeviceFound event
// since we have updated data for this device.
if (le_discovery_session_) {
AdapterFoundDevice(device_ptr->AsFlossDeviceId());
}
}
void BluetoothAdapterFloss::AdvertisementFound(uint8_t scanner_id,
ScanResult scan_result) {
BLUETOOTH_LOG(DEBUG) << __func__ << ": " << scan_result.address;
CreateOrGetDeviceForUpdate(scan_result.address, scan_result.name);
// MSFT event does not arrive together with the advertisement data, but they
// always arrive very close to each other.
// Ideally Floss daemon should consolidate the advertisement data into the
// AdvertisementFound callback, but for now the workaround is to delay
// notifying client for a little bit to practically be sure that the client
// will have updated the advertisement data by the time they hear
// OnDeviceFound.
// TODO(b/271165074): Fix this by combining AdvertisementFound with the first
// advertisement data.
base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&BluetoothAdapterFloss::NotifyDeviceFound,
weak_ptr_factory_.GetWeakPtr(), scanner_id,
device::CanonicalizeBluetoothAddress(scan_result.address)),
base::Seconds(1));
}
void BluetoothAdapterFloss::AdvertisementLost(uint8_t scanner_id,
ScanResult scan_result) {
BLUETOOTH_LOG(DEBUG) << __func__ << ": " << scan_result.address;
auto device = CreateBluetoothDeviceFloss(FlossDeviceId(
{.address = scan_result.address, .name = scan_result.name}));
std::string canonical_address =
device::CanonicalizeBluetoothAddress(device->GetAddress());
if (!base::Contains(devices_, canonical_address)) {
BLUETOOTH_LOG(EVENT) << __func__
<< ": Device lost but never previously found: "
<< scan_result.address;
return;
}
BluetoothDeviceFloss* device_ptr = device.get();
BluetoothDeviceFloss* deleted_ptr =
static_cast<BluetoothDeviceFloss*>(GetDevice(device->GetAddress()));
// Only remove devices from devices_ that are not paired or connected.
if (!deleted_ptr ||
(!deleted_ptr->IsPaired() && !deleted_ptr->IsConnected())) {
devices_.erase(canonical_address);
}
for (const auto& [key, scanner] : scanners_) {
if (scanner->GetScannerId() == scanner_id) {
scanner->OnDeviceLost(device_ptr);
}
}
}
void BluetoothAdapterFloss::RemovePairingDelegateInternal(
device::BluetoothDevice::PairingDelegate* pairing_delegate) {
NOTIMPLEMENTED();
}
base::WeakPtr<device::BluetoothAdapter> BluetoothAdapterFloss::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
bool BluetoothAdapterFloss::SetPoweredImpl(bool powered) {
NOTREACHED();
return false;
}
void BluetoothAdapterFloss::StartScanWithFilter(
std::unique_ptr<device::BluetoothDiscoveryFilter> discovery_filter,
DiscoverySessionResultCallback callback) {
// Also return ADAPTER_NOT_PRESENT if not powered.
// TODO(b/193839304) - !IsPowered should return ADAPTER_NOT_POWERED
if (!IsPresent() || !IsPowered()) {
std::move(callback).Run(
true, UMABluetoothDiscoverySessionOutcome::ADAPTER_NOT_PRESENT);
return;
}
BLUETOOTH_LOG(EVENT) << __func__;
#if BUILDFLAG(IS_CHROMEOS)
// First start LE scan before discovery
if (!le_discovery_session_) {
le_discovery_session_ = StartLowEnergyScanSession(
nullptr, static_cast<BleDelegateForDiscovery*>(
le_discovery_session_delegate_.get())
->GetWeakPtr());
}
#endif
// TODO(b/192251662) - Support scan filtering. For now, start scanning with no
// filters in place.
FlossDBusManager::Get()->GetAdapterClient()->StartDiscovery(
base::BindOnce(&BluetoothAdapterFloss::OnStartDiscovery,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void BluetoothAdapterFloss::UpdateFilter(
std::unique_ptr<device::BluetoothDiscoveryFilter> discovery_filter,
DiscoverySessionResultCallback callback) {
// Also return ADAPTER_NOT_PRESENT if not powered.
// TODO(b/193839304) - !IsPowered should return ADAPTER_NOT_POWERED
if (!IsPresent() || !IsPowered()) {
std::move(callback).Run(
true, UMABluetoothDiscoverySessionOutcome::ADAPTER_NOT_PRESENT);
return;
}
BLUETOOTH_LOG(EVENT) << __func__;
// TODO(b/192251662) - Support scan filtering. For now, always return success
std::move(callback).Run(false, UMABluetoothDiscoverySessionOutcome::SUCCESS);
}
void BluetoothAdapterFloss::StopScan(DiscoverySessionResultCallback callback) {
// Also return ADAPTER_NOT_PRESENT if not powered.
// TODO(b/193839304) - !IsPowered should return ADAPTER_NOT_POWERED
if (!IsPresent() || !IsPowered()) {
std::move(callback).Run(
/*is_error= */ false,
UMABluetoothDiscoverySessionOutcome::ADAPTER_NOT_PRESENT);
return;
}
BLUETOOTH_LOG(EVENT) << __func__;
DCHECK_EQ(NumDiscoverySessions(), 0);
FlossDBusManager::Get()->GetAdapterClient()->CancelDiscovery(
base::BindOnce(&BluetoothAdapterFloss::OnStopDiscovery,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
// Deleting the scan session will stop any active scanning.
le_discovery_session_.reset(nullptr);
}
void BluetoothAdapterFloss::OnRegisterScanner(
base::WeakPtr<BluetoothLowEnergyScanSessionFloss> scan_session,
DBusResult<device::BluetoothUUID> ret) {
if (!scan_session) {
BLUETOOTH_LOG(ERROR)
<< "Scan session removed before registration completed.";
return;
}
if (!ret.has_value()) {
BLUETOOTH_LOG(ERROR) << "Failed RegisterScanner: " << ret.error();
scan_session->OnRelease();
return;
}
scan_session->OnRegistered(ret.value());
scanners_[ret.value()] = scan_session;
BLUETOOTH_LOG(EVENT) << "Registering scanner " << ret.value();
}
void BluetoothAdapterFloss::OnStartScan(
device::BluetoothUUID uuid,
uint8_t scanner_id,
DBusResult<FlossDBusClient::BtifStatus> ret) {
if (!base::Contains(scanners_, uuid)) {
VLOG(1) << "Started scanning but scanner no longer exists " << uuid;
return;
}
if (!ret.has_value() ||
ret.value() != FlossDBusClient::BtifStatus::kSuccess) {
if (ret.has_value()) {
BLUETOOTH_LOG(ERROR) << "Failed StartScan, status: "
<< static_cast<uint32_t>(ret.value());
} else {
BLUETOOTH_LOG(ERROR) << "Failed StartScan, D-Bus error: " << ret.error();
}
scanners_[uuid]->OnActivate(scanner_id, /*success=*/false);
return;
}
BLUETOOTH_LOG(EVENT) << "OnStartScan succeeded";
scanners_[uuid]->OnActivate(scanner_id, /*success=*/true);
}
void BluetoothAdapterFloss::OnLowEnergyScanSessionDestroyed(
const std::string& uuid_str) {
BLUETOOTH_LOG(EVENT) << __func__ << ": UUID = " << uuid_str;
device::BluetoothUUID uuid = device::BluetoothUUID(uuid_str);
if (!base::Contains(scanners_, uuid)) {
return;
}
uint8_t scanner_id = scanners_[uuid]->GetScannerId();
scanners_.erase(uuid);
if (IsPowered()) {
FlossDBusManager::Get()->GetLEScanClient()->UnregisterScanner(
base::BindOnce(&BluetoothAdapterFloss::OnUnregisterScanner,
weak_ptr_factory_.GetWeakPtr(), scanner_id),
scanner_id);
}
}
void BluetoothAdapterFloss::OnUnregisterScanner(uint8_t scanner_id,
DBusResult<bool> ret) {
BLUETOOTH_LOG(EVENT) << __func__ << ": scanner_id = " << scanner_id;
if (!ret.has_value()) {
BLUETOOTH_LOG(ERROR) << "Failed UnregisterScanner: " << ret.error();
}
}
} // namespace floss