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_ERROR3("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__) 64#define print_events(events) do { \ 65 APPL_TRACE_DEBUG1("print poll event:%x", events); \ 66 if (events & POLLIN) APPL_TRACE_DEBUG0( " POLLIN "); \ 67 if (events & POLLPRI) APPL_TRACE_DEBUG0( " POLLPRI "); \ 68 if (events & POLLOUT) APPL_TRACE_DEBUG0( " POLLOUT "); \ 69 if (events & POLLERR) APPL_TRACE_DEBUG0( " POLLERR "); \ 70 if (events & POLLHUP) APPL_TRACE_DEBUG0( " POLLHUP "); \ 71 if (events & POLLNVAL) APPL_TRACE_DEBUG0(" POLLNVAL "); \ 72 if (events & POLLRDHUP) APPL_TRACE_DEBUG0(" 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 87typedef struct { 88 struct pollfd pfd; 89 uint32_t user_id; 90 int type; 91 int flags; 92} poll_slot_t; 93typedef 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; 103static thread_slot_t ts[MAX_THREAD]; 104 105 106 107static void *sock_poll_thread(void *arg); 108static inline void close_cmd_fd(int h); 109 110static inline void add_poll(int h, int fd, int type, int flags, uint32_t user_id); 111 112static pthread_mutex_t thread_slot_lock; 113 114 115static 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_ERROR1("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 126static inline int create_server_socket(const char* name) 127{ 128 int s = socket(AF_LOCAL, SOCK_STREAM, 0); 129 APPL_TRACE_DEBUG1("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_DEBUG2("listen to local socket:%s, fd:%d", name, s); 135 return s; 136 } 137 else APPL_TRACE_ERROR3("listen to local socket:%s, fd:%d failed, errno:%d", name, s, errno); 138 } 139 else APPL_TRACE_ERROR3("create local socket:%s fd:%d, failed, errno:%d", name, s, errno); 140 close(s); 141 return -1; 142} 143static 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_DEBUG2("connected to local socket:%s, fd:%d", name, s); 150 return s; 151 } 152 else APPL_TRACE_ERROR3("connect to local socket:%s, fd:%d failed, errno:%d", name, s, errno); 153 close(s); 154 return -1; 155} 156static 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_DEBUG2("accepted fd:%d for server fd:%d", fd, s); 162 return fd; 163} 164static 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_ERROR1("pthread_create : %s", strerror(errno)); 173 return -1; 174 } 175 return thread_id; 176} 177static void init_poll(int cmd_fd); 178static 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_DEBUG2("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_ERROR0("execeeded max thread count"); 192 return -1; 193} 194static 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_ERROR1("invalid thread handle:%d", h); 202} 203int btsock_thread_init() 204{ 205 static int initialized; 206 APPL_TRACE_DEBUG1("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} 224int 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_DEBUG1("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*)h)) != -1) 236 { 237 APPL_TRACE_DEBUG2("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 */ 251static 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_ERROR1("socketpair failed: %s", strerror(errno)); 257 return; 258 } 259 APPL_TRACE_DEBUG3("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} 263static 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} 276typedef struct 277{ 278 int id; 279 int fd; 280 int type; 281 int flags; 282 uint32_t user_id; 283} sock_cmd_t; 284int 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_ERROR1("invalid bt thread handle:%d", h); 289 return FALSE; 290 } 291 if(ts[h].cmd_fdw == -1) 292 { 293 APPL_TRACE_ERROR0("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_DEBUG0("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_DEBUG2("adding fd:%d, flags:0x%x", fd, flags); 310 return send(ts[h].cmd_fdw, &cmd, sizeof(cmd), 0) == sizeof(cmd); 311} 312int 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_ERROR1("invalid bt thread handle:%d", h); 317 return FALSE; 318 } 319 if(ts[h].cmd_fdw == -1) 320 { 321 APPL_TRACE_ERROR0("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_DEBUG3("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_ERROR3("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} 345int btsock_thread_wakeup(int h) 346{ 347 if(h < 0 || h >= MAX_THREAD) 348 { 349 APPL_TRACE_ERROR1("invalid bt thread handle:%d", h); 350 return FALSE; 351 } 352 if(ts[h].cmd_fdw == -1) 353 { 354 APPL_TRACE_ERROR1("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} 360int btsock_thread_exit(int h) 361{ 362 if(h < 0 || h >= MAX_THREAD) 363 { 364 APPL_TRACE_ERROR1("invalid bt thread handle:%d", h); 365 return FALSE; 366 } 367 if(ts[h].cmd_fdw == -1) 368 { 369 APPL_TRACE_ERROR0("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} 383static 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} 397static 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 408static 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_ERROR2("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} 419static 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_ERROR1("exceeded max poll slot:%d!", MAX_POLL); 446} 447static 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} 464static 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_ERROR1("recv cmd errno:%d", errno); 471 return FALSE; 472 } 473 APPL_TRACE_DEBUG1("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_DEBUG1("unknown cmd: %d", cmd.id); 490 break; 491 } 492 return TRUE; 493} 494static 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 530static 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_ERROR4("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} 555static void *sock_poll_thread(void *arg) 556{ 557 struct pollfd pfds[MAX_POLL]; 558 memset(pfds, 0, sizeof(pfds)); 559 int h = (int)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_ERROR2("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_DEBUG1("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_DEBUG1("no data, select ret: %d", ret)}; 588 } 589 ts[h].thread_id = -1; 590 APPL_TRACE_DEBUG1("socket poll thread exiting, h:%d", h); 591 return 0; 592} 593 594