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