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

Commit 9214448b authored by Arman Uguray's avatar Arman Uguray Committed by Jakub Pawlowski
Browse files

service: Make Adapter mockable.

Turned the Adapter class into an abstract interface so that we
can inject a mock Adapter in tests where there is an Adapter dependency
but where we don't care about side-effects/stack-calls created from the
Adapter.

Bug: 25744656

Change-Id: Ibf7dd9a4cc1008cbb36e60f7b87cfcb4ef2bd5d8
parent 5a10b58d
Loading
Loading
Loading
Loading
+283 −225
Original line number Diff line number Diff line
@@ -16,9 +16,20 @@

#include "service/adapter.h"

#include <atomic>
#include <mutex>
#include <string>
#include <unordered_set>

#include <base/logging.h>
#include <base/observer_list.h>

#include "service/common/bluetooth/util/atomic_string.h"
#include "service/gatt_client.h"
#include "service/gatt_server.h"
#include "service/hal/bluetooth_interface.h"
#include "service/logging_helpers.h"
#include "service/low_energy_client.h"

using std::lock_guard;
using std::mutex;
@@ -56,7 +67,11 @@ void Adapter::Observer::OnDeviceConnectionStateChanged(
  // Default implementation does nothing
}

Adapter::Adapter()
// The real Adapter implementation used in production.
class AdapterImpl : public Adapter,
                    public hal::BluetoothInterface::Observer {
 public:
  AdapterImpl()
    : state_(ADAPTER_STATE_OFF),
      address_(kDefaultAddress),
      name_(kDefaultName) {
@@ -68,29 +83,29 @@ Adapter::Adapter()
    hal::BluetoothInterface::Get()->GetHALInterface()->get_adapter_properties();
  }

Adapter::~Adapter() {
  ~AdapterImpl() override {
    hal::BluetoothInterface::Get()->RemoveObserver(this);
  }

void Adapter::AddObserver(Observer* observer) {
  void AddObserver(Adapter::Observer* observer) override {
    lock_guard<mutex> lock(observers_lock_);
    observers_.AddObserver(observer);
  }

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

AdapterState Adapter::GetState() const {
  AdapterState GetState() const override {
    return state_.load();
  }

bool Adapter::IsEnabled() const {
  bool IsEnabled() const override {
    return state_.load() == ADAPTER_STATE_ON;
  }

bool Adapter::Enable() {
  bool Enable() override {
    AdapterState current_state = GetState();
    if (current_state != ADAPTER_STATE_OFF) {
      LOG(INFO) << "Adapter not disabled - state: "
@@ -98,8 +113,8 @@ bool Adapter::Enable() {
      return false;
    }

  // Set the state before calling enable() as there might be a race between here
  // and the AdapterStateChangedCallback.
    // Set the state before calling enable() as there might be a race between
    // here and the AdapterStateChangedCallback.
    state_ = ADAPTER_STATE_TURNING_ON;
    NotifyAdapterStateChanged(current_state, state_);

@@ -115,7 +130,7 @@ bool Adapter::Enable() {
    return true;
  }

bool Adapter::Disable() {
  bool Disable() override {
    if (!IsEnabled()) {
      LOG(INFO) << "Adapter is not enabled";
      return false;
@@ -123,8 +138,8 @@ bool Adapter::Disable() {

    AdapterState current_state = GetState();

  // Set the state before calling enable() as there might be a race between here
  // and the AdapterStateChangedCallback.
    // Set the state before calling enable() as there might be a race between
    // here and the AdapterStateChangedCallback.
    state_ = ADAPTER_STATE_TURNING_OFF;
    NotifyAdapterStateChanged(current_state, state_);

@@ -140,18 +155,18 @@ bool Adapter::Disable() {
    return true;
  }

std::string Adapter::GetName() const {
  std::string GetName() const override {
    return name_.Get();
  }

bool Adapter::SetName(const std::string& name) {
  bool SetName(const std::string& name) override {
    bt_bdname_t hal_name;
    size_t max_name_len = sizeof(hal_name.name);

    // Include the \0 byte in size measurement.
    if (name.length() >= max_name_len) {
    LOG(ERROR) << "Given name \"" << name << "\" is larger than maximum allowed"
               << " size: " << max_name_len;
      LOG(ERROR) << "Given name \"" << name << "\" is larger than maximum"
                 << " allowed size: " << max_name_len;
      return false;
    }

@@ -168,49 +183,50 @@ bool Adapter::SetName(const std::string& name) {
    return true;
  }

std::string Adapter::GetAddress() const {
  std::string GetAddress() const override {
    return address_.Get();
  }

bool Adapter::IsMultiAdvertisementSupported() {
  bool IsMultiAdvertisementSupported() override {
    lock_guard<mutex> lock(local_le_features_lock_);
    return local_le_features_.max_adv_instance >= kMinAdvInstancesForMultiAdv;
  }

bool Adapter::IsDeviceConnected(const std::string& device_address) {
  bool IsDeviceConnected(const std::string& device_address) override {
    lock_guard<mutex> lock(connected_devices_lock_);
    return connected_devices_.find(device_address) != connected_devices_.end();
  }

int Adapter::GetTotalNumberOfTrackableAdvertisements() {
  int GetTotalNumberOfTrackableAdvertisements() override {
    lock_guard<mutex> lock(local_le_features_lock_);
    return local_le_features_.total_trackable_advertisers;
  }

bool Adapter::IsOffloadedFilteringSupported() {
  bool IsOffloadedFilteringSupported() override {
    lock_guard<mutex> lock(local_le_features_lock_);
    return local_le_features_.max_adv_filter_supported >= kMinOffloadedFilters;
  }

bool Adapter::IsOffloadedScanBatchingSupported() {
  bool IsOffloadedScanBatchingSupported() override {
    lock_guard<mutex> lock(local_le_features_lock_);
    return local_le_features_.scan_result_storage_size >=
        kMinOffloadedScanStorageBytes;
  }

LowEnergyClientFactory* Adapter::GetLowEnergyClientFactory() const {
  LowEnergyClientFactory* GetLowEnergyClientFactory() const override {
    return ble_client_factory_.get();
  }

GattClientFactory* Adapter::GetGattClientFactory() const {
  GattClientFactory* GetGattClientFactory() const override {
    return gatt_client_factory_.get();
  }

GattServerFactory* Adapter::GetGattServerFactory() const {
  GattServerFactory* GetGattServerFactory() const override {
    return gatt_server_factory_.get();
  }

void Adapter::AdapterStateChangedCallback(bt_state_t state) {
  // hal::BluetoothInterface::Observer overrides.
  void AdapterStateChangedCallback(bt_state_t state) override {
    LOG(INFO) << "Adapter state changed: " << BtStateText(state);

    AdapterState prev_state = GetState();
@@ -231,9 +247,9 @@ void Adapter::AdapterStateChangedCallback(bt_state_t state) {
    NotifyAdapterStateChanged(prev_state, GetState());
  }

void Adapter::AdapterPropertiesCallback(bt_status_t status,
  void AdapterPropertiesCallback(bt_status_t status,
                                 int num_properties,
                                        bt_property_t* properties) {
                                 bt_property_t* properties) override {
    LOG(INFO) << "Adapter properties changed";

    if (status != BT_STATUS_SUCCESS) {
@@ -281,9 +297,9 @@ void Adapter::AdapterPropertiesCallback(bt_status_t status,
    }
  }

void Adapter::AclStateChangedCallback(bt_status_t status,
  void AclStateChangedCallback(bt_status_t status,
                               const bt_bdaddr_t& remote_bdaddr,
                                      bt_acl_state_t state) {
                               bt_acl_state_t state) override {
    std::string device_address = BtAddrString(&remote_bdaddr);
    bool connected = (state == BT_ACL_STATE_CONNECTED);
    LOG(INFO) << "ACL state changed: " << device_address << " - connected: "
@@ -292,8 +308,7 @@ void Adapter::AclStateChangedCallback(bt_status_t status,
    // If this is reported with an error status, I suppose the best thing we can
    // do is to log it and ignore the event.
    if (status != BT_STATUS_SUCCESS) {
    LOG(ERROR) << "AclStateChangedCallback called with status: "
               << BtStatusText(status);
      LOG(ERROR) << "status: " << BtStatusText(status);
      return;
    }

@@ -308,12 +323,12 @@ void Adapter::AclStateChangedCallback(bt_status_t status,

    lock_guard<mutex> lock(observers_lock_);
    FOR_EACH_OBSERVER(
      Observer, observers_,
        Adapter::Observer, observers_,
        OnDeviceConnectionStateChanged(this, device_address, connected));
  }

bool Adapter::SetAdapterProperty(bt_property_type_t type,
                                 void* value, int length) {
  // Sends a request to set the given HAL adapter property type and value.
  bool SetAdapterProperty(bt_property_type_t type, void* value, int length) {
    CHECK(length > 0);
    CHECK(value);

@@ -332,14 +347,57 @@ bool Adapter::SetAdapterProperty(bt_property_type_t type,
    return true;
  }

void Adapter::NotifyAdapterStateChanged(AdapterState prev_state,
  // Helper for invoking the AdapterStateChanged observer method.
  void NotifyAdapterStateChanged(AdapterState prev_state,
                                 AdapterState new_state) {
    if (prev_state == new_state)
      return;

    lock_guard<mutex> lock(observers_lock_);
  FOR_EACH_OBSERVER(Observer, observers_,
    FOR_EACH_OBSERVER(Adapter::Observer, observers_,
                      OnAdapterStateChanged(this, prev_state, new_state));
  }

 private:
  // The current adapter state.
  std::atomic<AdapterState> state_;

  // The Bluetooth device address of the local adapter in string from
  // (i.e.. XX:XX:XX:XX:XX:XX)
  util::AtomicString address_;

  // The current local adapter name.
  util::AtomicString name_;

  // The current set of supported LE features as obtained from the stack. The
  // values here are all initially set to 0 and updated when the corresponding
  // adapter property has been received from the stack.
  std::mutex local_le_features_lock_;
  bt_local_le_features_t local_le_features_;

  // List of observers that are interested in notifications from us.
  std::mutex observers_lock_;
  base::ObserverList<Adapter::Observer> observers_;

  // List of devices addresses that are currently connected.
  std::mutex connected_devices_lock_;
  std::unordered_set<std::string> connected_devices_;

  // Factory used to create per-app LowEnergyClient instances.
  std::unique_ptr<LowEnergyClientFactory> ble_client_factory_;

  // Factory used to create per-app GattClient instances.
  std::unique_ptr<GattClientFactory> gatt_client_factory_;

  // Factory used to create per-app GattServer instances.
  std::unique_ptr<GattServerFactory> gatt_server_factory_;

  DISALLOW_COPY_AND_ASSIGN(AdapterImpl);
};

// static
std::unique_ptr<Adapter> Adapter::Create() {
  return std::unique_ptr<Adapter>(new AdapterImpl());
}

}  // namespace bluetooth
+31 −79
Original line number Diff line number Diff line
@@ -16,25 +16,20 @@

#pragma once

#include <atomic>
#include <mutex>
#include <string>
#include <unordered_set>
#include <memory>

#include <base/macros.h>
#include <base/observer_list.h>

#include "service/common/bluetooth/adapter_state.h"
#include "service/common/bluetooth/util/atomic_string.h"
#include "service/gatt_client.h"
#include "service/gatt_server.h"
#include "service/hal/bluetooth_interface.h"
#include "service/low_energy_client.h"

namespace bluetooth {

class GattClientFactory;
class GattServerFactory;
class LowEnergyClientFactory;

// Represents the local Bluetooth adapter.
class Adapter : public hal::BluetoothInterface::Observer {
class Adapter {
 public:
  // The default values returned before the Adapter is fully initialized and
  // powered. The complete values for these fields are obtained following a
@@ -66,122 +61,79 @@ class Adapter : public hal::BluetoothInterface::Observer {
        Adapter* adapter, const std::string& device_address, bool connected);
  };

  Adapter();
  ~Adapter() override;
  // Returns an Adapter implementation to be used in production. Don't use these
  // in tests; use MockAdapter instead.
  static std::unique_ptr<Adapter> Create();

  virtual ~Adapter() = default;

  // Add or remove an observer.
  void AddObserver(Observer* observer);
  void RemoveObserver(Observer* observer);
  virtual void AddObserver(Observer* observer) = 0;
  virtual void RemoveObserver(Observer* observer) = 0;

  // Returns the current Adapter state.
  AdapterState GetState() const;
  virtual AdapterState GetState() const = 0;

  // Returns true, if the adapter radio is current powered.
  bool IsEnabled() const;
  virtual bool IsEnabled() const = 0;

  // Enables Bluetooth. This method will send a request to the Bluetooth adapter
  // to power up its radio. Returns true, if the request was successfully sent
  // to the controller, otherwise returns false. A successful call to this
  // method only means that the enable request has been sent to the Bluetooth
  // controller and does not imply that the operation itself succeeded.
  bool Enable();
  virtual bool Enable() = 0;

  // Powers off the Bluetooth radio. Returns true, if the disable request was
  // successfully sent to the Bluetooth controller.
  bool Disable();
  virtual bool Disable() = 0;

  // Returns the name currently assigned to the local adapter.
  std::string GetName() const;
  virtual std::string GetName() const = 0;

  // Sets the name assigned to the local Bluetooth adapter. This is the name
  // that the local controller will present to remote devices.
  bool SetName(const std::string& name);
  virtual bool SetName(const std::string& name) = 0;

  // Returns the local adapter addess in string form (XX:XX:XX:XX:XX:XX).
  std::string GetAddress() const;
  virtual std::string GetAddress() const = 0;

  // Returns true if the local adapter supports the Low-Energy
  // multi-advertisement feature.
  bool IsMultiAdvertisementSupported();
  virtual bool IsMultiAdvertisementSupported() = 0;

  // Returns true if the remote device with address |device_address| is
  // currently connected. This is not a const method as it modifies the state of
  // the associated internal mutex.
  bool IsDeviceConnected(const std::string& device_address);
  virtual bool IsDeviceConnected(const std::string& device_address) = 0;

  // Returns the total number of trackable advertisements as supported by the
  // underlying hardware.
  int GetTotalNumberOfTrackableAdvertisements();
  virtual int GetTotalNumberOfTrackableAdvertisements() = 0;

  // Returns true if hardware-backed scan filtering is supported.
  bool IsOffloadedFilteringSupported();
  virtual bool IsOffloadedFilteringSupported() = 0;

  // Returns true if hardware-backed batch scanning is supported.
  bool IsOffloadedScanBatchingSupported();
  virtual bool IsOffloadedScanBatchingSupported() = 0;

  // Returns a pointer to the LowEnergyClientFactory. This can be used to
  // register per-application LowEnergyClient instances to perform BLE GAP
  // operations.
  LowEnergyClientFactory* GetLowEnergyClientFactory() const;
  virtual LowEnergyClientFactory* GetLowEnergyClientFactory() const = 0;

  // Returns a pointer to the GattClientFactory. This can be used to register
  // per-application GATT server instances.
  GattClientFactory* GetGattClientFactory() const;
  virtual GattClientFactory* GetGattClientFactory() const = 0;

  // Returns a pointer to the GattServerFactory. This can be used to register
  // per-application GATT server instances.
  GattServerFactory* GetGattServerFactory() const;

 private:
  // hal::BluetoothInterface::Observer overrides.
  void AdapterStateChangedCallback(bt_state_t state) override;
  void AdapterPropertiesCallback(bt_status_t status,
                                 int num_properties,
                                 bt_property_t* properties) override;
  void AclStateChangedCallback(bt_status_t status,
                               const bt_bdaddr_t& remote_bdaddr,
                               bt_acl_state_t state) override;

  // Sends a request to set the given HAL adapter property type and value.
  bool SetAdapterProperty(bt_property_type_t type, void* value, int length);

  // Helper for invoking observer method.
  void NotifyAdapterStateChanged(AdapterState prev_state,
                                 AdapterState new_state);

  // The current adapter state.
  std::atomic<AdapterState> state_;

  // The Bluetooth device address of the local adapter in string from
  // (i.e.. XX:XX:XX:XX:XX:XX)
  util::AtomicString address_;
  virtual GattServerFactory* GetGattServerFactory() const = 0;

  // The current local adapter name.
  util::AtomicString name_;

  // The current set of supported LE features as obtained from the stack. The
  // values here are all initially set to 0 and updated when the corresponding
  // adapter property has been received from the stack.
  std::mutex local_le_features_lock_;
  bt_local_le_features_t local_le_features_;

  // List of observers that are interested in notifications from us.
  std::mutex observers_lock_;
  base::ObserverList<Observer> observers_;

  // List of devices addresses that are currently connected.
  std::mutex connected_devices_lock_;
  std::unordered_set<std::string> connected_devices_;

  // Factory used to create per-app LowEnergyClient instances.
  std::unique_ptr<LowEnergyClientFactory> ble_client_factory_;

  // Factory used to create per-app GattClient instances.
  std::unique_ptr<GattClientFactory> gatt_client_factory_;

  // Factory used to create per-app GattServer instances.
  std::unique_ptr<GattServerFactory> gatt_server_factory_;
 protected:
  Adapter() = default;

 private:
  DISALLOW_COPY_AND_ASSIGN(Adapter);
};

+1 −1
Original line number Diff line number Diff line
@@ -117,7 +117,7 @@ class DaemonImpl : public Daemon {
      return false;
    }

    adapter_.reset(new Adapter());
    adapter_ = Adapter::Create();
    ipc_manager_.reset(new ipc::IPCManager(adapter_.get()));

    if (!SetUpIPC()) {
+1 −1
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@ class AdapterTest : public ::testing::Test {
    hal::BluetoothGattInterface::InitializeForTesting(
        new hal::FakeBluetoothGattInterface(nullptr, nullptr));

    adapter_.reset(new Adapter());
    adapter_ = Adapter::Create();
  }

  void TearDown() override {
+1 −1
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@ class IPCLinuxTest : public ::testing::Test {
    bluetooth::hal::BluetoothGattInterface::InitializeForTesting(
        new bluetooth::hal::FakeBluetoothGattInterface(nullptr, nullptr));

    adapter_.reset(new bluetooth::Adapter());
    adapter_ = bluetooth::Adapter::Create();
    ipc_manager_.reset(new ipc::IPCManager(adapter_.get()));
  }

Loading