blob: 9454be0c4edc5fb54dd945ad942bfa2839aff93a [file] [log] [blame]
Jakub Pawlowski80808622018-10-29 10:17:23 +01001/******************************************************************************
2 *
3 * Copyright 2018 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
Jakub Pawlowskiddba8a62018-11-09 11:53:11 +010019#include "connection_manager.h"
Jakub Pawlowski80808622018-10-29 10:17:23 +010020
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +010021#include <base/bind.h>
22#include <base/callback.h>
23#include <base/location.h>
Jakub Pawlowski80808622018-10-29 10:17:23 +010024#include <base/logging.h>
Jakub Pawlowskic4366122018-11-10 16:45:35 +010025#include <map>
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +010026#include <memory>
Jakub Pawlowskid1d30882018-11-09 18:40:04 +010027#include <set>
Jakub Pawlowski05af1732018-10-29 15:53:35 +010028
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +010029#include "internal_include/bt_trace.h"
30#include "osi/include/alarm.h"
Jakub Pawlowski05af1732018-10-29 15:53:35 +010031#include "stack/btm/btm_ble_bgconn.h"
Jakub Pawlowski80808622018-10-29 10:17:23 +010032
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +010033#define DIRECT_CONNECT_TIMEOUT (30 * 1000) /* 30 seconds */
34
35struct closure_data {
36 base::OnceClosure user_task;
37 base::Location posted_from;
38};
39
40static void alarm_closure_cb(void* p) {
41 closure_data* data = (closure_data*)p;
42 VLOG(1) << "executing timer scheduled at %s" << data->posted_from.ToString();
43 std::move(data->user_task).Run();
44 delete data;
45}
46
47// Periodic alarms are not supported, because we clean up data in callback
48void alarm_set_closure(const base::Location& posted_from, alarm_t* alarm,
49 uint64_t interval_ms, base::OnceClosure user_task) {
50 closure_data* data = new closure_data;
51 data->posted_from = posted_from;
52 data->user_task = std::move(user_task);
53 VLOG(1) << "scheduling timer %s" << data->posted_from.ToString();
54 alarm_set_on_mloop(alarm, interval_ms, alarm_closure_cb, data);
55}
56
57using unique_alarm_ptr = std::unique_ptr<alarm_t, decltype(&alarm_free)>;
58
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +010059namespace connection_manager {
60
61struct tAPPS_CONNECTING {
Jakub Pawlowskic4366122018-11-10 16:45:35 +010062 // ids of clients doing background connection to given device
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +010063 std::set<tAPP_ID> doing_bg_conn;
Jakub Pawlowskic4366122018-11-10 16:45:35 +010064
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +010065 // Apps trying to do direct connection.
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +010066 std::map<tAPP_ID, unique_alarm_ptr> doing_direct_conn;
Jakub Pawlowskid28727e2018-11-09 12:42:32 +010067};
68
Jakub Pawlowskibd2aac92018-10-29 11:24:32 +010069namespace {
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +010070// Maps address to apps trying to connect to it
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +010071std::map<RawAddress, tAPPS_CONNECTING> bgconn_dev;
Jakub Pawlowski05af1732018-10-29 15:53:35 +010072
Jakub Pawlowskic4366122018-11-10 16:45:35 +010073bool anyone_connecting(
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +010074 const std::map<RawAddress, tAPPS_CONNECTING>::iterator it) {
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +010075 return (!it->second.doing_bg_conn.empty() ||
76 !it->second.doing_direct_conn.empty());
Jakub Pawlowski05af1732018-10-29 15:53:35 +010077}
78
Jakub Pawlowskibd2aac92018-10-29 11:24:32 +010079} // namespace
Jakub Pawlowski80808622018-10-29 10:17:23 +010080
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +010081/** background connection device from the list. Returns pointer to the device
82 * record, or nullptr if not found */
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +010083std::set<tAPP_ID> get_apps_connecting_to(const RawAddress& address) {
Jakub Pawlowskic4366122018-11-10 16:45:35 +010084 auto it = bgconn_dev.find(address);
85 return (it != bgconn_dev.end()) ? it->second.doing_bg_conn
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +010086 : std::set<tAPP_ID>();
Jakub Pawlowski80808622018-10-29 10:17:23 +010087}
88
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +010089/** Add a device from the background connection list. Returns true if device
90 * added to the list, or already in list, false otherwise */
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +010091bool background_connect_add(uint8_t app_id, const RawAddress& address) {
Jakub Pawlowskic4366122018-11-10 16:45:35 +010092 auto it = bgconn_dev.find(address);
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +010093 bool in_white_list = false;
Jakub Pawlowskic4366122018-11-10 16:45:35 +010094 if (it != bgconn_dev.end()) {
Jakub Pawlowski80808622018-10-29 10:17:23 +010095 // device already in the whitelist, just add interested app to the list
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +010096 if (it->second.doing_bg_conn.count(app_id)) {
97 LOG(INFO) << "App id=" << loghex(app_id)
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +010098 << "already doing background connection to " << address;
99 return true;
Jakub Pawlowski80808622018-10-29 10:17:23 +0100100 }
101
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +0100102 // Already in white list ?
103 if (anyone_connecting(it)) {
104 in_white_list = true;
105 }
Jakub Pawlowski80808622018-10-29 10:17:23 +0100106 }
Jakub Pawlowski80808622018-10-29 10:17:23 +0100107
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +0100108 if (!in_white_list) {
109 // the device is not in the whitelist
110 if (!BTM_WhiteListAdd(address)) return false;
111 }
Jakub Pawlowski80808622018-10-29 10:17:23 +0100112
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +0100113 // create endtry for address, and insert app_id.
114 bgconn_dev[address].doing_bg_conn.insert(app_id);
Jakub Pawlowski80808622018-10-29 10:17:23 +0100115 return true;
116}
117
Jakub Pawlowski552dc5a2019-01-17 22:31:39 +0100118/** Removes all registrations for connection for given device.
Jakub Pawlowski80808622018-10-29 10:17:23 +0100119 * Returns true if anything was removed, false otherwise */
Jakub Pawlowski552dc5a2019-01-17 22:31:39 +0100120bool remove_unconditional(const RawAddress& address) {
Jakub Pawlowskic4366122018-11-10 16:45:35 +0100121 auto it = bgconn_dev.find(address);
122 if (it == bgconn_dev.end()) return false;
Jakub Pawlowski80808622018-10-29 10:17:23 +0100123
Jakub Pawlowskic4366122018-11-10 16:45:35 +0100124 BTM_WhiteListRemove(address);
125 bgconn_dev.erase(it);
Jakub Pawlowski80808622018-10-29 10:17:23 +0100126 return true;
127}
128
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +0100129/** Remove device from the background connection device list or listening to
130 * advertising list. Returns true if device was on the list and was succesfully
131 * removed */
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +0100132bool background_connect_remove(uint8_t app_id, const RawAddress& address) {
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +0100133 VLOG(2) << __func__;
Jakub Pawlowskic4366122018-11-10 16:45:35 +0100134 auto it = bgconn_dev.find(address);
135 if (it == bgconn_dev.end()) return false;
Jakub Pawlowski80808622018-10-29 10:17:23 +0100136
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +0100137 if (!it->second.doing_bg_conn.erase(app_id)) return false;
Jakub Pawlowski80808622018-10-29 10:17:23 +0100138
Jakub Pawlowskic4366122018-11-10 16:45:35 +0100139 if (anyone_connecting(it)) return true;
Jakub Pawlowski80808622018-10-29 10:17:23 +0100140
141 // no more apps interested - remove from whitelist and delete record
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +0100142 BTM_WhiteListRemove(address);
Jakub Pawlowskic4366122018-11-10 16:45:35 +0100143 bgconn_dev.erase(it);
Jakub Pawlowski80808622018-10-29 10:17:23 +0100144 return true;
145}
146
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +0100147/** deregister all related background connetion device. */
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +0100148void on_app_deregistered(uint8_t app_id) {
Jakub Pawlowskibd2aac92018-10-29 11:24:32 +0100149 auto it = bgconn_dev.begin();
150 auto end = bgconn_dev.end();
Jakub Pawlowski80808622018-10-29 10:17:23 +0100151 /* update the BG conn device list */
152 while (it != end) {
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +0100153 it->second.doing_bg_conn.erase(app_id);
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +0100154
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +0100155 it->second.doing_direct_conn.erase(app_id);
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +0100156
157 if (anyone_connecting(it)) {
Jakub Pawlowski80808622018-10-29 10:17:23 +0100158 it++;
159 continue;
160 }
161
Jakub Pawlowskic4366122018-11-10 16:45:35 +0100162 BTM_WhiteListRemove(it->first);
Jakub Pawlowskibd2aac92018-10-29 11:24:32 +0100163 it = bgconn_dev.erase(it);
Jakub Pawlowski80808622018-10-29 10:17:23 +0100164 }
165}
166
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +0100167void on_connection_complete(const RawAddress& address) {
168 VLOG(2) << __func__;
169 auto it = bgconn_dev.find(address);
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +0100170
Hansong Zhang4d17a8e2019-01-23 14:03:24 -0800171 while (it != bgconn_dev.end() && !it->second.doing_direct_conn.empty()) {
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +0100172 uint8_t app_id = it->second.doing_direct_conn.begin()->first;
173 direct_connect_remove(app_id, address);
Hansong Zhang4d17a8e2019-01-23 14:03:24 -0800174 it = bgconn_dev.find(address);
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +0100175 }
176}
177
Jakub Pawlowski80808622018-10-29 10:17:23 +0100178/** Reset bg device list. If called after controller reset, set |after_reset| to
179 * true, as there is no need to wipe controller white list in this case. */
Jakub Pawlowskid28727e2018-11-09 12:42:32 +0100180void reset(bool after_reset) {
Jakub Pawlowskibd2aac92018-10-29 11:24:32 +0100181 bgconn_dev.clear();
Jakub Pawlowski80808622018-10-29 10:17:23 +0100182 if (!after_reset) BTM_WhiteListClear();
183}
Jakub Pawlowskid28727e2018-11-09 12:42:32 +0100184
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +0100185void wl_direct_connect_timeout_cb(uint8_t app_id, const RawAddress& address) {
Jakub Pawlowski8edcc902019-04-02 19:21:14 +0200186 on_connection_timed_out(app_id, address);
187
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +0100188 // TODO: this would free the timer, from within the timer callback, which is
189 // bad.
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +0100190 direct_connect_remove(app_id, address);
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +0100191}
192
193/** Add a device to the direcgt connection list. Returns true if device
194 * added to the list, false otherwise */
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +0100195bool direct_connect_add(uint8_t app_id, const RawAddress& address) {
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +0100196 auto it = bgconn_dev.find(address);
197 bool in_white_list = false;
198
199 if (it != bgconn_dev.end()) {
200 // app already trying to connect to this particular device
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +0100201 if (it->second.doing_direct_conn.count(app_id)) {
202 LOG(INFO) << "direct connect attempt from app_id=" << loghex(app_id)
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +0100203 << " already in progress";
204 return false;
205 }
206
207 // are we already in the white list ?
208 if (anyone_connecting(it)) {
209 in_white_list = true;
210 }
211 }
212
213 bool params_changed = BTM_SetLeConnectionModeToFast();
214
215 if (!in_white_list) {
216 if (!BTM_WhiteListAdd(address)) {
217 // if we can't add to white list, turn parameters back to slow.
218 if (params_changed) BTM_SetLeConnectionModeToSlow();
219 return false;
220 }
221 }
222
223 // Setup a timer
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +0100224 alarm_t* timeout = alarm_new("wl_conn_params_30s");
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +0100225 alarm_set_closure(
226 FROM_HERE, timeout, DIRECT_CONNECT_TIMEOUT,
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +0100227 base::BindOnce(&wl_direct_connect_timeout_cb, app_id, address));
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +0100228
229 bgconn_dev[address].doing_direct_conn.emplace(
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +0100230 app_id, unique_alarm_ptr(timeout, &alarm_free));
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +0100231 return true;
232}
233
234bool any_direct_connect_left() {
235 for (const auto& tmp : bgconn_dev) {
236 if (!tmp.second.doing_direct_conn.empty()) return true;
237 }
238 return false;
239}
240
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +0100241bool direct_connect_remove(uint8_t app_id, const RawAddress& address) {
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +0100242 VLOG(2) << __func__ << ": "
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +0100243 << "app_id: " << +app_id << ", address:" << address;
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +0100244 auto it = bgconn_dev.find(address);
245 if (it == bgconn_dev.end()) return false;
246
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +0100247 auto app_it = it->second.doing_direct_conn.find(app_id);
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +0100248 if (app_it == it->second.doing_direct_conn.end()) return false;
249
250 // this will free the alarm
251 it->second.doing_direct_conn.erase(app_it);
252
253 // if we removed last direct connection, lower the scan parameters used for
254 // connecting
255 if (!any_direct_connect_left()) {
256 BTM_SetLeConnectionModeToSlow();
257 }
258
259 if (anyone_connecting(it)) return true;
260
261 // no more apps interested - remove from whitelist
262 BTM_WhiteListRemove(address);
263 bgconn_dev.erase(it);
264 return true;
265}
266
Jakub Pawlowski8ae68be2018-11-13 15:41:42 +0100267void dump(int fd) {
Jakub Pawlowskif20d94a2018-12-28 19:03:09 +0100268 dprintf(fd, "\nconnection_manager state:\n");
Jakub Pawlowski8ae68be2018-11-13 15:41:42 +0100269 if (bgconn_dev.empty()) {
Jakub Pawlowski3a582172019-09-23 19:03:57 +0200270 dprintf(fd, "\tno Low Energy connection attempts\n");
Jakub Pawlowski8ae68be2018-11-13 15:41:42 +0100271 return;
272 }
273
Jakub Pawlowski3a582172019-09-23 19:03:57 +0200274 dprintf(fd, "\tdevices attempting connection: %d", (int)bgconn_dev.size());
Jakub Pawlowski8ae68be2018-11-13 15:41:42 +0100275 for (const auto& entry : bgconn_dev) {
276 dprintf(fd, "\n\t * %s: ", entry.first.ToString().c_str());
277
Jakub Pawlowskicab1ae12018-11-14 16:15:04 +0100278 if (!entry.second.doing_direct_conn.empty()) {
279 dprintf(fd, "\n\t\tapps doing direct connect: ");
280 for (const auto& id : entry.second.doing_direct_conn) {
281 dprintf(fd, "%d, ", id.first);
282 }
283 }
284
Jakub Pawlowski3a582172019-09-23 19:03:57 +0200285 if (!entry.second.doing_bg_conn.empty()) {
Jakub Pawlowski8ae68be2018-11-13 15:41:42 +0100286 dprintf(fd, "\n\t\tapps doing background connect: ");
287 for (const auto& id : entry.second.doing_bg_conn) {
288 dprintf(fd, "%d, ", id);
289 }
290 }
291 }
Jakub Pawlowski3a582172019-09-23 19:03:57 +0200292 dprintf(fd, "\n");
Jakub Pawlowski8ae68be2018-11-13 15:41:42 +0100293}
294
Jakub Pawlowskid28727e2018-11-09 12:42:32 +0100295} // namespace connection_manager