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