1 /*
2 * Copyright 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "hci/acl_manager/acl_scheduler.h"
18
19 #include <com_android_bluetooth_flags.h>
20 #include <flag_macros.h>
21 #include <gmock/gmock.h>
22 #include <gtest/gtest.h>
23
24 #include <chrono>
25 #include <future>
26 #include <utility>
27
28 #include "hci/address.h"
29 #include "os/thread.h"
30
31 #define TEST_BT com::android::bluetooth::flags
32
33 namespace bluetooth {
34 namespace hci {
35 namespace acl_manager {
36 namespace {
37
38 const auto address1 = Address::FromString("A1:A2:A3:A4:A5:A6").value();
39 const auto address2 = Address::FromString("B1:B2:B3:B4:B5:B6").value();
40 const auto address3 = Address::FromString("C1:C2:C3:C4:C5:C6").value();
41
42 const auto timeout = std::chrono::milliseconds(100);
43
44 MATCHER(IsSet, "Future is set") {
45 if (arg.wait_for(timeout) != std::future_status::ready) {
46 return false;
47 }
48 const_cast<std::future<void>&>(arg).get();
49 return true;
50 }
51
52 class AclSchedulerTest : public ::testing::Test {
53 protected:
SetUp()54 void SetUp() override {
55 fake_registry_.Start<AclScheduler>(&thread_);
56 ASSERT_TRUE(fake_registry_.IsStarted<AclScheduler>());
57
58 client_handler_ = fake_registry_.GetTestModuleHandler(&AclScheduler::Factory);
59 ASSERT_NE(client_handler_, nullptr);
60
61 acl_scheduler_ =
62 static_cast<AclScheduler*>(fake_registry_.GetModuleUnderTest(&AclScheduler::Factory));
63
64 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
65 }
66
TearDown()67 void TearDown() override {
68 fake_registry_.SynchronizeModuleHandler(&AclScheduler::Factory, timeout);
69 fake_registry_.StopAll();
70 }
71
impossibleCallbackTakingString()72 common::ContextualOnceCallback<void(std::string)> impossibleCallbackTakingString() {
73 return client_handler_->BindOnce([](std::string /* _ */) { ADD_FAILURE(); });
74 }
75
emptyCallbackTakingString()76 common::ContextualOnceCallback<void(std::string)> emptyCallbackTakingString() {
77 return client_handler_->BindOnce([](std::string /* _ */) {});
78 }
79
promiseCallbackTakingString(std::promise<void> promise)80 common::ContextualOnceCallback<void(std::string)> promiseCallbackTakingString(
81 std::promise<void> promise) {
82 return client_handler_->BindOnce(
83 [](std::promise<void> promise, std::string /* _ */) { promise.set_value(); },
84 std::move(promise));
85 }
86
impossibleCallback()87 common::ContextualOnceCallback<void()> impossibleCallback() {
88 return client_handler_->BindOnce([] { ADD_FAILURE(); });
89 }
90
emptyCallback()91 common::ContextualOnceCallback<void()> emptyCallback() {
92 return client_handler_->BindOnce([] {});
93 }
94
promiseCallback(std::promise<void> promise)95 common::ContextualOnceCallback<void()> promiseCallback(std::promise<void> promise) {
96 return client_handler_->BindOnce([](std::promise<void> promise) { promise.set_value(); },
97 std::move(promise));
98 }
99
100 TestModuleRegistry fake_registry_;
101 os::Thread& thread_ = fake_registry_.GetTestThread();
102 AclScheduler* acl_scheduler_ = nullptr;
103 os::Handler* client_handler_ = nullptr;
104 };
105
TEST_F(AclSchedulerTest,SingleConnectionImmediatelyExecuted)106 TEST_F(AclSchedulerTest, SingleConnectionImmediatelyExecuted) {
107 auto promise = std::promise<void>{};
108 auto future = promise.get_future();
109
110 // start connection, which should immediately execute
111 acl_scheduler_->EnqueueOutgoingAclConnection(address1, promiseCallback(std::move(promise)));
112
113 // it has started
114 EXPECT_THAT(future, IsSet());
115 }
116
TEST_F(AclSchedulerTest,ThreeConnectionsQueue)117 TEST_F(AclSchedulerTest, ThreeConnectionsQueue) {
118 auto promise1 = std::promise<void>{};
119 auto future1 = promise1.get_future();
120 auto promise2 = std::promise<void>{};
121 auto future2 = promise2.get_future();
122
123 // start first connection, which immediately runs
124 acl_scheduler_->EnqueueOutgoingAclConnection(address1, emptyCallback());
125 // start second connection
126 acl_scheduler_->EnqueueOutgoingAclConnection(address2, (promiseCallback(std::move(promise1))));
127 // start third connection
128 acl_scheduler_->EnqueueOutgoingAclConnection(address3, (promiseCallback(std::move(promise2))));
129
130 // the second and third connections are currently queued
131 EXPECT_THAT(future1.wait_for(timeout), std::future_status::timeout);
132
133 // first connection fails, so next one should start
134 acl_scheduler_->ReportOutgoingAclConnectionFailure();
135
136 // the second connection has started, the third one is queued
137 EXPECT_THAT(future1, IsSet());
138 EXPECT_THAT(future2.wait_for(timeout), std::future_status::timeout);
139
140 // second connection fails, so third one should start
141 acl_scheduler_->ReportOutgoingAclConnectionFailure();
142
143 // the third connection has started
144 EXPECT_THAT(future2, IsSet());
145 }
146
TEST_F(AclSchedulerTest,SingleConnectionCompletionCallback)147 TEST_F(AclSchedulerTest, SingleConnectionCompletionCallback) {
148 auto promise = std::promise<void>{};
149 auto future = promise.get_future();
150
151 // start connection, which immediately runs
152 acl_scheduler_->EnqueueOutgoingAclConnection(address1, emptyCallback());
153
154 // the outgoing connection completes
155 acl_scheduler_->ReportAclConnectionCompletion(address1, promiseCallback(std::move(promise)),
156 impossibleCallback(),
157 impossibleCallbackTakingString());
158
159 // the outgoing_connection callback should have executed
160 EXPECT_THAT(future, IsSet());
161 }
162
TEST_F(AclSchedulerTest,SingleConnectionCompletionDequeueNext)163 TEST_F(AclSchedulerTest, SingleConnectionCompletionDequeueNext) {
164 auto promise = std::promise<void>{};
165 auto future = promise.get_future();
166
167 // start connection, which immediately runs
168 acl_scheduler_->EnqueueOutgoingAclConnection(address1, emptyCallback());
169 // start second connection which should queue
170 acl_scheduler_->EnqueueOutgoingAclConnection(address2, promiseCallback(std::move(promise)));
171
172 // complete the first connection
173 acl_scheduler_->ReportAclConnectionCompletion(address1, emptyCallback(), impossibleCallback(),
174 impossibleCallbackTakingString());
175
176 // the next connection should dequeue now
177 EXPECT_THAT(future, IsSet());
178 }
179
TEST_F(AclSchedulerTest,IncomingConnectionCallback)180 TEST_F(AclSchedulerTest, IncomingConnectionCallback) {
181 auto promise = std::promise<void>{};
182 auto future = promise.get_future();
183
184 // an incoming connection arrives
185 acl_scheduler_->RegisterPendingIncomingConnection(address1);
186
187 // and completes
188 acl_scheduler_->ReportAclConnectionCompletion(address1, impossibleCallback(),
189 promiseCallback(std::move(promise)),
190 impossibleCallbackTakingString());
191
192 // the incoming_connection callback should have executed
193 EXPECT_THAT(future, IsSet());
194 }
195
TEST_F(AclSchedulerTest,UnknownConnectionCallback)196 TEST_F(AclSchedulerTest, UnknownConnectionCallback) {
197 auto promise = std::promise<void>{};
198 auto future = promise.get_future();
199
200 // start outgoing connection
201 acl_scheduler_->EnqueueOutgoingAclConnection(address1, emptyCallback());
202
203 // an incoming connection arrives
204 acl_scheduler_->RegisterPendingIncomingConnection(address2);
205
206 // then an unknown connection completes
207 acl_scheduler_->ReportAclConnectionCompletion(address3, impossibleCallback(),
208 impossibleCallback(),
209 (promiseCallbackTakingString(std::move(promise))));
210
211 // the unknown_connection callback should have executed
212 EXPECT_THAT(future, IsSet());
213 }
214
TEST_F(AclSchedulerTest,TiebreakForOutgoingConnection)215 TEST_F(AclSchedulerTest, TiebreakForOutgoingConnection) {
216 auto promise = std::promise<void>{};
217 auto future = promise.get_future();
218
219 // start outgoing connection
220 acl_scheduler_->EnqueueOutgoingAclConnection(address1, emptyCallback());
221
222 // an incoming connection arrives *from the same address*
223 acl_scheduler_->RegisterPendingIncomingConnection(address1);
224
225 // then the connection to that address completes
226 acl_scheduler_->ReportAclConnectionCompletion(address1, promiseCallback(std::move(promise)),
227 impossibleCallback(),
228 impossibleCallbackTakingString());
229
230 // the outgoing_connection callback should have executed, NOT the incoming_connection one
231 // this preserves working behavior, it is not based on any principled decision (so if you need to
232 // break this test, go for it)
233 EXPECT_THAT(future, IsSet());
234 }
235
TEST_F(AclSchedulerTest,QueueWhileIncomingConnectionsPending)236 TEST_F(AclSchedulerTest, QueueWhileIncomingConnectionsPending) {
237 auto promise = std::promise<void>{};
238 auto future = promise.get_future();
239
240 // start outgoing connection
241 acl_scheduler_->EnqueueOutgoingAclConnection(address1, emptyCallback());
242 // queue a second outgoing connection
243 acl_scheduler_->EnqueueOutgoingAclConnection(address2, promiseCallback(std::move(promise)));
244
245 // an incoming connection arrives
246 acl_scheduler_->RegisterPendingIncomingConnection(address3);
247
248 // then the first outgoing connection completes
249 acl_scheduler_->ReportAclConnectionCompletion(address1, emptyCallback(), impossibleCallback(),
250 impossibleCallbackTakingString());
251
252 // the outgoing_connection callback should not have executed yet
253 EXPECT_THAT(future.wait_for(timeout), std::future_status::timeout);
254
255 // now the incoming connection completes
256 acl_scheduler_->ReportAclConnectionCompletion(address3, impossibleCallback(), emptyCallback(),
257 impossibleCallbackTakingString());
258
259 // only now does the next outgoing connection start
260 EXPECT_THAT(future, IsSet());
261 }
262
TEST_F(AclSchedulerTest,DoNothingWhileIncomingConnectionsExist)263 TEST_F(AclSchedulerTest, DoNothingWhileIncomingConnectionsExist) {
264 auto promise = std::promise<void>{};
265 auto future = promise.get_future();
266
267 // an incoming connection arrives
268 acl_scheduler_->RegisterPendingIncomingConnection(address1);
269
270 // try to start an outgoing connection to another device
271 acl_scheduler_->EnqueueOutgoingAclConnection(address2, promiseCallback(std::move(promise)));
272
273 // the outgoing_connection callback should not have executed yet
274 EXPECT_THAT(future.wait_for(timeout), std::future_status::timeout);
275
276 // a second incoming connection arrives
277 acl_scheduler_->RegisterPendingIncomingConnection(address3);
278
279 // the first incoming connection completes
280 acl_scheduler_->ReportAclConnectionCompletion(address1, impossibleCallback(), emptyCallback(),
281 impossibleCallbackTakingString());
282
283 // the outgoing_connection callback should *still* not have executed yet
284 EXPECT_THAT(future.wait_for(timeout), std::future_status::timeout);
285
286 // the second incoming connection completes, so none are left
287 acl_scheduler_->ReportAclConnectionCompletion(address3, impossibleCallback(), emptyCallback(),
288 impossibleCallbackTakingString());
289
290 // only now does the outgoing connection start
291 EXPECT_THAT(future, IsSet());
292 }
293
TEST_F_WITH_FLAGS(AclSchedulerTest,IncomingConnectionPendingWithOutgoingRemoteNameRequest,REQUIRES_FLAGS_ENABLED (ACONFIG_FLAG (TEST_BT,progress_acl_scheduler_upon_incoming_connection)))294 TEST_F_WITH_FLAGS(AclSchedulerTest, IncomingConnectionPendingWithOutgoingRemoteNameRequest,
295 REQUIRES_FLAGS_ENABLED(
296 ACONFIG_FLAG(TEST_BT, progress_acl_scheduler_upon_incoming_connection))) {
297 auto promise = std::promise<void>{};
298 auto future = promise.get_future();
299
300 // an incoming connection arrives
301 acl_scheduler_->RegisterPendingIncomingConnection(address1);
302
303 // start an outgoing RNR
304 acl_scheduler_->EnqueueRemoteNameRequest(address1, promiseCallback(std::move(promise)),
305 emptyCallback());
306
307 // we expect the outgoing RNR to queue while incoming pending connection from same device
308 EXPECT_THAT(future, IsSet());
309 }
310
TEST_F_WITH_FLAGS(AclSchedulerTest,ConnectionToSameDeviceIncomingConnectionPending,REQUIRES_FLAGS_ENABLED (ACONFIG_FLAG (TEST_BT,progress_acl_scheduler_upon_incoming_connection)))311 TEST_F_WITH_FLAGS(AclSchedulerTest, ConnectionToSameDeviceIncomingConnectionPending,
312 REQUIRES_FLAGS_ENABLED(
313 ACONFIG_FLAG(TEST_BT, progress_acl_scheduler_upon_incoming_connection))) {
314 auto promise = std::promise<void>{};
315 auto future = promise.get_future();
316
317 // an incoming connection arrives
318 acl_scheduler_->RegisterPendingIncomingConnection(address1);
319
320 // try to start an outgoing connection to same device
321 acl_scheduler_->EnqueueOutgoingAclConnection(address1, promiseCallback(std::move(promise)));
322
323 // we expect the outgoing connection to wait and then dropped once connection
324 // established
325 EXPECT_EQ(future.wait_for(timeout), std::future_status::timeout);
326 }
327
TEST_F(AclSchedulerTest,CancelOutgoingConnection)328 TEST_F(AclSchedulerTest, CancelOutgoingConnection) {
329 auto promise = std::promise<void>{};
330 auto future = promise.get_future();
331
332 // start an outgoing connection
333 acl_scheduler_->EnqueueOutgoingAclConnection(address1, emptyCallback());
334 // enqueue a second connection
335 acl_scheduler_->EnqueueOutgoingAclConnection(address2, promiseCallback(std::move(promise)));
336
337 // cancel the outgoing connection
338 acl_scheduler_->CancelAclConnection(address1, emptyCallback(), impossibleCallback());
339
340 // we expect the second connection to stay queued until the cancel completes
341 EXPECT_THAT(future.wait_for(timeout), std::future_status::timeout);
342
343 // now the cancel completes (with a failed status, in reality, but the scheduler doesn't care)
344 acl_scheduler_->ReportAclConnectionCompletion(address1, emptyCallback(), impossibleCallback(),
345 impossibleCallbackTakingString());
346
347 // so only now do we advance the queue
348 EXPECT_THAT(future, IsSet());
349 }
350
TEST_F(AclSchedulerTest,CancelOutgoingConnectionCallback)351 TEST_F(AclSchedulerTest, CancelOutgoingConnectionCallback) {
352 auto promise = std::promise<void>{};
353 auto future = promise.get_future();
354
355 // start an outgoing connection
356 acl_scheduler_->EnqueueOutgoingAclConnection(address1, emptyCallback());
357
358 // cancel the outgoing connection
359 acl_scheduler_->CancelAclConnection(address1, promiseCallback(std::move(promise)),
360 impossibleCallback());
361
362 // we expect the cancel_connection callback to be invoked since we are cancelling an actually
363 // active connection
364 EXPECT_THAT(future, IsSet());
365 }
366
TEST_F(AclSchedulerTest,CancelQueuedConnectionRemoveFromQueue)367 TEST_F(AclSchedulerTest, CancelQueuedConnectionRemoveFromQueue) {
368 auto promise = std::promise<void>{};
369 auto future = promise.get_future();
370
371 // start an outgoing connection
372 acl_scheduler_->EnqueueOutgoingAclConnection(address1, emptyCallback());
373 // start another connection that will queue
374 acl_scheduler_->EnqueueOutgoingAclConnection(address2, impossibleCallback());
375 // start a third connection that will queue
376 acl_scheduler_->EnqueueOutgoingAclConnection(address3, promiseCallback(std::move(promise)));
377
378 // cancel the first queued connection
379 acl_scheduler_->CancelAclConnection(address2, impossibleCallback(), emptyCallback());
380
381 // the second queued connection should remain enqueued, since another connection is in progress
382 EXPECT_THAT(future.wait_for(timeout), std::future_status::timeout);
383
384 // complete the outgoing connection
385 acl_scheduler_->ReportOutgoingAclConnectionFailure();
386
387 // only now can we dequeue the second queued connection
388 EXPECT_THAT(future, IsSet());
389 }
390
TEST_F(AclSchedulerTest,CancelQueuedConnectionCallback)391 TEST_F(AclSchedulerTest, CancelQueuedConnectionCallback) {
392 auto promise = std::promise<void>{};
393 auto future = promise.get_future();
394
395 // start an outgoing connection
396 acl_scheduler_->EnqueueOutgoingAclConnection(address1, emptyCallback());
397 // start another connection that will queue
398 acl_scheduler_->EnqueueOutgoingAclConnection(address2, emptyCallback());
399
400 // cancel the queued connection
401 acl_scheduler_->CancelAclConnection(address2, impossibleCallback(),
402 promiseCallback(std::move(promise)));
403
404 // we expect the cancel_connection_completed callback to be invoked since we are cancelling a
405 // connection in the queue
406 EXPECT_THAT(future, IsSet());
407 }
408
TEST_F(AclSchedulerTest,RemoteNameRequestImmediatelyExecuted)409 TEST_F(AclSchedulerTest, RemoteNameRequestImmediatelyExecuted) {
410 auto promise = std::promise<void>{};
411 auto future = promise.get_future();
412
413 // start an outgoing request
414 acl_scheduler_->EnqueueRemoteNameRequest(address1, promiseCallback(std::move(promise)),
415 emptyCallback());
416
417 // we expect the start callback to be invoked immediately
418 EXPECT_THAT(future, IsSet());
419 }
420
TEST_F(AclSchedulerTest,RemoteNameRequestQueuing)421 TEST_F(AclSchedulerTest, RemoteNameRequestQueuing) {
422 auto promise = std::promise<void>{};
423 auto future = promise.get_future();
424
425 // start an outgoing request
426 acl_scheduler_->EnqueueRemoteNameRequest(address1, emptyCallback(), impossibleCallback());
427 // enqueue a second one
428 acl_scheduler_->EnqueueRemoteNameRequest(address2, promiseCallback(std::move(promise)),
429 impossibleCallback());
430
431 // we should still be queued
432 EXPECT_THAT(future.wait_for(timeout), std::future_status::timeout);
433
434 // the first request completes
435 acl_scheduler_->ReportRemoteNameRequestCompletion(address1);
436
437 // so the second request should now have started
438 EXPECT_THAT(future, IsSet());
439 }
440
TEST_F(AclSchedulerTest,RemoteNameRequestCancellationCallback)441 TEST_F(AclSchedulerTest, RemoteNameRequestCancellationCallback) {
442 auto promise = std::promise<void>{};
443 auto future = promise.get_future();
444
445 // start an outgoing request
446 acl_scheduler_->EnqueueRemoteNameRequest(address1, emptyCallback(), impossibleCallback());
447
448 // cancel it
449 acl_scheduler_->CancelRemoteNameRequest(address1, promiseCallback(std::move(promise)));
450
451 // the cancel callback should be invoked
452 EXPECT_THAT(future, IsSet());
453 }
454
TEST_F(AclSchedulerTest,RemoteNameRequestCancellationWhileQueuedCallback)455 TEST_F(AclSchedulerTest, RemoteNameRequestCancellationWhileQueuedCallback) {
456 auto promise = std::promise<void>{};
457 auto future = promise.get_future();
458
459 // start an outgoing request
460 acl_scheduler_->EnqueueRemoteNameRequest(address1, emptyCallback(), impossibleCallback());
461 // enqueue a second one
462 acl_scheduler_->EnqueueRemoteNameRequest(address2, impossibleCallback(),
463 promiseCallback(std::move(promise)));
464
465 // cancel the second one
466 acl_scheduler_->CancelRemoteNameRequest(address2, impossibleCallback());
467
468 // the cancel_request_completed calback should be invoked
469 EXPECT_THAT(future, IsSet());
470
471 // the first request completes
472 acl_scheduler_->ReportRemoteNameRequestCompletion(address1);
473
474 // we don't dequeue the second one, since it was cancelled
475 // implicitly assert that its callback was never invoked
476 }
477
TEST_F(AclSchedulerTest,CancelQueuedRemoteNameRequestRemoveFromQueue)478 TEST_F(AclSchedulerTest, CancelQueuedRemoteNameRequestRemoveFromQueue) {
479 auto promise = std::promise<void>{};
480 auto future = promise.get_future();
481
482 // start an outgoing connection
483 acl_scheduler_->EnqueueOutgoingAclConnection(address1, emptyCallback());
484 // start another connection that will queue
485 acl_scheduler_->EnqueueRemoteNameRequest(address2, impossibleCallback(), emptyCallback());
486 // start a third connection that will queue
487 acl_scheduler_->EnqueueRemoteNameRequest(address3, promiseCallback(std::move(promise)),
488 impossibleCallback());
489
490 // cancel the first queued connection
491 acl_scheduler_->CancelRemoteNameRequest(address2, impossibleCallback());
492
493 // the second queued connection should remain enqueued, since another connection is in progress
494 EXPECT_THAT(future.wait_for(timeout), std::future_status::timeout);
495
496 // complete the outgoing connection
497 acl_scheduler_->ReportOutgoingAclConnectionFailure();
498
499 // only now can we dequeue the second queued connection
500 EXPECT_THAT(future, IsSet());
501 }
502
TEST_F(AclSchedulerTest,RemoteNameRequestCancellationShouldDequeueNext)503 TEST_F(AclSchedulerTest, RemoteNameRequestCancellationShouldDequeueNext) {
504 auto promise = std::promise<void>{};
505 auto future = promise.get_future();
506
507 // start an outgoing request
508 acl_scheduler_->EnqueueRemoteNameRequest(address1, emptyCallback(), impossibleCallback());
509 // enqueue a second one
510 acl_scheduler_->EnqueueRemoteNameRequest(address2, promiseCallback(std::move(promise)),
511 impossibleCallback());
512
513 // we should still be queued
514 EXPECT_THAT(future.wait_for(timeout), std::future_status::timeout);
515
516 // the first request is cancelled
517 acl_scheduler_->CancelRemoteNameRequest(address1, emptyCallback());
518
519 // we should still remain queued while we wait for the cancel to complete
520 EXPECT_THAT(future.wait_for(timeout), std::future_status::timeout);
521
522 // the cancel completes
523 acl_scheduler_->ReportRemoteNameRequestCompletion(address1);
524
525 // so the second request should now have started
526 EXPECT_THAT(future, IsSet());
527 }
528
529 } // namespace
530 } // namespace acl_manager
531 } // namespace hci
532 } // namespace bluetooth
533