Loading system/service/hal/fake_bluetooth_gatt_interface.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -246,6 +246,12 @@ void FakeBluetoothGattInterface::NotifyRegisterClientCallback( RegisterClientCallback(this, status, client_if, app_uuid)); } void FakeBluetoothGattInterface::NotifyScanResultCallback( const bt_bdaddr_t& bda, int rssi, uint8_t* adv_data) { FOR_EACH_OBSERVER(ClientObserver, client_observers_, ScanResultCallback(this, bda, rssi, adv_data)); } void FakeBluetoothGattInterface::NotifyMultiAdvEnableCallback( int client_if, int status) { FOR_EACH_OBSERVER(ClientObserver, client_observers_, Loading system/service/hal/fake_bluetooth_gatt_interface.h +2 −0 Original line number Diff line number Diff line Loading @@ -90,6 +90,8 @@ class FakeBluetoothGattInterface : public BluetoothGattInterface { // Client callbacks: void NotifyRegisterClientCallback(int status, int client_if, const bt_uuid_t& app_uuid); void NotifyScanResultCallback(const bt_bdaddr_t& bda, int rssi, uint8_t* adv_data); void NotifyMultiAdvEnableCallback(int client_if, int status); void NotifyMultiAdvDataCallback(int client_if, int status); void NotifyMultiAdvDisableCallback(int client_if, int status); Loading system/service/low_energy_client.cpp +57 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <base/logging.h> #include "service/adapter.h" #include "service/logging_helpers.h" #include "stack/include/bt_types.h" #include "stack/include/hcidefs.h" Loading @@ -29,6 +30,12 @@ namespace bluetooth { namespace { // 31 + 31 for advertising data and scan response. This is the maximum length // TODO(armansito): Fix the HAL to return a concatenated blob that contains the // true length of each field and also provide a length parameter so that we // can support advertising length extensions in the future. const size_t kScanRecordLength = 62; BLEStatus GetBLEStatus(int status) { if (status == BT_STATUS_FAIL) return BLE_STATUS_FAILURE; Loading @@ -36,6 +43,30 @@ BLEStatus GetBLEStatus(int status) { return static_cast<BLEStatus>(status); } // Returns the length of the given scan record array. We have to calculate this // based on the maximum possible data length and the TLV data. See TODO above // |kScanRecordLength|. size_t GetScanRecordLength(uint8_t* bytes) { for (size_t i = 0, field_len = 0; i < kScanRecordLength; i += (field_len + 1)) { field_len = bytes[i]; // Assert here that the data returned from the stack is correctly formatted // in TLV form and that the length of the current field won't exceed the // total data length. CHECK(i + field_len < kScanRecordLength); // If the field length is zero and we haven't reached the maximum length, // then we have found the length, as the stack will pad the data with zeros // accordingly. if (field_len == 0) return i; } // We have reached the end. return kScanRecordLength; } // TODO(armansito): BTIF currently expects each advertising field in a // specific format passed directly in arguments. We should fix BTIF to accept // the advertising data directly instead. Loading Loading @@ -303,6 +334,11 @@ LowEnergyClient::~LowEnergyClient() { StopScan(); } void LowEnergyClient::SetDelegate(Delegate* delegate) { lock_guard<mutex> lock(delegate_mutex_); delegate_ = delegate; } bool LowEnergyClient::StartScan(const ScanSettings& settings, const std::vector<ScanFilter>& filters) { VLOG(2) << __func__; Loading Loading @@ -456,6 +492,27 @@ int LowEnergyClient::GetInstanceId() const { return client_id_; } void LowEnergyClient::ScanResultCallback( hal::BluetoothGattInterface* gatt_iface, const bt_bdaddr_t& bda, int rssi, uint8_t* adv_data) { // Ignore scan results if this client didn't start a scan. if (!scan_started_.load()) return; lock_guard<mutex> lock(delegate_mutex_); if (!delegate_) return; // TODO(armansito): Apply software filters here. size_t record_len = GetScanRecordLength(adv_data); std::vector<uint8_t> scan_record(adv_data, adv_data + record_len); ScanResult result(BtAddrString(&bda), scan_record, rssi); delegate_->OnScanResult(this, result); } void LowEnergyClient::MultiAdvEnableCallback( hal::BluetoothGattInterface* gatt_iface, int client_id, int status) { Loading system/service/low_energy_client.h +29 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ #include "service/common/bluetooth/advertise_settings.h" #include "service/common/bluetooth/low_energy_constants.h" #include "service/common/bluetooth/scan_filter.h" #include "service/common/bluetooth/scan_result.h" #include "service/common/bluetooth/scan_settings.h" #include "service/common/bluetooth/uuid.h" #include "service/hal/bluetooth_gatt_interface.h" Loading @@ -42,10 +43,30 @@ class Adapter; class LowEnergyClient : private hal::BluetoothGattInterface::ClientObserver, public BluetoothInstance { public: // The Delegate interface is used to notify asynchronous events related to BLE // GAP operations. class Delegate { public: Delegate() = default; virtual ~Delegate() = default; // Called asynchronously to notify the delegate of nearby BLE advertisers // found during a device scan. virtual void OnScanResult(LowEnergyClient* client, const ScanResult& scan_result) = 0; private: DISALLOW_COPY_AND_ASSIGN(Delegate); }; // The destructor automatically unregisters this client instance from the // stack. ~LowEnergyClient() override; // Assigns a delegate to this instance. |delegate| must out-live this // LowEnergyClient instance. void SetDelegate(Delegate* delegate); // Callback type used to return the result of asynchronous operations below. using StatusCallback = std::function<void(BLEStatus)>; Loading Loading @@ -99,6 +120,9 @@ class LowEnergyClient : private hal::BluetoothGattInterface::ClientObserver, LowEnergyClient(Adapter& adapter, const UUID& uuid, int client_id); // BluetoothGattInterface::ClientObserver overrides: void ScanResultCallback( hal::BluetoothGattInterface* gatt_iface, const bt_bdaddr_t& bda, int rssi, uint8_t* adv_data) override; void MultiAdvEnableCallback( hal::BluetoothGattInterface* gatt_iface, int client_id, int status) override; Loading Loading @@ -161,6 +185,11 @@ class LowEnergyClient : private hal::BluetoothGattInterface::ClientObserver, // If true, then this client have a BLE device scan in progress. std::atomic_bool scan_started_; // Raw handle to the Delegate, which must outlive this LowEnergyClient // instance. std::mutex delegate_mutex_; Delegate* delegate_; DISALLOW_COPY_AND_ASSIGN(LowEnergyClient); }; Loading system/service/test/low_energy_client_unittest.cpp +86 −0 Original line number Diff line number Diff line Loading @@ -70,6 +70,29 @@ class MockGattHandler DISALLOW_COPY_AND_ASSIGN(MockGattHandler); }; class TestDelegate : public LowEnergyClient::Delegate { public: TestDelegate() : scan_result_count_(0) { } ~TestDelegate() override = default; int scan_result_count() const { return scan_result_count_; } const ScanResult& last_scan_result() const { return last_scan_result_; } void OnScanResult(LowEnergyClient* client, const ScanResult& scan_result) { ASSERT_TRUE(client); scan_result_count_++; last_scan_result_ = scan_result; } private: int scan_result_count_; ScanResult last_scan_result_; DISALLOW_COPY_AND_ASSIGN(TestDelegate); }; // Created this class for testing Advertising Data Setting // It provides a work around in order to verify the arguments // in the arrays passed to MultiAdvSetInstData due to mocks Loading Loading @@ -836,5 +859,68 @@ TEST_F(LowEnergyClientPostRegisterTest, ScanSettings) { ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get()); } TEST_F(LowEnergyClientPostRegisterTest, ScanRecord) { TestDelegate delegate; le_client_->SetDelegate(&delegate); EXPECT_EQ(0, delegate.scan_result_count()); const uint8_t kTestRecord0[] = { 0x02, 0x01, 0x00, 0x00 }; const uint8_t kTestRecord1[] = { 0x00 }; const uint8_t kTestRecord2[] = { 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00 }; const bt_bdaddr_t kTestAddress = { { 0x01, 0x02, 0x03, 0x0A, 0x0B, 0x0C } }; const char kTestAddressStr[] = "01:02:03:0A:0B:0C"; const int kTestRssi = 64; // Scan wasn't started. Result should be ignored. fake_hal_gatt_iface_->NotifyScanResultCallback( kTestAddress, kTestRssi, (uint8_t*) kTestRecord0); EXPECT_EQ(0, delegate.scan_result_count()); // Start a scan session for |le_client_|. EXPECT_CALL(mock_adapter_, IsEnabled()) .Times(1) .WillOnce(Return(true)); EXPECT_CALL(*mock_handler_, Scan(_)) .Times(2) .WillOnce(Return(BT_STATUS_SUCCESS)) .WillOnce(Return(BT_STATUS_SUCCESS)); ScanSettings settings; std::vector<ScanFilter> filters; ASSERT_TRUE(le_client_->StartScan(settings, filters)); fake_hal_gatt_iface_->NotifyScanResultCallback( kTestAddress, kTestRssi, (uint8_t*) kTestRecord0); EXPECT_EQ(1, delegate.scan_result_count()); EXPECT_EQ(kTestAddressStr, delegate.last_scan_result().device_address()); EXPECT_EQ(kTestRssi, delegate.last_scan_result().rssi()); EXPECT_EQ(3U, delegate.last_scan_result().scan_record().size()); fake_hal_gatt_iface_->NotifyScanResultCallback( kTestAddress, kTestRssi, (uint8_t*) kTestRecord1); EXPECT_EQ(2, delegate.scan_result_count()); EXPECT_EQ(kTestAddressStr, delegate.last_scan_result().device_address()); EXPECT_EQ(kTestRssi, delegate.last_scan_result().rssi()); EXPECT_TRUE(delegate.last_scan_result().scan_record().empty()); fake_hal_gatt_iface_->NotifyScanResultCallback( kTestAddress, kTestRssi, (uint8_t*) kTestRecord2); EXPECT_EQ(3, delegate.scan_result_count()); EXPECT_EQ(kTestAddressStr, delegate.last_scan_result().device_address()); EXPECT_EQ(kTestRssi, delegate.last_scan_result().rssi()); EXPECT_EQ(62U, delegate.last_scan_result().scan_record().size()); le_client_->SetDelegate(nullptr); } } // namespace } // namespace bluetooth Loading
system/service/hal/fake_bluetooth_gatt_interface.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -246,6 +246,12 @@ void FakeBluetoothGattInterface::NotifyRegisterClientCallback( RegisterClientCallback(this, status, client_if, app_uuid)); } void FakeBluetoothGattInterface::NotifyScanResultCallback( const bt_bdaddr_t& bda, int rssi, uint8_t* adv_data) { FOR_EACH_OBSERVER(ClientObserver, client_observers_, ScanResultCallback(this, bda, rssi, adv_data)); } void FakeBluetoothGattInterface::NotifyMultiAdvEnableCallback( int client_if, int status) { FOR_EACH_OBSERVER(ClientObserver, client_observers_, Loading
system/service/hal/fake_bluetooth_gatt_interface.h +2 −0 Original line number Diff line number Diff line Loading @@ -90,6 +90,8 @@ class FakeBluetoothGattInterface : public BluetoothGattInterface { // Client callbacks: void NotifyRegisterClientCallback(int status, int client_if, const bt_uuid_t& app_uuid); void NotifyScanResultCallback(const bt_bdaddr_t& bda, int rssi, uint8_t* adv_data); void NotifyMultiAdvEnableCallback(int client_if, int status); void NotifyMultiAdvDataCallback(int client_if, int status); void NotifyMultiAdvDisableCallback(int client_if, int status); Loading
system/service/low_energy_client.cpp +57 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <base/logging.h> #include "service/adapter.h" #include "service/logging_helpers.h" #include "stack/include/bt_types.h" #include "stack/include/hcidefs.h" Loading @@ -29,6 +30,12 @@ namespace bluetooth { namespace { // 31 + 31 for advertising data and scan response. This is the maximum length // TODO(armansito): Fix the HAL to return a concatenated blob that contains the // true length of each field and also provide a length parameter so that we // can support advertising length extensions in the future. const size_t kScanRecordLength = 62; BLEStatus GetBLEStatus(int status) { if (status == BT_STATUS_FAIL) return BLE_STATUS_FAILURE; Loading @@ -36,6 +43,30 @@ BLEStatus GetBLEStatus(int status) { return static_cast<BLEStatus>(status); } // Returns the length of the given scan record array. We have to calculate this // based on the maximum possible data length and the TLV data. See TODO above // |kScanRecordLength|. size_t GetScanRecordLength(uint8_t* bytes) { for (size_t i = 0, field_len = 0; i < kScanRecordLength; i += (field_len + 1)) { field_len = bytes[i]; // Assert here that the data returned from the stack is correctly formatted // in TLV form and that the length of the current field won't exceed the // total data length. CHECK(i + field_len < kScanRecordLength); // If the field length is zero and we haven't reached the maximum length, // then we have found the length, as the stack will pad the data with zeros // accordingly. if (field_len == 0) return i; } // We have reached the end. return kScanRecordLength; } // TODO(armansito): BTIF currently expects each advertising field in a // specific format passed directly in arguments. We should fix BTIF to accept // the advertising data directly instead. Loading Loading @@ -303,6 +334,11 @@ LowEnergyClient::~LowEnergyClient() { StopScan(); } void LowEnergyClient::SetDelegate(Delegate* delegate) { lock_guard<mutex> lock(delegate_mutex_); delegate_ = delegate; } bool LowEnergyClient::StartScan(const ScanSettings& settings, const std::vector<ScanFilter>& filters) { VLOG(2) << __func__; Loading Loading @@ -456,6 +492,27 @@ int LowEnergyClient::GetInstanceId() const { return client_id_; } void LowEnergyClient::ScanResultCallback( hal::BluetoothGattInterface* gatt_iface, const bt_bdaddr_t& bda, int rssi, uint8_t* adv_data) { // Ignore scan results if this client didn't start a scan. if (!scan_started_.load()) return; lock_guard<mutex> lock(delegate_mutex_); if (!delegate_) return; // TODO(armansito): Apply software filters here. size_t record_len = GetScanRecordLength(adv_data); std::vector<uint8_t> scan_record(adv_data, adv_data + record_len); ScanResult result(BtAddrString(&bda), scan_record, rssi); delegate_->OnScanResult(this, result); } void LowEnergyClient::MultiAdvEnableCallback( hal::BluetoothGattInterface* gatt_iface, int client_id, int status) { Loading
system/service/low_energy_client.h +29 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ #include "service/common/bluetooth/advertise_settings.h" #include "service/common/bluetooth/low_energy_constants.h" #include "service/common/bluetooth/scan_filter.h" #include "service/common/bluetooth/scan_result.h" #include "service/common/bluetooth/scan_settings.h" #include "service/common/bluetooth/uuid.h" #include "service/hal/bluetooth_gatt_interface.h" Loading @@ -42,10 +43,30 @@ class Adapter; class LowEnergyClient : private hal::BluetoothGattInterface::ClientObserver, public BluetoothInstance { public: // The Delegate interface is used to notify asynchronous events related to BLE // GAP operations. class Delegate { public: Delegate() = default; virtual ~Delegate() = default; // Called asynchronously to notify the delegate of nearby BLE advertisers // found during a device scan. virtual void OnScanResult(LowEnergyClient* client, const ScanResult& scan_result) = 0; private: DISALLOW_COPY_AND_ASSIGN(Delegate); }; // The destructor automatically unregisters this client instance from the // stack. ~LowEnergyClient() override; // Assigns a delegate to this instance. |delegate| must out-live this // LowEnergyClient instance. void SetDelegate(Delegate* delegate); // Callback type used to return the result of asynchronous operations below. using StatusCallback = std::function<void(BLEStatus)>; Loading Loading @@ -99,6 +120,9 @@ class LowEnergyClient : private hal::BluetoothGattInterface::ClientObserver, LowEnergyClient(Adapter& adapter, const UUID& uuid, int client_id); // BluetoothGattInterface::ClientObserver overrides: void ScanResultCallback( hal::BluetoothGattInterface* gatt_iface, const bt_bdaddr_t& bda, int rssi, uint8_t* adv_data) override; void MultiAdvEnableCallback( hal::BluetoothGattInterface* gatt_iface, int client_id, int status) override; Loading Loading @@ -161,6 +185,11 @@ class LowEnergyClient : private hal::BluetoothGattInterface::ClientObserver, // If true, then this client have a BLE device scan in progress. std::atomic_bool scan_started_; // Raw handle to the Delegate, which must outlive this LowEnergyClient // instance. std::mutex delegate_mutex_; Delegate* delegate_; DISALLOW_COPY_AND_ASSIGN(LowEnergyClient); }; Loading
system/service/test/low_energy_client_unittest.cpp +86 −0 Original line number Diff line number Diff line Loading @@ -70,6 +70,29 @@ class MockGattHandler DISALLOW_COPY_AND_ASSIGN(MockGattHandler); }; class TestDelegate : public LowEnergyClient::Delegate { public: TestDelegate() : scan_result_count_(0) { } ~TestDelegate() override = default; int scan_result_count() const { return scan_result_count_; } const ScanResult& last_scan_result() const { return last_scan_result_; } void OnScanResult(LowEnergyClient* client, const ScanResult& scan_result) { ASSERT_TRUE(client); scan_result_count_++; last_scan_result_ = scan_result; } private: int scan_result_count_; ScanResult last_scan_result_; DISALLOW_COPY_AND_ASSIGN(TestDelegate); }; // Created this class for testing Advertising Data Setting // It provides a work around in order to verify the arguments // in the arrays passed to MultiAdvSetInstData due to mocks Loading Loading @@ -836,5 +859,68 @@ TEST_F(LowEnergyClientPostRegisterTest, ScanSettings) { ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get()); } TEST_F(LowEnergyClientPostRegisterTest, ScanRecord) { TestDelegate delegate; le_client_->SetDelegate(&delegate); EXPECT_EQ(0, delegate.scan_result_count()); const uint8_t kTestRecord0[] = { 0x02, 0x01, 0x00, 0x00 }; const uint8_t kTestRecord1[] = { 0x00 }; const uint8_t kTestRecord2[] = { 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00 }; const bt_bdaddr_t kTestAddress = { { 0x01, 0x02, 0x03, 0x0A, 0x0B, 0x0C } }; const char kTestAddressStr[] = "01:02:03:0A:0B:0C"; const int kTestRssi = 64; // Scan wasn't started. Result should be ignored. fake_hal_gatt_iface_->NotifyScanResultCallback( kTestAddress, kTestRssi, (uint8_t*) kTestRecord0); EXPECT_EQ(0, delegate.scan_result_count()); // Start a scan session for |le_client_|. EXPECT_CALL(mock_adapter_, IsEnabled()) .Times(1) .WillOnce(Return(true)); EXPECT_CALL(*mock_handler_, Scan(_)) .Times(2) .WillOnce(Return(BT_STATUS_SUCCESS)) .WillOnce(Return(BT_STATUS_SUCCESS)); ScanSettings settings; std::vector<ScanFilter> filters; ASSERT_TRUE(le_client_->StartScan(settings, filters)); fake_hal_gatt_iface_->NotifyScanResultCallback( kTestAddress, kTestRssi, (uint8_t*) kTestRecord0); EXPECT_EQ(1, delegate.scan_result_count()); EXPECT_EQ(kTestAddressStr, delegate.last_scan_result().device_address()); EXPECT_EQ(kTestRssi, delegate.last_scan_result().rssi()); EXPECT_EQ(3U, delegate.last_scan_result().scan_record().size()); fake_hal_gatt_iface_->NotifyScanResultCallback( kTestAddress, kTestRssi, (uint8_t*) kTestRecord1); EXPECT_EQ(2, delegate.scan_result_count()); EXPECT_EQ(kTestAddressStr, delegate.last_scan_result().device_address()); EXPECT_EQ(kTestRssi, delegate.last_scan_result().rssi()); EXPECT_TRUE(delegate.last_scan_result().scan_record().empty()); fake_hal_gatt_iface_->NotifyScanResultCallback( kTestAddress, kTestRssi, (uint8_t*) kTestRecord2); EXPECT_EQ(3, delegate.scan_result_count()); EXPECT_EQ(kTestAddressStr, delegate.last_scan_result().device_address()); EXPECT_EQ(kTestRssi, delegate.last_scan_result().rssi()); EXPECT_EQ(62U, delegate.last_scan_result().scan_record().size()); le_client_->SetDelegate(nullptr); } } // namespace } // namespace bluetooth