1 #include "stack/gatt/connection_manager.h"
2
3 #include <base/bind.h>
4 #include <base/callback.h>
5 #include <base/location.h>
6 #include <gmock/gmock.h>
7 #include <gtest/gtest.h>
8 #include <memory>
9 #include "osi/include/alarm.h"
10 #include "osi/test/alarm_mock.h"
11
12 using testing::_;
13 using testing::DoAll;
14 using testing::Mock;
15 using testing::Return;
16 using testing::SaveArg;
17
18 using connection_manager::tAPP_ID;
19
20 namespace {
21 // convenience mock, for verifying acceptlist operations on lower layer are
22 // actually scheduled
23 class AcceptlistMock {
24 public:
25 MOCK_METHOD1(AcceptlistAdd, bool(const RawAddress&));
26 MOCK_METHOD1(AcceptlistRemove, void(const RawAddress&));
27 MOCK_METHOD0(AcceptlistClear, void());
28 MOCK_METHOD0(SetLeConnectionModeToFast, bool());
29 MOCK_METHOD0(SetLeConnectionModeToSlow, void());
30 MOCK_METHOD2(OnConnectionTimedOut, void(uint8_t, const RawAddress&));
31 };
32
33 std::unique_ptr<AcceptlistMock> localAcceptlistMock;
34 } // namespace
35
36 RawAddress address1{{0x01, 0x01, 0x01, 0x01, 0x01, 0x01}};
37 RawAddress address2{{0x22, 0x22, 0x02, 0x22, 0x33, 0x22}};
38
39 constexpr tAPP_ID CLIENT1 = 1;
40 constexpr tAPP_ID CLIENT2 = 2;
41 constexpr tAPP_ID CLIENT3 = 3;
42 constexpr tAPP_ID CLIENT10 = 10;
43
44 // Implementation of btm_ble_bgconn.h API for test.
BTM_AcceptlistAdd(const RawAddress & address)45 bool BTM_AcceptlistAdd(const RawAddress& address) {
46 return localAcceptlistMock->AcceptlistAdd(address);
47 }
48
BTM_AcceptlistRemove(const RawAddress & address)49 void BTM_AcceptlistRemove(const RawAddress& address) {
50 return localAcceptlistMock->AcceptlistRemove(address);
51 }
52
BTM_AcceptlistClear()53 void BTM_AcceptlistClear() { return localAcceptlistMock->AcceptlistClear(); }
54
BTM_SetLeConnectionModeToFast()55 bool BTM_SetLeConnectionModeToFast() {
56 return localAcceptlistMock->SetLeConnectionModeToFast();
57 }
58
BTM_SetLeConnectionModeToSlow()59 void BTM_SetLeConnectionModeToSlow() {
60 localAcceptlistMock->SetLeConnectionModeToSlow();
61 }
62
63 namespace bluetooth {
64 namespace shim {
is_gd_l2cap_enabled()65 bool is_gd_l2cap_enabled() { return false; }
66 } // namespace shim
67 } // namespace bluetooth
68
L2CA_ConnectFixedChnl(uint16_t fixed_cid,const RawAddress & bd_addr)69 bool L2CA_ConnectFixedChnl(uint16_t fixed_cid, const RawAddress& bd_addr) {
70 return false;
71 }
72
73 namespace connection_manager {
74 class BleConnectionManager : public testing::Test {
SetUp()75 void SetUp() override {
76 localAcceptlistMock = std::make_unique<AcceptlistMock>();
77 }
78
TearDown()79 void TearDown() override {
80 connection_manager::reset(true);
81 AlarmMock::Reset();
82 localAcceptlistMock.reset();
83 }
84 };
85
on_connection_timed_out(uint8_t app_id,const RawAddress & address)86 void on_connection_timed_out(uint8_t app_id, const RawAddress& address) {
87 localAcceptlistMock->OnConnectionTimedOut(app_id, address);
88 }
89
90 /** Verify that app can add a device to acceptlist, it is returned as interested
91 * app, and then can remove the device later. */
TEST_F(BleConnectionManager,test_background_connection_add_remove)92 TEST_F(BleConnectionManager, test_background_connection_add_remove) {
93 EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(address1))
94 .WillOnce(Return(true));
95 EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(_)).Times(0);
96
97 EXPECT_TRUE(background_connect_add(CLIENT1, address1));
98
99 Mock::VerifyAndClearExpectations(localAcceptlistMock.get());
100
101 std::set<tAPP_ID> apps = get_apps_connecting_to(address1);
102 EXPECT_EQ(apps.size(), 1UL);
103 EXPECT_EQ(apps.count(CLIENT1), 1UL);
104
105 EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(_)).Times(0);
106 EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(address1)).Times(1);
107
108 EXPECT_TRUE(background_connect_remove(CLIENT1, address1));
109
110 EXPECT_EQ(get_apps_connecting_to(address1).size(), 0UL);
111
112 Mock::VerifyAndClearExpectations(localAcceptlistMock.get());
113 }
114
115 /** Verify that multiple clients adding same device multiple times, result in
116 * device being added to whtie list only once, also, that device is removed only
117 * after last client removes it. */
TEST_F(BleConnectionManager,test_background_connection_multiple_clients)118 TEST_F(BleConnectionManager, test_background_connection_multiple_clients) {
119 EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(address1))
120 .WillOnce(Return(true));
121 EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(_)).Times(0);
122 EXPECT_TRUE(background_connect_add(CLIENT1, address1));
123 EXPECT_TRUE(background_connect_add(CLIENT1, address1));
124 EXPECT_TRUE(background_connect_add(CLIENT2, address1));
125 EXPECT_TRUE(background_connect_add(CLIENT3, address1));
126
127 EXPECT_EQ(get_apps_connecting_to(address1).size(), 3UL);
128
129 Mock::VerifyAndClearExpectations(localAcceptlistMock.get());
130
131 EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(_)).Times(0);
132
133 // removing from nonexisting client, should fail
134 EXPECT_FALSE(background_connect_remove(CLIENT10, address1));
135
136 EXPECT_TRUE(background_connect_remove(CLIENT1, address1));
137 // already removed, removing from same client twice should return false;
138 EXPECT_FALSE(background_connect_remove(CLIENT1, address1));
139 EXPECT_TRUE(background_connect_remove(CLIENT2, address1));
140
141 EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(address1)).Times(1);
142 EXPECT_TRUE(background_connect_remove(CLIENT3, address1));
143
144 EXPECT_EQ(get_apps_connecting_to(address1).size(), 0UL);
145
146 Mock::VerifyAndClearExpectations(localAcceptlistMock.get());
147 }
148
149 /** Verify adding/removing device to direct connection. */
TEST_F(BleConnectionManager,test_direct_connection_client)150 TEST_F(BleConnectionManager, test_direct_connection_client) {
151 // Direct connect attempt: use faster scan parameters, add to acceptlist,
152 // start 30 timeout
153 EXPECT_CALL(*localAcceptlistMock, SetLeConnectionModeToFast()).Times(1);
154 EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(address1))
155 .WillOnce(Return(true));
156 EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(_)).Times(0);
157 EXPECT_CALL(*AlarmMock::Get(), AlarmNew(_)).Times(1);
158 EXPECT_CALL(*AlarmMock::Get(), AlarmSetOnMloop(_, _, _, _)).Times(1);
159 EXPECT_TRUE(direct_connect_add(CLIENT1, address1));
160
161 // App already doing a direct connection, attempt to re-add result in failure
162 EXPECT_FALSE(direct_connect_add(CLIENT1, address1));
163
164 // Client that don't do direct connection should fail attempt to stop it
165 EXPECT_FALSE(direct_connect_remove(CLIENT2, address1));
166
167 Mock::VerifyAndClearExpectations(localAcceptlistMock.get());
168
169 EXPECT_CALL(*localAcceptlistMock, SetLeConnectionModeToSlow()).Times(1);
170 EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(_)).Times(1);
171 EXPECT_CALL(*AlarmMock::Get(), AlarmFree(_)).Times(1);
172
173 // Removal should lower the connection parameters, and free the alarm.
174 // Even though we call AcceptlistRemove, it won't be executed over HCI until
175 // acceptlist is in use, i.e. next connection attempt
176 EXPECT_TRUE(direct_connect_remove(CLIENT1, address1));
177
178 Mock::VerifyAndClearExpectations(localAcceptlistMock.get());
179 }
180
181 /** Verify direct connection timeout does remove device from acceptlist, and
182 * lower the connection scan parameters */
TEST_F(BleConnectionManager,test_direct_connect_timeout)183 TEST_F(BleConnectionManager, test_direct_connect_timeout) {
184 EXPECT_CALL(*localAcceptlistMock, SetLeConnectionModeToFast()).Times(1);
185 EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(address1))
186 .WillOnce(Return(true));
187 EXPECT_CALL(*AlarmMock::Get(), AlarmNew(_)).Times(1);
188 alarm_callback_t alarm_callback = nullptr;
189 void* alarm_data = nullptr;
190
191 EXPECT_CALL(*AlarmMock::Get(), AlarmSetOnMloop(_, _, _, _))
192 .Times(1)
193 .WillOnce(DoAll(SaveArg<2>(&alarm_callback), SaveArg<3>(&alarm_data)));
194
195 // Start direct connect attempt...
196 EXPECT_TRUE(direct_connect_add(CLIENT1, address1));
197
198 Mock::VerifyAndClearExpectations(localAcceptlistMock.get());
199
200 EXPECT_CALL(*localAcceptlistMock, SetLeConnectionModeToSlow()).Times(1);
201 EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(_)).Times(1);
202 EXPECT_CALL(*localAcceptlistMock, OnConnectionTimedOut(CLIENT1, address1))
203 .Times(1);
204 EXPECT_CALL(*AlarmMock::Get(), AlarmFree(_)).Times(1);
205
206 // simulate timeout seconds passed, alarm executing
207 alarm_callback(alarm_data);
208
209 Mock::VerifyAndClearExpectations(localAcceptlistMock.get());
210 }
211
212 /** Verify that we properly handle successfull direct connection */
TEST_F(BleConnectionManager,test_direct_connection_success)213 TEST_F(BleConnectionManager, test_direct_connection_success) {
214 EXPECT_CALL(*localAcceptlistMock, SetLeConnectionModeToFast()).Times(1);
215 EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(address1))
216 .WillOnce(Return(true));
217 EXPECT_CALL(*AlarmMock::Get(), AlarmNew(_)).Times(1);
218 EXPECT_CALL(*AlarmMock::Get(), AlarmSetOnMloop(_, _, _, _)).Times(1);
219
220 // Start direct connect attempt...
221 EXPECT_TRUE(direct_connect_add(CLIENT1, address1));
222
223 Mock::VerifyAndClearExpectations(localAcceptlistMock.get());
224
225 EXPECT_CALL(*localAcceptlistMock, SetLeConnectionModeToSlow()).Times(1);
226 EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(address1)).Times(1);
227 EXPECT_CALL(*AlarmMock::Get(), AlarmFree(_)).Times(1);
228 // simulate event from lower layers - connections was established
229 // successfully.
230 on_connection_complete(address1);
231 }
232
233 /** Verify that we properly handle application unregistration */
TEST_F(BleConnectionManager,test_app_unregister)234 TEST_F(BleConnectionManager, test_app_unregister) {
235 /* Test scenario:
236 * - Client 1 connecting to address1 and address2.
237 * - Client 2 connecting to address2
238 * - unregistration of Client1 should trigger address1 removal from acceptlist
239 * - unregistration of Client2 should trigger address2 removal
240 */
241
242 EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(address1))
243 .WillOnce(Return(true));
244 EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(address2))
245 .WillOnce(Return(true));
246 EXPECT_TRUE(direct_connect_add(CLIENT1, address1));
247 EXPECT_TRUE(background_connect_add(CLIENT1, address2));
248 EXPECT_TRUE(direct_connect_add(CLIENT2, address2));
249 Mock::VerifyAndClearExpectations(localAcceptlistMock.get());
250
251 EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(address1)).Times(1);
252 on_app_deregistered(CLIENT1);
253 Mock::VerifyAndClearExpectations(localAcceptlistMock.get());
254
255 EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(address2)).Times(1);
256 on_app_deregistered(CLIENT2);
257 }
258
259 /** Verify adding device to both direct connection and background connection. */
TEST_F(BleConnectionManager,test_direct_and_background_connect)260 TEST_F(BleConnectionManager, test_direct_and_background_connect) {
261 EXPECT_CALL(*localAcceptlistMock, SetLeConnectionModeToFast()).Times(1);
262 EXPECT_CALL(*localAcceptlistMock, AcceptlistAdd(address1))
263 .WillOnce(Return(true));
264 EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(_)).Times(0);
265 EXPECT_CALL(*AlarmMock::Get(), AlarmNew(_)).Times(1);
266 EXPECT_CALL(*AlarmMock::Get(), AlarmSetOnMloop(_, _, _, _)).Times(1);
267 // add device as both direct and background connection
268 EXPECT_TRUE(direct_connect_add(CLIENT1, address1));
269 EXPECT_TRUE(background_connect_add(CLIENT1, address1));
270
271 Mock::VerifyAndClearExpectations(localAcceptlistMock.get());
272
273 EXPECT_CALL(*localAcceptlistMock, SetLeConnectionModeToSlow()).Times(1);
274 EXPECT_CALL(*AlarmMock::Get(), AlarmFree(_)).Times(1);
275 // not removing from acceptlist yet, as the background connection is still
276 // pending.
277 EXPECT_TRUE(direct_connect_remove(CLIENT1, address1));
278
279 // remove from acceptlist, because no more interest in device.
280 EXPECT_CALL(*localAcceptlistMock, AcceptlistRemove(_)).Times(1);
281 EXPECT_TRUE(background_connect_remove(CLIENT1, address1));
282
283 Mock::VerifyAndClearExpectations(localAcceptlistMock.get());
284 }
285
286 } // namespace connection_manager
287