#include "stack/gatt/connection_manager.h" #include #include #include #include #include #include #include "osi/include/alarm.h" #include "osi/test/alarm_mock.h" using testing::_; using testing::DoAll; using testing::Mock; using testing::Return; using testing::SaveArg; using connection_manager::tAPP_ID; namespace { // convenience mock, for verifying acceptlist operations on lower layer are // actually scheduled class AcceptlistMock { public: MOCK_METHOD1(AcceptlistAdd, bool(const RawAddress&)); MOCK_METHOD1(AcceptlistRemove, void(const RawAddress&)); MOCK_METHOD0(AcceptlistClear, void()); MOCK_METHOD0(SetLeConnectionModeToFast, bool()); MOCK_METHOD0(SetLeConnectionModeToSlow, void()); MOCK_METHOD2(OnConnectionTimedOut, void(uint8_t, const RawAddress&)); }; std::unique_ptr localAcceptlistMock; } // namespace RawAddress address1{{0x01, 0x01, 0x01, 0x01, 0x01, 0x01}}; RawAddress address2{{0x22, 0x22, 0x02, 0x22, 0x33, 0x22}}; constexpr tAPP_ID CLIENT1 = 1; constexpr tAPP_ID CLIENT2 = 2; constexpr tAPP_ID CLIENT3 = 3; constexpr tAPP_ID CLIENT10 = 10; // Implementation of btm_ble_bgconn.h API for test. bool BTM_AcceptlistAdd(const RawAddress& address) { return localAcceptlistMock->AcceptlistAdd(address); } void BTM_AcceptlistRemove(const RawAddress& address) { return localAcceptlistMock->AcceptlistRemove(address); } void BTM_AcceptlistClear() { return localAcceptlistMock->AcceptlistClear(); } bool BTM_SetLeConnectionModeToFast() { return localAcceptlistMock->SetLeConnectionModeToFast(); } void BTM_SetLeConnectionModeToSlow() { localAcceptlistMock->SetLeConnectionModeToSlow(); } namespace bluetooth { namespace shim { bool is_gd_l2cap_enabled() { return false; } } // namespace shim } // namespace bluetooth bool L2CA_ConnectFixedChnl(uint16_t fixed_cid, const RawAddress& bd_addr) { return false; } namespace connection_manager { class BleConnectionManager : public testing::Test { void SetUp() override { localAcceptlistMock = std::make_unique(); } void TearDown() override { connection_manager::reset(true); AlarmMock::Reset(); localAcceptlistMock.reset(); } }; void on_connection_timed_out(uint8_t app_id, const RawAddress& address) { localAcceptlistMock->OnConnectionTimedOut(app_id, address); } /** Verify that app can add a device to acceptlist, it is returned as interested * app, and then can remove the device later. */ TEST_F(BleConnectionManager, test_background_connection_add_remove) { EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(address1)) .WillOnce(Return(true)); EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(_)).Times(0); EXPECT_TRUE(background_connect_add(CLIENT1, address1)); Mock::VerifyAndClearExpectations(localAcceptlistMock.get()); std::set apps = get_apps_connecting_to(address1); EXPECT_EQ(apps.size(), 1UL); EXPECT_EQ(apps.count(CLIENT1), 1UL); EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(_)).Times(0); EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(address1)).Times(1); EXPECT_TRUE(background_connect_remove(CLIENT1, address1)); EXPECT_EQ(get_apps_connecting_to(address1).size(), 0UL); Mock::VerifyAndClearExpectations(localAcceptlistMock.get()); } /** Verify that multiple clients adding same device multiple times, result in * device being added to whtie list only once, also, that device is removed only * after last client removes it. */ TEST_F(BleConnectionManager, test_background_connection_multiple_clients) { EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(address1)) .WillOnce(Return(true)); EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(_)).Times(0); EXPECT_TRUE(background_connect_add(CLIENT1, address1)); EXPECT_TRUE(background_connect_add(CLIENT1, address1)); EXPECT_TRUE(background_connect_add(CLIENT2, address1)); EXPECT_TRUE(background_connect_add(CLIENT3, address1)); EXPECT_EQ(get_apps_connecting_to(address1).size(), 3UL); Mock::VerifyAndClearExpectations(localAcceptlistMock.get()); EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(_)).Times(0); // removing from nonexisting client, should fail EXPECT_FALSE(background_connect_remove(CLIENT10, address1)); EXPECT_TRUE(background_connect_remove(CLIENT1, address1)); // already removed, removing from same client twice should return false; EXPECT_FALSE(background_connect_remove(CLIENT1, address1)); EXPECT_TRUE(background_connect_remove(CLIENT2, address1)); EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(address1)).Times(1); EXPECT_TRUE(background_connect_remove(CLIENT3, address1)); EXPECT_EQ(get_apps_connecting_to(address1).size(), 0UL); Mock::VerifyAndClearExpectations(localAcceptlistMock.get()); } /** Verify adding/removing device to direct connection. */ TEST_F(BleConnectionManager, test_direct_connection_client) { // Direct connect attempt: use faster scan parameters, add to acceptlist, // start 30 timeout EXPECT_CALL(*localAcceptlistMock, SetLeConnectionModeToFast()).Times(1); EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(address1)) .WillOnce(Return(true)); EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(_)).Times(0); EXPECT_CALL(*AlarmMock::Get(), AlarmNew(_)).Times(1); EXPECT_CALL(*AlarmMock::Get(), AlarmSetOnMloop(_, _, _, _)).Times(1); EXPECT_TRUE(direct_connect_add(CLIENT1, address1)); // App already doing a direct connection, attempt to re-add result in failure EXPECT_FALSE(direct_connect_add(CLIENT1, address1)); // Client that don't do direct connection should fail attempt to stop it EXPECT_FALSE(direct_connect_remove(CLIENT2, address1)); Mock::VerifyAndClearExpectations(localAcceptlistMock.get()); EXPECT_CALL(*localAcceptlistMock, SetLeConnectionModeToSlow()).Times(1); EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(_)).Times(1); EXPECT_CALL(*AlarmMock::Get(), AlarmFree(_)).Times(1); // Removal should lower the connection parameters, and free the alarm. // Even though we call AcceptlistRemove, it won't be executed over HCI until // acceptlist is in use, i.e. next connection attempt EXPECT_TRUE(direct_connect_remove(CLIENT1, address1)); Mock::VerifyAndClearExpectations(localAcceptlistMock.get()); } /** Verify direct connection timeout does remove device from acceptlist, and * lower the connection scan parameters */ TEST_F(BleConnectionManager, test_direct_connect_timeout) { EXPECT_CALL(*localAcceptlistMock, SetLeConnectionModeToFast()).Times(1); EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(address1)) .WillOnce(Return(true)); EXPECT_CALL(*AlarmMock::Get(), AlarmNew(_)).Times(1); alarm_callback_t alarm_callback = nullptr; void* alarm_data = nullptr; EXPECT_CALL(*AlarmMock::Get(), AlarmSetOnMloop(_, _, _, _)) .Times(1) .WillOnce(DoAll(SaveArg<2>(&alarm_callback), SaveArg<3>(&alarm_data))); // Start direct connect attempt... EXPECT_TRUE(direct_connect_add(CLIENT1, address1)); Mock::VerifyAndClearExpectations(localAcceptlistMock.get()); EXPECT_CALL(*localAcceptlistMock, SetLeConnectionModeToSlow()).Times(1); EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(_)).Times(1); EXPECT_CALL(*localAcceptlistMock, OnConnectionTimedOut(CLIENT1, address1)) .Times(1); EXPECT_CALL(*AlarmMock::Get(), AlarmFree(_)).Times(1); // simulate timeout seconds passed, alarm executing alarm_callback(alarm_data); Mock::VerifyAndClearExpectations(localAcceptlistMock.get()); } /** Verify that we properly handle successfull direct connection */ TEST_F(BleConnectionManager, test_direct_connection_success) { EXPECT_CALL(*localAcceptlistMock, SetLeConnectionModeToFast()).Times(1); EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(address1)) .WillOnce(Return(true)); EXPECT_CALL(*AlarmMock::Get(), AlarmNew(_)).Times(1); EXPECT_CALL(*AlarmMock::Get(), AlarmSetOnMloop(_, _, _, _)).Times(1); // Start direct connect attempt... EXPECT_TRUE(direct_connect_add(CLIENT1, address1)); Mock::VerifyAndClearExpectations(localAcceptlistMock.get()); EXPECT_CALL(*localAcceptlistMock, SetLeConnectionModeToSlow()).Times(1); EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(address1)).Times(1); EXPECT_CALL(*AlarmMock::Get(), AlarmFree(_)).Times(1); // simulate event from lower layers - connections was established // successfully. on_connection_complete(address1); } /** Verify that we properly handle application unregistration */ TEST_F(BleConnectionManager, test_app_unregister) { /* Test scenario: * - Client 1 connecting to address1 and address2. * - Client 2 connecting to address2 * - unregistration of Client1 should trigger address1 removal from acceptlist * - unregistration of Client2 should trigger address2 removal */ EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(address1)) .WillOnce(Return(true)); EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(address2)) .WillOnce(Return(true)); EXPECT_TRUE(direct_connect_add(CLIENT1, address1)); EXPECT_TRUE(background_connect_add(CLIENT1, address2)); EXPECT_TRUE(direct_connect_add(CLIENT2, address2)); Mock::VerifyAndClearExpectations(localAcceptlistMock.get()); EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(address1)).Times(1); on_app_deregistered(CLIENT1); Mock::VerifyAndClearExpectations(localAcceptlistMock.get()); EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(address2)).Times(1); on_app_deregistered(CLIENT2); } /** Verify adding device to both direct connection and background connection. */ TEST_F(BleConnectionManager, test_direct_and_background_connect) { EXPECT_CALL(*localAcceptlistMock, SetLeConnectionModeToFast()).Times(1); EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(address1)) .WillOnce(Return(true)); EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(_)).Times(0); EXPECT_CALL(*AlarmMock::Get(), AlarmNew(_)).Times(1); EXPECT_CALL(*AlarmMock::Get(), AlarmSetOnMloop(_, _, _, _)).Times(1); // add device as both direct and background connection EXPECT_TRUE(direct_connect_add(CLIENT1, address1)); EXPECT_TRUE(background_connect_add(CLIENT1, address1)); Mock::VerifyAndClearExpectations(localAcceptlistMock.get()); EXPECT_CALL(*localAcceptlistMock, SetLeConnectionModeToSlow()).Times(1); EXPECT_CALL(*AlarmMock::Get(), AlarmFree(_)).Times(1); // not removing from acceptlist yet, as the background connection is still // pending. EXPECT_TRUE(direct_connect_remove(CLIENT1, address1)); // remove from acceptlist, because no more interest in device. EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(_)).Times(1); EXPECT_TRUE(background_connect_remove(CLIENT1, address1)); Mock::VerifyAndClearExpectations(localAcceptlistMock.get()); } } // namespace connection_manager