• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 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 <bluetooth/log.h>
20 #include <com_android_bluetooth_flags.h>
21 
22 #include <deque>
23 #include <optional>
24 #include <unordered_set>
25 #include <utility>
26 #include <variant>
27 
28 namespace bluetooth {
29 namespace hci {
30 
31 namespace acl_manager {
32 
33 struct AclCreateConnectionQueueEntry {
34   Address address;
35   common::ContextualOnceCallback<void()> callback;
36 };
37 
38 struct RemoteNameRequestQueueEntry {
39   Address address;
40   common::ContextualOnceCallback<void()> callback;
41   common::ContextualOnceCallback<void()> callback_when_cancelled;
42 };
43 
44 using QueueEntry = std::variant<AclCreateConnectionQueueEntry, RemoteNameRequestQueueEntry>;
45 
46 struct AclScheduler::impl {
EnqueueOutgoingAclConnectionbluetooth::hci::acl_manager::AclScheduler::impl47   void EnqueueOutgoingAclConnection(Address address,
48                                     common::ContextualOnceCallback<void()> start_connection) {
49     pending_outgoing_operations_.push_back(
50             AclCreateConnectionQueueEntry{address, std::move(start_connection)});
51     try_dequeue_next_operation();
52   }
53 
RegisterPendingIncomingConnectionbluetooth::hci::acl_manager::AclScheduler::impl54   void RegisterPendingIncomingConnection(Address address) {
55     incoming_connecting_address_set_.insert(address);
56   }
57 
ReportAclConnectionCompletionbluetooth::hci::acl_manager::AclScheduler::impl58   void ReportAclConnectionCompletion(
59           Address address, common::ContextualOnceCallback<void()> handle_outgoing_connection,
60           common::ContextualOnceCallback<void()> handle_incoming_connection,
61           common::ContextualOnceCallback<void(std::string)> handle_unknown_connection) {
62     // Check if an outgoing request (a) exists, (b) is a Create Connection, (c) matches the received
63     // address
64     if (outgoing_entry_.has_value()) {
65       auto entry = std::get_if<AclCreateConnectionQueueEntry>(&outgoing_entry_.value());
66       if (entry != nullptr && entry->address == address) {
67         // If so, clear the current entry and advance the queue
68         outgoing_entry_.reset();
69         handle_outgoing_connection();
70         try_dequeue_next_operation();
71         return;
72       }
73     }
74 
75     // Otherwise check if it's an incoming request and advance the queue if so
76     if (incoming_connecting_address_set_.find(address) != incoming_connecting_address_set_.end()) {
77       incoming_connecting_address_set_.erase(address);
78       handle_incoming_connection();
79     } else {
80       handle_unknown_connection(set_of_incoming_connecting_addresses());
81     }
82     try_dequeue_next_operation();
83   }
84 
ReportOutgoingAclConnectionFailurebluetooth::hci::acl_manager::AclScheduler::impl85   void ReportOutgoingAclConnectionFailure() {
86     if (!outgoing_entry_.has_value()) {
87       log::error("Outgoing connection failure reported, but none present!");
88       return;
89     }
90     auto entry = std::get_if<AclCreateConnectionQueueEntry>(&outgoing_entry_.value());
91     if (entry == nullptr) {
92       log::error("Outgoing connection failure reported, but we're currently doing an RNR!");
93       return;
94     }
95     outgoing_entry_.reset();
96     try_dequeue_next_operation();
97   }
98 
CancelAclConnectionbluetooth::hci::acl_manager::AclScheduler::impl99   void CancelAclConnection(Address address,
100                            common::ContextualOnceCallback<void()> cancel_connection,
101                            common::ContextualOnceCallback<void()> cancel_connection_completed) {
102     auto ok = cancel_outgoing_or_queued_connection(
103             [&](auto& entry) {
104               auto entry_ptr = std::get_if<AclCreateConnectionQueueEntry>(&entry);
105               return entry_ptr != nullptr && entry_ptr->address == address;
106             },
107             [&]() { cancel_connection(); },
108             [&](auto /* entry */) { cancel_connection_completed(); });
109     if (!ok) {
110       log::error("Attempted to cancel connection to {} that does not exist", address);
111     }
112   }
113 
EnqueueRemoteNameRequestbluetooth::hci::acl_manager::AclScheduler::impl114   void EnqueueRemoteNameRequest(Address address,
115                                 common::ContextualOnceCallback<void()> start_request,
116                                 common::ContextualOnceCallback<void()> cancel_request_completed) {
117     pending_outgoing_operations_.push_back(RemoteNameRequestQueueEntry{
118             address, std::move(start_request), std::move(cancel_request_completed)});
119     try_dequeue_next_operation();
120   }
121 
ReportRemoteNameRequestCompletionbluetooth::hci::acl_manager::AclScheduler::impl122   void ReportRemoteNameRequestCompletion(Address /* address */) {
123     if (!outgoing_entry_.has_value()) {
124       log::error("Remote name request completion reported, but none taking place!");
125       return;
126     }
127 
128     std::visit(
129             [](auto&& entry) {
130               using T = std::decay_t<decltype(entry)>;
131               if constexpr (std::is_same_v<T, RemoteNameRequestQueueEntry>) {
132                 log::info("Remote name request completed");
133               } else if constexpr (std::is_same_v<T, AclCreateConnectionQueueEntry>) {
134                 log::error(
135                         "Received RNR completion when ACL connection is outstanding - assuming the "
136                         "connection has failed and continuing");
137               } else {
138                 static_assert(!sizeof(T*), "non-exhaustive visitor!");
139               }
140             },
141             outgoing_entry_.value());
142 
143     outgoing_entry_.reset();
144     try_dequeue_next_operation();
145   }
146 
CancelRemoteNameRequestbluetooth::hci::acl_manager::AclScheduler::impl147   void CancelRemoteNameRequest(Address address,
148                                common::ContextualOnceCallback<void()> cancel_request) {
149     auto ok = cancel_outgoing_or_queued_connection(
150             [&](auto& entry) {
151               auto entry_ptr = std::get_if<RemoteNameRequestQueueEntry>(&entry);
152               return entry_ptr != nullptr && entry_ptr->address == address;
153             },
154             [&]() { cancel_request(); },
155             [](auto entry) {
156               std::get<RemoteNameRequestQueueEntry>(entry).callback_when_cancelled();
157             });
158     if (!ok) {
159       log::error("Attempted to cancel remote name request to {} that does not exist", address);
160     }
161   }
162 
Stopbluetooth::hci::acl_manager::AclScheduler::impl163   void Stop() { stopped_ = true; }
164 
165 private:
ready_to_send_next_operationbluetooth::hci::acl_manager::AclScheduler::impl166   bool ready_to_send_next_operation() const {
167     if (stopped_) {
168       return false;
169     }
170     if (pending_outgoing_operations_.empty()) {
171       return false;
172     }
173     if (const RemoteNameRequestQueueEntry* peek =
174                 std::get_if<RemoteNameRequestQueueEntry>(&pending_outgoing_operations_.front())) {
175       if (incoming_connecting_address_set_.contains(peek->address)) {
176         log::info("Pending incoming connection and outgoing RNR to same peer:{}", peek->address);
177         return true;
178       }
179     }
180     return incoming_connecting_address_set_.empty() && !outgoing_entry_.has_value();
181   }
182 
try_dequeue_next_operationbluetooth::hci::acl_manager::AclScheduler::impl183   void try_dequeue_next_operation() {
184     if (ready_to_send_next_operation()) {
185       log::info("Pending connections is not empty; so sending next connection");
186       auto entry = std::move(pending_outgoing_operations_.front());
187       pending_outgoing_operations_.pop_front();
188       std::visit([](auto&& variant) { variant.callback(); }, entry);
189       outgoing_entry_ = std::move(entry);
190     }
191   }
192 
193   template <typename T, typename U, typename V>
cancel_outgoing_or_queued_connectionbluetooth::hci::acl_manager::AclScheduler::impl194   bool cancel_outgoing_or_queued_connection(T matcher, U cancel_outgoing, V cancelled_queued) {
195     // Check if relevant connection is currently outgoing
196     if (outgoing_entry_.has_value()) {
197       if (matcher(outgoing_entry_.value())) {
198         cancel_outgoing();
199         return true;
200       }
201     }
202     // Otherwise, clear from the queue
203     auto it = std::find_if(pending_outgoing_operations_.begin(), pending_outgoing_operations_.end(),
204                            matcher);
205     if (it == pending_outgoing_operations_.end()) {
206       return false;
207     }
208     cancelled_queued(std::move(*it));
209     pending_outgoing_operations_.erase(it);
210     return true;
211   }
212 
set_of_incoming_connecting_addressesbluetooth::hci::acl_manager::AclScheduler::impl213   const std::string set_of_incoming_connecting_addresses() const {
214     std::stringstream buffer;
215     for (const auto& c : incoming_connecting_address_set_) {
216       buffer << " " << c.ToRedactedStringForLogging();
217     }
218     return buffer.str();
219   }
220 
221   std::optional<QueueEntry> outgoing_entry_;
222   std::deque<QueueEntry> pending_outgoing_operations_;
223   std::unordered_set<Address> incoming_connecting_address_set_;
224   bool stopped_ = false;
225 };
226 
__anon903ec63c0902() 227 const ModuleFactory AclScheduler::Factory = ModuleFactory([]() { return new AclScheduler(); });
228 
AclScheduler()229 AclScheduler::AclScheduler() : pimpl_(std::make_unique<impl>()) {}
230 AclScheduler::~AclScheduler() = default;
231 
EnqueueOutgoingAclConnection(Address address,common::ContextualOnceCallback<void ()> start_connection)232 void AclScheduler::EnqueueOutgoingAclConnection(
233         Address address, common::ContextualOnceCallback<void()> start_connection) {
234   GetHandler()->Call(&impl::EnqueueOutgoingAclConnection, common::Unretained(pimpl_.get()), address,
235                      std::move(start_connection));
236 }
237 
RegisterPendingIncomingConnection(Address address)238 void AclScheduler::RegisterPendingIncomingConnection(Address address) {
239   GetHandler()->Call(&impl::RegisterPendingIncomingConnection, common::Unretained(pimpl_.get()),
240                      address);
241 }
242 
ReportAclConnectionCompletion(Address address,common::ContextualOnceCallback<void ()> handle_outgoing_connection,common::ContextualOnceCallback<void ()> handle_incoming_connection,common::ContextualOnceCallback<void (std::string)> handle_unknown_connection)243 void AclScheduler::ReportAclConnectionCompletion(
244         Address address, common::ContextualOnceCallback<void()> handle_outgoing_connection,
245         common::ContextualOnceCallback<void()> handle_incoming_connection,
246         common::ContextualOnceCallback<void(std::string)> handle_unknown_connection) {
247   GetHandler()->Call(&impl::ReportAclConnectionCompletion, common::Unretained(pimpl_.get()),
248                      address, std::move(handle_outgoing_connection),
249                      std::move(handle_incoming_connection), std::move(handle_unknown_connection));
250 }
251 
ReportOutgoingAclConnectionFailure()252 void AclScheduler::ReportOutgoingAclConnectionFailure() {
253   GetHandler()->Call(&impl::ReportOutgoingAclConnectionFailure, common::Unretained(pimpl_.get()));
254 }
255 
CancelAclConnection(Address address,common::ContextualOnceCallback<void ()> cancel_connection,common::ContextualOnceCallback<void ()> cancel_connection_completed)256 void AclScheduler::CancelAclConnection(
257         Address address, common::ContextualOnceCallback<void()> cancel_connection,
258         common::ContextualOnceCallback<void()> cancel_connection_completed) {
259   GetHandler()->Call(&impl::CancelAclConnection, common::Unretained(pimpl_.get()), address,
260                      std::move(cancel_connection), std::move(cancel_connection_completed));
261 }
262 
EnqueueRemoteNameRequest(Address address,common::ContextualOnceCallback<void ()> start_request,common::ContextualOnceCallback<void ()> cancel_request_completed)263 void AclScheduler::EnqueueRemoteNameRequest(
264         Address address, common::ContextualOnceCallback<void()> start_request,
265         common::ContextualOnceCallback<void()> cancel_request_completed) {
266   GetHandler()->Call(&impl::EnqueueRemoteNameRequest, common::Unretained(pimpl_.get()), address,
267                      std::move(start_request), std::move(cancel_request_completed));
268 }
269 
ReportRemoteNameRequestCompletion(Address address)270 void AclScheduler::ReportRemoteNameRequestCompletion(Address address) {
271   GetHandler()->Call(&impl::ReportRemoteNameRequestCompletion, common::Unretained(pimpl_.get()),
272                      address);
273 }
274 
CancelRemoteNameRequest(Address address,common::ContextualOnceCallback<void ()> cancel_request)275 void AclScheduler::CancelRemoteNameRequest(Address address,
276                                            common::ContextualOnceCallback<void()> cancel_request) {
277   GetHandler()->Call(&impl::CancelRemoteNameRequest, common::Unretained(pimpl_.get()), address,
278                      std::move(cancel_request));
279 }
280 
ListDependencies(ModuleList *) const281 void AclScheduler::ListDependencies(ModuleList* /* list */) const {}
282 
Start()283 void AclScheduler::Start() {}
284 
Stop()285 void AclScheduler::Stop() { pimpl_->Stop(); }
286 
287 }  // namespace acl_manager
288 }  // namespace hci
289 }  // namespace bluetooth
290