• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 **     http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16 
17 #define LOG_TAG "BluetoothAudioGateway.cpp"
18 
19 #include "android_bluetooth_common.h"
20 #include "android_runtime/AndroidRuntime.h"
21 #include "JNIHelp.h"
22 #include "jni.h"
23 #include "utils/Log.h"
24 #include "utils/misc.h"
25 
26 #define USE_ACCEPT_DIRECTLY (0)
27 #define USE_SELECT (0) /* 1 for select(), 0 for poll(); used only when
28                           USE_ACCEPT_DIRECTLY == 0 */
29 
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <errno.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <sys/socket.h>
37 #include <sys/time.h>
38 #include <sys/types.h>
39 #include <unistd.h>
40 #include <fcntl.h>
41 #include <sys/uio.h>
42 #include <ctype.h>
43 
44 #if USE_SELECT
45 #include <sys/select.h>
46 #else
47 #include <sys/poll.h>
48 #endif
49 
50 #ifdef HAVE_BLUETOOTH
51 #include <bluetooth/bluetooth.h>
52 #include <bluetooth/rfcomm.h>
53 #include <bluetooth/sco.h>
54 #endif
55 
56 namespace android {
57 
58 #ifdef HAVE_BLUETOOTH
59 static jfieldID field_mNativeData;
60     /* in */
61 static jfieldID field_mHandsfreeAgRfcommChannel;
62 static jfieldID field_mHeadsetAgRfcommChannel;
63     /* out */
64 static jfieldID field_mTimeoutRemainingMs; /* out */
65 
66 static jfieldID field_mConnectingHeadsetAddress;
67 static jfieldID field_mConnectingHeadsetRfcommChannel; /* -1 when not connected */
68 static jfieldID field_mConnectingHeadsetSocketFd;
69 
70 static jfieldID field_mConnectingHandsfreeAddress;
71 static jfieldID field_mConnectingHandsfreeRfcommChannel; /* -1 when not connected */
72 static jfieldID field_mConnectingHandsfreeSocketFd;
73 
74 
75 typedef struct {
76     int hcidev;
77     int hf_ag_rfcomm_channel;
78     int hs_ag_rfcomm_channel;
79     int hf_ag_rfcomm_sock;
80     int hs_ag_rfcomm_sock;
81 } native_data_t;
82 
get_native_data(JNIEnv * env,jobject object)83 static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
84     return (native_data_t *)(env->GetIntField(object,
85                                                  field_mNativeData));
86 }
87 
88 static int setup_listening_socket(int dev, int channel);
89 #endif
90 
classInitNative(JNIEnv * env,jclass clazz)91 static void classInitNative(JNIEnv* env, jclass clazz) {
92     LOGV(__FUNCTION__);
93 #ifdef HAVE_BLUETOOTH
94 
95     /* in */
96     field_mNativeData = get_field(env, clazz, "mNativeData", "I");
97     field_mHandsfreeAgRfcommChannel =
98         get_field(env, clazz, "mHandsfreeAgRfcommChannel", "I");
99     field_mHeadsetAgRfcommChannel =
100         get_field(env, clazz, "mHeadsetAgRfcommChannel", "I");
101 
102     /* out */
103     field_mConnectingHeadsetAddress =
104         get_field(env, clazz,
105                   "mConnectingHeadsetAddress", "Ljava/lang/String;");
106     field_mConnectingHeadsetRfcommChannel =
107         get_field(env, clazz, "mConnectingHeadsetRfcommChannel", "I");
108     field_mConnectingHeadsetSocketFd =
109         get_field(env, clazz, "mConnectingHeadsetSocketFd", "I");
110 
111     field_mConnectingHandsfreeAddress =
112         get_field(env, clazz,
113                   "mConnectingHandsfreeAddress", "Ljava/lang/String;");
114     field_mConnectingHandsfreeRfcommChannel =
115         get_field(env, clazz, "mConnectingHandsfreeRfcommChannel", "I");
116     field_mConnectingHandsfreeSocketFd =
117         get_field(env, clazz, "mConnectingHandsfreeSocketFd", "I");
118 
119     field_mTimeoutRemainingMs =
120         get_field(env, clazz, "mTimeoutRemainingMs", "I");
121 #endif
122 }
123 
initializeNativeDataNative(JNIEnv * env,jobject object)124 static void initializeNativeDataNative(JNIEnv* env, jobject object) {
125     LOGV(__FUNCTION__);
126 #ifdef HAVE_BLUETOOTH
127     native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
128     if (NULL == nat) {
129         LOGE("%s: out of memory!", __FUNCTION__);
130         return;
131     }
132 
133     nat->hcidev = BLUETOOTH_ADAPTER_HCI_NUM;
134 
135     env->SetIntField(object, field_mNativeData, (jint)nat);
136     nat->hf_ag_rfcomm_channel =
137         env->GetIntField(object, field_mHandsfreeAgRfcommChannel);
138     nat->hs_ag_rfcomm_channel =
139         env->GetIntField(object, field_mHeadsetAgRfcommChannel);
140     LOGV("HF RFCOMM channel = %d.", nat->hf_ag_rfcomm_channel);
141     LOGV("HS RFCOMM channel = %d.", nat->hs_ag_rfcomm_channel);
142 
143     /* Set the default values of these to -1. */
144     env->SetIntField(object, field_mConnectingHeadsetRfcommChannel, -1);
145     env->SetIntField(object, field_mConnectingHandsfreeRfcommChannel, -1);
146 
147     nat->hf_ag_rfcomm_sock = -1;
148     nat->hs_ag_rfcomm_sock = -1;
149 #endif
150 }
151 
cleanupNativeDataNative(JNIEnv * env,jobject object)152 static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
153     LOGV(__FUNCTION__);
154 #ifdef HAVE_BLUETOOTH
155     native_data_t *nat = get_native_data(env, object);
156     if (nat) {
157         free(nat);
158     }
159 #endif
160 }
161 
162 #ifdef HAVE_BLUETOOTH
163 
164 #if USE_ACCEPT_DIRECTLY==0
set_nb(int sk,bool nb)165 static int set_nb(int sk, bool nb) {
166     int flags = fcntl(sk, F_GETFL);
167     if (flags < 0) {
168         LOGE("Can't get socket flags with fcntl(): %s (%d)",
169              strerror(errno), errno);
170         close(sk);
171         return -1;
172     }
173     flags &= ~O_NONBLOCK;
174     if (nb) flags |= O_NONBLOCK;
175     int status = fcntl(sk, F_SETFL, flags);
176     if (status < 0) {
177         LOGE("Can't set socket to nonblocking mode with fcntl(): %s (%d)",
178              strerror(errno), errno);
179         close(sk);
180         return -1;
181     }
182     return 0;
183 }
184 #endif /*USE_ACCEPT_DIRECTLY==0*/
185 
do_accept(JNIEnv * env,jobject object,int ag_fd,jfieldID out_fd,jfieldID out_address,jfieldID out_channel)186 static int do_accept(JNIEnv* env, jobject object, int ag_fd,
187                      jfieldID out_fd,
188                      jfieldID out_address,
189                      jfieldID out_channel) {
190 
191 #if USE_ACCEPT_DIRECTLY==0
192     if (set_nb(ag_fd, true) < 0)
193         return -1;
194 #endif
195 
196     struct sockaddr_rc raddr;
197     int alen = sizeof(raddr);
198     int nsk = accept(ag_fd, (struct sockaddr *) &raddr, &alen);
199     if (nsk < 0) {
200         LOGE("Error on accept from socket fd %d: %s (%d).",
201              ag_fd,
202              strerror(errno),
203              errno);
204 #if USE_ACCEPT_DIRECTLY==0
205         set_nb(ag_fd, false);
206 #endif
207         return -1;
208     }
209 
210     env->SetIntField(object, out_fd, nsk);
211     env->SetIntField(object, out_channel, raddr.rc_channel);
212 
213     char addr[BTADDR_SIZE];
214     get_bdaddr_as_string(&raddr.rc_bdaddr, addr);
215     env->SetObjectField(object, out_address, env->NewStringUTF(addr));
216 
217     LOGI("Successful accept() on AG socket %d: new socket %d, address %s, RFCOMM channel %d",
218          ag_fd,
219          nsk,
220          addr,
221          raddr.rc_channel);
222 #if USE_ACCEPT_DIRECTLY==0
223     set_nb(ag_fd, false);
224 #endif
225     return 0;
226 }
227 
228 #if USE_SELECT
on_accept_set_fields(JNIEnv * env,jobject object,fd_set * rset,int ag_fd,jfieldID out_fd,jfieldID out_address,jfieldID out_channel)229 static inline int on_accept_set_fields(JNIEnv* env, jobject object,
230                                        fd_set *rset, int ag_fd,
231                                        jfieldID out_fd,
232                                        jfieldID out_address,
233                                        jfieldID out_channel) {
234 
235     env->SetIntField(object, out_channel, -1);
236 
237     if (ag_fd >= 0 && FD_ISSET(ag_fd, &rset)) {
238         return do_accept(env, object, ag_fd,
239                          out_fd, out_address, out_channel);
240     }
241     else {
242         LOGI("fd = %d, FD_ISSET() = %d",
243              ag_fd,
244              FD_ISSET(ag_fd, &rset));
245         if (ag_fd >= 0 && !FD_ISSET(ag_fd, &rset)) {
246             LOGE("WTF???");
247             return -1;
248         }
249     }
250 
251     return 0;
252 }
253 #endif
254 #endif /* HAVE_BLUETOOTH */
255 
waitForHandsfreeConnectNative(JNIEnv * env,jobject object,jint timeout_ms)256 static jboolean waitForHandsfreeConnectNative(JNIEnv* env, jobject object,
257                                               jint timeout_ms) {
258 //    LOGV(__FUNCTION__);
259 #ifdef HAVE_BLUETOOTH
260 
261     env->SetIntField(object, field_mTimeoutRemainingMs, timeout_ms);
262 
263     int n = 0;
264     native_data_t *nat = get_native_data(env, object);
265 #if USE_ACCEPT_DIRECTLY
266     if (nat->hf_ag_rfcomm_channel > 0) {
267         LOGI("Setting HF AG server socket to RFCOMM port %d!",
268              nat->hf_ag_rfcomm_channel);
269         struct timeval tv;
270         int len = sizeof(tv);
271         if (getsockopt(nat->hf_ag_rfcomm_channel,
272                        SOL_SOCKET, SO_RCVTIMEO, &tv, &len) < 0) {
273             LOGE("getsockopt(%d, SOL_SOCKET, SO_RCVTIMEO): %s (%d)",
274                  nat->hf_ag_rfcomm_channel,
275                  strerror(errno),
276                  errno);
277             return JNI_FALSE;
278         }
279         LOGI("Current HF AG server socket RCVTIMEO is (%d(s), %d(us))!",
280              (int)tv.tv_sec, (int)tv.tv_usec);
281         if (timeout_ms >= 0) {
282             tv.tv_sec = timeout_ms / 1000;
283             tv.tv_usec = 1000 * (timeout_ms % 1000);
284             if (setsockopt(nat->hf_ag_rfcomm_channel,
285                            SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
286                 LOGE("setsockopt(%d, SOL_SOCKET, SO_RCVTIMEO): %s (%d)",
287                      nat->hf_ag_rfcomm_channel,
288                      strerror(errno),
289                      errno);
290                 return JNI_FALSE;
291             }
292             LOGI("Changed HF AG server socket RCVTIMEO to (%d(s), %d(us))!",
293                  (int)tv.tv_sec, (int)tv.tv_usec);
294         }
295 
296         if (!do_accept(env, object, nat->hf_ag_rfcomm_sock,
297                        field_mConnectingHandsfreeSocketFd,
298                        field_mConnectingHandsfreeAddress,
299                        field_mConnectingHandsfreeRfcommChannel))
300         {
301             env->SetIntField(object, field_mTimeoutRemainingMs, 0);
302             return JNI_TRUE;
303         }
304         return JNI_FALSE;
305     }
306 #else
307 #if USE_SELECT
308     fd_set rset;
309     FD_ZERO(&rset);
310     int cnt = 0;
311     if (nat->hf_ag_rfcomm_channel > 0) {
312         LOGI("Setting HF AG server socket to RFCOMM port %d!",
313              nat->hf_ag_rfcomm_channel);
314         cnt++;
315         FD_SET(nat->hf_ag_rfcomm_sock, &rset);
316     }
317     if (nat->hs_ag_rfcomm_channel > 0) {
318         LOGI("Setting HS AG server socket to RFCOMM port %d!",
319              nat->hs_ag_rfcomm_channel);
320         cnt++;
321         FD_SET(nat->hs_ag_rfcomm_sock, &rset);
322     }
323     if (cnt == 0) {
324         LOGE("Neither HF nor HS listening sockets are open!");
325         return JNI_FALSE;
326     }
327 
328     struct timeval to;
329     if (timeout_ms >= 0) {
330         to.tv_sec = timeout_ms / 1000;
331         to.tv_usec = 1000 * (timeout_ms % 1000);
332     }
333     n = select(MAX(nat->hf_ag_rfcomm_sock,
334                        nat->hs_ag_rfcomm_sock) + 1,
335                    &rset,
336                    NULL,
337                    NULL,
338                    (timeout_ms < 0 ? NULL : &to));
339     if (timeout_ms > 0) {
340         jint remaining = to.tv_sec*1000 + to.tv_usec/1000;
341         LOGI("Remaining time %ldms", (long)remaining);
342         env->SetIntField(object, field_mTimeoutRemainingMs,
343                          remaining);
344     }
345 
346     LOGI("listening select() returned %d", n);
347 
348     if (n <= 0) {
349         if (n < 0)  {
350             LOGE("listening select() on RFCOMM sockets: %s (%d)",
351                  strerror(errno),
352                  errno);
353         }
354         return JNI_FALSE;
355     }
356 
357     n = on_accept_set_fields(env, object,
358                              &rset, nat->hf_ag_rfcomm_sock,
359                              field_mConnectingHandsfreeSocketFd,
360                              field_mConnectingHandsfreeAddress,
361                              field_mConnectingHandsfreeRfcommChannel);
362 
363     n += on_accept_set_fields(env, object,
364                               &rset, nat->hs_ag_rfcomm_sock,
365                               field_mConnectingHeadsetSocketFd,
366                               field_mConnectingHeadsetAddress,
367                               field_mConnectingHeadsetRfcommChannel);
368 
369     return !n ? JNI_TRUE : JNI_FALSE;
370 #else
371     struct pollfd fds[2];
372     int cnt = 0;
373     if (nat->hf_ag_rfcomm_channel > 0) {
374 //        LOGI("Setting HF AG server socket %d to RFCOMM port %d!",
375 //             nat->hf_ag_rfcomm_sock,
376 //             nat->hf_ag_rfcomm_channel);
377         fds[cnt].fd = nat->hf_ag_rfcomm_sock;
378         fds[cnt].events = POLLIN | POLLPRI | POLLOUT | POLLERR;
379         cnt++;
380     }
381     if (nat->hs_ag_rfcomm_channel > 0) {
382 //        LOGI("Setting HS AG server socket %d to RFCOMM port %d!",
383 //             nat->hs_ag_rfcomm_sock,
384 //             nat->hs_ag_rfcomm_channel);
385         fds[cnt].fd = nat->hs_ag_rfcomm_sock;
386         fds[cnt].events = POLLIN | POLLPRI | POLLOUT | POLLERR;
387         cnt++;
388     }
389     if (cnt == 0) {
390         LOGE("Neither HF nor HS listening sockets are open!");
391         return JNI_FALSE;
392     }
393     n = poll(fds, cnt, timeout_ms);
394     if (n <= 0) {
395         if (n < 0)  {
396             LOGE("listening poll() on RFCOMM sockets: %s (%d)",
397                  strerror(errno),
398                  errno);
399         }
400         else {
401             env->SetIntField(object, field_mTimeoutRemainingMs, 0);
402 //            LOGI("listening poll() on RFCOMM socket timed out");
403         }
404         return JNI_FALSE;
405     }
406 
407     //LOGI("listening poll() on RFCOMM socket returned %d", n);
408     int err = 0;
409     for (cnt = 0; cnt < (int)(sizeof(fds)/sizeof(fds[0])); cnt++) {
410         //LOGI("Poll on fd %d revent = %d.", fds[cnt].fd, fds[cnt].revents);
411         if (fds[cnt].fd == nat->hf_ag_rfcomm_sock) {
412             if (fds[cnt].revents & (POLLIN | POLLPRI | POLLOUT)) {
413                 LOGI("Accepting HF connection.\n");
414                 err += do_accept(env, object, fds[cnt].fd,
415                                field_mConnectingHandsfreeSocketFd,
416                                field_mConnectingHandsfreeAddress,
417                                field_mConnectingHandsfreeRfcommChannel);
418                 n--;
419             }
420         }
421         else if (fds[cnt].fd == nat->hs_ag_rfcomm_sock) {
422             if (fds[cnt].revents & (POLLIN | POLLPRI | POLLOUT)) {
423                 LOGI("Accepting HS connection.\n");
424                 err += do_accept(env, object, fds[cnt].fd,
425                                field_mConnectingHeadsetSocketFd,
426                                field_mConnectingHeadsetAddress,
427                                field_mConnectingHeadsetRfcommChannel);
428                 n--;
429             }
430         }
431     } /* for */
432 
433     if (n != 0) {
434         LOGI("Bogus poll(): %d fake pollfd entrie(s)!", n);
435         return JNI_FALSE;
436     }
437 
438     return !err ? JNI_TRUE : JNI_FALSE;
439 #endif /* USE_SELECT */
440 #endif /* USE_ACCEPT_DIRECTLY */
441 #else
442     return JNI_FALSE;
443 #endif /* HAVE_BLUETOOTH */
444 }
445 
setUpListeningSocketsNative(JNIEnv * env,jobject object)446 static jboolean setUpListeningSocketsNative(JNIEnv* env, jobject object) {
447     LOGV(__FUNCTION__);
448 #ifdef HAVE_BLUETOOTH
449     native_data_t *nat = get_native_data(env, object);
450 
451     nat->hf_ag_rfcomm_sock =
452         setup_listening_socket(nat->hcidev, nat->hf_ag_rfcomm_channel);
453     if (nat->hf_ag_rfcomm_sock < 0)
454         return JNI_FALSE;
455 
456     nat->hs_ag_rfcomm_sock =
457         setup_listening_socket(nat->hcidev, nat->hs_ag_rfcomm_channel);
458     if (nat->hs_ag_rfcomm_sock < 0) {
459         close(nat->hf_ag_rfcomm_sock);
460         nat->hf_ag_rfcomm_sock = -1;
461         return JNI_FALSE;
462     }
463 
464     return JNI_TRUE;
465 #else
466     return JNI_FALSE;
467 #endif /* HAVE_BLUETOOTH */
468 }
469 
470 #ifdef HAVE_BLUETOOTH
setup_listening_socket(int dev,int channel)471 static int setup_listening_socket(int dev, int channel) {
472     struct sockaddr_rc laddr;
473     int sk, lm;
474 
475     sk = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
476     if (sk < 0) {
477         LOGE("Can't create RFCOMM socket");
478         return -1;
479     }
480 
481     if (debug_no_encrypt()) {
482         lm = RFCOMM_LM_AUTH;
483     } else {
484         lm = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
485     }
486 
487 	if (lm && setsockopt(sk, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0) {
488 		LOGE("Can't set RFCOMM link mode");
489 		close(sk);
490 		return -1;
491 	}
492 
493     laddr.rc_family = AF_BLUETOOTH;
494     bacpy(&laddr.rc_bdaddr, BDADDR_ANY);
495     laddr.rc_channel = channel;
496 
497 	if (bind(sk, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) {
498 		LOGE("Can't bind RFCOMM socket");
499 		close(sk);
500 		return -1;
501 	}
502 
503     listen(sk, 10);
504     return sk;
505 }
506 #endif /* HAVE_BLUETOOTH */
507 
508 /*
509     private native void tearDownListeningSocketsNative();
510 */
tearDownListeningSocketsNative(JNIEnv * env,jobject object)511 static void tearDownListeningSocketsNative(JNIEnv *env, jobject object) {
512     LOGV(__FUNCTION__);
513 #ifdef HAVE_BLUETOOTH
514     native_data_t *nat = get_native_data(env, object);
515 
516     if (nat->hf_ag_rfcomm_sock > 0) {
517         if (close(nat->hf_ag_rfcomm_sock) < 0) {
518             LOGE("Could not close HF server socket: %s (%d)\n",
519                  strerror(errno), errno);
520         }
521         nat->hf_ag_rfcomm_sock = -1;
522     }
523     if (nat->hs_ag_rfcomm_sock > 0) {
524         if (close(nat->hs_ag_rfcomm_sock) < 0) {
525             LOGE("Could not close HS server socket: %s (%d)\n",
526                  strerror(errno), errno);
527         }
528         nat->hs_ag_rfcomm_sock = -1;
529     }
530 #endif /* HAVE_BLUETOOTH */
531 }
532 
533 static JNINativeMethod sMethods[] = {
534      /* name, signature, funcPtr */
535 
536     {"classInitNative", "()V", (void*)classInitNative},
537     {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
538     {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
539 
540     {"setUpListeningSocketsNative", "()Z", (void *)setUpListeningSocketsNative},
541     {"tearDownListeningSocketsNative", "()V", (void *)tearDownListeningSocketsNative},
542     {"waitForHandsfreeConnectNative", "(I)Z", (void *)waitForHandsfreeConnectNative},
543 };
544 
register_android_bluetooth_BluetoothAudioGateway(JNIEnv * env)545 int register_android_bluetooth_BluetoothAudioGateway(JNIEnv *env) {
546     return AndroidRuntime::registerNativeMethods(env,
547             "android/bluetooth/BluetoothAudioGateway", sMethods,
548             NELEM(sMethods));
549 }
550 
551 } /* namespace android */
552