Home | History | Annotate | Download | only in src
      1 /******************************************************************************
      2  *
      3  *  Copyright (C) 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/logging.h>
     32 #include <string.h>
     33 
     34 #include "bt_common.h"
     35 #include "btif_common.h"
     36 #include "osi/include/allocator.h"
     37 #include "osi/include/list.h"
     38 #include "stack_manager.h"
     39 
     40 /*******************************************************************************
     41  *  Local type definitions
     42  ******************************************************************************/
     43 
     44 typedef enum {
     45   BTIF_QUEUE_CONNECT_EVT,
     46   BTIF_QUEUE_ADVANCE_EVT,
     47   BTIF_QUEUE_CLEANUP_EVT
     48 } btif_queue_event_t;
     49 
     50 typedef struct {
     51   RawAddress bda;
     52   uint16_t uuid;
     53   bool busy;
     54   btif_connect_cb_t connect_cb;
     55 } connect_node_t;
     56 
     57 /*******************************************************************************
     58  *  Static variables
     59  ******************************************************************************/
     60 
     61 static list_t* connect_queue;
     62 
     63 static const size_t MAX_REASONABLE_REQUESTS = 10;
     64 
     65 /*******************************************************************************
     66  *  Queue helper functions
     67  ******************************************************************************/
     68 
     69 static void queue_int_add(connect_node_t* p_param) {
     70   if (!connect_queue) {
     71     LOG_INFO(LOG_TAG, "%s: allocating profile queue", __func__);
     72     connect_queue = list_new(osi_free);
     73     CHECK(connect_queue != NULL);
     74   }
     75 
     76   // Sanity check to make sure we're not leaking connection requests
     77   CHECK(list_length(connect_queue) < MAX_REASONABLE_REQUESTS);
     78 
     79   for (const list_node_t* node = list_begin(connect_queue);
     80        node != list_end(connect_queue); node = list_next(node)) {
     81     if (((connect_node_t*)list_node(node))->uuid == p_param->uuid) {
     82       LOG_ERROR(LOG_TAG,
     83                 "%s dropping duplicate connection request UUID=%04X, "
     84                 "bd_addr=%s, busy=%d",
     85                 __func__, p_param->uuid, p_param->bda.ToString().c_str(),
     86                 p_param->busy);
     87       return;
     88     }
     89   }
     90 
     91   LOG_INFO(
     92       LOG_TAG, "%s: adding connection request UUID=%04X, bd_addr=%s, busy=%d",
     93       __func__, p_param->uuid, p_param->bda.ToString().c_str(), p_param->busy);
     94   connect_node_t* p_node = (connect_node_t*)osi_malloc(sizeof(connect_node_t));
     95   memcpy(p_node, p_param, sizeof(connect_node_t));
     96   list_append(connect_queue, p_node);
     97 }
     98 
     99 static void queue_int_advance() {
    100   if (connect_queue && !list_is_empty(connect_queue)) {
    101     connect_node_t* p_head = (connect_node_t*)list_front(connect_queue);
    102     LOG_INFO(LOG_TAG,
    103              "%s: removing connection request UUID=%04X, bd_addr=%s, busy=%d",
    104              __func__, p_head->uuid, p_head->bda.ToString().c_str(),
    105              p_head->busy);
    106     list_remove(connect_queue, p_head);
    107   }
    108 }
    109 
    110 static void queue_int_cleanup(uint16_t* p_uuid) {
    111   if (!p_uuid) {
    112     LOG_ERROR(LOG_TAG, "%s: UUID is null", __func__);
    113     return;
    114   }
    115   uint16_t uuid = *p_uuid;
    116   LOG_INFO(LOG_TAG, "%s: UUID=%04X", __func__, uuid);
    117   if (!connect_queue) {
    118     return;
    119   }
    120   connect_node_t* connection_request;
    121   const list_node_t* node = list_begin(connect_queue);
    122   while (node && node != list_end(connect_queue)) {
    123     connection_request = (connect_node_t*)list_node(node);
    124     node = list_next(node);
    125     if (connection_request->uuid == uuid) {
    126       LOG_INFO(LOG_TAG,
    127                "%s: removing connection request UUID=%04X, bd_addr=%s, busy=%d",
    128                __func__, connection_request->uuid,
    129                connection_request->bda.ToString().c_str(),
    130                connection_request->busy);
    131       list_remove(connect_queue, connection_request);
    132     }
    133   }
    134 }
    135 
    136 static void queue_int_handle_evt(uint16_t event, char* p_param) {
    137   switch (event) {
    138     case BTIF_QUEUE_CONNECT_EVT:
    139       queue_int_add((connect_node_t*)p_param);
    140       break;
    141 
    142     case BTIF_QUEUE_ADVANCE_EVT:
    143       queue_int_advance();
    144       break;
    145 
    146     case BTIF_QUEUE_CLEANUP_EVT:
    147       queue_int_cleanup((uint16_t*)(p_param));
    148       return;
    149   }
    150 
    151   if (stack_manager_get_interface()->get_stack_is_running())
    152     btif_queue_connect_next();
    153 }
    154 
    155 /*******************************************************************************
    156  *
    157  * Function         btif_queue_connect
    158  *
    159  * Description      Add a new connection to the queue and trigger the next
    160  *                  scheduled connection.
    161  *
    162  * Returns          BT_STATUS_SUCCESS if successful
    163  *
    164  ******************************************************************************/
    165 bt_status_t btif_queue_connect(uint16_t uuid, const RawAddress* bda,
    166                                btif_connect_cb_t connect_cb) {
    167   connect_node_t node;
    168   memset(&node, 0, sizeof(connect_node_t));
    169   node.bda = *bda;
    170   node.uuid = uuid;
    171   node.connect_cb = connect_cb;
    172 
    173   return btif_transfer_context(queue_int_handle_evt, BTIF_QUEUE_CONNECT_EVT,
    174                                (char*)&node, sizeof(connect_node_t), NULL);
    175 }
    176 
    177 /*******************************************************************************
    178  *
    179  * Function         btif_queue_cleanup
    180  *
    181  * Description      Clean up existing connection requests for a UUID
    182  *
    183  * Returns          void, always succeed
    184  *
    185  ******************************************************************************/
    186 void btif_queue_cleanup(uint16_t uuid) {
    187   btif_transfer_context(queue_int_handle_evt, BTIF_QUEUE_CLEANUP_EVT,
    188                         (char*)&uuid, sizeof(uint16_t), NULL);
    189 }
    190 
    191 /*******************************************************************************
    192  *
    193  * Function         btif_queue_advance
    194  *
    195  * Description      Clear the queue's busy status and advance to the next
    196  *                  scheduled connection.
    197  *
    198  * Returns          void
    199  *
    200  ******************************************************************************/
    201 void btif_queue_advance() {
    202   btif_transfer_context(queue_int_handle_evt, BTIF_QUEUE_ADVANCE_EVT, NULL, 0,
    203                         NULL);
    204 }
    205 
    206 // This function dispatches the next pending connect request. It is called from
    207 // stack_manager when the stack comes up.
    208 bt_status_t btif_queue_connect_next(void) {
    209   if (!connect_queue || list_is_empty(connect_queue)) return BT_STATUS_FAIL;
    210 
    211   connect_node_t* p_head = (connect_node_t*)list_front(connect_queue);
    212 
    213   LOG_INFO(LOG_TAG,
    214            "%s: executing connection request UUID=%04X, bd_addr=%s, busy=%d",
    215            __func__, p_head->uuid, p_head->bda.ToString().c_str(),
    216            p_head->busy);
    217   // If the queue is currently busy, we return success anyway,
    218   // since the connection has been queued...
    219   if (p_head->busy) return BT_STATUS_SUCCESS;
    220 
    221   p_head->busy = true;
    222   return p_head->connect_cb(&p_head->bda, p_head->uuid);
    223 }
    224 
    225 /*******************************************************************************
    226  *
    227  * Function         btif_queue_release
    228  *
    229  * Description      Free up all the queue nodes and set the queue head to NULL
    230  *
    231  * Returns          void
    232  *
    233  ******************************************************************************/
    234 void btif_queue_release() {
    235   LOG_INFO(LOG_TAG, "%s", __func__);
    236   list_free(connect_queue);
    237   connect_queue = NULL;
    238 }
    239