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
set_socket_blocking(int s,int blocking)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
create_server_socket(const char * name)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 }
connect_server_socket(const char * name)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 }
accept_server_socket(int s)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 }
create_thread(void * (* start_routine)(void *),void * arg)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);
alloc_thread_slot()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 }
free_thread_slot(int h)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 }
btsock_thread_init()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 }
btsock_thread_create(btsock_signaled_cb callback,btsock_cmd_cb cmd_callback)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 */
init_cmd_fd(int h)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 }
close_cmd_fd(int h)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;
btsock_thread_add_fd(int h,int fd,int type,int flags,uint32_t user_id)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 }
btsock_thread_post_cmd(int h,int type,const unsigned char * data,int size,uint32_t user_id)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 }
btsock_thread_wakeup(int h)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 }
btsock_thread_exit(int h)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 }
init_poll(int h)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 }
flags2pevents(int flags)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
set_poll(poll_slot_t * ps,int fd,int type,int flags,uint32_t user_id)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 }
add_poll(int h,int fd,int type,int flags,uint32_t user_id)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 }
remove_poll(int h,poll_slot_t * ps,int flags)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 }
process_cmd_sock(int h)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 }
process_data_sock(int h,struct pollfd * pfds,int count)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
prepare_poll_fds(int h,struct pollfd * pfds)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 }
sock_poll_thread(void * arg)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