blob: 209a3c787c06cc51c607515403b3775c96f961c1 [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/dbus/bluetooth_manager_proxy.h"
#include <cstdint>
#include <vector>
#include <brillo/variant_dictionary.h>
#include "bluetooth/dbus-proxies.h"
#include "shill/bluetooth/bluetooth_manager_interface.h"
#include "shill/error.h"
#include "shill/logging.h"
#include "shill/scope_logger.h"
namespace shill {
namespace {
// TOOD(b/262931830): Use constants defined in system_api once they've been
// added.
constexpr char kBTManagerServiceName[] = "org.chromium.bluetooth.Manager";
constexpr base::TimeDelta kDBusInitializationDelay = base::Seconds(1);
}
namespace Logging {
static auto kModuleLogScope = ScopeLogger::kBluetooth;
} // namespace Logging
BluetoothManagerProxy::BluetoothManagerProxy(
const scoped_refptr<dbus::Bus>& bus,
EventDispatcher* dispatcher,
const base::RepeatingClosure& service_appeared_callback)
: manager_proxy_(new org::chromium::bluetooth::ManagerProxy(
bus, kBTManagerServiceName)),
dispatcher_(dispatcher),
service_appeared_callback_(service_appeared_callback) {
// One time callback when service becomes available.
manager_proxy_->GetObjectProxy()->WaitForServiceToBeAvailable(base::BindOnce(
&BluetoothManagerProxy::OnServiceAvailable, weak_factory_.GetWeakPtr()));
}
bool BluetoothManagerProxy::GetFlossEnabled(bool* enabled) const {
brillo::ErrorPtr error;
if (!manager_proxy_->GetFlossEnabled(enabled, &error)) {
LOG(ERROR) << "Failed to query Floss status: " << error->GetCode() << " "
<< error->GetMessage();
return false;
}
SLOG(3) << __func__ << ": " << manager_proxy_->GetObjectPath().value()
<< ": BT uses " << (*enabled ? "Floss" : "BlueZ");
return true;
}
void BluetoothManagerProxy::OnServiceAvailable(bool /* available */) const {
SLOG(2) << __func__ << ": " << manager_proxy_->GetObjectPath().value()
<< ": BT manager service is available";
// |service_appeared_callback_| might invoke calls to the ObjectProxy, so
// defer the callback to the event loop.
// Note:
// Race condition in btmanagerd/D-Bus: btmanagerd's D-Bus interface reports
// that it's available before all the methods have been registered. Wait a
// little bit before querying.
// TODO(b/263432564): remove the delay once the race condition has been fixed,
// but keep deferring the callback to the event loop.
dispatcher_->PostDelayedTask(
FROM_HERE,
base::BindOnce(&BluetoothManagerProxy::OnServiceReady,
weak_factory_.GetWeakPtr()),
kDBusInitializationDelay);
}
void BluetoothManagerProxy::OnServiceReady() const {
SLOG(2) << __func__ << ": " << manager_proxy_->GetObjectPath().value()
<< ": BT manager service ready";
if (!service_appeared_callback_.is_null()) {
service_appeared_callback_.Run();
}
}
bool BluetoothManagerProxy::GetAvailableAdapters(
bool force_query,
bool* is_floss,
std::vector<BluetoothManagerInterface::BTAdapterWithEnabled>* adapters)
const {
if (!GetFlossEnabled(is_floss)) {
return false;
}
if (!*is_floss && !force_query) {
// The device is not using Floss at the moment. Return immediately since
// Floss won't know if the BT adapters are enabled or not in that case.
// Callers may choose to fallback to BlueZ.
return true;
}
std::vector<brillo::VariantDictionary> bt_adapters;
brillo::ErrorPtr error;
if (!manager_proxy_->GetAvailableAdapters(&bt_adapters, &error)) {
LOG(ERROR) << "Failed to query available BT adapters: " << error->GetCode()
<< " " << error->GetMessage();
return false;
}
for (auto bt_adapter : bt_adapters) {
BluetoothManagerInterface::BTAdapterWithEnabled adapter{
.hci_interface = brillo::GetVariantValueOrDefault<int32_t>(
bt_adapter, "hci_interface"),
.enabled =
brillo::GetVariantValueOrDefault<bool>(bt_adapter, "enabled")};
adapters->push_back(adapter);
SLOG(3) << __func__ << ": " << manager_proxy_->GetObjectPath().value()
<< ": Found BT adapter HCI " << adapter.hci_interface;
if (*is_floss) {
// The "enabled" bit is not valid if the device is using BlueZ.
SLOG(3) << __func__ << ": " << manager_proxy_->GetObjectPath().value()
<< ": BT adapter " << (adapter.enabled ? "enabled" : "disabled");
}
}
return true;
}
bool BluetoothManagerProxy::GetDefaultAdapter(int32_t* hci) const {
brillo::ErrorPtr error;
if (!manager_proxy_->GetDefaultAdapter(hci, &error)) {
LOG(ERROR) << "Failed to get default adapter:" << error->GetCode() << " "
<< error->GetMessage();
return false;
}
SLOG(3) << __func__ << ": " << manager_proxy_->GetObjectPath().value()
<< ": Found default BT adapter, HCI " << *hci;
return true;
}
} // namespace shill