1 /****************************************************************************** 2 * 3 * Copyright 2009-2012 Broadcom Corporation 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 19 /******************************************************************************* 20 * 21 * Filename: btif_profile_queue.c 22 * 23 * Description: Bluetooth remote device connection queuing implementation. 24 * 25 ******************************************************************************/ 26 27 #define LOG_TAG "bt_btif_queue" 28 29 #include "btif_profile_queue.h" 30 31 #include <base/bind.h> 32 #include <base/logging.h> 33 #include <base/strings/stringprintf.h> 34 #include <string.h> 35 #include <list> 36 37 #include "bt_common.h" 38 #include "btif_common.h" 39 #include "stack_manager.h" 40 41 /******************************************************************************* 42 * Local type definitions 43 ******************************************************************************/ 44 45 // Class to store connect info. 46 class ConnectNode { 47 public: 48 ConnectNode(const RawAddress& address, uint16_t uuid, 49 btif_connect_cb_t connect_cb) 50 : address_(address), uuid_(uuid), busy_(false), connect_cb_(connect_cb) {} 51 52 std::string ToString() const { 53 return base::StringPrintf("address=%s UUID=%04X busy=%s", 54 address_.ToString().c_str(), uuid_, 55 (busy_) ? "true" : "false"); 56 } 57 58 const RawAddress& address() const { return address_; } 59 uint16_t uuid() const { return uuid_; } 60 61 /** 62 * Initiate the connection. 63 * 64 * @return BT_STATUS_SUCCESS on success, othewise the corresponding error 65 * code. Note: if a previous connect request hasn't been completed, the 66 * return value is BT_STATUS_SUCCESS. 67 */ 68 bt_status_t connect() { 69 if (busy_) return BT_STATUS_SUCCESS; 70 busy_ = true; 71 return connect_cb_(&address_, uuid_); 72 } 73 74 private: 75 RawAddress address_; 76 uint16_t uuid_; 77 bool busy_; 78 btif_connect_cb_t connect_cb_; 79 }; 80 81 /******************************************************************************* 82 * Static variables 83 ******************************************************************************/ 84 85 static std::list<ConnectNode> connect_queue; 86 87 static const size_t MAX_REASONABLE_REQUESTS = 20; 88 89 /******************************************************************************* 90 * Queue helper functions 91 ******************************************************************************/ 92 93 static void queue_int_add(uint16_t uuid, const RawAddress& bda, 94 btif_connect_cb_t connect_cb) { 95 // Sanity check to make sure we're not leaking connection requests 96 CHECK(connect_queue.size() < MAX_REASONABLE_REQUESTS); 97 98 ConnectNode param(bda, uuid, connect_cb); 99 for (const auto& node : connect_queue) { 100 if (node.uuid() == param.uuid() && node.address() == param.address()) { 101 LOG_ERROR(LOG_TAG, "%s: dropping duplicate connection request: %s", 102 __func__, param.ToString().c_str()); 103 return; 104 } 105 } 106 107 LOG_INFO(LOG_TAG, "%s: adding connection request: %s", __func__, 108 param.ToString().c_str()); 109 connect_queue.push_back(param); 110 111 btif_queue_connect_next(); 112 } 113 114 static void queue_int_advance() { 115 if (connect_queue.empty()) return; 116 117 const ConnectNode& head = connect_queue.front(); 118 LOG_INFO(LOG_TAG, "%s: removing connection request: %s", __func__, 119 head.ToString().c_str()); 120 connect_queue.pop_front(); 121 122 btif_queue_connect_next(); 123 } 124 125 static void queue_int_cleanup(uint16_t uuid) { 126 LOG_INFO(LOG_TAG, "%s: UUID=%04X", __func__, uuid); 127 128 for (auto it = connect_queue.begin(); it != connect_queue.end();) { 129 auto it_prev = it++; 130 const ConnectNode& node = *it_prev; 131 if (node.uuid() == uuid) { 132 LOG_INFO(LOG_TAG, "%s: removing connection request: %s", __func__, 133 node.ToString().c_str()); 134 connect_queue.erase(it_prev); 135 } 136 } 137 } 138 139 static void queue_int_release() { connect_queue.clear(); } 140 141 /******************************************************************************* 142 * 143 * Function btif_queue_connect 144 * 145 * Description Add a new connection to the queue and trigger the next 146 * scheduled connection. 147 * 148 * Returns BT_STATUS_SUCCESS if successful 149 * 150 ******************************************************************************/ 151 bt_status_t btif_queue_connect(uint16_t uuid, const RawAddress* bda, 152 btif_connect_cb_t connect_cb) { 153 return do_in_jni_thread(FROM_HERE, 154 base::Bind(&queue_int_add, uuid, *bda, connect_cb)); 155 } 156 157 /******************************************************************************* 158 * 159 * Function btif_queue_cleanup 160 * 161 * Description Clean up existing connection requests for a UUID 162 * 163 * Returns void, always succeed 164 * 165 ******************************************************************************/ 166 void btif_queue_cleanup(uint16_t uuid) { 167 do_in_jni_thread(FROM_HERE, base::Bind(&queue_int_cleanup, uuid)); 168 } 169 170 /******************************************************************************* 171 * 172 * Function btif_queue_advance 173 * 174 * Description Clear the queue's busy status and advance to the next 175 * scheduled connection. 176 * 177 * Returns void 178 * 179 ******************************************************************************/ 180 void btif_queue_advance() { 181 do_in_jni_thread(FROM_HERE, base::Bind(&queue_int_advance)); 182 } 183 184 bt_status_t btif_queue_connect_next(void) { 185 // The call must be on the JNI thread, otherwise the access to connect_queue 186 // is not thread-safe. 187 CHECK(is_on_jni_thread()); 188 189 if (connect_queue.empty()) return BT_STATUS_FAIL; 190 if (!stack_manager_get_interface()->get_stack_is_running()) 191 return BT_STATUS_FAIL; 192 193 ConnectNode& head = connect_queue.front(); 194 195 LOG_INFO(LOG_TAG, "%s: executing connection request: %s", __func__, 196 head.ToString().c_str()); 197 return head.connect(); 198 } 199 200 /******************************************************************************* 201 * 202 * Function btif_queue_release 203 * 204 * Description Free up all the queue nodes and set the queue head to NULL 205 * 206 * Returns void 207 * 208 ******************************************************************************/ 209 void btif_queue_release() { 210 LOG_INFO(LOG_TAG, "%s", __func__); 211 if (do_in_jni_thread(FROM_HERE, base::Bind(&queue_int_release)) != 212 BT_STATUS_SUCCESS) { 213 // Scheduling failed - the thread to schedule on is probably dead 214 queue_int_release(); 215 } 216 } 217