blob: 54a41ba907e98656d7e6ee5c05743ea0304dee28 [file] [log] [blame] [edit]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "shill/bluetooth/bluetooth_manager.h"
#include <cstdint>
#include <utility>
#include <vector>
#include <base/functional/bind.h>
#include "shill/control_interface.h"
#include "shill/logging.h"
namespace shill {
namespace Logging {
static auto kModuleLogScope = ScopeLogger::kBluetooth;
} // namespace Logging
BluetoothManager::BluetoothManager(ControlInterface* control_interface)
: init_complete_(false), control_interface_(control_interface) {}
bool BluetoothManager::Start() {
bluetooth_manager_proxy_ =
control_interface_->CreateBluetoothManagerProxy(base::BindRepeating(
&BluetoothManager::OnBTManagerAvailable, weak_factory_.GetWeakPtr()));
if (!bluetooth_manager_proxy_) {
LOG(ERROR) << "Failed to initialize BT manager proxy";
TearDown();
return false;
}
bluez_proxy_ = control_interface_->CreateBluetoothBlueZProxy();
if (!bluez_proxy_) {
LOG(ERROR) << "Failed to initialize BlueZ proxy";
TearDown();
return false;
}
return true;
}
void BluetoothManager::Stop() {
TearDown();
}
void BluetoothManager::TearDown() {
init_complete_ = false;
bluez_proxy_.reset();
adapter_proxies_.clear();
bluetooth_manager_proxy_.reset();
}
bool BluetoothManager::UpdateAdapterProxy(int hci) const {
if (adapter_proxies_.contains(hci)) {
return true;
}
auto proxy = control_interface_->CreateBluetoothAdapterProxy(hci);
if (!proxy) {
return false;
}
SLOG(3) << __func__ << ": adding BT adapter " << hci;
adapter_proxies_.emplace(hci, std::move(proxy));
return true;
}
void BluetoothManager::CompleteInitialization() {
LOG(INFO) << "Completing initialization of BT manager";
// On startup we want to know the list of adapters that are present on the
// device even if we can't get all the information we would like (are they
// actually enabled?) at the time so we force the discovery even if the device
// is currently using BlueZ.
bool floss;
std::vector<BluetoothManagerInterface::BTAdapterWithEnabled> adapters;
if (!bluetooth_manager_proxy_->GetAvailableAdapters(/*force_query=*/true,
&floss, &adapters)) {
LOG(ERROR) << __func__ << ": Failed to query available BT adapters";
TearDown();
return;
}
LOG(INFO) << "BT manager found " << adapters.size() << " adapters";
for (auto adapter : adapters) {
if (!UpdateAdapterProxy(adapter.hci_interface)) {
LOG(ERROR) << "Failed to initialize BT adapter proxy "
<< adapter.hci_interface;
TearDown();
return;
}
}
init_complete_ = true;
LOG(INFO) << "Completed initialization of BT manager";
}
void BluetoothManager::OnBTManagerAvailable() {
LOG(INFO) << __func__ << ": BT manager is available";
CompleteInitialization();
}
bool BluetoothManager::GetAvailableAdapters(
bool* is_floss,
std::vector<BluetoothManagerInterface::BTAdapterWithEnabled>* adapters)
const {
if (is_floss == nullptr) {
LOG(ERROR) << __func__ << ": Null 'is_floss' argument";
return false;
}
if (adapters == nullptr) {
LOG(ERROR) << __func__ << ": Null 'adapters' arguments";
return false;
}
if (!init_complete_) {
LOG(ERROR) << __func__ << ": BT manager is not ready";
return false;
}
if (!bluetooth_manager_proxy_->GetAvailableAdapters(/*force_query=*/false,
is_floss, adapters)) {
LOG(ERROR) << __func__ << ": Failed to query available BT adapters";
return false;
}
// Make sure we have proxies to all adapters.
for (auto adapter : *adapters) {
if (!UpdateAdapterProxy(adapter.hci_interface)) {
LOG(ERROR) << "Failed to initialize BT adapter proxy "
<< adapter.hci_interface;
return false;
}
}
if (*is_floss) {
// The device is using Floss so in that case BluetoothManagerProxy was able
// to report the state of the BT adapters. Nothing left to do, return
// success.
return true;
}
SLOG(3) << __func__ << ": Floss disabled, fallback to BlueZ";
bool powered;
if (!bluez_proxy_->GetAdapterPowered(&powered)) {
LOG(ERROR) << __func__ << ": Failed to query BT powered state from BlueZ";
return false;
}
// For BlueZ we only support 1 adapter, interface 0.
for (auto adapter : *adapters) {
if (adapter.hci_interface == 0) {
adapter.enabled = powered;
return true;
}
}
SLOG(2) << __func__ << ": Adapter 0 not found";
adapters->push_back({.hci_interface = 0, .enabled = powered});
return true;
}
bool BluetoothManager::GetDefaultAdapter(int32_t* hci) const {
if (hci == nullptr) {
LOG(ERROR) << __func__ << ": Null 'hci' argument";
return false;
}
if (!init_complete_) {
LOG(ERROR) << __func__ << ": BT manager is not ready";
return false;
}
if (!bluetooth_manager_proxy_->GetDefaultAdapter(hci)) {
LOG(ERROR) << __func__ << ": Failed to query the default BT adapter";
return false;
}
if (!UpdateAdapterProxy(*hci)) {
LOG(ERROR) << "Failed to initialize BT adapter proxy " << *hci;
return false;
}
return true;
}
bool BluetoothManager::GetProfileConnectionState(
int32_t hci, BTProfile profile, BTProfileConnectionState* state) const {
if (!init_complete_) {
LOG(ERROR) << __func__ << ": BT manager is not ready";
return false;
}
auto it = adapter_proxies_.find(hci);
if (it == adapter_proxies_.end()) {
LOG(ERROR) << "Adapter " << hci << " not found";
return false;
}
if (!it->second->GetProfileConnectionState(profile, state)) {
LOG(ERROR) << "Failed to query profile connection state";
return false;
}
return true;
}
bool BluetoothManager::IsDiscovering(int32_t hci, bool* discovering) const {
if (!init_complete_) {
LOG(ERROR) << __func__ << ": BT manager is not ready";
return false;
}
auto it = adapter_proxies_.find(hci);
if (it == adapter_proxies_.end()) {
LOG(ERROR) << "Adapter " << hci << " not found";
return false;
}
if (!it->second->IsDiscovering(discovering)) {
LOG(ERROR) << "Failed to query discovering state";
return false;
}
return true;
}
} // namespace shill