Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e1d697d6 authored by Arman Uguray's avatar Arman Uguray
Browse files

service: Introduce hal::BluetoothInterface

This CL introduces the bluetooth::hal::BluetoothInterface class. This is meant
to be an abstraction over the underlying bt_interface_t and bt_callbacks_t
interfaces from libhardware. BluetoothInterface is defined as an abstract
singleton that allows a fake/mock implementation to be injected for testing.

Bug: 23169364
Change-Id: Ia6f21f505dca08651b9a83e30287f638e8ec9a8e
parent 61a8f203
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ btserviceCommonSrc := \
	core_stack.cpp \
	daemon.cpp \
	gatt_server.cpp \
	hal/bluetooth_interface.cpp \
	ipc/ipc_handler.cpp \
	ipc/ipc_handler_unix.cpp \
	ipc/ipc_manager.cpp \
@@ -66,6 +67,7 @@ ifeq ($(HOST_OS),linux)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
	$(btserviceCommonSrc) \
	test/fake_hal_bluetooth_interface.cpp \
	test/fake_hal_util.cpp \
	test/ipc_unix_unittest.cpp \
	test/settings_unittest.cpp \
+289 −0
Original line number Diff line number Diff line
//
//  Copyright (C) 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 <base/logging.h>
#include <base/observer_list.h>

#include "service/logging_helpers.h"

extern "C" {
#include "btcore/include/hal_util.h"
}  // extern "C"

using std::lock_guard;
using std::mutex;

