blob: 699a4ffd4dd9b1182510bae979ebafaf6e58fd3d [file] [log] [blame]
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "host.h"
#include <fidl/fuchsia.hardware.bluetooth/cpp/wire.h>
#include <lib/fdio/directory.h>
#include <lib/inspect/component/cpp/component.h>
#include "fidl/host_server.h"
#include "fuchsia/hardware/bluetooth/cpp/fidl.h"
#include "lib/async/default.h"
#include "src/connectivity/bluetooth/core/bt-host/controllers/fidl_controller.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/log.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/random.h"
using namespace bt;
namespace bthost {
BtHostComponent::BtHostComponent(async_dispatcher_t* dispatcher, const std::string& device_path,
bool initialize_rng)
: pw_dispatcher_(dispatcher),
device_path_(device_path),
initialize_rng_(initialize_rng),
inspector_(inspect::ComponentInspector(dispatcher, {})) {
if (initialize_rng) {
set_random_generator(&random_generator_);
}
inspector_.root().RecordString("name", device_path_);
}
BtHostComponent::~BtHostComponent() {
if (initialize_rng_) {
set_random_generator(nullptr);
}
}
// static
std::unique_ptr<BtHostComponent> BtHostComponent::Create(async_dispatcher_t* dispatcher,
const std::string& device_path) {
std::unique_ptr<BtHostComponent> host(
new BtHostComponent(dispatcher, device_path, /*initialize_rng=*/true));
return host;
}
// static
std::unique_ptr<BtHostComponent> BtHostComponent::CreateForTesting(async_dispatcher_t* dispatcher,
const std::string& device_path) {
std::unique_ptr<BtHostComponent> host(
new BtHostComponent(dispatcher, device_path, /*initialize_rng=*/false));
return host;
}
bool BtHostComponent::Initialize(fuchsia::hardware::bluetooth::VendorHandle vendor_handle,
InitCallback init_cb, ErrorCallback error_cb) {
std::unique_ptr<bt::controllers::FidlController> controller =
std::make_unique<bt::controllers::FidlController>(std::move(vendor_handle),
async_get_default_dispatcher());
bt_log(INFO, "bt-host", "Create HCI transport layer");
hci_ = std::make_unique<hci::Transport>(std::move(controller), pw_dispatcher_);
bt_log(INFO, "bt-host", "Create GATT layer");
gatt_ = gatt::GATT::Create();
gap_ = gap::Adapter::Create(pw_dispatcher_, hci_->GetWeakPtr(), gatt_->GetWeakPtr());
if (!gap_) {
bt_log(WARN, "bt-host", "GAP could not be created");
return false;
}
gap_->AttachInspect(inspector_.root(), "adapter");
// Called when the GAP layer is ready. We initialize the GATT profile after
// initial setup in GAP. The data domain will be initialized by GAP because it
// both sets up the HCI ACL data channel that L2CAP relies on and registers
// L2CAP services.
auto gap_init_callback = [callback = std::move(init_cb)](bool success) mutable {
bt_log(DEBUG, "bt-host", "GAP init complete status: (%s)", (success ? "success" : "failure"));
callback(success);
};
auto transport_closed_callback = [error_cb = std::move(error_cb)]() mutable {
bt_log(WARN, "bt-host", "HCI transport has closed");
error_cb();
};
bt_log(DEBUG, "bt-host", "Initializing GAP");
return gap_->Initialize(std::move(gap_init_callback), std::move(transport_closed_callback));
}
void BtHostComponent::ShutDown() {
bt_log(DEBUG, "bt-host", "Shutting down");
if (!gap_) {
bt_log(DEBUG, "bt-host", "Already shut down");
return;
}
// Closes all FIDL channels owned by |host_server_|.
host_server_ = nullptr;
// Make sure that |gap_| gets shut down and destroyed on its creation thread
// as it is not thread-safe.
gap_->ShutDown();
gap_ = nullptr;
// This shuts down the GATT profile and all of its clients.
gatt_ = nullptr;
// Shuts down HCI command channel and ACL data channel.
hci_ = nullptr;
}
void BtHostComponent::BindToHostInterface(
fidl::ServerEnd<fuchsia_bluetooth_host::Host> host_client) {
if (host_server_) {
bt_log(WARN, "bt-host", "Host interface channel already open");
return;
}
BT_DEBUG_ASSERT(gap_);
BT_DEBUG_ASSERT(gatt_);
zx::channel channel = host_client.TakeChannel();
host_server_ =
std::make_unique<HostServer>(std::move(channel), gap_->AsWeakPtr(), gatt_->GetWeakPtr());
host_server_->set_error_handler([this](zx_status_t status) {
BT_DEBUG_ASSERT(host_server_);
bt_log(WARN, "bt-host", "Host interface disconnected");
host_server_ = nullptr;
});
}
} // namespace bthost