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

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

service/hal: Add per-client Scan interface

Added a new per-client scan function to hal::BluetoothGattInterface.
The intention here is to push most of the per-client reference counting,
scan settings and filter coalescence below the HAL. This CL does this
first inside the Bluetooth daemon's HAL wrappers in a way that
represents what the future HAL scan API might look like.

This implements a basic reference counting scheme to share the global
controller scan session among different clients.

Bug: 25744656
Change-Id: I20c5cfc291be70d72576ebee014cc13544d5a299
parent 2d9fdf12
Loading
Loading
Loading
Loading
+48 −0
Original line number Diff line number Diff line
@@ -670,5 +670,53 @@ void BluetoothGattInterface::InitializeForTesting(
  g_interface = test_instance;
}

bt_status_t BluetoothGattInterface::StartScan(int client_id) {
  lock_guard<mutex> lock(scan_clients_lock_);

  // Scan already initiated for this client.
  if (scan_client_set_.find(client_id) != scan_client_set_.end()) {
    // Assume starting scan multiple times is not error, but warn user.
    LOG(WARNING) << "Scan already initiated for client";
    return BT_STATUS_SUCCESS;
  }

  // If this is the first scan client, then make a call into the stack. We
  // only do this when the reference count changes to or from 0.
  if (scan_client_set_.empty()) {
    bt_status_t status = GetClientHALInterface()->scan(true);
    if (status != BT_STATUS_SUCCESS) {
      LOG(ERROR) << "HAL call to scan failed";
      return status;
    }
  }

  scan_client_set_.insert(client_id);

  return BT_STATUS_SUCCESS;
}

bt_status_t BluetoothGattInterface::StopScan(int client_id) {
  lock_guard<mutex> lock(scan_clients_lock_);

  // Scan not initiated for this client.
  auto iter = scan_client_set_.find(client_id);
  if (iter == scan_client_set_.end()) {
    // Assume stopping scan multiple times is not error, but warn user.
    LOG(WARNING) << "Scan already stopped or not initiated for client";
    return BT_STATUS_SUCCESS;
  }

  if (scan_client_set_.size() == 1) {
    bt_status_t status = GetClientHALInterface()->scan(false);
    if (status != BT_STATUS_SUCCESS) {
      LOG(ERROR) << "HAL call to stop scan failed";
      return status;
    }
  }

  scan_client_set_.erase(iter);
  return BT_STATUS_SUCCESS;
}

}  // namespace hal
}  // namespace bluetooth
+14 −0
Original line number Diff line number Diff line
@@ -16,6 +16,10 @@

#pragma once

#include <mutex>
#include <unordered_set>
#include <vector>

#include <base/macros.h>
#include <hardware/bluetooth.h>
#include <hardware/bt_gatt.h>
@@ -226,11 +230,21 @@ class BluetoothGattInterface {
  // structure.
  virtual const btgatt_server_interface_t* GetServerHALInterface() const = 0;

  // Initiates a regular BLE device scan. This is called internally from each
  // LowEnergyClient. This function synchronizes the scan requests and maintains
  // an internal reference count for each scan client that is interested.
  bt_status_t StartScan(int client_id);
  bt_status_t StopScan(int client_id);

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

 private:
  // Used to keep a reference count for the different BLE scan clients.
  std::mutex scan_clients_lock_;
  std::unordered_set<int> scan_client_set_;

  DISALLOW_COPY_AND_ASSIGN(BluetoothGattInterface);
};

+8 −1
Original line number Diff line number Diff line
@@ -40,6 +40,13 @@ bt_status_t FakeUnregisterClient(int client_if) {
  return BT_STATUS_FAIL;
}

bt_status_t FakeScan(bool start) {
  if (g_client_handler)
    return g_client_handler->Scan(start);

  return BT_STATUS_FAIL;
}

bt_status_t FakeMultiAdvEnable(
    int client_if, int min_interval, int max_interval, int adv_type,
    int chnl_map, int tx_power, int timeout_s) {
@@ -152,7 +159,7 @@ bt_status_t FakeSendResponse(int conn_id, int trans_id, int status,
btgatt_client_interface_t fake_btgattc_iface = {
  FakeRegisterClient,
  FakeUnregisterClient,
  nullptr,  // scan
  FakeScan,
  nullptr,  // connect
  nullptr,  // disconnect
  nullptr,  // listen
+4 −0
Original line number Diff line number Diff line
@@ -35,6 +35,9 @@ class FakeBluetoothGattInterface : public BluetoothGattInterface {

    virtual bt_status_t RegisterClient(bt_uuid_t* app_uuid) = 0;
    virtual bt_status_t UnregisterClient(int client_if) = 0;

    virtual bt_status_t Scan(bool start) = 0;

    virtual bt_status_t MultiAdvEnable(
        int client_if, int min_interval, int max_interval, int adv_type,
        int chnl_map, int tx_power, int timeout_s) = 0;
@@ -136,6 +139,7 @@ class FakeBluetoothGattInterface : public BluetoothGattInterface {
  std::shared_ptr<TestClientHandler> client_handler_;
  std::shared_ptr<TestServerHandler> server_handler_;


  DISALLOW_COPY_AND_ASSIGN(FakeBluetoothGattInterface);
};

+19 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ class MockGattHandler

  MOCK_METHOD1(RegisterClient, bt_status_t(bt_uuid_t*));
  MOCK_METHOD1(UnregisterClient, bt_status_t(int));
  MOCK_METHOD1(Scan, bt_status_t(bool));

  // Stub implementations for uninteresting TestClientHandler methods:
  bt_status_t MultiAdvEnable(int, int, int, int, int, int, int) override {
@@ -170,5 +171,23 @@ TEST_F(GattClientTest, RegisterInstance) {
  EXPECT_EQ(uuid1, cb_uuid);
}

TEST_F(GattClientTest, StartStopScan) {
  EXPECT_CALL(*mock_handler_, Scan(true))
      .Times(1)
      .WillOnce(Return(BT_STATUS_SUCCESS));

  EXPECT_CALL(*mock_handler_, Scan(false))
      .Times(1)
      .WillOnce(Return(BT_STATUS_SUCCESS));

  for(int i=0; i<5; i++)
    hal::BluetoothGattInterface::Get()->StartScan(i);

  for(int i=0; i<5; i++)
    hal::BluetoothGattInterface::Get()->StopScan(i);

  testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
}

}  // namespace
}  // namespace bluetooth
Loading