namespace bluetooth {
namespace hal {

namespace {

// The global BluetoothInterface instance.
BluetoothInterface* g_bluetooth_interface = nullptr;

// Mutex used by callbacks to access |g_bluetooth_interface|. Since there is no
// good way to unregister callbacks and since the global instance can be deleted
// concurrently during shutdown, this lock is used.
//
// TODO(armansito): There should be a way to cleanly shut down the Bluetooth
// stack.
mutex g_instance_lock;

// Helper for obtaining the observer list. This is forward declared here and
// defined below since it depends on BluetoothInterfaceImpl.
base::ObserverList<BluetoothInterface::Observer>* GetObservers();

#define FOR_EACH_BLUETOOTH_OBSERVER(func) \
  FOR_EACH_OBSERVER(BluetoothInterface::Observer, *GetObservers(), func)

void AdapterStateChangedCallback(bt_state_t state) {
  lock_guard<mutex> lock(g_instance_lock);
  if (!g_bluetooth_interface) {
    LOG(WARNING) << "Callback received after global instance was destroyed";
    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) {
  lock_guard<mutex> lock(g_instance_lock);
  if (!g_bluetooth_interface) {
    LOG(WARNING) << "Callback received after global instance was destroyed";
    return;
  }

  VLOG(1) << "Adapter properties changed - status: " << BtStatusText(status)
          << ", num_properties: " << num_properties;
  FOR_EACH_BLUETOOTH_OBSERVER(
      AdapterPropertiesCallback(status, num_properties, properties));
}

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): Figure out what to do with this callback. It's not being
  // used by us right now but the code crashes without setting it. The stack
  // should be refactored to make things optional and definitely not crash.
  // (See http://b/23315739)
  return true;
}

int AcquireWakeLockCallout(const char* /* lock_name */) {
  // TODO(armansito): Figure out what to do with this callback. It's not being
  // used by us right now but the code crashes without setting it. The stack
  // should be refactored to make things optional and definitely not crash.
  // (See http://b/23315739)
  return BT_STATUS_SUCCESS;
}

int ReleaseWakeLockCallout(const char* /* lock_name */) {
  // TODO(armansito): Figure out what to do with this callback. It's not being
  // used by us right now but the code crashes without setting it. The stack
  // should be refactored to make things optional and definitely not crash.
  // (See http://b/23315739)
  return BT_STATUS_SUCCESS;
}

// The HAL Bluetooth DM callbacks.
bt_callbacks_t bt_callbacks = {
  sizeof(bt_callbacks_t),
  AdapterStateChangedCallback,
  AdapterPropertiesCallback,
  nullptr, /* remote_device_properties_cb */
  nullptr, /* device_found_cb */
  nullptr, /* discovery_state_changed_cb */
  nullptr, /* pin_request_cb  */
  nullptr, /* ssp_request_cb  */
  nullptr, /* bond_state_changed_cb */
  nullptr, /* acl_state_changed_cb */
  ThreadEventCallback,
  nullptr, /* dut_mode_recv_cb */
  nullptr, /* le_test_mode_cb */
  nullptr  /* energy_info_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),
        hal_adapter_(nullptr) {
  }

  ~BluetoothInterfaceImpl() override {
    hal_iface_->cleanup();
  };

  // BluetoothInterface overrides.
  void AddObserver(Observer* observer) override {
    lock_guard<mutex> lock(g_instance_lock);
    observers_.AddObserver(observer);
  }

  void RemoveObserver(Observer* observer) override {
    lock_guard<mutex> lock(g_instance_lock);
    observers_.RemoveObserver(observer);
  }

  const bt_interface_t* GetHALInterface() const override {
    return hal_iface_;
  }

  const bluetooth_device_t* GetHALAdapter() const override {
    return hal_adapter_;
  }

  // Initialize the interface. This loads the shared Bluetooth library and sets
  // up the callbacks.
  bool Initialize() {
    // Load the Bluetooth shared library module.
    const hw_module_t* module;
    int status = hal_util_load_bt_library(&module);
    if (status) {
      LOG(ERROR) << "Failed to load Bluetooth library";
      return false;
    }

    // Open the Bluetooth adapter.
    hw_device_t* device;
    status = module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
    if (status) {
      LOG(ERROR) << "Failed to open the Bluetooth module";
      return false;
    }

    hal_adapter_ = reinterpret_cast<bluetooth_device_t*>(device);
    hal_iface_ = hal_adapter_->get_bluetooth_interface();

    // Initialize the Bluetooth interface. Set up the adapter (Bluetooth DM) API
    // callbacks.
    status = hal_iface_->init(&bt_callbacks);
    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;
  }

  base::ObserverList<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.
  base::ObserverList<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_;

  // The HAL handle that represents the underlying Bluetooth adapter. We hold a
  // weak reference to this since the actual data resides in the shared
  // Bluetooth library.
  const bluetooth_device_t* hal_adapter_;

  DISALLOW_COPY_AND_ASSIGN(BluetoothInterfaceImpl);
};

namespace {

// Helper for obtaining the observer list from the global instance. This
// function is NOT thread safe.
base::ObserverList<BluetoothInterface::Observer>* GetObservers() {
  CHECK(g_bluetooth_interface);
  return static_cast<BluetoothInterfaceImpl*>(
      g_bluetooth_interface)->observers();
}

}  // namespace

// static
bool BluetoothInterface::Initialize() {
  lock_guard<mutex> 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() {
  lock_guard<mutex> lock(g_instance_lock);
  CHECK(g_bluetooth_interface);

  delete g_bluetooth_interface;
  g_bluetooth_interface = nullptr;
}

// static
BluetoothInterface* BluetoothInterface::Get() {
  lock_guard<mutex> lock(g_instance_lock);
  CHECK(g_bluetooth_interface);
  return g_bluetooth_interface;
}

// static
void BluetoothInterface::InitializeForTesting(
    BluetoothInterface* test_instance) {
  lock_guard<mutex> lock(g_instance_lock);
  CHECK(test_instance);
  CHECK(!g_bluetooth_interface);

  g_bluetooth_interface = test_instance;
}

}  // namespace hal
}  // namespace bluetooth
+100 −0
Original line number Diff line number Diff line
//
//  Copyright (C) 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.
//

#pragma once

#include <base/macros.h>
#include <hardware/bluetooth.h>

namespace bluetooth {
namespace hal {

// This class represents the HAL Bluetooth adapter interface, wrapping around
// the underlying bt_interface_t structure, its methods, and callbacks. A single
// instance of this class exists per application and it allows multiple classes
// to interface with the global HAL interface by multiplexing callbacks among
// registered clients.
//
// This is declared as an abstract interface so that a fake implementation can
// be injected for testing the upper layer.
//
// TODO: (expose callback types directly but via redirection) methods for
// initialize, clean up, and set for testing.
class BluetoothInterface {
 public:
  // The standard Bluetooth adapter management callback interface. The HAL
  // interface doesn't allow registering "user data" that carries context beyond
  // the callback parameters, forcing implementations to deal with global
  // variables. The Observer interface is to redirect these events to interested
  // parties in an object-oriented manner.
  //
  // TODO(armansito): We should fix this in the HAL.
  class Observer {
   public:
    virtual ~Observer() = default;

    // All of the events below correspond to callbacks defined in
    // "bt_callbacks_t" in the HAL API definitions.

    virtual void AdapterStateChangedCallback(bt_state_t state) = 0;
    virtual void AdapterPropertiesCallback(bt_status_t status,
                                           int num_properties,
                                           bt_property_t* properties) = 0;

    // TODO(armansito): Complete the list of callbacks.
  };

  // Initialize and clean up the BluetoothInterface singleton. CleanUp must be
  // called on the same thread that called Initialize.
  static bool Initialize();
  static void CleanUp();

  // Initialize for testing. Use this to inject a test version of
  // BlueoothInterface. To be used from unit tests only.
  static void InitializeForTesting(BluetoothInterface* test_instance);

  // Returns the BluetoothInterface singleton. If the interface has not been
  // initialized, returns nullptr.
  static BluetoothInterface* Get();

  // Add or remove an observer that is interested in notifications from us.
  virtual void AddObserver(Observer* observer) = 0;
  virtual void RemoveObserver(Observer* observer) = 0;

  // The HAL module pointer that represents the standard Bluetooth adapter
  // management interface. This is implemented in and provided by the shared
  // Bluetooth library, so this isn't owned by us.
  //
  // Upper layers can make bt_interface_t API calls through this structure.
  // However, DO NOT call the "init" function as this is called and managed by
  // us. The behavior is undefined if "init" is called directly by upper layers.
  virtual const bt_interface_t* GetHALInterface() const = 0;

  // The HAL module pointer that represents the underlying Bluetooth adapter.
  // This is implemented in and provided by the shared Bluetooth library, so
  // this isn't owned by us.
  virtual const bluetooth_device_t* GetHALAdapter() const = 0;

 protected:
  BluetoothInterface() = default;
  virtual ~BluetoothInterface() = default;

 private:
  DISALLOW_COPY_AND_ASSIGN(BluetoothInterface);
};

}  // namespace hal
}  // namespace bluetooth
+41 −0
Original line number Diff line number Diff line
//
//  Copyright (C) 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/test/fake_hal_bluetooth_interface.h"

namespace bluetooth {
namespace testing {

void FakeHALBluetoothInterface::AddObserver(Observer* observer) {
  // TODO(armansito): Do something meaningful here to simulate test behavior.
}

void FakeHALBluetoothInterface::RemoveObserver(Observer* observer) {
  // TODO(armansito): Do something meaningful here to simulate test behavior.
}

const bt_interface_t* FakeHALBluetoothInterface::GetHALInterface() const {
  // TODO(armansito): Do something meaningful here to simulate test behavior.
  return nullptr;
}

const bluetooth_device_t* FakeHALBluetoothInterface::GetHALAdapter() const {
  // TODO(armansito): Do something meaningful here to simulate test behavior.
  return nullptr;
}

}  // namespace testing
}  // namespace bluetooth
+42 −0
Original line number Diff line number Diff line
//
//  Copyright (C) 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 <base/macros.h>

namespace bluetooth {
namespace testing {

class FakeHALBluetoothInterface : public hal::BluetoothInterface {
 public:
  FakeHALBluetoothInterface() = default;
  ~FakeHALBluetoothInterface() override = default;

  // TODO(armansito): Add hooks here to simulate test behavior.

  // hal::BluetoothInterface overrides:
  void AddObserver(Observer* observer) override;
  void RemoveObserver(Observer* observer) override;
  const bt_interface_t* GetHALInterface() const override;
  const bluetooth_device_t* GetHALAdapter() const override;

 private:
  DISALLOW_COPY_AND_ASSIGN(FakeHALBluetoothInterface);
};

}  // namespace testing
}  // namespace bluetooth