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
diff --git a/service/hal/bluetooth_gatt_interface.cpp b/service/hal/bluetooth_gatt_interface.cpp
index 4ad6304..107d9ee 100644
--- a/service/hal/bluetooth_gatt_interface.cpp
+++ b/service/hal/bluetooth_gatt_interface.cpp
@@ -670,5 +670,53 @@
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
diff --git a/service/hal/bluetooth_gatt_interface.h b/service/hal/bluetooth_gatt_interface.h
index e8d7561..9b2bea6 100644
--- a/service/hal/bluetooth_gatt_interface.h
+++ b/service/hal/bluetooth_gatt_interface.h
@@ -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 @@
// 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);
};
diff --git a/service/hal/fake_bluetooth_gatt_interface.cpp b/service/hal/fake_bluetooth_gatt_interface.cpp
index 41183aa..c29bb1b 100644
--- a/service/hal/fake_bluetooth_gatt_interface.cpp
+++ b/service/hal/fake_bluetooth_gatt_interface.cpp
@@ -40,6 +40,13 @@
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 @@
btgatt_client_interface_t fake_btgattc_iface = {
FakeRegisterClient,
FakeUnregisterClient,
- nullptr, // scan
+ FakeScan,
nullptr, // connect
nullptr, // disconnect
nullptr, // listen
diff --git a/service/hal/fake_bluetooth_gatt_interface.h b/service/hal/fake_bluetooth_gatt_interface.h
index 03f25f9..cdcb794 100644
--- a/service/hal/fake_bluetooth_gatt_interface.h
+++ b/service/hal/fake_bluetooth_gatt_interface.h
@@ -35,6 +35,9 @@
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 @@
std::shared_ptr<TestClientHandler> client_handler_;
std::shared_ptr<TestServerHandler> server_handler_;
+
DISALLOW_COPY_AND_ASSIGN(FakeBluetoothGattInterface);
};
diff --git a/service/test/gatt_client_unittest.cpp b/service/test/gatt_client_unittest.cpp
index 0df3132..167609c 100644
--- a/service/test/gatt_client_unittest.cpp
+++ b/service/test/gatt_client_unittest.cpp
@@ -35,6 +35,7 @@
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 @@
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
diff --git a/service/test/low_energy_client_unittest.cpp b/service/test/low_energy_client_unittest.cpp
index da57d8b..a2c9121 100644
--- a/service/test/low_energy_client_unittest.cpp
+++ b/service/test/low_energy_client_unittest.cpp
@@ -37,6 +37,7 @@
MOCK_METHOD1(RegisterClient, bt_status_t(bt_uuid_t*));
MOCK_METHOD1(UnregisterClient, bt_status_t(int));
+ MOCK_METHOD1(Scan, bt_status_t(bool));
MOCK_METHOD7(MultiAdvEnable, bt_status_t(int, int, int, int, int, int, int));
MOCK_METHOD10(
MultiAdvSetInstDataMock,