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_sock_thread.c
     22  *
     23  *  Description:   socket select thread
     24  *
     25  *
     26  ***********************************************************************************/
     27 
     28 #include <hardware/bluetooth.h>
     29 #include <hardware/bt_sock.h>
     30 
     31 //bta_jv_co_rfc_data
     32 #include <stdio.h>
     33 #include <stdlib.h>
     34 #include <errno.h>
     35 #include <string.h>
     36 #include <sys/types.h>
     37 #include <sys/socket.h>
     38 #include <sys/un.h>
     39 #include <time.h>
     40 #include <fcntl.h>
     41 #include <unistd.h>
     42 #include <signal.h>
     43 #include <pthread.h>
     44 #include <ctype.h>
     45 
     46 #include <sys/select.h>
     47 #include <sys/poll.h>
     48 #include <cutils/sockets.h>
     49 #include <alloca.h>
     50 
     51 #define LOG_TAG "BTIF_SOCK"
     52 #include "btif_common.h"
     53 #include "btif_util.h"
     54 
     55 #include "bd.h"
     56 
     57 #include "bta_api.h"
     58 #include "btif_sock.h"
     59 #include "btif_sock_thread.h"
     60 #include "btif_sock_util.h"
     61 
     62 #include <cutils/log.h>
     63 #define asrt(s) if(!(s)) APPL_TRACE_ERROR("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
     64 #define print_events(events) do { \
     65     APPL_TRACE_DEBUG("print poll event:%x", events); \
     66     if (events & POLLIN) APPL_TRACE_DEBUG(  "   POLLIN "); \
     67     if (events & POLLPRI) APPL_TRACE_DEBUG( "   POLLPRI "); \
     68     if (events & POLLOUT) APPL_TRACE_DEBUG( "   POLLOUT "); \
     69     if (events & POLLERR) APPL_TRACE_DEBUG( "   POLLERR "); \
     70     if (events & POLLHUP) APPL_TRACE_DEBUG( "   POLLHUP "); \
     71     if (events & POLLNVAL) APPL_TRACE_DEBUG("   POLLNVAL "); \
     72     if (events & POLLRDHUP) APPL_TRACE_DEBUG("   POLLRDHUP"); \
     73     } while(0)
     74 
     75 #define MAX_THREAD 8
     76 #define MAX_POLL 64
     77 #define POLL_EXCEPTION_EVENTS (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)
     78 #define IS_EXCEPTION(e) ((e) & POLL_EXCEPTION_EVENTS)
     79 #define IS_READ(e) ((e) & POLLIN)
     80 #define IS_WRITE(e) ((e) & POLLOUT)
     81 /*cmd executes in socket poll thread */
     82 #define CMD_WAKEUP       1
     83 #define CMD_EXIT         2
     84 #define CMD_ADD_FD       3
     85 #define CMD_USER_PRIVATE 4
     86 
     87 typedef struct {
     88     struct pollfd pfd;
     89     uint32_t user_id;
     90     int type;
     91     int flags;
     92 } poll_slot_t;
     93 typedef struct {
     94     int cmd_fdr, cmd_fdw;
     95     int poll_count;
     96     poll_slot_t ps[MAX_POLL];
     97     int psi[MAX_POLL]; //index of poll slot
     98     volatile pid_t thread_id;
     99     btsock_signaled_cb callback;
    100     btsock_cmd_cb cmd_callback;
    101     int used;
    102 } thread_slot_t;
    103 static thread_slot_t ts[MAX_THREAD];
    104 
    105 
    106 
    107 static void *sock_poll_thread(void *arg);
    108 static inline void close_cmd_fd(int h);
    109 
    110 static inline void add_poll(int h, int fd, int type, int flags, uint32_t user_id);
    111 
    112 static pthread_mutex_t thread_slot_lock;
    113 
    114 
    115 static inline void set_socket_blocking(int s, int blocking)
    116 {
    117     int opts;
    118     opts = fcntl(s, F_GETFL);
    119     if (opts<0) APPL_TRACE_ERROR("set blocking (%s)", strerror(errno));
    120     if(blocking)
    121         opts &= ~O_NONBLOCK;
    122     else opts |= O_NONBLOCK;
    123     fcntl(s, F_SETFL, opts);
    124 }
    125 
    126 static inline int create_server_socket(const char* name)
    127 {
    128     int s = socket(AF_LOCAL, SOCK_STREAM, 0);
    129     APPL_TRACE_DEBUG("covert name to android abstract name:%s", name);
    130     if(socket_local_server_bind(s, name, ANDROID_SOCKET_NAMESPACE_ABSTRACT) >= 0)
    131     {
    132         if(listen(s, 5) == 0)
    133         {
    134             APPL_TRACE_DEBUG("listen to local socket:%s, fd:%d", name, s);
    135             return s;
    136         }
    137         else APPL_TRACE_ERROR("listen to local socket:%s, fd:%d failed, errno:%d", name, s, errno);
    138     }
    139     else APPL_TRACE_ERROR("create local socket:%s fd:%d, failed, errno:%d", name, s, errno);
    140     close(s);
    141     return -1;
    142 }
    143 static inline int connect_server_socket(const char* name)
    144 {
    145     int s = socket(AF_LOCAL, SOCK_STREAM, 0);
    146     set_socket_blocking(s, TRUE);
    147     if(socket_local_client_connect(s, name, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM) >= 0)
    148     {
    149         APPL_TRACE_DEBUG("connected to local socket:%s, fd:%d", name, s);
    150         return s;
    151     }
    152     else APPL_TRACE_ERROR("connect to local socket:%s, fd:%d failed, errno:%d", name, s, errno);
    153     close(s);
    154     return -1;
    155 }
    156 static inline int accept_server_socket(int s)
    157 {
    158     struct sockaddr_un client_address;
    159     socklen_t clen;
    160     int fd = accept(s, (struct sockaddr*)&client_address, &clen);
    161     APPL_TRACE_DEBUG("accepted fd:%d for server fd:%d", fd, s);
    162     return fd;
    163 }
    164 static inline pthread_t create_thread(void *(*start_routine)(void *), void * arg)
    165 {
    166     pthread_attr_t thread_attr;
    167     pthread_attr_init(&thread_attr);
    168     pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
    169     pthread_t thread_id = -1;
    170     if( pthread_create(&thread_id, &thread_attr, start_routine, arg)!=0 )
    171     {
    172         APPL_TRACE_ERROR("pthread_create : %s", strerror(errno));
    173         return -1;
    174     }
    175     return thread_id;
    176 }
    177 static void init_poll(int cmd_fd);
    178 static int alloc_thread_slot()
    179 {
    180     int i;
    181     //revserd order to save guard uninitialized access to 0 index
    182     for(i = MAX_THREAD - 1; i >=0; i--)
    183     {
    184         APPL_TRACE_DEBUG("ts[%d].used:%d", i, ts[i].used);
    185         if(!ts[i].used)
    186         {
    187             ts[i].used = 1;
    188             return i;
    189         }
    190     }
    191     APPL_TRACE_ERROR("execeeded max thread count");
    192     return -1;
    193 }
    194 static void free_thread_slot(int h)
    195 {
    196     if(0 <= h && h < MAX_THREAD)
    197     {
    198         close_cmd_fd(h);
    199         ts[h].used = 0;
    200     }
    201     else APPL_TRACE_ERROR("invalid thread handle:%d", h);
    202 }
    203 int btsock_thread_init()
    204 {
    205     static int initialized;
    206     APPL_TRACE_DEBUG("in initialized:%d", initialized);
    207     if(!initialized)
    208     {
    209         initialized = 1;
    210         init_slot_lock(&thread_slot_lock);
    211         int h;
    212         for(h = 0; h < MAX_THREAD; h++)
    213         {
    214             ts[h].cmd_fdr = ts[h].cmd_fdw = -1;
    215             ts[h].used = 0;
    216             ts[h].thread_id = -1;
    217             ts[h].poll_count = 0;
    218             ts[h].callback = NULL;
    219             ts[h].cmd_callback = NULL;
    220         }
    221     }
    222     return TRUE;
    223 }
    224 int btsock_thread_create(btsock_signaled_cb callback, btsock_cmd_cb cmd_callback)
    225 {
    226     int ret = FALSE;
    227     asrt(callback || cmd_callback);
    228     lock_slot(&thread_slot_lock);
    229     int h = alloc_thread_slot();
    230     unlock_slot(&thread_slot_lock);
    231     APPL_TRACE_DEBUG("alloc_thread_slot ret:%d", h);
    232     if(h >= 0)
    233     {
    234         init_poll(h);
    235         if((ts[h].thread_id = create_thread(sock_poll_thread, (void*)(uintptr_t)h)) != -1)
    236         {
    237             APPL_TRACE_DEBUG("h:%d, thread id:%d", h, ts[h].thread_id);
    238             ts[h].callback = callback;
    239             ts[h].cmd_callback = cmd_callback;
    240         }
    241         else
    242         {
    243             free_thread_slot(h);
    244             h = -1;
    245         }
    246     }
    247     return h;
    248 }
    249 
    250 /* create dummy socket pair used to wake up select loop */
    251 static inline void init_cmd_fd(int h)
    252 {
    253     asrt(ts[h].cmd_fdr == -1 && ts[h].cmd_fdw == -1);
    254     if(socketpair(AF_UNIX, SOCK_STREAM, 0, &ts[h].cmd_fdr) < 0)
    255     {
    256         APPL_TRACE_ERROR("socketpair failed: %s", strerror(errno));
    257         return;
    258     }
    259     APPL_TRACE_DEBUG("h:%d, cmd_fdr:%d, cmd_fdw:%d", h, ts[h].cmd_fdr, ts[h].cmd_fdw);
    260     //add the cmd fd for read & write
    261     add_poll(h, ts[h].cmd_fdr, 0, SOCK_THREAD_FD_RD, 0);
    262 }
    263 static inline void close_cmd_fd(int h)
    264 {
    265     if(ts[h].cmd_fdr != -1)
    266     {
    267         close(ts[h].cmd_fdr);
    268         ts[h].cmd_fdr = -1;
    269     }
    270     if(ts[h].cmd_fdw != -1)
    271     {
    272         close(ts[h].cmd_fdw);
    273         ts[h].cmd_fdw = -1;
    274     }
    275 }
    276 typedef struct
    277 {
    278     int id;
    279     int fd;
    280     int type;
    281     int flags;
    282     uint32_t user_id;
    283 } sock_cmd_t;
    284 int btsock_thread_add_fd(int h, int fd, int type, int flags, uint32_t user_id)
    285 {
    286     if(h < 0 || h >= MAX_THREAD)
    287     {
    288         APPL_TRACE_ERROR("invalid bt thread handle:%d", h);
    289         return FALSE;
    290     }
    291     if(ts[h].cmd_fdw == -1)
    292     {
    293         APPL_TRACE_ERROR("cmd socket is not created. socket thread may not initialized");
    294         return FALSE;
    295     }
    296     if(flags & SOCK_THREAD_ADD_FD_SYNC)
    297     {
    298         //must executed in socket poll thread
    299         if(ts[h].thread_id == pthread_self())
    300         {
    301             //cleanup one-time flags
    302             flags &= ~SOCK_THREAD_ADD_FD_SYNC;
    303             add_poll(h, fd, type, flags, user_id);
    304             return TRUE;
    305         }
    306         APPL_TRACE_DEBUG("THREAD_ADD_FD_SYNC is not called in poll thread, fallback to async");
    307     }
    308     sock_cmd_t cmd = {CMD_ADD_FD, fd, type, flags, user_id};
    309     APPL_TRACE_DEBUG("adding fd:%d, flags:0x%x", fd, flags);
    310     return send(ts[h].cmd_fdw, &cmd, sizeof(cmd), 0) == sizeof(cmd);
    311 }
    312 int btsock_thread_post_cmd(int h, int type, const unsigned char* data, int size, uint32_t user_id)
    313 {
    314     if(h < 0 || h >= MAX_THREAD)
    315     {
    316         APPL_TRACE_ERROR("invalid bt thread handle:%d", h);
    317         return FALSE;
    318     }
    319     if(ts[h].cmd_fdw == -1)
    320     {
    321         APPL_TRACE_ERROR("cmd socket is not created. socket thread may not initialized");
    322         return FALSE;
    323     }
    324     sock_cmd_t cmd = {CMD_USER_PRIVATE, 0, type, size, user_id};
    325     APPL_TRACE_DEBUG("post cmd type:%d, size:%d, h:%d, ", type, size, h);
    326     sock_cmd_t* cmd_send = &cmd;
    327     int size_send = sizeof(cmd);
    328     if(data && size)
    329     {
    330         size_send = sizeof(cmd) + size;
    331         cmd_send = (sock_cmd_t*)alloca(size_send);
    332         if(cmd_send)
    333         {
    334             *cmd_send = cmd;
    335             memcpy(cmd_send + 1, data, size);
    336         }
    337         else
    338         {
    339             APPL_TRACE_ERROR("alloca failed at h:%d, cmd type:%d, size:%d", h, type, size_send);
    340             return FALSE;
    341         }
    342     }
    343     return send(ts[h].cmd_fdw, cmd_send, size_send, 0) == size_send;
    344 }
    345 int btsock_thread_wakeup(int h)
    346 {
    347     if(h < 0 || h >= MAX_THREAD)
    348     {
    349         APPL_TRACE_ERROR("invalid bt thread handle:%d", h);
    350         return FALSE;
    351     }
    352     if(ts[h].cmd_fdw == -1)
    353     {
    354         APPL_TRACE_ERROR("thread handle:%d, cmd socket is not created", h);
    355         return FALSE;
    356     }
    357     sock_cmd_t cmd = {CMD_WAKEUP, 0, 0, 0, 0};
    358     return send(ts[h].cmd_fdw, &cmd, sizeof(cmd), 0) == sizeof(cmd);
    359 }
    360 int btsock_thread_exit(int h)
    361 {
    362     if(h < 0 || h >= MAX_THREAD)
    363     {
    364         APPL_TRACE_ERROR("invalid bt thread handle:%d", h);
    365         return FALSE;
    366     }
    367     if(ts[h].cmd_fdw == -1)
    368     {
    369         APPL_TRACE_ERROR("cmd socket is not created");
    370         return FALSE;
    371     }
    372     sock_cmd_t cmd = {CMD_EXIT, 0, 0, 0, 0};
    373     if(send(ts[h].cmd_fdw, &cmd, sizeof(cmd), 0) == sizeof(cmd))
    374     {
    375         pthread_join(ts[h].thread_id, 0);
    376         lock_slot(&thread_slot_lock);
    377         free_thread_slot(h);
    378         unlock_slot(&thread_slot_lock);
    379         return TRUE;
    380     }
    381     return FALSE;
    382 }
    383 static void init_poll(int h)
    384 {
    385     int i;
    386     ts[h].poll_count = 0;
    387     ts[h].thread_id = -1;
    388     ts[h].callback = NULL;
    389     ts[h].cmd_callback = NULL;
    390     for(i = 0; i < MAX_POLL; i++)
    391     {
    392         ts[h].ps[i].pfd.fd = -1;
    393         ts[h].psi[i] = -1;
    394     }
    395     init_cmd_fd(h);
    396 }
    397 static inline unsigned int flags2pevents(int flags)
    398 {
    399     unsigned int pevents = 0;
    400     if(flags & SOCK_THREAD_FD_WR)
    401         pevents |= POLLOUT;
    402     if(flags & SOCK_THREAD_FD_RD)
    403         pevents |= POLLIN;
    404     pevents |= POLL_EXCEPTION_EVENTS;
    405     return pevents;
    406 }
    407 
    408 static inline void set_poll(poll_slot_t* ps, int fd, int type, int flags, uint32_t user_id)
    409 {
    410     ps->pfd.fd = fd;
    411     ps->user_id = user_id;
    412     if(ps->type != 0 && ps->type != type)
    413         APPL_TRACE_ERROR("poll socket type should not changed! type was:%d, type now:%d", ps->type, type);
    414     ps->type = type;
    415     ps->flags = flags;
    416     ps->pfd.events = flags2pevents(flags);
    417     ps->pfd.revents = 0;
    418 }
    419 static inline void add_poll(int h, int fd, int type, int flags, uint32_t user_id)
    420 {
    421     asrt(fd != -1);
    422     int i;
    423     int empty = -1;
    424     poll_slot_t* ps = ts[h].ps;
    425 
    426     for(i = 0; i < MAX_POLL; i++)
    427     {
    428         if(ps[i].pfd.fd == fd)
    429         {
    430             asrt(ts[h].poll_count < MAX_POLL);
    431 
    432             set_poll(&ps[i], fd, type, flags | ps[i].flags, user_id);
    433             return;
    434         }
    435         else if(empty < 0 && ps[i].pfd.fd == -1)
    436             empty = i;
    437     }
    438     if(empty >= 0)
    439     {
    440         asrt(ts[h].poll_count < MAX_POLL);
    441         set_poll(&ps[empty], fd, type, flags, user_id);
    442         ++ts[h].poll_count;
    443         return;
    444     }
    445     APPL_TRACE_ERROR("exceeded max poll slot:%d!", MAX_POLL);
    446 }
    447 static inline void remove_poll(int h, poll_slot_t* ps, int flags)
    448 {
    449     if(flags == ps->flags)
    450     {
    451         //all monitored events signaled. To remove it, just clear the slot
    452         --ts[h].poll_count;
    453         memset(ps, 0, sizeof(*ps));
    454         ps->pfd.fd = -1;
    455     }
    456     else
    457     {
    458         //one read or one write monitor event signaled, removed the accordding bit
    459         ps->flags &= ~flags;
    460         //update the poll events mask
    461         ps->pfd.events = flags2pevents(ps->flags);
    462     }
    463 }
    464 static int process_cmd_sock(int h)
    465 {
    466     sock_cmd_t cmd = {-1, 0, 0, 0, 0};
    467     int fd = ts[h].cmd_fdr;
    468     if(recv(fd, &cmd, sizeof(cmd), MSG_WAITALL) != sizeof(cmd))
    469     {
    470         APPL_TRACE_ERROR("recv cmd errno:%d", errno);
    471         return FALSE;
    472     }
    473     APPL_TRACE_DEBUG("cmd.id:%d", cmd.id);
    474     switch(cmd.id)
    475     {
    476         case CMD_ADD_FD:
    477             add_poll(h, cmd.fd, cmd.type, cmd.flags, cmd.user_id);
    478             break;
    479         case CMD_WAKEUP:
    480             break;
    481         case CMD_USER_PRIVATE:
    482             asrt(ts[h].cmd_callback);
    483             if(ts[h].cmd_callback)
    484                 ts[h].cmd_callback(fd, cmd.type, cmd.flags, cmd.user_id);
    485             break;
    486         case CMD_EXIT:
    487             return FALSE;
    488         default:
    489             APPL_TRACE_DEBUG("unknown cmd: %d", cmd.id);
    490              break;
    491     }
    492     return TRUE;
    493 }
    494 static void process_data_sock(int h, struct pollfd *pfds, int count)
    495 {
    496     asrt(count <= ts[h].poll_count);
    497     int i;
    498     for( i= 1; i < ts[h].poll_count; i++)
    499     {
    500         if(pfds[i].revents)
    501         {
    502             int ps_i = ts[h].psi[i];
    503             asrt(pfds[i].fd == ts[h].ps[ps_i].pfd.fd);
    504             uint32_t user_id = ts[h].ps[ps_i].user_id;
    505             int type = ts[h].ps[ps_i].type;
    506             int flags = 0;
    507             print_events(pfds[i].revents);
    508             if(IS_READ(pfds[i].revents))
    509             {
    510                 flags |= SOCK_THREAD_FD_RD;
    511             }
    512             if(IS_WRITE(pfds[i].revents))
    513             {
    514                 flags |= SOCK_THREAD_FD_WR;
    515             }
    516             if(IS_EXCEPTION(pfds[i].revents))
    517             {
    518                 flags |= SOCK_THREAD_FD_EXCEPTION;
    519                 //remove the whole slot not flags
    520                 remove_poll(h, &ts[h].ps[ps_i], ts[h].ps[ps_i].flags);
    521             }
    522             else if(flags)
    523                  remove_poll(h, &ts[h].ps[ps_i], flags); //remove the monitor flags that already processed
    524             if(flags)
    525                 ts[h].callback(pfds[i].fd, type, flags, user_id);
    526         }
    527     }
    528 }
    529 
    530 static void prepare_poll_fds(int h, struct pollfd* pfds)
    531 {
    532     int count = 0;
    533     int ps_i = 0;
    534     int pfd_i = 0;
    535     asrt(ts[h].poll_count <= MAX_POLL);
    536     memset(pfds, 0, sizeof(pfds[0])*ts[h].poll_count);
    537     while(count < ts[h].poll_count)
    538     {
    539         if(ps_i >= MAX_POLL)
    540         {
    541             APPL_TRACE_ERROR("exceed max poll range, ps_i:%d, MAX_POLL:%d, count:%d, ts[h].poll_count:%d",
    542                     ps_i, MAX_POLL, count, ts[h].poll_count);
    543             return;
    544         }
    545         if(ts[h].ps[ps_i].pfd.fd >= 0)
    546         {
    547             pfds[pfd_i] =  ts[h].ps[ps_i].pfd;
    548             ts[h].psi[pfd_i] = ps_i;
    549             count++;
    550             pfd_i++;
    551         }
    552         ps_i++;
    553     }
    554 }
    555 static void *sock_poll_thread(void *arg)
    556 {
    557     struct pollfd pfds[MAX_POLL];
    558     memset(pfds, 0, sizeof(pfds));
    559     int h = (intptr_t)arg;
    560     for(;;)
    561     {
    562         prepare_poll_fds(h, pfds);
    563         int ret = poll(pfds, ts[h].poll_count, -1);
    564         if(ret == -1)
    565         {
    566             APPL_TRACE_ERROR("poll ret -1, exit the thread, errno:%d, err:%s", errno, strerror(errno));
    567             break;
    568         }
    569         if(ret != 0)
    570         {
    571             int need_process_data_fd = TRUE;
    572             if(pfds[0].revents) //cmd fd always is the first one
    573             {
    574                 asrt(pfds[0].fd == ts[h].cmd_fdr);
    575                 if(!process_cmd_sock(h))
    576                 {
    577                     APPL_TRACE_DEBUG("h:%d, process_cmd_sock return false, exit...", h);
    578                     break;
    579                 }
    580                 if(ret == 1)
    581                     need_process_data_fd = FALSE;
    582                 else ret--; //exclude the cmd fd
    583             }
    584             if(need_process_data_fd)
    585                 process_data_sock(h, pfds, ret);
    586         }
    587         else {APPL_TRACE_DEBUG("no data, select ret: %d", ret)};
    588     }
    589     ts[h].thread_id = -1;
    590     APPL_TRACE_DEBUG("socket poll thread exiting, h:%d", h);
    591     return 0;
    592 }
    593 
    594