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