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