blob: ea6c2dba9318683c6cfafe009c2aadee4eeaebb1 [file] [log] [blame]
// Copyright 2017 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.
#ifndef GARNET_DRIVERS_BLUETOOTH_LIB_GAP_ADAPTER_H_
#define GARNET_DRIVERS_BLUETOOTH_LIB_GAP_ADAPTER_H_
#include <memory>
#include <string>
#include <lib/async/dispatcher.h>
#include <lib/fit/function.h>
#include <zircon/assert.h>
#include "garnet/drivers/bluetooth/lib/data/domain.h"
#include "garnet/drivers/bluetooth/lib/gap/adapter_state.h"
#include "garnet/drivers/bluetooth/lib/gap/low_energy_connection_manager.h"
#include "garnet/drivers/bluetooth/lib/gap/remote_device_cache.h"
#include "garnet/drivers/bluetooth/lib/gatt/gatt.h"
#include "garnet/drivers/bluetooth/lib/sdp/server.h"
#include "lib/fxl/macros.h"
#include "lib/fxl/memory/weak_ptr.h"
#include "lib/fxl/synchronization/thread_checker.h"
namespace btlib {
namespace hci {
class LowEnergyAdvertiser;
class LowEnergyConnector;
class SequentialCommandRunner;
class Transport;
} // namespace hci
namespace gap {
class BrEdrConnectionManager;
class BrEdrDiscoveryManager;
class PairingDelegate;
class LowEnergyAdvertisingManager;
class LowEnergyDiscoveryManager;
// Represents the host-subsystem state for a Bluetooth controller. All
// asynchronous callbacks are posted on the Loop on which this Adapter
// instance is created.
//
// This class is not thread-safe and it is intended to be created, deleted, and
// accessed on the same event loop. No internal locking is provided.
//
// NOTE: We currently only support primary controllers. AMP controllers are not
// supported.
class Adapter final {
public:
// There must be an async_t dispatcher registered as a default when an Adapter
// instance is created. The Adapter instance will use it for all of its
// asynchronous tasks.
//
// This will take ownership of |hci_device|.
explicit Adapter(fxl::RefPtr<hci::Transport> hci,
fbl::RefPtr<data::Domain> data_domain,
fbl::RefPtr<gatt::GATT> gatt);
~Adapter();
// Returns a 128-bit UUID that uniquely identifies this adapter on the current
// system.
const std::string& identifier() const { return identifier_; }
// Initializes the host-subsystem state for the HCI device this was created
// for. This performs the initial HCI transport set up. Returns false if an
// immediate error occurs. Otherwise this returns true and asynchronously
// notifies the caller on the initialization status via |callback|.
//
// After successful initialization, |transport_closed_callback| will be
// invoked when the underlying HCI transport closed for any reason (e.g. the
// device disappeared or the transport channels were closed for an unknown
// reason). The implementation is responsible for cleaning up this adapter by
// calling ShutDown().
using InitializeCallback = fit::function<void(bool success)>;
bool Initialize(InitializeCallback callback,
fit::closure transport_closed_callback);
// Shuts down this Adapter. Invokes |callback| when shut down has completed.
// TODO(armansito): This needs to do several things to potentially preserve
// the state of various sub-protocols. For now we keep the interface pretty
// simple.
void ShutDown();
// Returns true if the Initialize() sequence has started but not completed yet
// (i.e. the InitializeCallback that was passed to Initialize() has not yet
// been called).
bool IsInitializing() const { return init_state_ == State::kInitializing; }
// Returns true if this Adapter has been fully initialized.
bool IsInitialized() const { return init_state_ == State::kInitialized; }
// Returns the global adapter setting parameters.
const AdapterState& state() const { return state_; }
// Returns a weak pointer to this adapter.
fxl::WeakPtr<Adapter> AsWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); }
// Returns this Adapter's remote device cache.
const RemoteDeviceCache& device_cache() const { return device_cache_; }
// Returns this Adapter's BR/EDR connection manager.
BrEdrConnectionManager* bredr_connection_manager() const {
return bredr_connection_manager_.get();
}
// Returns this Adapter's BR/EDR discovery manager.
BrEdrDiscoveryManager* bredr_discovery_manager() const {
return bredr_discovery_manager_.get();
}
// Returns this Adapter's SDP server.
sdp::Server* sdp_server() const { return sdp_server_.get(); }
// Returns this Adapter's LE discovery manager.
LowEnergyDiscoveryManager* le_discovery_manager() const {
ZX_DEBUG_ASSERT(le_discovery_manager_);
return le_discovery_manager_.get();
}
// Returns this Adapter's LE connection manager.
LowEnergyConnectionManager* le_connection_manager() const {
ZX_DEBUG_ASSERT(le_connection_manager_);
return le_connection_manager_.get();
}
// Returns this Adapter's LE advertising manager.
LowEnergyAdvertisingManager* le_advertising_manager() const {
ZX_DEBUG_ASSERT(le_advertising_manager_);
return le_advertising_manager_.get();
}
// Returns this Adapter's remote device cache.
RemoteDeviceCache* remote_device_cache() { return &device_cache_; }
// Add a previously bonded device to the device cache and set it up for
// auto-connect procedures.
bool AddBondedDevice(const std::string& identifier,
const common::DeviceAddress& address,
const sm::PairingData& le_bond_data);
// Assigns a pairing delegate to this adapter. This PairingDelegate and its
// I/O capabilities will be used for all future pairing procedures. Setting a
// new PairingDelegate cancels all ongoing pairing procedures.
void SetPairingDelegate(fxl::WeakPtr<PairingDelegate> delegate);
// Returns true if any discovery process (LE or BR/EDR) is running on this
// adapter.
bool IsDiscovering() const;
// Sets the Local Name of this adapter, for both BR/EDR discoverability and
// public LE services.
void SetLocalName(std::string name, hci::StatusCallback callback);
// Sets the Device Class of this adapter.
void SetClassOfDevice(common::DeviceClass dev_class,
hci::StatusCallback callback);
// Assign a callback to be notified when a connection is automatically
// established to a bonded LE device in the directed connectable mode (Vol 3,
// Part C, 9.3.3).
using AutoConnectCallback = fit::function<void(LowEnergyConnectionRefPtr)>;
void set_auto_connect_callback(AutoConnectCallback callback) {
auto_conn_cb_ = std::move(callback);
}
private:
// Second step of the initialization sequence. Called by Initialize() when the
// first batch of HCI commands have been sent.
void InitializeStep2(InitializeCallback callback);
// Third step of the initialization sequence. Called by InitializeStep2() when
// the second batch of HCI commands have been sent.
void InitializeStep3(InitializeCallback callback);
// Fourth step of the initialization sequence. Called by InitializeStep3()
// when the third batch of HCI commands have been sent.
void InitializeStep4(InitializeCallback callback);
// Builds and returns the HCI event mask based on our supported host side
// features and controller capabilities. This is used to mask events that we
// do not know how to handle.
uint64_t BuildEventMask();
// Builds and returns the LE event mask based on our supported host side
// features and controller capabilities. This is used to mask LE events that
// we do not know how to handle.
uint64_t BuildLEEventMask();
// Called by ShutDown() and during Initialize() in case of failure. This
// synchronously cleans up the transports and resets initialization state.
void CleanUp();
// Called by Transport after it has been unexpectedly closed.
void OnTransportClosed();
// Called when a directed connectable advertisement is received from a bonded
// LE device. This amounts to a connection request from a bonded peripheral
// which is handled by routing the request to |le_connection_manager_| to
// initiate a Direct Connection Establishment procedure (Vol 3, Part C,
// 9.3.8).
void OnLeAutoConnectRequest(const std::string& device_id);
// Uniquely identifies this adapter on the current system.
std::string identifier_;
async_dispatcher_t* dispatcher_;
fxl::RefPtr<hci::Transport> hci_;
// Callback invoked to notify clients when the underlying transport is closed.
fit::closure transport_closed_cb_;
// Parameters relevant to the initialization sequence.
// TODO(armansito): The Initialize()/ShutDown() pattern has become common
// enough in this project that it might be worth considering moving the
// init-state-keeping into an abstract base.
enum State {
kNotInitialized = 0,
kInitializing,
kInitialized,
};
std::atomic<State> init_state_;
std::unique_ptr<hci::SequentialCommandRunner> init_seq_runner_;
// Contains the global adapter state.
AdapterState state_;
// The maximum LMP feature page that we will read.
size_t max_lmp_feature_page_index_;
// Provides access to discovered, connected, and/or bonded remote Bluetooth
// devices.
RemoteDeviceCache device_cache_;
// The data domain used by GAP to interact with L2CAP and RFCOMM layers.
fbl::RefPtr<data::Domain> data_domain_;
// The GATT profile. We use this reference to add and remove data bearers and
// for service discovery.
fbl::RefPtr<gatt::GATT> gatt_;
// Objects that abstract the controller for connection and advertising
// procedures.
// TODO(armansito): Move hci::LowEnergyScanner here.
std::unique_ptr<hci::LowEnergyAdvertiser> hci_le_advertiser_;
std::unique_ptr<hci::LowEnergyConnector> hci_le_connector_;
// Objects that perform LE procedures.
std::unique_ptr<LowEnergyDiscoveryManager> le_discovery_manager_;
std::unique_ptr<LowEnergyConnectionManager> le_connection_manager_;
std::unique_ptr<LowEnergyAdvertisingManager> le_advertising_manager_;
// Objects that perform BR/EDR procedures.
std::unique_ptr<BrEdrConnectionManager> bredr_connection_manager_;
std::unique_ptr<BrEdrDiscoveryManager> bredr_discovery_manager_;
std::unique_ptr<sdp::Server> sdp_server_;
// Callback to propagate ownership of an auto-connected LE link.
AutoConnectCallback auto_conn_cb_;
fxl::ThreadChecker thread_checker_;
// This must remain the last member to make sure that all weak pointers are
// invalidating before other members are destroyed.
fxl::WeakPtrFactory<Adapter> weak_ptr_factory_;
FXL_DISALLOW_COPY_AND_ASSIGN(Adapter);
};
} // namespace gap
} // namespace btlib
#endif // GARNET_DRIVERS_BLUETOOTH_LIB_GAP_ADAPTER_H_