You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
432 lines
15 KiB
432 lines
15 KiB
//
|
|
// Copyright 2015 Google, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at:
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
|
|
#include "service/hal/bluetooth_interface.h"
|
|
|
|
#include <mutex>
|
|
#include <shared_mutex>
|
|
|
|
#include <base/logging.h>
|
|
#include <base/observer_list.h>
|
|
|
|
#include "abstract_observer_list.h"
|
|
#include "service/logging_helpers.h"
|
|
|
|
#include "btcore/include/hal_util.h"
|
|
|
|
using std::lock_guard;
|
|
using std::unique_lock;
|
|
using std::shared_lock;
|
|
using std::mutex;
|
|
#if defined(OS_GENERIC) && defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION < 3500)
|
|
using shared_mutex_impl = std::shared_mutex;
|
|
#else
|
|
using shared_mutex_impl = std::shared_timed_mutex;
|
|
#endif
|
|
|
|
namespace bluetooth {
|
|
namespace hal {
|
|
|
|
namespace {
|
|
|
|
// The global BluetoothInterface instance.
|
|
BluetoothInterface* g_bluetooth_interface = nullptr;
|
|
|
|
// Mutex used by callbacks to access |g_interface|. If we initialize or clean it
|
|
// use unique_lock. If only accessing |g_interface| use shared lock.
|
|
// TODO(jpawlowski): this should be just shared_mutex, as we currently don't use
|
|
// timed methods. Change to shared_mutex when we upgrade to C++14
|
|
shared_mutex_impl g_instance_lock;
|
|
|
|
// Helper for obtaining the observer list. This is forward declared here and
|
|
// defined below since it depends on BluetoothInterfaceImpl.
|
|
btbase::AbstractObserverList<BluetoothInterface::Observer>* GetObservers();
|
|
|
|
#define FOR_EACH_BLUETOOTH_OBSERVER(func) \
|
|
for (auto& observer : *GetObservers()) { \
|
|
observer.func; \
|
|
}
|
|
|
|
#define VERIFY_INTERFACE_OR_RETURN() \
|
|
do { \
|
|
if (!g_bluetooth_interface) { \
|
|
LOG(WARNING) << "Callback received while |g_interface| is NULL"; \
|
|
return; \
|
|
} \
|
|
} while (0)
|
|
|
|
void AdapterStateChangedCallback(bt_state_t state) {
|
|
shared_lock<shared_mutex_impl> lock(g_instance_lock);
|
|
VERIFY_INTERFACE_OR_RETURN();
|
|
VLOG(1) << "Adapter state changed: " << BtStateText(state);
|
|
FOR_EACH_BLUETOOTH_OBSERVER(AdapterStateChangedCallback(state));
|
|
}
|
|
|
|
void AdapterPropertiesCallback(bt_status_t status, int num_properties,
|
|
bt_property_t* properties) {
|
|
shared_lock<shared_mutex_impl> lock(g_instance_lock);
|
|
VERIFY_INTERFACE_OR_RETURN();
|
|
VLOG(1) << "Adapter properties changed - status: " << BtStatusText(status)
|
|
<< ", num_properties: " << num_properties;
|
|
FOR_EACH_BLUETOOTH_OBSERVER(
|
|
AdapterPropertiesCallback(status, num_properties, properties));
|
|
}
|
|
|
|
void RemoteDevicePropertiesCallback(bt_status_t status,
|
|
RawAddress* remote_bd_addr,
|
|
int num_properties,
|
|
bt_property_t* properties) {
|
|
shared_lock<shared_mutex_impl> lock(g_instance_lock);
|
|
VERIFY_INTERFACE_OR_RETURN();
|
|
VLOG(1) << " Remote device properties changed - status: "
|
|
<< BtStatusText(status)
|
|
<< " - BD_ADDR: " << BtAddrString(remote_bd_addr)
|
|
<< ", num_properties: " << num_properties;
|
|
FOR_EACH_BLUETOOTH_OBSERVER(RemoteDevicePropertiesCallback(
|
|
status, remote_bd_addr, num_properties, properties));
|
|
}
|
|
|
|
void DeviceFoundCallback(int num_properties, bt_property_t* properties) {
|
|
shared_lock<shared_mutex_impl> lock(g_instance_lock);
|
|
VERIFY_INTERFACE_OR_RETURN();
|
|
VLOG(1) << " Device found.";
|
|
FOR_EACH_BLUETOOTH_OBSERVER(DeviceFoundCallback(num_properties, properties));
|
|
}
|
|
|
|
void DiscoveryStateChangedCallback(bt_discovery_state_t state) {
|
|
shared_lock<shared_mutex_impl> lock(g_instance_lock);
|
|
VERIFY_INTERFACE_OR_RETURN();
|
|
VLOG(1) << "Discovery state changed - state: " << BtDiscoveryStateText(state);
|
|
FOR_EACH_BLUETOOTH_OBSERVER(DiscoveryStateChangedCallback(state));
|
|
}
|
|
|
|
void PinRequestCallback(RawAddress* remote_bd_addr, bt_bdname_t* bd_name,
|
|
uint32_t cod, bool min_16_digit) {
|
|
shared_lock<shared_mutex_impl> lock(g_instance_lock);
|
|
VERIFY_INTERFACE_OR_RETURN();
|
|
VLOG(2) << __func__ << " - remote_bd_addr: " << remote_bd_addr
|
|
<< " - bd_name: " << bd_name << " - cod: " << cod
|
|
<< " - min_16_digit: " << min_16_digit;
|
|
FOR_EACH_BLUETOOTH_OBSERVER(
|
|
PinRequestCallback(remote_bd_addr, bd_name, cod, min_16_digit));
|
|
}
|
|
|
|
void SSPRequestCallback(RawAddress* remote_bd_addr, bt_bdname_t* bd_name,
|
|
uint32_t cod, bt_ssp_variant_t pairing_variant,
|
|
uint32_t pass_key) {
|
|
shared_lock<shared_mutex_impl> lock(g_instance_lock);
|
|
VERIFY_INTERFACE_OR_RETURN();
|
|
VLOG(2) << __func__ << " - remote_bd_addr: " << remote_bd_addr
|
|
<< " - bd_name: " << bd_name << " - cod: " << cod
|
|
<< " - pairing_variant: " << pairing_variant;
|
|
FOR_EACH_BLUETOOTH_OBSERVER(SSPRequestCallback(remote_bd_addr, bd_name, cod,
|
|
pairing_variant, pass_key));
|
|
}
|
|
|
|
void BondStateChangedCallback(bt_status_t status, RawAddress* remote_bd_addr,
|
|
bt_bond_state_t state) {
|
|
shared_lock<shared_mutex_impl> lock(g_instance_lock);
|
|
VERIFY_INTERFACE_OR_RETURN();
|
|
VLOG(2) << __func__ << " - remote_bd_addr: " << BtAddrString(remote_bd_addr)
|
|
<< " - status: " << status << " - state: " << state;
|
|
FOR_EACH_BLUETOOTH_OBSERVER(
|
|
BondStateChangedCallback(status, remote_bd_addr, state));
|
|
}
|
|
|
|
void AclStateChangedCallback(bt_status_t status, RawAddress* remote_bd_addr,
|
|
bt_acl_state_t state, bt_hci_error_code_t hci_reason) {
|
|
shared_lock<shared_mutex_impl> lock(g_instance_lock);
|
|
VERIFY_INTERFACE_OR_RETURN();
|
|
CHECK(remote_bd_addr);
|
|
VLOG(1) << "Remote device ACL state changed - status: "
|
|
<< BtStatusText(status)
|
|
<< " - BD_ADDR: " << BtAddrString(remote_bd_addr) << " - state: "
|
|
<< ((state == BT_ACL_STATE_CONNECTED) ? "CONNECTED" : "DISCONNECTED")
|
|
<< " - HCI_REASON: " << std::to_string(hci_reason);
|
|
FOR_EACH_BLUETOOTH_OBSERVER(
|
|
AclStateChangedCallback(status, *remote_bd_addr, state, hci_reason));
|
|
}
|
|
|
|
void ThreadEventCallback(bt_cb_thread_evt evt) {
|
|
VLOG(1) << "ThreadEventCallback" << BtEventText(evt);
|
|
|
|
// TODO(armansito): This callback is completely useless to us but btif borks
|
|
// out if this is not set. Consider making this optional.
|
|
}
|
|
|
|
bool SetWakeAlarmCallout(uint64_t /* delay_millis */, bool /* should_wake */,
|
|
alarm_cb /* cb */, void* /* data */) {
|
|
// TODO(armansito): According to sharvil@, this interface doesn't even need to
|
|
// exist and can be done entirely from within osi by interfacing directly with
|
|
// the kernel. Remove these stubs once that's fixed. (See http://b/23390297)
|
|
return false;
|
|
}
|
|
|
|
int AcquireWakeLockCallout(const char* /* lock_name */) {
|
|
// TODO(armansito): According to sharvil@, this interface doesn't even need to
|
|
// exist and can be done entirely from within osi by interfacing directly with
|
|
// the kernel. Remove these stubs once that's fixed. (See http://b/23390297)
|
|
// Lie here and return success so that enabling and disabling the controller
|
|
// works before this is properly implemented.
|
|
return BT_STATUS_SUCCESS;
|
|
}
|
|
|
|
int ReleaseWakeLockCallout(const char* /* lock_name */) {
|
|
// TODO(armansito): According to sharvil@, this interface doesn't even need to
|
|
// exist and can be done entirely from within osi by interfacing directly with
|
|
// the kernel. Remove these stubs once that's fixed. (See http://b/23390297)
|
|
// Lie here and return success so that enabling and disabling the controller
|
|
// works before this is properly implemented.
|
|
return BT_STATUS_SUCCESS;
|
|
}
|
|
|
|
void LinkQualityReportCallback(uint64_t timestamp, int report_id, int rssi,
|
|
int snr, int retransmission_count, int packets_not_receive_count,
|
|
int negative_acknowledgement_count) {
|
|
shared_lock<shared_mutex_impl> lock(g_instance_lock);
|
|
VERIFY_INTERFACE_OR_RETURN();
|
|
LOG(WARNING) << __func__ << " - timestamp: " << timestamp
|
|
<< " - report_id: " << report_id << " - rssi: " << rssi
|
|
<< " - snr: " << snr
|
|
<< " - retransmission_count: " << retransmission_count
|
|
<< " - packets_not_receive_count: " << packets_not_receive_count
|
|
<< " - negative_acknowledgement_count: "
|
|
<< negative_acknowledgement_count;
|
|
FOR_EACH_BLUETOOTH_OBSERVER(LinkQualityReportCallback(
|
|
timestamp, report_id, rssi, snr, retransmission_count,
|
|
packets_not_receive_count, negative_acknowledgement_count));
|
|
}
|
|
|
|
// The HAL Bluetooth DM callbacks.
|
|
bt_callbacks_t bt_callbacks = {
|
|
sizeof(bt_callbacks_t),
|
|
AdapterStateChangedCallback,
|
|
AdapterPropertiesCallback,
|
|
RemoteDevicePropertiesCallback,
|
|
DeviceFoundCallback,
|
|
DiscoveryStateChangedCallback,
|
|
PinRequestCallback,
|
|
SSPRequestCallback,
|
|
BondStateChangedCallback,
|
|
AclStateChangedCallback,
|
|
ThreadEventCallback,
|
|
nullptr, /* dut_mode_recv_cb */
|
|
nullptr, /* le_test_mode_cb */
|
|
nullptr, /* energy_info_cb */
|
|
LinkQualityReportCallback,
|
|
nullptr /* generate_local_oob_data_cb */
|
|
};
|
|
|
|
bt_os_callouts_t bt_os_callouts = {sizeof(bt_os_callouts_t),
|
|
SetWakeAlarmCallout, AcquireWakeLockCallout,
|
|
ReleaseWakeLockCallout};
|
|
|
|
} // namespace
|
|
|
|
// BluetoothInterface implementation for production.
|
|
class BluetoothInterfaceImpl : public BluetoothInterface {
|
|
public:
|
|
BluetoothInterfaceImpl() : hal_iface_(nullptr) {}
|
|
|
|
~BluetoothInterfaceImpl() override {
|
|
if (hal_iface_) hal_iface_->cleanup();
|
|
}
|
|
|
|
// BluetoothInterface overrides.
|
|
void AddObserver(Observer* observer) override {
|
|
shared_lock<shared_mutex_impl> lock(g_instance_lock);
|
|
observers_.AddObserver(observer);
|
|
}
|
|
|
|
void RemoveObserver(Observer* observer) override {
|
|
shared_lock<shared_mutex_impl> lock(g_instance_lock);
|
|
observers_.RemoveObserver(observer);
|
|
}
|
|
|
|
const bt_interface_t* GetHALInterface() const override { return hal_iface_; }
|
|
|
|
bt_callbacks_t* GetHALCallbacks() const override { return &bt_callbacks; }
|
|
|
|
// Initialize the interface. This loads the shared Bluetooth library and sets
|
|
// up the callbacks.
|
|
bool Initialize() {
|
|
// Load the Bluetooth shared library module.
|
|
const bt_interface_t* interface;
|
|
int status = hal_util_load_bt_library(&interface);
|
|
if (status) {
|
|
LOG(ERROR) << "Failed to open the Bluetooth module";
|
|
return false;
|
|
}
|
|
|
|
hal_iface_ = interface;
|
|
|
|
// Initialize the Bluetooth interface. Set up the adapter (Bluetooth DM) API
|
|
// callbacks.
|
|
status = hal_iface_->init(&bt_callbacks, false, false, 0, nullptr, false);
|
|
if (status != BT_STATUS_SUCCESS) {
|
|
LOG(ERROR) << "Failed to initialize Bluetooth stack";
|
|
return false;
|
|
}
|
|
|
|
status = hal_iface_->set_os_callouts(&bt_os_callouts);
|
|
if (status != BT_STATUS_SUCCESS) {
|
|
LOG(ERROR) << "Failed to set up Bluetooth OS callouts";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
btbase::AbstractObserverList<Observer>* observers() { return &observers_; }
|
|
|
|
private:
|
|
// List of observers that are interested in notifications from us. We're not
|
|
// using a base::ObserverListThreadSafe, which it posts observer events
|
|
// automatically on the origin threads, as we want to avoid that overhead and
|
|
// simply forward the events to the upper layer.
|
|
btbase::AbstractObserverList<Observer> observers_;
|
|
|
|
// The HAL handle obtained from the shared library. We hold a weak reference
|
|
// to this since the actual data resides in the shared Bluetooth library.
|
|
const bt_interface_t* hal_iface_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(BluetoothInterfaceImpl);
|
|
};
|
|
|
|
namespace {
|
|
|
|
// Helper for obtaining the observer list from the global instance. This
|
|
// function is NOT thread safe.
|
|
btbase::AbstractObserverList<BluetoothInterface::Observer>* GetObservers() {
|
|
CHECK(g_bluetooth_interface);
|
|
return static_cast<BluetoothInterfaceImpl*>(g_bluetooth_interface)
|
|
->observers();
|
|
}
|
|
|
|
} // namespace
|
|
|
|
// Default observer implementations. These are provided so that the methods
|
|
// themselves are optional.
|
|
void BluetoothInterface::Observer::AdapterStateChangedCallback(
|
|
bt_state_t /* state*/) {
|
|
// Do nothing.
|
|
}
|
|
|
|
void BluetoothInterface::Observer::AdapterPropertiesCallback(
|
|
bt_status_t /* status */, int /* num_properties */,
|
|
bt_property_t* /* properties */) {
|
|
// Do nothing.
|
|
}
|
|
|
|
void BluetoothInterface::Observer::RemoteDevicePropertiesCallback(
|
|
bt_status_t /* status */, RawAddress* /* remote_bd_addr */,
|
|
int /* num_properties */, bt_property_t* /* properties */) {
|
|
// Do nothing.
|
|
}
|
|
|
|
void BluetoothInterface::Observer::DeviceFoundCallback(
|
|
int /* num_properties */, bt_property_t* /* properties */) {
|
|
// Do nothing.
|
|
}
|
|
|
|
void BluetoothInterface::Observer::DiscoveryStateChangedCallback(
|
|
bt_discovery_state_t /* state */) {
|
|
// Do nothing.
|
|
}
|
|
|
|
void BluetoothInterface::Observer::PinRequestCallback(
|
|
RawAddress* remote_bd_addr, bt_bdname_t* bd_name, uint32_t cod,
|
|
bool min_16_digit) {
|
|
// Do nothing.
|
|
}
|
|
|
|
void BluetoothInterface::Observer::SSPRequestCallback(
|
|
RawAddress* remote_bd_addr, bt_bdname_t* bd_name, uint32_t cod,
|
|
bt_ssp_variant_t pairing_variant, uint32_t pass_key) {
|
|
// Do nothing.
|
|
}
|
|
|
|
void BluetoothInterface::Observer::BondStateChangedCallback(
|
|
bt_status_t status, RawAddress* remote_bd_addr, bt_bond_state_t state) {
|
|
// Do nothing.
|
|
}
|
|
|
|
void BluetoothInterface::Observer::AclStateChangedCallback(
|
|
bt_status_t /* status */, const RawAddress& /* remote_bdaddr */,
|
|
bt_acl_state_t /* state */, bt_hci_error_code_t /* hci_reason */) {
|
|
// Do nothing.
|
|
}
|
|
|
|
void BluetoothInterface::Observer::LinkQualityReportCallback(
|
|
uint64_t /* timestamp */, int /* report_id */, int /* rssi */,
|
|
int /* snr */, int /* retransmission_count */,
|
|
int /* packets_not_receive_count */,
|
|
int /* negative_acknowledgement_count */) {
|
|
// Do nothing.
|
|
}
|
|
|
|
// static
|
|
bool BluetoothInterface::Initialize() {
|
|
unique_lock<shared_mutex_impl> lock(g_instance_lock);
|
|
CHECK(!g_bluetooth_interface);
|
|
|
|
std::unique_ptr<BluetoothInterfaceImpl> impl(new BluetoothInterfaceImpl());
|
|
if (!impl->Initialize()) {
|
|
LOG(ERROR) << "Failed to initialize BluetoothInterface";
|
|
return false;
|
|
}
|
|
|
|
g_bluetooth_interface = impl.release();
|
|
|
|
return true;
|
|
}
|
|
|
|
// static
|
|
void BluetoothInterface::CleanUp() {
|
|
unique_lock<shared_mutex_impl> lock(g_instance_lock);
|
|
CHECK(g_bluetooth_interface);
|
|
|
|
delete g_bluetooth_interface;
|
|
g_bluetooth_interface = nullptr;
|
|
}
|
|
|
|
// static
|
|
bool BluetoothInterface::IsInitialized() {
|
|
shared_lock<shared_mutex_impl> lock(g_instance_lock);
|
|
|
|
return g_bluetooth_interface != nullptr;
|
|
}
|
|
|
|
// static
|
|
BluetoothInterface* BluetoothInterface::Get() {
|
|
shared_lock<shared_mutex_impl> lock(g_instance_lock);
|
|
CHECK(g_bluetooth_interface);
|
|
return g_bluetooth_interface;
|
|
}
|
|
|
|
// static
|
|
void BluetoothInterface::InitializeForTesting(
|
|
BluetoothInterface* test_instance) {
|
|
unique_lock<shared_mutex_impl> lock(g_instance_lock);
|
|
CHECK(test_instance);
|
|
CHECK(!g_bluetooth_interface);
|
|
|
|
g_bluetooth_interface = test_instance;
|
|
}
|
|
|
|
} // namespace hal
|
|
} // namespace bluetooth
|